From: Moriel Schottlender Date: Thu, 3 Aug 2017 01:29:25 +0000 (-0700) Subject: Fix highlight display for enhanced mode X-Git-Tag: 1.31.0-rc.0~2256^2 X-Git-Url: https://git.heureux-cyclage.org/?a=commitdiff_plain;h=c00ee215579ed7e40a6e54e9322b9f2add373aa7;p=lhc%2Fweb%2Fwiklou.git Fix highlight display for enhanced mode Bug: T170875 Change-Id: Ibd7d447aba1ae5576ea637a2d5ef06cb3f622b26 --- 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 a8ee06bf49..62ba002c1f 100644 --- a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js +++ b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js @@ -724,6 +724,25 @@ return result; }; + /** + * Get an array of currently applied highlight colors + * + * @return {string[]} Currently applied highlight colors + */ + mw.rcfilters.dm.FiltersViewModel.prototype.getCurrentlyUsedHighlightColors = function () { + var result = []; + + this.getHighlightedItems().forEach( function ( filterItem ) { + var color = filterItem.getHighlightColor(); + + if ( result.indexOf( color ) === -1 ) { + result.push( color ); + } + } ); + + return result; + }; + /** * Sanitize value group of a string_option groups type * Remove duplicates and make sure to only use valid diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.UriProcessor.js b/resources/src/mediawiki.rcfilters/mw.rcfilters.UriProcessor.js index a1ef981aae..1894b619d4 100644 --- a/resources/src/mediawiki.rcfilters/mw.rcfilters.UriProcessor.js +++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.UriProcessor.js @@ -110,7 +110,6 @@ this.filtersModel.toggleInvertedNamespaces( !!Number( parameters.invert ) ); // Update highlight state - this.filtersModel.toggleHighlight( !!Number( parameters.highlight ) ); this.filtersModel.getItems().forEach( function ( filterItem ) { var color = parameters[ filterItem.getName() + '_color' ]; if ( color ) { @@ -119,6 +118,7 @@ filterItem.clearHighlightColor(); } } ); + this.filtersModel.toggleHighlight( !!Number( parameters.highlight ) ); // Check all filter interactions this.filtersModel.reassessFilterInteractions(); diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less index 5a885eccf5..796cf2aa28 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less @@ -37,6 +37,19 @@ } } +// A mixin just for changesListWrapperWidget page, to output the scope of the widget +// so it is before the rest of the rule; we need the li& to be in +// between the wrapper scope and the color-cX class, which doesn't +// work if the rules are inside the above widget LESS scope +.highlight-changesListWrapperWidget( @bgcolor ) { + .mw-rcfilters-ui-changesListWrapperWidget li&, + .mw-rcfilters-ui-changesListWrapperWidget & tr:first-child, + .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel:not(.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey) td:not( :nth-child( -n+2 ) ), + .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested:not(.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey) td:not( :nth-child( -n+3 ) ) { + background-color: @bgcolor; + } +} + // This mixin produces color mixes for two, three and four colors .highlight-color-mix( @color1, @color2, @color3: false, @color4: false ) { @highlight-color-class-var: ~'.mw-rcfilters-highlight-color-@{color1}.mw-rcfilters-highlight-color-@{color2}'; @@ -51,18 +64,18 @@ // Two colors @{highlight-color-class-var} when ( @color3 = false ) and ( @color4 = false ) and not ( @color1 = false ), ( @color2 = false ) { - background-color: tint( average( @@c1var, @@c2var ), 50% ); + .highlight-changesListWrapperWidget( tint( average( @@c1var, @@c2var ), 50% ) ); } // Three colors @{highlight-color-class-var}.mw-rcfilters-highlight-color-@{color3} when ( @color4 = false ) and not ( @color3 = false ) { @c3var: ~'highlight-@{color3}'; - background-color: tint( mix( @@c1var, average( @@c2var, @@c3var ), 33% ), 30% ); + .highlight-changesListWrapperWidget( tint( mix( @@c1var, average( @@c2var, @@c3var ), 33% ), 30% ) ); } // Four colors @{highlight-color-class-var}.mw-rcfilters-highlight-color-@{color3}.mw-rcfilters-highlight-color-@{color4} when not ( @color4 = false ) { @c3var: ~'highlight-@{color3}'; @c4var: ~'highlight-@{color4}'; - background-color: tint( mix( @@c1var, mix( @@c2var, average( @@c3var, @@c4var ), 25% ), 25% ), 25% ); + .highlight-changesListWrapperWidget( tint( mix( @@c1var, mix( @@c2var, average( @@c3var, @@c4var ), 25% ), 25% ), 25% ) ); } } diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less index dc7afab1b5..31f19b8785 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less @@ -34,6 +34,13 @@ } } + // Rule needs to be specific + // We want the expand button to appear outside the color + // to match the way the general highlight background appears + &-enhanced-grey td:not( :nth-child( -n+2 ) ) { + background-color: #dee0e3; + } + h4:first-of-type { margin-top: 0; padding-top: 0; @@ -77,8 +84,9 @@ // and then plus the general margin width: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * 5 )'; // And we want to shift the entire block to the left of the li - position: absolute; - left: 0; + position: relative; + // Negative left margin of width + padding + margin-left: ~'calc( ( @{result-circle-diameter} + @{result-circle-margin} ) * -5 - @{result-circle-general-margin} )'; .mw-rcfilters-ui-changesListWrapperWidget-highlighted & { display: inline-block; @@ -114,66 +122,66 @@ .result-circle( c5 ); } } +} - // One color - .mw-rcfilters-highlight-color-c1 { - background-color: tint( @highlight-c1, 70% ); - } +// One color +.mw-rcfilters-highlight-color-c1 { + .highlight-changesListWrapperWidget( tint( @highlight-c1, 70% ); ); +} - .mw-rcfilters-highlight-color-c2 { - background-color: tint( @highlight-c2, 70% ); - } +.mw-rcfilters-highlight-color-c2 { + .highlight-changesListWrapperWidget( tint( @highlight-c2, 70% ); ); +} - .mw-rcfilters-highlight-color-c3 { - background-color: tint( @highlight-c3, 70% ); - } +.mw-rcfilters-highlight-color-c3 { + .highlight-changesListWrapperWidget( tint( @highlight-c3, 70% ); ); +} - .mw-rcfilters-highlight-color-c4 { - background-color: tint( @highlight-c4, 70% ); - } +.mw-rcfilters-highlight-color-c4 { + .highlight-changesListWrapperWidget( tint( @highlight-c4, 70% ); ); +} - .mw-rcfilters-highlight-color-c5 { - background-color: tint( @highlight-c5, 70% ); - } +.mw-rcfilters-highlight-color-c5 { + .highlight-changesListWrapperWidget( tint( @highlight-c5, 70% ); ); +} - // Two colors - .highlight-color-mix( c1, c2 ); - // Overriding .highlight-color-mix( c1, c3 ); to produce - // a custom color rather than the computed tint - // see https://phabricator.wikimedia.org/T161267 - .mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c3 { - background-color: #ccdecc; - } - .highlight-color-mix( c1, c4 ); - .highlight-color-mix( c1, c5 ); - .highlight-color-mix( c2, c3 ); - .highlight-color-mix( c2, c4 ); - .highlight-color-mix( c2, c5 ); - .highlight-color-mix( c3, c4 ); - .highlight-color-mix( c3, c5 ); - .highlight-color-mix( c4, c5 ); - - // Three colors - .highlight-color-mix( c1, c2, c3 ); - .highlight-color-mix( c1, c2, c5 ); - .highlight-color-mix( c1, c2, c4 ); - .highlight-color-mix( c1, c3, c4 ); - .highlight-color-mix( c1, c3, c5 ); - .highlight-color-mix( c1, c4, c5 ); - .highlight-color-mix( c2, c3, c4 ); - .highlight-color-mix( c2, c3, c5 ); - .highlight-color-mix( c2, c4, c5 ); - .highlight-color-mix( c3, c4, c5 ); - - // Four colors - .highlight-color-mix( c1, c2, c3, c4 ); - .highlight-color-mix( c1, c2, c3, c5 ); - .highlight-color-mix( c1, c2, c4, c5 ); - .highlight-color-mix( c1, c3, c4, c5 ); - .highlight-color-mix( c2, c3, c4, c5 ); - - // Five colors: - .mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c2.mw-rcfilters-highlight-color-c3.mw-rcfilters-highlight-color-c4.mw-rcfilters-highlight-color-c5 { - background-color: tint( mix( @highlight-c1, mix( @highlight-c2, mix( @highlight-c3, average( @highlight-c4, @highlight-c5 ), 20% ), 20% ), 20% ), 15% ); - } +// Two colors +.highlight-color-mix( c1, c2 ); +// Overriding .highlight-color-mix( c1, c3 ); to produce +// a custom color rather than the computed tint +// see https://phabricator.wikimedia.org/T161267 +.mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c3 { + .highlight-changesListWrapperWidget( #ccdecc ); +} +.highlight-color-mix( c1, c4 ); +.highlight-color-mix( c1, c5 ); +.highlight-color-mix( c2, c3 ); +.highlight-color-mix( c2, c4 ); +.highlight-color-mix( c2, c5 ); +.highlight-color-mix( c3, c4 ); +.highlight-color-mix( c3, c5 ); +.highlight-color-mix( c4, c5 ); + +// Three colors +.highlight-color-mix( c1, c2, c3 ); +.highlight-color-mix( c1, c2, c5 ); +.highlight-color-mix( c1, c2, c4 ); +.highlight-color-mix( c1, c3, c4 ); +.highlight-color-mix( c1, c3, c5 ); +.highlight-color-mix( c1, c4, c5 ); +.highlight-color-mix( c2, c3, c4 ); +.highlight-color-mix( c2, c3, c5 ); +.highlight-color-mix( c2, c4, c5 ); +.highlight-color-mix( c3, c4, c5 ); + +// Four colors +.highlight-color-mix( c1, c2, c3, c4 ); +.highlight-color-mix( c1, c2, c3, c5 ); +.highlight-color-mix( c1, c2, c4, c5 ); +.highlight-color-mix( c1, c3, c4, c5 ); +.highlight-color-mix( c2, c3, c4, c5 ); + +// Five colors: +.mw-rcfilters-highlight-color-c1.mw-rcfilters-highlight-color-c2.mw-rcfilters-highlight-color-c3.mw-rcfilters-highlight-color-c4.mw-rcfilters-highlight-color-c5 { + .highlight-changesListWrapperWidget( tint( mix( @highlight-c1, mix( @highlight-c2, mix( @highlight-c3, average( @highlight-c4, @highlight-c5 ), 20% ), 20% ), 20% ), 15% ) ); } diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js index a97ffe93d6..d550809044 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js @@ -28,11 +28,14 @@ this.filtersViewModel = filtersViewModel; this.changesListViewModel = changesListViewModel; this.controller = controller; + this.highlightClasses = null; + this.filtersModelInitialized = false; // Events this.filtersViewModel.connect( this, { itemUpdate: 'onItemUpdate', - highlightChange: 'onHighlightChange' + highlightChange: 'onHighlightChange', + initialize: 'onFiltersModelInitialize' } ); this.changesListViewModel.connect( this, { invalidate: 'onModelInvalidate', @@ -45,9 +48,6 @@ // We handle our own display/hide of the empty results message .removeClass( 'mw-changeslist-empty' ); - // Set up highlight containers - this.setupHighlightContainers( this.$element ); - this.setupNewChangesButtonContainer( this.$element ); }; @@ -55,6 +55,33 @@ OO.inheritClass( mw.rcfilters.ui.ChangesListWrapperWidget, OO.ui.Widget ); + /** + * Respond to filters model initialize event + */ + mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onFiltersModelInitialize = function () { + this.filtersModelInitialized = true; + // Set up highlight containers. We need to wait for the filters model + // to be initialized, so we can make sure we have all the css class definitions + // we get from the server with our filters + this.setupHighlightContainers( this.$element ); + }; + + /** + * Get all available highlight classes + * + * @return {string[]} An array of available highlight class names + */ + mw.rcfilters.ui.ChangesListWrapperWidget.prototype.getHighlightClasses = function () { + if ( !this.highlightClasses || !this.highlightClasses.length ) { + this.highlightClasses = this.filtersViewModel.getItemsSupportingHighlights() + .map( function ( filterItem ) { + return filterItem.getCssClass(); + } ); + } + + return this.highlightClasses; + }; + /** * Respond to the highlight feature being toggled on and off * @@ -72,7 +99,7 @@ * Respond to a filter item model update */ mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onItemUpdate = function () { - if ( this.filtersViewModel.isHighlightEnabled() ) { + if ( this.filtersModelInitialized && this.filtersViewModel.isHighlightEnabled() ) { this.clearHighlight(); this.applyHighlight(); } @@ -246,7 +273,9 @@ * @param {jQuery|string} $content The content of the updated changes list */ mw.rcfilters.ui.ChangesListWrapperWidget.prototype.setupHighlightContainers = function ( $content ) { - var highlightClass = 'mw-rcfilters-ui-changesListWrapperWidget-highlights', + var $enhancedTopPageCell, $enhancedNestedPagesCell, + widget = this, + highlightClass = 'mw-rcfilters-ui-changesListWrapperWidget-highlights', $highlights = $( '
' ) .addClass( highlightClass ) .append( @@ -269,13 +298,56 @@ } ); if ( this.inEnhancedMode() ) { - // Enhanced RC - $content.find( 'td.mw-enhanced-rc' ) - .parent() + $enhancedTopPageCell = $content.find( 'table.mw-enhanced-rc.mw-collapsible' ); + $enhancedNestedPagesCell = $content.find( 'td.mw-enhanced-rc-nested' ); + + // Enhanced RC highlight containers + $content.find( 'table.mw-enhanced-rc tr:first-child' ) + .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel' ) .prepend( $( '' ) .append( $highlights.clone() ) ); + + // We are adding and changing cells in a table that, despite having nested rows, + // is actually all one big table. To do that right, we want to remove the 'placeholder' + // cell from the top row, because we're actually adding that placeholder in the children + // with the highlights. + $content.find( 'table.mw-enhanced-rc tr:first-child td.mw-changeslist-line-prefix' ) + .detach(); + $content.find( 'table.mw-enhanced-rc tr:first-child td.mw-enhanced-rc' ) + .prop( 'colspan', '2' ); + + $enhancedNestedPagesCell + .before( + $( '' ) + .append( $highlights.clone().addClass( 'mw-enhanced-rc-nested' ) ) + ); + + // We need to target the nested rows differently than the top rows so that the + // LESS rules applies correctly. In top rows, the rule should highlight all but + // the first 2 cells td:not( :nth-child( -n+2 ) and the nested rows, the rule + // should highlight all but the first 3 cells td:not( :nth-child( -n+3 ) + $enhancedNestedPagesCell + .closest( 'tr' ) + .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested' ); + + // Go over pages that have sub results + // HACK: We really only can collect those by targetting the collapsible class + $enhancedTopPageCell.each( function () { + var collectedClasses, + $table = $( this ); + + // Go over s and pick up all recognized classes + collectedClasses = widget.getHighlightClasses().filter( function ( className ) { + return $table.find( 'tr' ).hasClass( className ); + } ); + + $table.find( 'tr:first-child' ) + .addClass( collectedClasses.join( ' ' ) ); + } ); + + $content.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhancedView' ); } else { // Regular RC $content.find( 'ul.special li' ) @@ -283,6 +355,52 @@ } }; + /** + * In enhanced mode, we need to check whether the grouped results all have the + * same active highlights in order to see whether the "parent" of the group should + * be grey or highlighted normally. + * + * This is called every time highlights are applied. + */ + mw.rcfilters.ui.ChangesListWrapperWidget.prototype.updateEnhancedParentHighlight = function () { + var activeHighlightClasses, + $enhancedTopPageCell = this.$element.find( 'table.mw-enhanced-rc.mw-collapsible' ); + + activeHighlightClasses = this.filtersViewModel.getCurrentlyUsedHighlightColors().map( function ( color ) { + return 'mw-rcfilters-highlight-color-' + color; + } ); + + // Go over top pages and their children, and figure out if all sub-pages have the + // same highlights between themselves. If they do, the parent should be highlighted + // with all colors. If classes are different, the parent should receive a grey + // background + $enhancedTopPageCell.each( function () { + var firstChildClasses, $rowsWithDifferentHighlights, + $table = $( this ); + + // Collect the relevant classes from the first nested child + firstChildClasses = activeHighlightClasses.filter( function ( className ) { + return $table.find( 'tr:nth-child(2)' ).hasClass( className ); + } ); + // Filter the non-head rows and see if they all have the same classes + // to the first row + $rowsWithDifferentHighlights = $table.find( 'tr:not(:first-child)' ).filter( function () { + var classesInThisRow, + $this = $( this ); + + classesInThisRow = activeHighlightClasses.filter( function ( className ) { + return $this.hasClass( className ); + } ); + + return !OO.compare( firstChildClasses, classesInThisRow ); + } ); + + // If classes are different, tag the row for using grey color + $table.find( 'tr:first-child' ) + .toggleClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey', $rowsWithDifferentHighlights.length > 0 ); + } ); + }; + /** * @return {boolean} Whether the changes are grouped by page */ @@ -329,6 +447,10 @@ } } ); + if ( this.inEnhancedMode() ) { + this.updateEnhancedParentHighlight(); + } + // Turn on highlights this.$element.addClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' ); }; @@ -345,6 +467,11 @@ this.$element.find( '[data-highlightedFilters]' ) .removeAttr( 'title' ) .removeAttr( 'data-highlightedFilters' ); + + // Remove grey from enhanced rows + this.$element.find( '.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' ) + .removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey' ); + // Turn off highlights this.$element.removeClass( 'mw-rcfilters-ui-changesListWrapperWidget-highlighted' ); };