Merge "Fix StatusValue::setResult phpdoc typo"
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / ui / mw.rcfilters.ui.FilterWrapperWidget.js
1 ( function ( mw ) {
2 /**
3 * List displaying all filter groups
4 *
5 * @extends OO.ui.Widget
6 * @mixins OO.ui.mixin.PendingElement
7 *
8 * @constructor
9 * @param {mw.rcfilters.Controller} controller Controller
10 * @param {mw.rcfilters.dm.FiltersViewModel} model View model
11 * @param {Object} [config] Configuration object
12 * @cfg {Object} [filters] A definition of the filter groups in this list
13 * @cfg {jQuery} [$overlay] A jQuery object serving as overlay for popups
14 */
15 mw.rcfilters.ui.FilterWrapperWidget = function MwRcfiltersUiFilterWrapperWidget( controller, model, config ) {
16 config = config || {};
17
18 // Parent
19 mw.rcfilters.ui.FilterWrapperWidget.parent.call( this, config );
20 // Mixin constructors
21 OO.ui.mixin.PendingElement.call( this, config );
22
23 this.controller = controller;
24 this.model = model;
25 this.$overlay = config.$overlay || this.$element;
26
27 this.filterPopup = new mw.rcfilters.ui.FiltersListWidget(
28 this.controller,
29 this.model,
30 {
31 label: mw.msg( 'rcfilters-filterlist-title' ),
32 $overlay: this.$overlay
33 }
34 );
35
36 this.textInput = new OO.ui.TextInputWidget( {
37 classes: [ 'mw-rcfilters-ui-filterWrapperWidget-search' ],
38 icon: 'search',
39 placeholder: mw.msg( 'rcfilters-search-placeholder' )
40 } );
41
42 this.capsule = new mw.rcfilters.ui.FilterCapsuleMultiselectWidget( controller, this.model, this.textInput, {
43 $overlay: this.$overlay,
44 popup: {
45 $content: this.filterPopup.$element,
46 classes: [ 'mw-rcfilters-ui-filterWrapperWidget-popup' ],
47 width: 650
48 }
49 } );
50
51 // Events
52 this.model.connect( this, {
53 initialize: 'onModelInitialize',
54 itemUpdate: 'onModelItemUpdate'
55 } );
56 this.textInput.connect( this, {
57 change: 'onTextInputChange'
58 } );
59 this.capsule.connect( this, { capsuleItemClick: 'onCapsuleItemClick' } );
60 this.capsule.popup.connect( this, { toggle: 'onCapsulePopupToggle' } );
61
62 // Initialize
63 this.$element
64 .addClass( 'mw-rcfilters-ui-filterWrapperWidget' )
65 .append( this.capsule.$element, this.textInput.$element );
66 };
67
68 /* Initialization */
69
70 OO.inheritClass( mw.rcfilters.ui.FilterWrapperWidget, OO.ui.Widget );
71 OO.mixinClass( mw.rcfilters.ui.FilterWrapperWidget, OO.ui.mixin.PendingElement );
72
73 /**
74 * Respond to capsule item click and make the popup scroll down to the requested item
75 *
76 * @param {mw.rcfilters.ui.CapsuleItemWidget} item Clicked item
77 */
78 mw.rcfilters.ui.FilterWrapperWidget.prototype.onCapsuleItemClick = function ( item ) {
79 var filterName = item.getData(),
80 // Find the item in the popup
81 filterWidget = this.filterPopup.getItemWidget( filterName );
82
83 // Highlight item
84 this.filterPopup.select( filterName );
85
86 this.scrollToTop( filterWidget.$element );
87 };
88
89 /**
90 * Respond to popup toggle event. Reset selection in the list when the popup is closed.
91 *
92 * @param {boolean} isVisible Popup is visible
93 */
94 mw.rcfilters.ui.FilterWrapperWidget.prototype.onCapsulePopupToggle = function ( isVisible ) {
95 if ( !isVisible ) {
96 this.filterPopup.resetSelection();
97 } else {
98 this.scrollToTop( this.capsule.$element, 10 );
99 }
100 };
101
102 /**
103 * Respond to text input change
104 *
105 * @param {string} newValue Current value
106 */
107 mw.rcfilters.ui.FilterWrapperWidget.prototype.onTextInputChange = function ( newValue ) {
108 this.filterPopup.resetSelection();
109
110 // Filter the results
111 this.filterPopup.filter( this.model.findMatches( newValue ) );
112 this.capsule.popup.clip();
113 };
114
115 /**
116 * Respond to model update event and set up the available filters to choose
117 * from.
118 */
119 mw.rcfilters.ui.FilterWrapperWidget.prototype.onModelInitialize = function () {
120 var wrapper = this;
121
122 // Add defaults to capsule. We have to do this
123 // after we added to the capsule menu, since that's
124 // how the capsule multiselect widget knows which
125 // object to add
126 this.model.getItems().forEach( function ( filterItem ) {
127 if ( filterItem.isSelected() ) {
128 wrapper.capsule.addItemByName( filterItem.getName() );
129 }
130 } );
131 };
132
133 /**
134 * Respond to item update and reset the selection. This will make it so that
135 * any actual interaction with the system resets the selection state of any item.
136 */
137 mw.rcfilters.ui.FilterWrapperWidget.prototype.onModelItemUpdate = function () {
138 this.filterPopup.resetSelection();
139 };
140
141 /**
142 * Scroll the element to top within its container
143 *
144 * @private
145 * @param {jQuery} $element Element to position
146 * @param {number} [marginFromTop] When scrolling the entire widget to the top, leave this
147 * much space (in pixels) above the widget.
148 */
149 mw.rcfilters.ui.FilterWrapperWidget.prototype.scrollToTop = function ( $element, marginFromTop ) {
150 var container = OO.ui.Element.static.getClosestScrollableContainer( $element[ 0 ], 'y' ),
151 pos = OO.ui.Element.static.getRelativePosition( $element, $( container ) );
152
153 // Scroll to item
154 $( container ).animate( {
155 scrollTop: $( container ).scrollTop() + pos.top + ( marginFromTop || 0 )
156 } );
157 };
158 }( mediaWiki ) );