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

Reply via email to