Page MenuHomePhabricator

mw.util.addPortletLink incorrectly adds link to mutiple <ul> tags
Closed, ResolvedPublic

Description

Author: Amalthea.wikimedia

Description:
mediaWiki.util.addPortletLink incorrectly adds the created portlet link to all uw tags in a portlet.

For most skins, addPortletLink uses the following logic to decide where to add the newly created link:

// Select the first (most likely only) unordered list inside the portlet
$ul = $portlet.find( 'ul' );

.find('ul') does of course find /all/ unordered list tags in the portlet element.

This can be problematic for utilities that place further unordered lists in the portlet to create submenus.
While doing that might not be directly supported by MediaWiki, I don't see there's ever a cause to add a portlet link multiple times.
Assuming that the jQuery filter function ".first()" is deterministic and works as I think it does, I assume that changing the aforementioned line to

$ul = $portlet.find( 'ul' ).first();

would fix the issue without breaking functionality that anybody relies on (or should rely on). Judging by the comment that was the intended behavior in the first place.

Steps to reproduce:

wgUserGroups.push("sysop"); //to convince easyblock to show up
importScriptURI('//en.wikipedia.org/w/index.php?action=raw&ctype='+
                'text/javascript&title=User:Animum/easyblock.js');
//wait till import finished before executing the next line
mw.util.addPortletLink( "p-cactions", "#", "TEST" );

-> the 'TEST' item is both in the "p-cactions" menu and in each of easyblock's submenus.


Version: 1.18.x
Severity: normal

Details

Reference
bz35082

Event Timeline

bzimport raised the priority of this task from to Low.Nov 22 2014, 12:09 AM
bzimport set Reference to bz35082.

Yes, this is a valid bug. I've reproduced it with the following on en.wikipedia.org:

"easyblock.js" is sysop-only
mw.config.get( 'wgUserGroups' ).push( 'sysop' );
$.getScript('
en.wikipedia.org/w/index.php?title=User:Animum/easyblock.js&action=raw&ctype=text/javascript',

function () {
    mw.util.addPortletLink( 'p-cactions', '#', 'TEST' );
}

);

I suggest fixing it by using ".children( 'ul' ).eq(0)" instead of ".find( 'ul' )"

Went with .find( 'ul' ).eq( 0 ), because it can be inside a sub <div> (like in Vector), so children() wouldn't find it.

Change-Id: I51e9053292f03c1b833db0df2fb1b40f1eaf8b1a