Sbisson has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/378103 )
Change subject: [WIP] RCLFilters: convert related changes tool to new UX ...................................................................... [WIP] RCLFilters: convert related changes tool to new UX Bug: T172161 Change-Id: I96af7ba583d03e6ff9833ac3b5f4b80cfd0ee626 --- M languages/i18n/en.json M languages/i18n/qqq.json M resources/Resources.php M resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js M resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js M resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ItemModel.js M resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js M resources/src/mediawiki.rcfilters/mw.rcfilters.init.js A resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less A resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less A resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTopSectionWidget.less M resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js A resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js A resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclToOrFromWidget.js A resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTopSectionWidget.js 15 files changed, 374 insertions(+), 17 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/03/378103/1 diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 1a0f6a6..4eaa3bf 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1475,6 +1475,11 @@ "rcfilters-watchlist-showupdated": "Changes to pages you haven't visited since the changes occurred are in <strong>bold</strong>, with solid markers.", "rcfilters-preference-label": "Hide the improved version of Recent Changes", "rcfilters-preference-help": "Rolls back the 2017 interface redesign and all tools added then and since.", + "rcfilters-filter-showlinkedfrom-label": "Show changes on pages linked from:", + "rcfilters-filter-showlinkedfrom-option-label": "Show changes on pages linked FROM a page", + "rcfilters-filter-showlinkedto-label": "Show changes on pages linked to:", + "rcfilters-filter-showlinkedto-option-label": "Show changes on pages linked TO a page", + "rcfilters-target-page-placeholder": "Select a page", "rcnotefrom": "Below {{PLURAL:$5|is the change|are the changes}} since <strong>$3, $4</strong> (up to <strong>$1</strong> shown).", "rclistfromreset": "Reset date selection", "rclistfrom": "Show new changes starting from $2, $3", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 607e5c3..4a6aa21 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1666,6 +1666,11 @@ "rcfilters-watchlist-showupdated": "Message at the top of [[Special:Watchlist]] when the Structured filters are enabled that describes what unseen changes look like.\n\nCf. {{msg-mw|wlheader-showupdated}}", "rcfilters-preference-label": "Option in RecentChanges tab of [[Special:Preferences]].", "rcfilters-preference-help": "Explanation for the option in the RecentChanges tab of [[Special:Preferences]].", + "rcfilters-filter-showlinkedfrom-label": "Label that indicates that the page is showing changes that link FROM the target page. Used on [[Special:Recentchangeslinked]] when structured filters are enabled.", + "rcfilters-filter-showlinkedfrom-option-label": "Menu option to show changes FROM the target page. Used on [[Special:Recentchangeslinked]] when structured filters are enabled.", + "rcfilters-filter-showlinkedto-label": "Label that indicates that the page is showing changes that link TO the target page. Used on [[Special:Recentchangeslinked]] when structured filters are enabled.", + "rcfilters-filter-showlinkedto-option-label": "Menu option to show changes TO the target page. Used on [[Special:Recentchangeslinked]] when structured filters are enabled.", + "rcfilters-target-page-placeholder": "Placeholder text for the title lookup [[Special:Recentchangeslinked]] when structured filters are enabled.", "rcnotefrom": "This message is displayed at [[Special:RecentChanges]] when viewing recentchanges from some specific time.\n\nThe corresponding message is {{msg-mw|Rclistfrom}}.\n\nParameters:\n* $1 - the maximum number of changes that are displayed\n* $2 - (Optional) a date and time\n* $3 - a date\n* $4 - a time\n* $5 - Number of changes are displayed, for use with PLURAL", "rclistfromreset": "Used on [[Special:RecentChanges]] to reset a selection of a certain date range.", "rclistfrom": "Used on [[Special:RecentChanges]]. Parameters:\n* $1 - (Currently not use) date and time. The date and the time adds to the rclistfrom description.\n* $2 - time. The time adds to the rclistfrom link description (with split of date and time).\n* $3 - date. The date adds to the rclistfrom link description (with split of date and time).\n\nThe corresponding message is {{msg-mw|Rcnotefrom}}.", diff --git a/resources/Resources.php b/resources/Resources.php index 10786da..39a80f0 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1781,6 +1781,7 @@ 'mediawiki.api.options', 'mediawiki.Uri', 'mediawiki.user', + 'mediawiki.widgets', ], ], 'mediawiki.rcfilters.filters.ui' => [ @@ -1811,6 +1812,9 @@ 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.LiveUpdateButtonWidget.js', 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MarkSeenButtonWidget.js', 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RcTopSectionWidget.js', + 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTopSectionWidget.js', + 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js', + 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclToOrFromWidget.js', 'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.WatchlistTopSectionWidget.js', 'resources/src/mediawiki.rcfilters/mw.rcfilters.HighlightColors.js', 'resources/src/mediawiki.rcfilters/mw.rcfilters.init.js', @@ -1840,6 +1844,9 @@ 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.less', 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.LiveUpdateButtonWidget.less', 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less', + 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTopSectionWidget.less', + 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less', + 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less', 'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.WatchlistTopSectionWidget.less', ], 'skinStyles' => [ @@ -1909,6 +1916,11 @@ 'rcfilters-watchlist-markseen-button', 'rcfilters-watchlist-edit-watchlist-button', 'rcfilters-other-review-tools', + 'rcfilters-filter-showlinkedfrom-label', + 'rcfilters-filter-showlinkedfrom-option-label', + 'rcfilters-filter-showlinkedto-label', + 'rcfilters-filter-showlinkedto-option-label', + 'rcfilters-target-page-placeholder', 'blanknamespace', 'namespaces', 'invert', diff --git a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js index 4dc86f6..80edcf4 100644 --- a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js +++ b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js @@ -152,6 +152,8 @@ // For this group type, parameter values are direct // We need to convert from a boolean to a string ('1' and '0') model.defaultParams[ filter.name ] = String( Number( filter.default || 0 ) ); + } else if ( model.getType() === 'any_value' ) { + model.defaultParams[ filter.name ] = filter.default; } } ); @@ -573,7 +575,7 @@ if ( buildFromCurrentState ) { // This means we have not been given a filter representation // so we are building one based on current state - filterRepresentation[ item.getName() ] = item.isSelected(); + filterRepresentation[ item.getName() ] = item.getValue(); } else if ( filterRepresentation[ item.getName() ] === undefined ) { // We are given a filter representation, but we have to make // sure that we fill in the missing filters if there are any @@ -593,7 +595,8 @@ // Build result if ( this.getType() === 'send_unselected_if_any' || - this.getType() === 'boolean' + this.getType() === 'boolean' || + this.getType() === 'any_value' ) { // First, check if any of the items are selected at all. // If none is selected, we're treating it as if they are @@ -610,6 +613,8 @@ // Representation is straight-forward and direct from // the parameter value to the filter state result[ filterParamNames[ name ] ] = String( Number( !!value ) ); + } else if ( model.getType() === 'any_value' ) { + result[ filterParamNames[ name ] ] = value; } } ); } else if ( this.getType() === 'string_options' ) { @@ -727,6 +732,10 @@ result[ filterItem.getName() ] = selected; oneWasSelected = oneWasSelected || selected; } ); + } else if ( this.getType() === 'any_value' ) { + this.getItems().forEach( function ( filterItem ) { + result[ filterItem.getName() ] = paramRepresentation[ filterItem.getParamName() ]; + } ); } // Go over result and make sure all filters are represented. diff --git a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js index 62ba002..704c857 100644 --- a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js +++ b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js @@ -393,7 +393,8 @@ $.each( this.groups, function ( group, groupModel ) { if ( groupModel.getType() === 'send_unselected_if_any' || - groupModel.getType() === 'boolean' + groupModel.getType() === 'boolean' || + groupModel.getType() === 'any_value' ) { // Individual filters groupModel.getItems().forEach( function ( filterItem ) { diff --git a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ItemModel.js b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ItemModel.js index aa82e21..dc92195 100644 --- a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ItemModel.js +++ b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ItemModel.js @@ -14,6 +14,7 @@ * with 'default' and 'inverted' as keys. * @cfg {boolean} [active=true] The filter is active and affecting the result * @cfg {boolean} [selected] The item is selected + * @cfg {*} [value] The value of this item * @cfg {boolean} [inverted] The item is inverted, meaning the search is excluding * this parameter. * @cfg {string} [namePrefix='item_'] A prefix to add to the param name to act as a unique @@ -35,7 +36,12 @@ this.label = config.label || this.name; this.labelPrefixKey = config.labelPrefixKey; this.description = config.description || ''; - this.selected = !!config.selected; + if ( config.selected ) { + this.setSelected( config.selected ); + } + if ( config.value ) { + this.setValue( config.value ); + } this.inverted = !!config.inverted; this.identifiers = config.identifiers || []; @@ -159,7 +165,7 @@ * @return {boolean} Filter is selected */ mw.rcfilters.dm.ItemModel.prototype.isSelected = function () { - return this.selected; + return !!this.value; }; /** @@ -169,10 +175,27 @@ * @fires update */ mw.rcfilters.dm.ItemModel.prototype.toggleSelected = function ( isSelected ) { - isSelected = isSelected === undefined ? !this.selected : isSelected; + isSelected = isSelected === undefined ? !this.isSelected() : isSelected; + this.setValue( isSelected ); + }; - if ( this.selected !== isSelected ) { - this.selected = isSelected; + /** + * Get the value + * + * @returns {*} + */ + mw.rcfilters.dm.ItemModel.prototype.getValue = function () { + return this.value; + }; + + /** + * Set the value + * + * @param {*} newValue + */ + mw.rcfilters.dm.ItemModel.prototype.setValue = function ( newValue ) { + if ( this.value !== newValue ) { + this.value = newValue; this.emit( 'update' ); } }; diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js index b07df57..ad14c58 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js @@ -178,6 +178,37 @@ ] }; + views.recentChangesLinked = { + groups: [ + { + name: 'page', + type: 'any_value', + title: '', + hidden: true, + isSticky: false, + filters: [ + { + name: 'target', + 'default': '' + } + ] + }, + { + name: 'toOrFrom', + type: 'boolean', + title: '', + hidden: true, + isSticky: false, + filters: [ + { + name: 'showlinkedto', + 'default': false + } + ] + } + ] + }; + // Before we do anything, we need to see if we require additional items in the // groups that have 'AllowArbitrary'. For the moment, those are only single_option // groups; if we ever expand it, this might need further generalization: @@ -465,6 +496,33 @@ }; /** + * Set the value of the 'showlinkedto' parameter + * @param {boolean} value + */ + mw.rcfilters.Controller.prototype.setShowLinkedTo = function ( value ) { + var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' ), + showLinkedToItem = this.filtersModel.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' ); + + this.filtersModel.toggleFilterSelected( showLinkedToItem.getName(), value ); + this._updateURL(); + // reload the results only when target is set + if ( targetItem.getValue() ) { + this.updateChangesList(); + } + }; + + /** + * Set the target page + * @param {string} page + */ + mw.rcfilters.Controller.prototype.setTargetPage = function ( page ) { + var targetItem = this.filtersModel.getGroup( 'page' ).getItemByParamName( 'target' ); + targetItem.setValue( page ); + this._updateURL(); + this.updateChangesList(); + }; + + /** * Set the highlight color for a filter item * * @param {string} filterName Name of the filter item diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js index 83e5796..887e360 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js @@ -9,9 +9,8 @@ */ init: function () { var $topLinks, - rcTopSection, + topSection, $watchlistDetails, - wlTopSection, savedQueriesPreferenceName = mw.config.get( 'wgStructuredChangeFiltersSavedQueriesPreferenceName' ), filtersModel = new mw.rcfilters.dm.FiltersViewModel(), changesListModel = new mw.rcfilters.dm.ChangesListViewModel(), @@ -60,24 +59,32 @@ controller.replaceUrl(); - if ( currentPage === 'Special:Recentchanges' || - currentPage === 'Special:Recentchangeslinked' ) { + if ( currentPage === 'Special:Recentchanges' ) { $topLinks = $( '.mw-recentchanges-toplinks' ).detach(); - rcTopSection = new mw.rcfilters.ui.RcTopSectionWidget( + topSection = new mw.rcfilters.ui.RcTopSectionWidget( savedLinksListWidget, $topLinks ); - filtersWidget.setTopSection( rcTopSection.$element ); - } // end Special:RC + filtersWidget.setTopSection( topSection.$element ); + } // end Special:Recentchanges + + if ( currentPage === 'Special:Recentchangeslinked' ) { + topSection = new mw.rcfilters.ui.RclTopSectionWidget( + savedLinksListWidget, controller, + filtersModel.getGroup( 'toOrFrom' ).getItemByParamName( 'showlinkedto' ), + filtersModel.getGroup( 'page' ).getItemByParamName( 'target' ) + ); + filtersWidget.setTopSection( topSection.$element ); + } // end Special:Recentchangeslinked if ( currentPage === 'Special:Watchlist' ) { $( '#contentSub, form#mw-watchlist-resetbutton' ).detach(); $watchlistDetails = $( '.watchlistDetails' ).detach().contents(); - wlTopSection = new mw.rcfilters.ui.WatchlistTopSectionWidget( + topSection = new mw.rcfilters.ui.WatchlistTopSectionWidget( controller, changesListModel, savedLinksListWidget, $watchlistDetails ); - filtersWidget.setTopSection( wlTopSection.$element ); + filtersWidget.setTopSection( topSection.$element ); } // end Special:WL /** diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less new file mode 100644 index 0000000..433a799 --- /dev/null +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less @@ -0,0 +1,28 @@ +.mw-rcfilters-ui-rclTargetPageWidget { + position: relative; + + .oo-ui-searchWidget-query { + position: static; + padding: 0; + height: auto; + border: 0; + + .oo-ui-textInputWidget { + margin: 0; + } + } + + .oo-ui-searchWidget-results { + position: absolute; + top: 35px; + padding: 0; + overflow: visible; + z-index: 2; + + .mw-widget-titleWidget-menu { + background-color: #fff; + border: solid 1px #a9a9a9; // todo: find the right color + border-radius: 2px; + } + } +} diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less new file mode 100644 index 0000000..19bf272 --- /dev/null +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less @@ -0,0 +1,10 @@ +.mw-rcfilters-ui-rclToOrFromWidget { + + // need to be very specific to override bg-color + &.oo-ui-dropdownWidget.oo-ui-widget-enabled { + .oo-ui-dropdownWidget-handle { + border: 0; + background-color: transparent; + } + } +} diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTopSectionWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTopSectionWidget.less new file mode 100644 index 0000000..58a137a --- /dev/null +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTopSectionWidget.less @@ -0,0 +1,3 @@ +.mw-rcfilters-ui-rclTopSectionWidget { + // todo: make wide enough to see the options' text +} 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 cfcdf35..415e02a 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js @@ -134,6 +134,9 @@ this.$element.find( '.namespaceForm' ).detach(); this.$element.find( '.mw-tagfilter-label' ).closest( 'tr' ).detach(); + // Hide Related Changes page name form + // this.$element.find( '.targetForm' ).detach(); + // misc: limit, days, watchlist info msg this.$element.find( '.rclinks, .cldays, .wlinfo' ).detach(); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js new file mode 100644 index 0000000..3378bc2 --- /dev/null +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js @@ -0,0 +1,62 @@ +( function ( mw ) { + /** + * Widget to select and display target page on Special:RecentChangesLinked (AKA Related Changes) + * + * @extends OO.ui.Widget + * + * @constructor + * @param {mw.rcfilters.controller} controller + * @param {mw.rcfilters.dm.FilterItem} targetPageModel + * @param {Object} [config] Configuration object + */ + mw.rcfilters.ui.RclTargetPageWidget = function MwRcfiltersUiRclTargetPageWidget( + controller, targetPageModel, config + ) { + config = config || {}; + + // Parent + mw.rcfilters.ui.RclTargetPageWidget.parent.call( this, config ); + + this.controller = controller; + + this.titleSearch = new mw.widgets.TitleSearchWidget( { + placeholder: mw.msg( 'rcfilters-target-page-placeholder' ), + showImages: true, + showDescription: true + } ); + this.titleSearch.$element.prepend( this.titleSearch.$query ); + + this.selectedPageLabel = new OO.ui.LabelWidget(); + + // TEMPORARY: this is only so I can test the new group filter type (any_value) + this.selectedPageLabel.$element.on( 'click', function () { + this.$element.empty().append( this.titleSearch.$element ); + this.titleSearch.query.setValue( '' ); + this.titleSearch.query.focus(); + this.controller.setTargetPage( null ); + }.bind( this ) ); + + // Events + this.titleSearch.results.connect( this, { choose: 'onChooseTitle' } ); + + // Initialize + this.$element + .addClass( 'mw-rcfilters-ui-rclTargetPageWidget' ) + .append( this.titleSearch.$element ); + }; + + /* Initialization */ + + OO.inheritClass( mw.rcfilters.ui.RclTargetPageWidget, OO.ui.Widget ); + + /* Methods */ + + mw.rcfilters.ui.RclTargetPageWidget.prototype.onChooseTitle = function ( chosenTitle ) { + var target = chosenTitle.getData(); + this.titleSearch.results.toggle(); + this.selectedPageLabel.setLabel( target ); + this.$element.empty().append( this.selectedPageLabel.$element ); + + this.controller.setTargetPage( target ); + }; +}( mediaWiki ) ); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclToOrFromWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclToOrFromWidget.js new file mode 100644 index 0000000..eb4466a --- /dev/null +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclToOrFromWidget.js @@ -0,0 +1,65 @@ +( function ( mw ) { + /** + * Widget to select to view changes that link TO or FROM the target page + * on Special:RecentChangesLinked (AKA Related Changes) + * + * @extends OO.ui.DropdownWidget + * + * @constructor + * @param {mw.rcfilters.controller} controller + * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel model this widget is bound to + * @param {Object} [config] Configuration object + */ + mw.rcfilters.ui.RclToOrFromWidget = function MwRcfiltersUiRclToOrFromWidget( + controller, showLinkedToModel, config + ) { + config = config || {}; + + this.showLinkedFrom = new OO.ui.MenuOptionWidget( { + data: 'from', // default (showlinkedto=0) + label: mw.msg( 'rcfilters-filter-showlinkedfrom-option-label' ) + } ); + this.showLinkedTo = new OO.ui.MenuOptionWidget( { + data: 'to', // showlinkedto=1 + label: mw.msg( 'rcfilters-filter-showlinkedto-option-label' ) + } ); + + // Parent + mw.rcfilters.ui.RclToOrFromWidget.parent.call( this, $.extend( { + classes: [ 'mw-rcfilters-ui-rclToOrFromWidget' ], + menu: { items: [ this.showLinkedFrom, this.showLinkedTo ] } + }, config ) ); + + this.controller = controller; + this.model = showLinkedToModel; + + this.getMenu().connect( this, { choose: 'onUserChooseItem' } ); + this.model.connect( this, { update: 'onModelUpdate' } ); + + // force an initial update of the component based on the state + this.onModelUpdate(); + }; + + /* Initialization */ + + OO.inheritClass( mw.rcfilters.ui.RclToOrFromWidget, OO.ui.DropdownWidget ); + + /* Methods */ + + mw.rcfilters.ui.RclToOrFromWidget.prototype.onUserChooseItem = function ( chosenItem ) { + this.controller.setShowLinkedTo( chosenItem.getData() === 'to' ); + }; + + mw.rcfilters.ui.RclToOrFromWidget.prototype.onModelUpdate = function () { + this.getMenu().selectItem( + this.model.isSelected() ? + this.showLinkedTo : + this.showLinkedFrom + ); + this.setLabel( mw.msg( + this.model.isSelected() ? + 'rcfilters-filter-showlinkedto-label' : + 'rcfilters-filter-showlinkedfrom-label' + ) ); + }; +}( mediaWiki ) ); diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTopSectionWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTopSectionWidget.js new file mode 100644 index 0000000..5c70774 --- /dev/null +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTopSectionWidget.js @@ -0,0 +1,66 @@ +( function ( mw ) { + /** + * Top section (between page title and filters) on Special:RecentChangesLinked (AKA RelatedChanges) + * + * @extends OO.ui.Widget + * + * @constructor + * @param {mw.rcfilters.ui.SavedLinksListWidget} savedLinksListWidget + * @param {mw.rcfilters.controller} controller + * @param {mw.rcfilters.dm.FilterItem} showLinkedToModel Model for 'showlinkedto' parameter + * @param {mw.rcfilters.dm.FilterItem} targetPageModel Model for 'target' parameter + * @param {Object} [config] Configuration object + */ + mw.rcfilters.ui.RclTopSectionWidget = function MwRcfiltersUiRclTopSectionWidget( + savedLinksListWidget, controller, showLinkedToModel, targetPageModel, config + ) { + var toOrFromWidget, + targetPage; + config = config || {}; + + // Parent + mw.rcfilters.ui.RclTopSectionWidget.parent.call( this, config ); + + this.controller = controller; + + toOrFromWidget = new mw.rcfilters.ui.RclToOrFromWidget( controller, showLinkedToModel ); + targetPage = new mw.rcfilters.ui.RclTargetPageWidget( controller, targetPageModel ); + + // Initialize + this.$element + .addClass( 'mw-rcfilters-ui-rclTopSectionWidget' ) + .append( + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-table' ) + .append( + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-row' ) + .append( + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-cell' ) + .append( toOrFromWidget.$element ) + ), + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-row' ) + .append( + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-cell' ) + .append( targetPage.$element ), + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-table-placeholder' ) + .addClass( 'mw-rcfilters-ui-cell' ), + !mw.user.isAnon() ? + $( '<div>' ) + .addClass( 'mw-rcfilters-ui-cell' ) + .addClass( 'mw-rcfilters-ui-rclTopSectionWidget-savedLinks' ) + .append( savedLinksListWidget.$element ) : + null + ) + ) + ); + }; + + /* Initialization */ + + OO.inheritClass( mw.rcfilters.ui.RclTopSectionWidget, OO.ui.Widget ); +}( mediaWiki ) ); -- To view, visit https://gerrit.wikimedia.org/r/378103 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I96af7ba583d03e6ff9833ac3b5f4b80cfd0ee626 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/core Gerrit-Branch: master Gerrit-Owner: Sbisson <sbis...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits