2 * JavaScript for Special:Preferences: Tab navigation.
6 var $preferences
, tabs
, wrapper
, previousTab
, switchingNoHash
;
8 $preferences
= $( '#preferences' );
10 // Make sure the accessibility tip is selectable so that screen reader users take notice,
11 // but hide it by default to reduce visual clutter.
12 // Make sure it becomes visible when focused.
13 $( '<div>' ).addClass( 'mw-navigation-hint' )
14 .text( mw
.msg( 'prefs-tabs-navigation-hint' ) )
15 .attr( 'tabIndex', 0 )
16 .prependTo( '#mw-content-text' );
18 tabs
= new OO
.ui
.IndexLayout( {
20 // Do not remove focus from the tabs menu after choosing a tab
24 mw
.config
.get( 'wgPreferencesTabs' ).forEach( function ( tabConfig
) {
25 var panel
, $panelContents
;
27 panel
= new OO
.ui
.TabPanelLayout( tabConfig
.name
, {
29 label
: tabConfig
.label
31 $panelContents
= $( '#mw-prefsection-' + tabConfig
.name
);
33 // Hide the unnecessary PHP PanelLayouts
34 // (Do not use .remove(), as that would remove event handlers for everything inside them)
35 $panelContents
.parent().detach();
37 panel
.$element
.append( $panelContents
);
38 tabs
.addTabPanels( [ panel
] );
40 // Remove duplicate labels
41 // (This must be after .addTabPanels(), otherwise the tab item doesn't exist yet)
42 $panelContents
.children( 'legend' ).remove();
43 $panelContents
.attr( 'aria-labelledby', panel
.getTabItem().getElementId() );
46 wrapper
= new OO
.ui
.PanelLayout( {
51 wrapper
.$element
.append( tabs
.$element
);
52 $preferences
.prepend( wrapper
.$element
);
53 $( '.mw-prefs-faketabs' ).remove();
55 function enhancePanel( panel
) {
56 if ( !panel
.$element
.data( 'mw-section-infused' ) ) {
57 // mw-htmlform-autoinfuse-lazy class has been removed by replacing faketabs
58 mw
.hook( 'htmlform.enhance' ).fire( panel
.$element
);
59 panel
.$element
.data( 'mw-section-infused', true );
63 function onTabPanelSet( panel
) {
64 var scrollTop
, active
;
66 if ( switchingNoHash
) {
69 // Handle hash manually to prevent jumping,
70 // therefore save and restore scrollTop to prevent jumping.
71 scrollTop
= $( window
).scrollTop();
72 // Changing the hash apparently causes keyboard focus to be lost?
73 // Save and restore it. This makes no sense though.
74 active
= document
.activeElement
;
75 location
.hash
= '#mw-prefsection-' + panel
.getName();
79 $( window
).scrollTop( scrollTop
);
82 tabs
.on( 'set', onTabPanelSet
);
86 * @param {string} name the name of a tab without the prefix ("mw-prefsection-")
87 * @param {boolean} [noHash] A hash will be set according to the current
88 * open section. Use this flag to suppress this.
90 function switchPrefTab( name
, noHash
) {
92 switchingNoHash
= true;
94 tabs
.setTabPanel( name
);
95 enhancePanel( tabs
.getCurrentTabPanel() );
97 switchingNoHash
= false;
101 // Jump to correct section as indicated by the hash.
102 // This function is called onload and onhashchange.
103 function detectHash() {
104 var hash
= location
.hash
,
105 matchedElement
, parentSection
;
106 if ( hash
.match( /^#mw-prefsection-[\w]+$/ ) ) {
107 mw
.storage
.session
.remove( 'mwpreferences-prevTab' );
108 switchPrefTab( hash
.replace( '#mw-prefsection-', '' ) );
109 } else if ( hash
.match( /^#mw-[\w-]+$/ ) ) {
110 matchedElement
= document
.getElementById( hash
.slice( 1 ) );
111 parentSection
= $( matchedElement
).parent().closest( '[id^="mw-prefsection-"]' );
112 if ( parentSection
.length
) {
113 mw
.storage
.session
.remove( 'mwpreferences-prevTab' );
114 // Switch to proper tab and scroll to selected item.
115 switchPrefTab( parentSection
.attr( 'id' ).replace( 'mw-prefsection-', '' ), true );
116 matchedElement
.scrollIntoView();
121 $( window
).on( 'hashchange', function () {
122 var hash
= location
.hash
;
123 if ( hash
.match( /^#mw-[\w-]+/ ) ) {
125 } else if ( hash
=== '' ) {
126 switchPrefTab( 'personal', true );
129 // Run the function immediately to select the proper tab on startup.
130 .trigger( 'hashchange' );
132 // Restore the active tab after saving the preferences
133 previousTab
= mw
.storage
.session
.get( 'mwpreferences-prevTab' );
135 switchPrefTab( previousTab
, true );
136 // Deleting the key, the tab states should be reset until we press Save
137 mw
.storage
.session
.remove( 'mwpreferences-prevTab' );
140 $( '#mw-prefs-form' ).on( 'submit', function () {
141 var value
= tabs
.getCurrentTabPanelName();
142 mw
.storage
.session
.set( 'mwpreferences-prevTab', value
);