collapsibleNav.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /**
  2. * Collapsible navigation for Vector
  3. */
  4. ( function ( mw, $ ) {
  5. 'use strict';
  6. var map;
  7. // Use the same function for all navigation headings - don't repeat
  8. function toggle( $element ) {
  9. var isCollapsed = $element.parent().is( '.collapsed' );
  10. $.cookie(
  11. 'vector-nav-' + $element.parent().attr( 'id' ),
  12. isCollapsed,
  13. { 'expires': 30, 'path': '/' }
  14. );
  15. $element
  16. .parent()
  17. .toggleClass( 'expanded' )
  18. .toggleClass( 'collapsed' )
  19. .find( '.body' )
  20. .slideToggle( 'fast' );
  21. isCollapsed = !isCollapsed;
  22. $element
  23. .find( '> a' )
  24. .attr( {
  25. 'aria-pressed': isCollapsed ? 'false' : 'true',
  26. 'aria-expanded': isCollapsed ? 'false' : 'true'
  27. } );
  28. }
  29. /* Browser Support */
  30. map = {
  31. // Left-to-right languages
  32. ltr: {
  33. // Collapsible Nav is broken in Opera < 9.6 and Konqueror < 4
  34. opera: [['>=', 9.6]],
  35. konqueror: [['>=', 4.0]],
  36. blackberry: false,
  37. ipod: false,
  38. iphone: false,
  39. ps3: false
  40. },
  41. // Right-to-left languages
  42. rtl: {
  43. opera: [['>=', 9.6]],
  44. konqueror: [['>=', 4.0]],
  45. blackberry: false,
  46. ipod: false,
  47. iphone: false,
  48. ps3: false
  49. }
  50. };
  51. if ( !$.client.test( map ) ) {
  52. return true;
  53. }
  54. $( function ( $ ) {
  55. var $headings, tabIndex;
  56. /* General Portal Modification */
  57. // Always show the first portal
  58. $( '#mw-panel > .portal:first' ).addClass( 'first persistent' );
  59. // Apply a class to the entire panel to activate styles
  60. $( '#mw-panel' ).addClass( 'collapsible-nav' );
  61. // Use cookie data to restore preferences of what to show and hide
  62. $( '#mw-panel > .portal:not(.persistent)' )
  63. .each( function ( i ) {
  64. var id = $(this).attr( 'id' ),
  65. state = $.cookie( 'vector-nav-' + id );
  66. $(this).find( 'ul:first' ).attr( 'id', id + '-list' );
  67. // Add anchor tag to heading for better accessibility
  68. $( this ).find( 'h3' ).wrapInner(
  69. $( '<a>' )
  70. .attr( {
  71. href: '#',
  72. 'aria-haspopup': 'true',
  73. 'aria-controls': id + '-list',
  74. role: 'button'
  75. } )
  76. .click( false )
  77. );
  78. // In the case that we are not showing the new version, let's show the languages by default
  79. if (
  80. state === 'true' ||
  81. ( state === null && i < 1 ) ||
  82. ( state === null && id === 'p-lang' )
  83. ) {
  84. $(this)
  85. .addClass( 'expanded' )
  86. .removeClass( 'collapsed' )
  87. .find( '.body' )
  88. .hide() // bug 34450
  89. .show();
  90. $(this).find( 'h3 > a' )
  91. .attr( {
  92. 'aria-pressed': 'true',
  93. 'aria-expanded': 'true'
  94. } );
  95. } else {
  96. $(this)
  97. .addClass( 'collapsed' )
  98. .removeClass( 'expanded' );
  99. $(this).find( 'h3 > a' )
  100. .attr( {
  101. 'aria-pressed': 'false',
  102. 'aria-expanded': 'false'
  103. } );
  104. }
  105. // Re-save cookie
  106. if ( state !== null ) {
  107. $.cookie( 'vector-nav-' + $(this).attr( 'id' ), state, { 'expires': 30, 'path': '/' } );
  108. }
  109. } );
  110. /* Tab Indexing */
  111. $headings = $( '#mw-panel > .portal:not(.persistent) > h3' );
  112. // Get the highest tab index
  113. tabIndex = $( document ).lastTabIndex() + 1;
  114. // Fix the search not having a tabindex
  115. $( '#searchInput' ).attr( 'tabindex', tabIndex++ );
  116. // Make it keyboard accessible
  117. $headings.attr( 'tabindex', function () {
  118. return tabIndex++;
  119. });
  120. // Toggle the selected menu's class and expand or collapse the menu
  121. $( '#mw-panel' )
  122. .delegate( '.portal:not(.persistent) > h3', 'keydown', function ( e ) {
  123. // Make the space and enter keys act as a click
  124. if ( e.which === 13 /* Enter */ || e.which === 32 /* Space */ ) {
  125. toggle( $(this) );
  126. }
  127. } )
  128. .delegate( '.portal:not(.persistent) > h3', 'mousedown', function ( e ) {
  129. if ( e.which !== 3 ) { // Right mouse click
  130. toggle( $(this) );
  131. $(this).blur();
  132. }
  133. return false;
  134. } );
  135. });
  136. }( mediaWiki, jQuery ) );