X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=resources%2Fsrc%2Fmediawiki.rcfilters%2Fui%2FFilterTagMultiselectWidget.js;h=7c8a2f5a264443775b3c336836d20b5b50bbcec1;hb=529fc12d2ad2032337594389448fdb5b55802830;hp=3429590294eda52683d5674128b9e30002bd302a;hpb=35252b7aaf421d44e15811095b07d5e0d011864e;p=lhc%2Fweb%2Fwiklou.git diff --git a/resources/src/mediawiki.rcfilters/ui/FilterTagMultiselectWidget.js b/resources/src/mediawiki.rcfilters/ui/FilterTagMultiselectWidget.js index 3429590294..7c8a2f5a26 100644 --- a/resources/src/mediawiki.rcfilters/ui/FilterTagMultiselectWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/FilterTagMultiselectWidget.js @@ -40,6 +40,7 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c this.matchingQuery = null; this.currentView = this.model.getCurrentView(); this.collapsed = false; + this.isMobile = config.isMobile; // Parent FilterTagMultiselectWidget.parent.call( this, $.extend( true, { @@ -55,6 +56,8 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c filterFromInput: false, hideWhenOutOfView: false, hideOnChoose: false, + // Only set width and footers for desktop + isMobile: this.isMobile, width: 650, footers: [ { @@ -81,9 +84,17 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c } ] }, + /** + * In the presence of an onscreen keyboard (i.e. isMobile) the filter input should act as a button + * rather than a text input. Mobile screens are too small to accommodate both an + * onscreen keyboard and a popup-menu, so readyOnly is set to disable the keyboard. + * A different icon and shorter message is used for mobile as well. (See T224655 for details). + */ input: { - icon: 'menu', - placeholder: mw.msg( 'rcfilters-search-placeholder' ) + icon: this.isMobile ? 'funnel' : 'menu', + placeholder: this.isMobile ? mw.msg( 'rcfilters-search-placeholder-mobile' ) : mw.msg( 'rcfilters-search-placeholder' ), + readOnly: !!this.isMobile, + classes: [ 'oo-ui-tagMultiselectWidget-input' ] } }, config ) ); @@ -148,11 +159,14 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c this.model.connect( this, { initialize: 'onModelInitialize', update: 'onModelUpdate', - searchChange: 'onModelSearchChange', + searchChange: this.isMobile ? function () {} : 'onModelSearchChange', itemUpdate: 'onModelItemUpdate', highlightChange: 'onModelHighlightChange' } ); - this.input.connect( this, { change: 'onInputChange' } ); + + if ( !this.isMobile ) { + this.input.connect( this, { change: 'onInputChange' } ); + } // The filter list and button should appear side by side regardless of how // wide the button is; the button also changes its width depending @@ -176,46 +190,10 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c } // Add a selector at the right of the input - this.viewsSelectWidget = new OO.ui.ButtonSelectWidget( { - classes: [ 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select-widget' ], - items: [ - new OO.ui.ButtonOptionWidget( { - framed: false, - data: 'namespaces', - icon: 'article', - label: mw.msg( 'namespaces' ), - title: mw.msg( 'rcfilters-view-namespaces-tooltip' ) - } ), - new OO.ui.ButtonOptionWidget( { - framed: false, - data: 'tags', - icon: 'tag', - label: mw.msg( 'tags-title' ), - title: mw.msg( 'rcfilters-view-tags-tooltip' ) - } ) - ] - } ); + this.viewsSelectWidget = this.createViewsSelectWidget(); - // Rearrange the UI so the select widget is at the right of the input - this.$element.append( - $( '
' ) - .addClass( 'mw-rcfilters-ui-table' ) - .append( - $( '
' ) - .addClass( 'mw-rcfilters-ui-row' ) - .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views' ) - .append( - $( '
' ) - .addClass( 'mw-rcfilters-ui-cell' ) - .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-input' ) - .append( this.input.$element ), - $( '
' ) - .addClass( 'mw-rcfilters-ui-cell' ) - .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select' ) - .append( this.viewsSelectWidget.$element ) - ) - ) - ); + // change the layout of the viewsSelectWidget + this.restructureViewsSelectWidget(); // Event this.viewsSelectWidget.connect( this, { choose: 'onViewsSelectWidgetChoose' } ); @@ -258,6 +236,11 @@ FilterTagMultiselectWidget = function MwRcfiltersUiFilterTagMultiselectWidget( c this.$element .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget' ); + if ( this.isMobile ) { + this.$element + .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-mobile' ); + } + this.reevaluateResetRestoreState(); }; @@ -267,6 +250,78 @@ OO.inheritClass( FilterTagMultiselectWidget, OO.ui.MenuTagMultiselectWidget ); /* Methods */ +/** + * Create a OOUI ButtonSelectWidget. The buttons are framed and have additional CSS + * classes applied on mobile. + * @return {OO.ui.ButtonSelectWidget} + */ +FilterTagMultiselectWidget.prototype.createViewsSelectWidget = function () { + return new OO.ui.ButtonSelectWidget( { + classes: this.isMobile ? + [ + 'mw-rcfilters-ui-table', + 'mw-rcfilters-ui-filterTagMultiselectWidget-mobile-view' + ] : + [ + 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select-widget' + ], + items: [ + new OO.ui.ButtonOptionWidget( { + framed: !!this.isMobile, + data: 'namespaces', + icon: 'article', + label: mw.msg( 'namespaces' ), + classes: this.isMobile ? [ 'mw-rcfilters-ui-cell' ] : [] + } ), + new OO.ui.ButtonOptionWidget( { + framed: !!this.isMobile, + data: 'tags', + icon: 'tag', + label: mw.msg( 'tags-title' ), + title: mw.msg( 'rcfilters-view-tags-tooltip' ), + classes: this.isMobile ? [ 'mw-rcfilters-ui-cell' ] : [] + } ) + ] + } ); +}; + +/** + * Rearrange the DOM structure of the viewsSelectWiget so that on the namespace & tags buttons + * are at the right of the input on desktop, and below the input on mobile. + */ +FilterTagMultiselectWidget.prototype.restructureViewsSelectWidget = function () { + if ( this.isMobile ) { + // On mobile, append the search input and the extra buttons below the search input. + this.$element.append( + $( '
' ) + .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-input' ) + .append( this.input.$element ) + .append( this.viewsSelectWidget.$element ) + ); + } else { + // On desktop, rearrange the UI so the select widget is at the right of the input + this.$element.append( + $( '
' ) + .addClass( 'mw-rcfilters-ui-table' ) + .append( + $( '
' ) + .addClass( 'mw-rcfilters-ui-row' ) + .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views' ) + .append( + $( '
' ) + .addClass( 'mw-rcfilters-ui-cell' ) + .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-input' ) + .append( this.input.$element ), + $( '
' ) + .addClass( 'mw-rcfilters-ui-cell' ) + .addClass( 'mw-rcfilters-ui-filterTagMultiselectWidget-views-select' ) + .append( this.viewsSelectWidget.$element ) + ) + ) + ); + } +}; + /** * Respond to view select widget choose event * @@ -329,11 +384,16 @@ FilterTagMultiselectWidget.prototype.onSavedQueriesItemUpdate = function ( item * @param {boolean} isVisible Menu is visible */ FilterTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) { + + var scrollToElement = this.isMobile ? this.input.$input : this.$element; + // Parent FilterTagMultiselectWidget.parent.prototype.onMenuToggle.call( this ); if ( isVisible ) { - this.focus(); + if ( !this.isMobile ) { + this.focus(); + } mw.hook( 'RcFilters.popup.open' ).fire(); @@ -347,6 +407,13 @@ FilterTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) { }.bind( this ) ); } + + // Only scroll to top of the viewport if: + // - The widget is more than 20px from the top + // - The widget is not above the top of the viewport (do not scroll downwards) + // (This isn't represented because >20 is, anyways and always, bigger than 0) + this.scrollToTop( scrollToElement, 0, { min: 20, max: Infinity } ); + } else { // Clear selection this.selectTag( null ); @@ -360,21 +427,26 @@ FilterTagMultiselectWidget.prototype.onMenuToggle = function ( isVisible ) { this.blur(); } - this.input.setIcon( isVisible ? 'search' : 'menu' ); + if ( this.isMobile ) { + this.input.setIcon( isVisible ? 'close' : 'funnel' ); + } else { + this.input.setIcon( isVisible ? 'search' : 'menu' ); + } }; /** * @inheritdoc */ FilterTagMultiselectWidget.prototype.onInputFocus = function () { - // Parent - FilterTagMultiselectWidget.parent.prototype.onInputFocus.call( this ); - // Only scroll to top of the viewport if: - // - The widget is more than 20px from the top - // - The widget is not above the top of the viewport (do not scroll downwards) - // (This isn't represented because >20 is, anyways and always, bigger than 0) - this.scrollToTop( this.$element, 0, { min: 20, max: Infinity } ); + // treat the input as a menu toggle rather than a text field on mobile + if ( this.isMobile ) { + this.input.$input.trigger( 'blur' ); + this.getMenu().toggle(); + } else { + // Parent + FilterTagMultiselectWidget.parent.prototype.onInputFocus.call( this ); + } }; /** @@ -525,7 +597,10 @@ FilterTagMultiselectWidget.prototype.onMenuChoose = function ( item ) { // Select the tag if it exists, or reset selection otherwise this.selectTag( this.findItemFromData( item.model.getName() ) ); - this.focus(); + if ( !this.isMobile ) { + this.focus(); + } + }; /**