From a7b985f6b6c412b772015d8805ebc2d9462d9e0f Mon Sep 17 00:00:00 2001 From: Moriel Schottlender Date: Fri, 3 Mar 2017 12:46:22 -0800 Subject: [PATCH] RCFilters UI, Followup I97a45208: Replace the entire fieldset Instead of replacing pieces of the fieldset, replace the entire thing whenever results are requested (whether there are results or not) Bug: T159582 Change-Id: I962ad8f44eb9431e86239bbe3cb3a852227dec17 --- .../mw.rcfilters.Controller.js | 1 - .../mediawiki.rcfilters/mw.rcfilters.init.js | 48 +------- .../ui/mw.rcfilters.ui.FormWrapperWidget.js | 113 ++++++++++-------- 3 files changed, 67 insertions(+), 95 deletions(-) diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js index c0f453ca59..5a68428058 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js @@ -211,7 +211,6 @@ function ( pieces ) { var $changesListContent = pieces.changes, $fieldset = pieces.fieldset; - this.changesListModel.update( $changesListContent, $fieldset ); }.bind( this ) // Do nothing for failure diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js index 746907bb7e..089b10609e 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js @@ -17,14 +17,12 @@ filtersWidget = new mw.rcfilters.ui.FilterWrapperWidget( controller, filtersModel, { $overlay: $overlay } ); + // TODO: The changesListWrapperWidget should be able to initialize + // after the model is ready. // eslint-disable-next-line no-new new mw.rcfilters.ui.ChangesListWrapperWidget( filtersModel, changesListModel, $( '.mw-changeslist, .mw-changeslist-empty' ) ); - // eslint-disable-next-line no-new - new mw.rcfilters.ui.FormWrapperWidget( - changesListModel, controller, $( 'fieldset.rcoptions' ) ); - controller.initialize( { registration: { title: mw.msg( 'rcfilters-filtergroup-registration' ), @@ -184,47 +182,13 @@ } } ); + // eslint-disable-next-line no-new + new mw.rcfilters.ui.FormWrapperWidget( + filtersModel, changesListModel, controller, $( 'fieldset.rcoptions' ) ); + $( '.rcfilters-container' ).append( filtersWidget.$element ); $( 'body' ).append( $overlay ); - // HACK: Remove old-style filter links for filters handled by the widget - // Ideally the widget would handle all filters and we'd just remove .rcshowhide entirely - $( '.rcshowhide' ).children().each( function () { - // HACK: Interpret the class name to get the filter name - // This should really be set as a data attribute - var i, - name = null, - // Some of the older browsers we support don't have .classList, - // so we have to interpret the class attribute manually. - classes = this.getAttribute( 'class' ).split( ' ' ); - for ( i = 0; i < classes.length; i++ ) { - if ( classes[ i ].substr( 0, 'rcshow'.length ) === 'rcshow' ) { - name = classes[ i ].substr( 'rcshow'.length ); - break; - } - } - if ( name === null ) { - return; - } - if ( name === 'hidemine' ) { - // HACK: the span for hidemyself is called hidemine - name = 'hidemyself'; - } - // This span corresponds to a filter that's in our model, so remove it - 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. - if ( this.nextSibling && this.nextSibling.nodeType === Node.TEXT_NODE ) { - this.parentNode.removeChild( this.nextSibling ); - } else if ( this.previousSibling && this.previousSibling.nodeType === Node.TEXT_NODE ) { - this.parentNode.removeChild( this.previousSibling ); - } - // Remove the span itself - this.parentNode.removeChild( this ); - } - } ); - window.addEventListener( 'popstate', function () { controller.updateChangesList(); } ); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js index 3c81ff1e80..51311e1695 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js @@ -1,16 +1,18 @@ ( function ( mw ) { /** * Wrapper for the RC form with hide/show links + * Must be constructed after the model is initialized. * * @extends OO.ui.Widget * * @constructor - * @param {mw.rcfilters.dm.ChangesListViewModel} model Changes list view model + * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Changes list view model + * @param {mw.rcfilters.dm.ChangesListViewModel} changeListModel Changes list view model * @param {mw.rcfilters.Controller} controller RCfilters controller * @param {jQuery} $formRoot Root element of the form to attach to * @param {Object} config Configuration object */ - mw.rcfilters.ui.FormWrapperWidget = function MwRcfiltersUiFormWrapperWidget( model, controller, $formRoot, config ) { + mw.rcfilters.ui.FormWrapperWidget = function MwRcfiltersUiFormWrapperWidget( filtersModel, changeListModel, controller, $formRoot, config ) { config = config || {}; // Parent @@ -20,7 +22,8 @@ // Mixin constructors OO.ui.mixin.PendingElement.call( this, config ); - this.model = model; + this.changeListModel = changeListModel; + this.filtersModel = filtersModel; this.controller = controller; this.$submitButton = this.$element.find( 'form input[type=submit]' ); @@ -31,13 +34,13 @@ .on( 'submit', 'form', this.onFormSubmit.bind( this ) ); // Events - this.model.connect( this, { - invalidate: 'onModelInvalidate', - update: 'onModelUpdate' + this.changeListModel.connect( this, { + invalidate: 'onChangesModelInvalidate', + update: 'onChangesModelUpdate' } ); // Initialize - this.cleanupForm(); + this.cleanUpFieldset(); this.$element .addClass( 'mw-rcfilters-ui-FormWrapperWidget' ) .addClass( 'mw-rcfilters-ui-ready' ); @@ -48,21 +51,6 @@ OO.inheritClass( mw.rcfilters.ui.FormWrapperWidget, OO.ui.Widget ); OO.mixinClass( mw.rcfilters.ui.FormWrapperWidget, OO.ui.mixin.PendingElement ); - /** - * Clean up the base form we're getting from the back-end. - * Remove tags and replace those with classes, so - * we can toggle those on click. - */ - mw.rcfilters.ui.FormWrapperWidget.prototype.cleanupForm = function () { - this.$element.find( '[data-keys] strong' ).each( function () { - $( this ) - .parent().addClass( 'mw-rcfilters-staticfilters-selected' ); - - $( this ) - .replaceWith( $( this ).contents() ); - } ); - }; - /** * Respond to link click * @@ -70,22 +58,7 @@ * @return {boolean} false */ mw.rcfilters.ui.FormWrapperWidget.prototype.onLinkClick = function ( e ) { - var $element = $( e.target ), - data = $element.data( 'params' ), - keys = $element.data( 'keys' ), - $similarElements = $element.parent().find( '[data-keys="' + keys + '"]' ); - - // Only highlight choice if this link isn't a show/hide link - if ( !$element.parents( '.rcshowhideoption' ).length ) { - // Remove the class from similar elements - $similarElements.removeClass( 'mw-rcfilters-staticfilters-selected' ); - // Add the class to this element - $element.addClass( 'mw-rcfilters-staticfilters-selected' ); - } - - e.stopPropagation(); - - this.controller.updateChangesList( data ); + this.controller.updateChangesList( $( e.target ).data( 'params' ) ); return false; }; @@ -112,7 +85,7 @@ /** * Respond to model invalidate */ - mw.rcfilters.ui.FormWrapperWidget.prototype.onModelInvalidate = function () { + mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelInvalidate = function () { this.pushPending(); this.$submitButton.prop( 'disabled', true ); }; @@ -124,24 +97,60 @@ * @param {jQuery|string} $changesList Updated changes list * @param {jQuery} $fieldset Updated fieldset */ - mw.rcfilters.ui.FormWrapperWidget.prototype.onModelUpdate = function ( $changesList, $fieldset ) { + mw.rcfilters.ui.FormWrapperWidget.prototype.onChangesModelUpdate = function ( $changesList, $fieldset ) { this.$submitButton.prop( 'disabled', false ); - // Replace the links we have in the content - // We don't want to replace the entire thing, because there is a big difference between - // the links in the backend and the links we have initialized, since we are removing - // the ones that are implemented in the new system + // Replace the entire fieldset + this.$element.empty().append( $fieldset.contents() ); + + this.cleanUpFieldset(); + + this.popPending(); + }; + + /** + * Clean up the old-style show/hide that we have implemented in the filter list + */ + mw.rcfilters.ui.FormWrapperWidget.prototype.cleanUpFieldset = function () { + var widget = this; + + // HACK: Remove old-style filter links for filters handled by the widget + // Ideally the widget would handle all filters and we'd just remove .rcshowhide entirely this.$element.find( '.rcshowhide' ).children().each( function () { - // Go over existing links and replace only them - var classes = $( this ).attr( 'class' ).split( ' ' ), - // Look for that item in the fieldset from the server - $remoteItem = $fieldset.find( '.' + classes.join( '.' ) ); + // HACK: Interpret the class name to get the filter name + // This should really be set as a data attribute + var i, + name = null, + // Some of the older browsers we support don't have .classList, + // so we have to interpret the class attribute manually. + classes = this.getAttribute( 'class' ).split( ' ' ); + for ( i = 0; i < classes.length; i++ ) { + if ( classes[ i ].substr( 0, 'rcshow'.length ) === 'rcshow' ) { + name = classes[ i ].substr( 'rcshow'.length ); + break; + } + } + if ( name === null ) { + return; + } + if ( name === 'hidemine' ) { + // HACK: the span for hidemyself is called hidemine + name = 'hidemyself'; + } - if ( $remoteItem ) { - $( this ).replaceWith( $remoteItem ); + // This span corresponds to a filter that's in our model, so remove it + if ( widget.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. + if ( this.nextSibling && this.nextSibling.nodeType === Node.TEXT_NODE ) { + this.parentNode.removeChild( this.nextSibling ); + } else if ( this.previousSibling && this.previousSibling.nodeType === Node.TEXT_NODE ) { + this.parentNode.removeChild( this.previousSibling ); + } + // Remove the span itself + this.parentNode.removeChild( this ); } } ); - - this.popPending(); }; }( mediaWiki ) ); -- 2.20.1