aboutsummaryrefslogtreecommitdiffstats
path: root/resources/src/mediawiki.special.preferences.ooui/confirmClose.js
blob: 51abf731eeaf253766230fa4597015c03acda291 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*!
 * JavaScript for Special:Preferences: Enable save button and prevent the window being accidentally
 * closed when any form field is changed.
 */
( function () {
	$( () => {
		// Check if all of the form values are unchanged.
		// (This function could be changed to infuse and check OOUI widgets, but that would only make it
		// slower and more complicated. It works fine to treat them as HTML elements.)
		function isPrefsChanged() {
			// eslint-disable-next-line no-jquery/no-sizzle
			const $inputs = $( '#mw-prefs-form :input[name]' );

			for ( let index = 0; index < $inputs.length; index++ ) {
				const input = $inputs[ index ];
				const $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 ( let optIndex = 0; optIndex < input.options.length; optIndex++ ) {
						const opt = input.options[ optIndex ];
						if ( opt.selected !== opt.defaultSelected ) {
							return true;
						}
					}
				} else if ( $input.is( 'input' ) || $input.is( 'textarea' ) ) {
					// <input> has defaultValue or defaultChecked
					const 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;
		}

		const saveButton = OO.ui.infuse( $( '#prefcontrol' ) );

		// Disable the button to save preferences unless preferences have changed
		// Check if preferences have been changed before JS has finished loading
		saveButton.setDisabled( !isPrefsChanged() );
		// Attach capturing event handlers to the document, to catch events inside OOUI dropdowns:
		// * Use capture because OO.ui.SelectWidget also does, and it stops event propagation,
		//   so the event is not fired on descendant elements
		// * Attach to the document because the dropdowns are in the .oo-ui-defaultOverlay element
		//   (and it doesn't exist yet at this point, so we can't attach them to it)
		[ 'change', 'keyup', 'mouseup' ].forEach( ( eventType ) => {
			document.addEventListener( eventType, () => {
				// Make sure SelectWidget's event handlers run first
				setTimeout( () => {
					saveButton.setDisabled( !isPrefsChanged() );
				} );
			}, true );
		} );

		// Prompt users if they try to leave the page without saving.
		const allowCloseWindow = mw.confirmCloseWindow( {
			test: isPrefsChanged
		} );
		$( '#mw-prefs-form' ).on( 'submit', allowCloseWindow.release );
	} );
}() );