( function ( mw, $ ) {
$( function () {
var $preftoc, $preferences, $fieldsets,
- hash, labelFunc,
+ labelFunc,
$tzSelect, $tzTextbox, $localtimeHolder, servertime,
allowCloseWindow, notif;
notif = null;
}
} );
-
- // Remove now-unnecessary success=1 querystring to prevent reappearance of notification on reload
- if ( history.replaceState ) {
- history.replaceState( {}, document.title, location.href.replace( /&?success=1/, '' ) );
- }
}
}
}
} );
- // If we've reloaded the page or followed an open-in-new-window,
- // make the selected tab visible.
- hash = location.hash;
- if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
- switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+ // Jump to correct section as indicated by the hash.
+ // This function is called onload and onhashchange.
+ function detectHash() {
+ var hash = location.hash,
+ matchedElement, parentSection;
+ if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
+ switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+ } else if ( hash.match( /^#mw-[\w\-]+/ ) ) {
+ matchedElement = document.getElementById( hash.slice( 1 ) );
+ parentSection = $( matchedElement ).closest( '.prefsection' );
+ if ( parentSection.length ) {
+ // Switch to proper tab and scroll to selected item.
+ switchPrefTab( parentSection.attr( 'id' ).replace( 'mw-prefsection-', '' ), 'noHash' );
+ matchedElement.scrollIntoView();
+ }
+ }
}
// In browsers that support the onhashchange event we will not bind click
// handlers and instead let the browser do the default behavior (clicking the
// <a href="#.."> will naturally set the hash, handled by onhashchange.
- // But other things that change the hash will also be catched (e.g. using
+ // But other things that change the hash will also be caught (e.g. using
// the Back and Forward browser navigation).
// Note the special check for IE "compatibility" mode.
if ( 'onhashchange' in window &&
) {
$( window ).on( 'hashchange', function () {
var hash = location.hash;
- if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
- switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+ if ( hash.match( /^#mw-[\w\-]+/ ) ) {
+ detectHash();
} else if ( hash === '' ) {
switchPrefTab( 'personal', 'noHash' );
}
- } );
+ } )
+ // Run the function immediately to select the proper tab on startup.
+ .trigger( 'hashchange' );
// In older browsers we'll bind a click handler as fallback.
- // We must not have onhashchange *and* the click handlers, other wise
+ // We must not have onhashchange *and* the click handlers, otherwise
// the click handler calls switchPrefTab() which sets the hash value,
- // which triggers onhashcange and calls switchPrefTab() again.
+ // which triggers onhashchange and calls switchPrefTab() again.
} else {
$preftoc.on( 'click', 'li a', function ( e ) {
switchPrefTab( $( this ).attr( 'href' ).replace( '#mw-prefsection-', '' ) );
e.preventDefault();
} );
+ // If we've reloaded the page or followed an open-in-new-window,
+ // make the selected tab visible.
+ detectHash();
}
// Timezone functions.
var minuteDiff, localTime,
type = $tzSelect.val();
- if ( type === 'guess' ) {
- // Get browser timezone & fill it in
- minuteDiff = -( new Date().getTimezoneOffset() );
- $tzTextbox.val( minutesToHours( minuteDiff ) );
- $tzSelect.val( 'other' );
- $tzTextbox.prop( 'disabled', false );
- } else if ( type === 'other' ) {
+ if ( type === 'other' ) {
+ // User specified time zone manually in <input>
// Grab data from the textbox, parse it.
minuteDiff = hoursToMinutes( $tzTextbox.val() );
} else {
- // Grab data from the $tzSelect value
- minuteDiff = parseInt( type.split( '|' )[ 1 ], 10 ) || 0;
- $tzTextbox.val( minutesToHours( minuteDiff ) );
+ // Time zone not manually specified by user
+ if ( type === 'guess' ) {
+ // Get browser timezone & fill it in
+ minuteDiff = -( new Date().getTimezoneOffset() );
+ $tzTextbox.val( minutesToHours( minuteDiff ) );
+ $tzSelect.val( 'other' );
+ $tzTextbox.prop( 'disabled', false );
+ } else {
+ // Grab data from the $tzSelect value
+ minuteDiff = parseInt( type.split( '|' )[ 1 ], 10 ) || 0;
+ $tzTextbox.val( minutesToHours( minuteDiff ) );
+ }
+
+ // Set defaultValue prop on the generated box so we don't trigger the
+ // unsaved preferences check
+ $tzTextbox.prop( 'defaultValue', $tzTextbox.val() );
}
// Determine local time from server time and minutes difference, for display.
} );
}
+ // Check if all of the form values are unchanged
+ function isPrefsChanged() {
+ var inputs = $( '#mw-prefs-form :input' ),
+ input, $input, inputType,
+ index, optIndex,
+ opt;
+
+ for ( index = 0; index < inputs.length; index++ ) {
+ input = inputs[ index ];
+ $input = $( input );
+
+ // Different types of inputs have different methods for accessing defaults
+ if ( $input.is( 'select' ) ) { // <select> has the property defaultSelected for each option
+ for ( optIndex = 0; optIndex < input.options.length; optIndex++ ) {
+ opt = input.options[ optIndex ];
+ if ( opt.selected !== opt.defaultSelected ) {
+ return true;
+ }
+ }
+ } else if ( $input.is( 'input' ) ) { // <input> has defaultValue or defaultChecked
+ inputType = input.type;
+ if ( inputType === 'radio' || inputType === 'checkbox' ) {
+ if ( input.checked !== input.defaultChecked ) {
+ return true;
+ }
+ } else if ( input.value !== input.defaultValue ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Disable the button to save preferences unless preferences have changed
+ // Check if preferences have been changed before JS has finished loading
+ if ( !isPrefsChanged() ) {
+ $( '#prefcontrol' ).prop( 'disabled', true );
+ $( '#preferences > fieldset' ).one( 'change keydown mousedown', function () {
+ $( '#prefcontrol' ).prop( 'disabled', false );
+ } );
+ }
+
// Set up a message to notify users if they try to leave the page without
// saving.
- $( '#mw-prefs-form' ).data( 'origdata', $( '#mw-prefs-form' ).serialize() );
allowCloseWindow = mw.confirmCloseWindow( {
- test: function () {
- return $( '#mw-prefs-form' ).serialize() !== $( '#mw-prefs-form' ).data( 'origdata' );
- },
-
+ test: isPrefsChanged,
message: mw.msg( 'prefswarning-warning', mw.msg( 'saveprefs' ) ),
namespace: 'prefswarning'
} );