Merge "Some fixes to our jQuery UI skin for buttons"
[lhc/web/wiklou.git] / resources / mediawiki.special / mediawiki.special.preferences.js
1 /*
2 * JavaScript for Special:Preferences
3 */
4 jQuery( document ).ready( function ( $ ) {
5 $( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
6 var $preftoc = $('<ul id="preftoc"></ul>');
7 var $preferences = $( '#preferences' )
8 .addClass( 'jsprefs' )
9 .before( $preftoc );
10
11 var $fieldsets = $preferences.children( 'fieldset' )
12 .hide()
13 .addClass( 'prefsection' );
14
15 var $legends = $fieldsets.children( 'legend' )
16 .addClass( 'mainLegend' );
17
18 /**
19 * It uses document.getElementById for security reasons (html injections in
20 * jQuery()).
21 *
22 * @param String name: the name of a tab without the prefix ("mw-prefsection-")
23 * @param String mode: [optional] A hash will be set according to the current
24 * open section. Set mode 'noHash' to surpress this.
25 */
26 function switchPrefTab( name, mode ) {
27 var $tab, scrollTop;
28 // Handle hash manually to prevent jumping,
29 // therefore save and restore scrollTop to prevent jumping.
30 scrollTop = $( window ).scrollTop();
31 if ( mode !== 'noHash' ) {
32 window.location.hash = '#mw-prefsection-' + name;
33 }
34 $( window ).scrollTop( scrollTop );
35
36 $preftoc.find( 'li' ).removeClass( 'selected' );
37 $tab = $( document.getElementById( 'preftab-' + name ) );
38 if ( $tab.length ) {
39 $tab.parent().addClass( 'selected' );
40 $preferences.children( 'fieldset' ).hide();
41 $( document.getElementById( 'mw-prefsection-' + name ) ).show();
42 }
43 }
44
45 // Populate the prefToc
46 $legends.each( function ( i, legend ) {
47 var $legend = $(legend);
48 if ( i === 0 ) {
49 $legend.parent().show();
50 }
51 var ident = $legend.parent().attr( 'id' );
52
53 var $li = $( '<li/>', {
54 'class' : ( i === 0 ) ? 'selected' : null
55 });
56 var $a = $( '<a/>', {
57 text : $legend.text(),
58 id : ident.replace( 'mw-prefsection', 'preftab' ),
59 href : '#' + ident
60 });
61 $li.append( $a );
62 $preftoc.append( $li );
63 } );
64
65 // If we've reloaded the page or followed an open-in-new-window,
66 // make the selected tab visible.
67 var hash = window.location.hash;
68 if ( hash.match( /^#mw-prefsection-[\w-]+/ ) ) {
69 switchPrefTab( hash.replace( '#mw-prefsection-' , '' ) );
70 }
71
72 // In browsers that support the onhashchange event we will not bind click
73 // handlers and instead let the browser do the default behavior (clicking the
74 // <a href="#.."> will naturally set the hash, handled by onhashchange.
75 // But other things that change the hash will also be catched (e.g. using
76 // the Back and Forward browser navigation).
77 if ( 'onhashchange' in window ) {
78 $(window).on( 'hashchange' , function () {
79 var hash = window.location.hash;
80 if ( hash.match( /^#mw-prefsection-[\w-]+/ ) ) {
81 switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
82 } else if ( hash === '' ) {
83 switchPrefTab( 'personal', 'noHash' );
84 }
85 });
86 // In older browsers we'll bind a click handler as fallback.
87 // We must not have onhashchange *and* the click handlers, other wise
88 // the click handler calls switchPrefTab() which sets the hash value,
89 // which triggers onhashcange and calls switchPrefTab() again.
90 } else {
91 $preftoc.on( 'click', 'li a', function ( e ) {
92 switchPrefTab( $( this ).attr( 'href' ).replace( '#mw-prefsection-', '' ) );
93 e.preventDefault();
94 });
95 }
96
97 /**
98 * Timezone functions.
99 * Guesses Timezone from browser and updates fields onchange
100 */
101
102 var $tzSelect = $( '#mw-input-wptimecorrection' );
103 var $tzTextbox = $( '#mw-input-wptimecorrection-other' );
104
105 var $localtimeHolder = $( '#wpLocalTime' );
106 var servertime = parseInt( $( 'input[name=wpServerTime]' ).val(), 10 );
107 var minuteDiff = 0;
108
109 var minutesToHours = function ( min ) {
110 var tzHour = Math.floor( Math.abs( min ) / 60 );
111 var tzMin = Math.abs( min ) % 60;
112 var tzString = ( ( min >= 0 ) ? '' : '-' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour +
113 ':' + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
114 return tzString;
115 };
116
117 var hoursToMinutes = function ( hour ) {
118 var arr = hour.split( ':' );
119 arr[0] = parseInt( arr[0], 10 );
120
121 var minutes;
122 if ( arr.length == 1 ) {
123 // Specification is of the form [-]XX
124 minutes = arr[0] * 60;
125 } else {
126 // Specification is of the form [-]XX:XX
127 minutes = Math.abs( arr[0] ) * 60 + parseInt( arr[1], 10 );
128 if ( arr[0] < 0 ) {
129 minutes *= -1;
130 }
131 }
132 // Gracefully handle non-numbers.
133 if ( isNaN( minutes ) ) {
134 return 0;
135 } else {
136 return minutes;
137 }
138 };
139
140 var updateTimezoneSelection = function () {
141 var type = $tzSelect.val();
142 if ( type == 'guess' ) {
143 // Get browser timezone & fill it in
144 minuteDiff = -new Date().getTimezoneOffset();
145 $tzTextbox.val( minutesToHours( minuteDiff ) );
146 $tzSelect.val( 'other' );
147 $tzTextbox.get( 0 ).disabled = false;
148 } else if ( type == 'other' ) {
149 // Grab data from the textbox, parse it.
150 minuteDiff = hoursToMinutes( $tzTextbox.val() );
151 } else {
152 // Grab data from the $tzSelect value
153 minuteDiff = parseInt( type.split( '|' )[1], 10 ) || 0;
154 $tzTextbox.val( minutesToHours( minuteDiff ) );
155 }
156
157 // Determine local time from server time and minutes difference, for display.
158 var localTime = servertime + minuteDiff;
159
160 // Bring time within the [0,1440) range.
161 while ( localTime < 0 ) {
162 localTime += 1440;
163 }
164 while ( localTime >= 1440 ) {
165 localTime -= 1440;
166 }
167 $localtimeHolder.text( minutesToHours( localTime ) );
168 };
169
170 if ( $tzSelect.length && $tzTextbox.length ) {
171 $tzSelect.change( function () { updateTimezoneSelection(); } );
172 $tzTextbox.blur( function () { updateTimezoneSelection(); } );
173 updateTimezoneSelection();
174 }
175 } );