r82471 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r82470‎ | r82471 | r82472 >
Date:17:46, 19 February 2011
Author:krinkle
Status:ok (Comments)
Tags:todo 
Comment:
Improving jquery.makeCollapsible & small fixed mw.util
* Making makeCollapsible more DRY.
* Small optimalizations and fixes in mw.util
Modified paths:
  • /trunk/phase3/resources/jquery/jquery.makeCollapsible.js (modified) (history)
  • /trunk/phase3/resources/mediawiki.util/mediawiki.util.js (modified) (history)

Diff [purge]

Index: trunk/phase3/resources/jquery/jquery.makeCollapsible.js
@@ -26,7 +26,7 @@
2727 that = this,
2828 collapsetext = $(this).attr( 'data-collapsetext' ),
2929 expandtext = $(this).attr( 'data-expandtext' ),
30 - toggleElement = function( $collapsible, action, $defaultToggle ) {
 30+ toggleElement = function( $collapsible, action, $defaultToggle, instantHide ) {
3131 // Validate parameters
3232 if ( !$collapsible.jquery ) { // $collapsible must be an instance of jQuery
3333 return;
@@ -35,10 +35,11 @@
3636 // action must be string with 'expand' or 'collapse'
3737 return;
3838 }
39 - if ( typeof $defaultToggle !== 'undefined' && !$defaultToggle.jquery ) {
 39+ if ( $defaultToggle && !$defaultToggle.jquery ) {
4040 // is optional, but if passed must be an instance of jQuery
4141 return;
4242 }
 43+ var $containers = null;
4344
4445 if ( action == 'collapse' ) {
4546
@@ -47,20 +48,29 @@
4849 // Hide all table rows of this table
4950 // Slide doens't work with tables, but fade does as of jQuery 1.1.3
5051 // http://stackoverflow.com/questions/467336#920480
51 -
52 - if ( $defaultToggle.jquery ) {
 52+ $containers = $collapsible.find( '>tbody>tr' );
 53+ if ( $defaultToggle && $defaultToggle.jquery ) {
5354 // Exclude tablerow containing togglelink
54 - $collapsible.find( '>tbody>tr' ).not( $defaultToggle.parent().parent() ).stop(true, true).fadeOut();
 55+ $containers.not( $defaultToggle.parent().parent() ).stop(true, true).fadeOut();
5556 } else {
56 - $collapsible.find( '>tbody>tr' ).stop( true, true ).fadeOut();
 57+ if ( instantHide ) {
 58+ $containers.hide();
 59+ } else {
 60+ $containers.stop( true, true ).fadeOut();
 61+ }
5762 }
5863
5964 } else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
60 - if ( $defaultToggle.jquery ) {
 65+ $containers = $collapsible.find( '> li' );
 66+ if ( $defaultToggle && $defaultToggle.jquery ) {
6167 // Exclude list-item containing togglelink
62 - $collapsible.find( '> li' ).not( $defaultToggle.parent() ).stop( true, true ).slideUp();
 68+ $containers.not( $defaultToggle.parent() ).stop( true, true ).slideUp();
6369 } else {
64 - $collapsible.find( '> li' ).stop( true, true ).slideUp();
 70+ if ( instantHide ) {
 71+ $containers.hide();
 72+ } else {
 73+ $containers.stop( true, true ).slideUp();
 74+ }
6575 }
6676
6777 } else { // <div>, <p> etc.
@@ -68,7 +78,11 @@
6979
7080 // If a collapsible-content is defined, collapse it
7181 if ( $collapsibleContent.size() ) {
72 - $collapsibleContent.slideUp();
 82+ if ( instantHide ) {
 83+ $collapsibleContent.hide();
 84+ } else {
 85+ $collapsibleContent.slideUp();
 86+ }
7387
7488 // Otherwise assume this is a customcollapse with a remote toggle
7589 // .. and there is no collapsible-content because the entire element should be toggled
@@ -85,19 +99,21 @@
86100
87101 // Expand the element
88102 if ( $collapsible.is( 'table' ) ) {
89 - if ( $defaultToggle.jquery ) {
 103+ $containers = $collapsible.find( '>tbody>tr' );
 104+ if ( $defaultToggle && $defaultToggle.jquery ) {
90105 // Exclude tablerow containing togglelink
91 - $collapsible.find( '>tbody>tr' ).not( $defaultToggle.parent().parent() ).stop(true, true).fadeIn();
 106+ $containers.not( $defaultToggle.parent().parent() ).stop(true, true).fadeIn();
92107 } else {
93 - $collapsible.find( '>tbody>tr' ).stop(true, true).fadeIn();
 108+ $containers.stop(true, true).fadeIn();
94109 }
95110
96111 } else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
97 - if ( $defaultToggle.jquery ) {
 112+ $containers = $collapsible.find( '> li' );
 113+ if ( $defaultToggle && $defaultToggle.jquery ) {
98114 // Exclude list-item containing togglelink
99 - $collapsible.find( '> li' ).not( $defaultToggle.parent() ).stop( true, true ).slideDown();
 115+ $containers.not( $defaultToggle.parent() ).stop( true, true ).slideDown();
100116 } else {
101 - $collapsible.find( '> li' ).stop( true, true ).slideDown();
 117+ $containers.stop( true, true ).slideDown();
102118 }
103119
104120 } else { // <div>, <p> etc.
@@ -293,6 +309,7 @@
294310 // The collapsible element could have multiple togglers
295311 // To toggle the initial state only click one of them (ie. the first one, eq(0) )
296312 // Else it would go like: hide,show,hide,show for each toggle link.
 313+ toggleElement( $that, 'collapse', null, /* instantHide = */ true );
297314 $toggleLink.eq(0).click();
298315 }
299316 } );
Index: trunk/phase3/resources/mediawiki.util/mediawiki.util.js
@@ -77,8 +77,8 @@
7878
7979 } else {
8080 // #content is present on almost all if not all skins. Most skins (the above cases)
81 - // have #content too, but as a outer wrapper instead of the article text container.
82 - // The skins that don't have an outer wrapper have #content for everything
 81+ // have #content too, but as an outer wrapper instead of the article text container.
 82+ // The skins that don't have an outer wrapper do have #content for everything
8383 // so it's a good fallback
8484 mw.util.$content = $( '#content' );
8585 }
@@ -323,17 +323,16 @@
324324 *
325325 * @param portlet ID of the target portlet ( 'p-cactions' or 'p-personal' etc.)
326326 * @param href Link URL
327 - * @param text Link text (will be automatically converted to lower
328 - * case by CSS for p-cactions in Monobook)
 327+ * @param text Link text
329328 * @param id ID of the new item, should be unique and preferably have
330329 * the appropriate prefix ( 'ca-', 'pt-', 'n-' or 't-' )
331330 * @param tooltip Text to show when hovering over the link, without accesskey suffix
332331 * @param accesskey Access key to activate this link (one character, try
333 - * to avoid conflicts. Use $( '[accesskey=x' ).get() in the console to
 332+ * to avoid conflicts. Use $( '[accesskey=x]' ).get() in the console to
334333 * see if 'x' is already used.
335 - * @param nextnode DOM node or jQuery-selector of the item that the new
 334+ * @param nextnode DOM node or jQuery-selector string of the item that the new
336335 * item should be added before, should be another item in the same
337 - * list will be ignored if not the so
 336+ * list, it will be ignored otherwise
338337 *
339338 * @return The DOM node of the new item (a LI element, or A element for
340339 * older skins) or null.
@@ -352,28 +351,28 @@
353352
354353 // Some skins don't have any portlets
355354 // just add it to the bottom of their 'sidebar' element as a fallback
356 - switch ( skin ) {
 355+ switch ( mw.config.get( 'skin' ) ) {
357356 case 'standard' :
358357 case 'cologneblue' :
359 - $("#quickbar").append($link.after( '<br />' ));
360 - return $link.get(0);
 358+ $( '#quickbar' ).append( $link.after( '<br />' ) );
 359+ return $link[0];
361360 case 'nostalgia' :
362 - $("#searchform").before($link).before( ' &#124; ' );
363 - return $link.get(0);
 361+ $( '#searchform' ).before( $link).before( ' &#124; ' );
 362+ return $link[0];
364363 default : // Skins like chick, modern, monobook, myskin, simple, vector...
365364
366365 // Select the specified portlet
367 - var $portlet = $( '#' + portlet);
 366+ var $portlet = $( '#' + portlet );
368367 if ( $portlet.length === 0 ) {
369368 return null;
370369 }
371370 // Select the first (most likely only) unordered list inside the portlet
372 - var $ul = $portlet.find( 'ul' ).eq( 0 );
 371+ var $ul = $portlet.find( 'ul' );
373372
374373 // If it didn't have an unordered list yet, create it
375 - if ($ul.length === 0) {
 374+ if ( $ul.length === 0 ) {
376375 // If there's no <div> inside, append it to the portlet directly
377 - if ($portlet.find( 'div' ).length === 0) {
 376+ if ( $portlet.find( 'div:first' ).length === 0 ) {
378377 $portlet.append( '<ul/>' );
379378 } else {
380379 // otherwise if there's a div (such as div.body or div.pBody)
@@ -409,7 +408,7 @@
410409 }
411410
412411 // Append using DOM-element passing
413 - if ( nextnode && nextnode.parentNode == $ul.get( 0 ) ) {
 412+ if ( nextnode && nextnode.parentNode == $ul[0] ) {
414413 $(nextnode).before( $item );
415414 } else {
416415 // If the jQuery selector isn't found within the <ul>, just
@@ -422,7 +421,7 @@
423422 }
424423 }
425424
426 - return $item.get( 0 );
 425+ return $item[0];
427426 }
428427 },
429428

Follow-up revisions

RevisionCommit summaryAuthorDate
r83309Fix bug in makeCollapsible....krinkle19:00, 5 March 2011

Comments

#Comment by Krinkle (talk | contribs)   17:49, 19 February 2011

Forgot to mention in the commit message:

makeCollapsible now instantly hides elements that have the mw-collapsed rather than sliding them up on-load (which was too visisble). now they really do start hidden.

#Comment by He7d3r (talk | contribs)   15:25, 22 July 2011

w:User:Emw reported at w:MediaWiki talk:JQuery-makeCollapsible.js that the collapsed content is still shown for some moments before being hidden. Could you take a look?

#Comment by Brion VIBBER (talk | contribs)   00:56, 26 October 2011

It looks like while it is doing a quickish hide at initialization time, it's still starting a fade-out animation afterwards (via the .click()) -- this could be causing the slowdowns described at bug 31945.

The previous note above about content still being shown uncollapsed for a bit before being hidden also matches what I see -- the initial state is visible until the initialize code gets run, hiding things. This means stuff will be visible expanded while the page is loading, if it takes long enough to load everything.

This can be (semi) solved by setting the style for the initially-collapsed class to make sure they're always hidden to begin with... however that's sub-ideal for non-JavaScript cases, where we need them to show initially visible. May need to resolve that.

#Comment by Krinkle (talk | contribs)   22:48, 8 November 2011

The non-JavaScript cases shouldn't be a problem due to the 'client-nojs' and 'client-js' classes we have available very early on.

The fadeOut via click(), I'm not seeing that. jQuery shouldn't be doing any animation since it's already hidden. However it may be doing some calculations to determine that. But since nothing visually get's done, I'm trying to understand the issue. Also, it only triggers the click event for 1 element (note eq(0)), so that can't realistically cause any slowdown.

Although it'll take a fairly major change, how about the following:

  • We use CSS (selecting .client-js only) to do the initial hiding of .mw-collapsible.mw-collapsed elements. That'll allow CSS to hide/prevent display of things before the browser even encounters them in the DOM.
    • This makes the added instantHide mode in this commit redundant.

and/or

  • Get rid of the .click() trigger. I like to do this very much. The reason it is currently still there is because custom trigggers need to be fired in order for them to be in the correct state (otherwise they will still 'think' the table is in the expanded state).
    • And instead of the click() trigger, we would trigger a custom event (i.e. "mw-collapsible-trigger.expand"). Then third parties would use that event to do anything fancy related to the collapsing/expanding, separate from the toggling of the main element.

Let me know what you think.

#Comment by Brion VIBBER (talk | contribs)   21:27, 13 December 2011

I like this idea; use of .client-js .mw-collapsible.mw-collapsed should indeed let us hide immediately, with at least less work than the synchronous loop. +1

Hopefully indeed the animation isn't an issue and it's just the sync loop on slower systems. Whee!

#Comment by Krinkle (talk | contribs)   22:49, 8 November 2011

Note that since this module is new in 1.18 (and the visible imperfection only appears for slower browsers), I'm not sure this is to stay a FIXME blocking 1.18 tarball. Perhaps turn it into a todo ? I'll leave it up to Brion.

#Comment by MarkAHershberger (talk | contribs)   17:41, 14 November 2011

We should probably put something in the release notes.

#Comment by Brion VIBBER (talk | contribs)   21:28, 13 December 2011

Switching to a todo -- still want the fixes Krinkle proposes above, but it's not a blocker for now. Danged annoying when it hits you though!

Status & tagging log