2 * JavaScript for Special:Block
5 // Like OO.ui.infuse(), but if the element doesn't exist, return null instead of throwing an exception.
6 function infuseIfExists( $el ) {
10 return OO.ui.infuse( $el );
14 let blockTargetWidget, anonOnlyWidget, enableAutoblockWidget, hideUserWidget, watchUserWidget = null,
15 expiryWidget, editingRestrictionWidget, partialActionsRestrictionsWidget, preventTalkPageEditWidget,
16 pageRestrictionsWidget, namespaceRestrictionsWidget, createAccountWidget,
17 userChangedCreateAccount, updatingBlockOptions;
19 function preserveSelectedStateOnDisable( widget ) {
20 let widgetWasSelected;
26 // 'disable' event fires if disabled state changes
27 widget.on( 'disable', ( disabled ) => {
29 // Disabling an enabled widget
30 // Save selected and set selected to false
31 widgetWasSelected = widget.isSelected();
32 widget.setSelected( false );
34 // Enabling a disabled widget
35 // Set selected to the saved value
36 if ( widgetWasSelected !== undefined ) {
37 widget.setSelected( widgetWasSelected );
39 widgetWasSelected = undefined;
44 function updateBlockOptions() {
45 const blocktarget = blockTargetWidget.getValue().trim(),
46 isEmpty = blocktarget === '',
47 isIp = mw.util.isIPAddress( blocktarget, true ),
48 isNonEmptyIp = isIp && !isEmpty,
49 expiryValue = expiryWidget.getValue(),
50 isIndefinite = mw.util.isInfinity( expiryValue ),
51 editingRestrictionValue = editingRestrictionWidget.getValue(),
52 isSitewide = editingRestrictionValue === 'sitewide';
54 enableAutoblockWidget.setDisabled( isNonEmptyIp );
56 anonOnlyWidget.setDisabled( !isIp && !isEmpty );
58 if ( hideUserWidget ) {
59 hideUserWidget.setDisabled( isNonEmptyIp || !isIndefinite || !isSitewide );
62 updateWatchOption( blocktarget );
64 pageRestrictionsWidget.setDisabled( isSitewide );
65 namespaceRestrictionsWidget.setDisabled( isSitewide );
66 if ( preventTalkPageEditWidget ) {
67 // Disable for partial blocks, unless the block is against the User_talk namespace
68 preventTalkPageEditWidget.setDisabled(
69 // Partial block that blocks editing and doesn't block the User_talk namespace
71 editingRestrictionValue === 'partial' &&
72 namespaceRestrictionsWidget.getValue().indexOf(
73 String( mw.config.get( 'wgNamespaceIds' ).user_talk )
79 if ( !userChangedCreateAccount ) {
80 updatingBlockOptions = true;
81 createAccountWidget.setSelected( isSitewide );
82 updatingBlockOptions = false;
85 if ( partialActionsRestrictionsWidget ) {
86 partialActionsRestrictionsWidget.setDisabled( isSitewide );
90 function updateWatchOption( blocktarget ) {
91 const isEmpty = blocktarget === '',
92 isIp = mw.util.isIPAddress( blocktarget, true ),
93 isIpRange = isIp && blocktarget.match( /\/\d+$/ ),
94 isAutoBlock = blocktarget.match( /^#\d+$/ );
96 if ( watchUserWidget ) {
97 watchUserWidget.setDisabled( ( isAutoBlock || isIpRange ) && !isEmpty );
101 watchUserWidget = infuseIfExists( $( '#mw-input-wpWatch' ) );
102 if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Unblock' ) {
103 const $wpTarget = $( '#mw-input-wpTarget' );
104 if ( $wpTarget.attr( 'type' ) === 'hidden' ) {
105 // target is not changeable, determine watch state once
106 updateWatchOption( $wpTarget.val() );
109 blockTargetWidget = infuseIfExists( $wpTarget );
110 if ( blockTargetWidget ) {
111 blockTargetWidget.on( 'change', () => {
112 updateWatchOption( blockTargetWidget.getValue().trim() );
114 updateWatchOption( blockTargetWidget.getValue().trim() );
119 // This code is also loaded on the "block succeeded" page where there is no form,
120 // so check for block target widget; if it exists, the form is present
121 blockTargetWidget = infuseIfExists( $( '#mw-bi-target' ) );
123 if ( blockTargetWidget ) {
124 userChangedCreateAccount = mw.config.get( 'wgCreateAccountDirty' );
125 updatingBlockOptions = false;
127 // Always present if blockTargetWidget is present
128 expiryWidget = OO.ui.infuse( $( '#mw-input-wpExpiry' ) );
129 createAccountWidget = OO.ui.infuse( $( '#mw-input-wpCreateAccount' ) );
130 enableAutoblockWidget = OO.ui.infuse( $( '#mw-input-wpAutoBlock' ) );
131 anonOnlyWidget = OO.ui.infuse( $( '#mw-input-wpHardBlock' ) );
132 blockTargetWidget.on( 'change', updateBlockOptions );
133 expiryWidget.on( 'change', updateBlockOptions );
134 createAccountWidget.on( 'change', () => {
135 if ( !updatingBlockOptions ) {
136 userChangedCreateAccount = true;
139 editingRestrictionWidget = OO.ui.infuse( $( '#mw-input-wpEditingRestriction' ) );
140 pageRestrictionsWidget = OO.ui.infuse( $( '#mw-input-wpPageRestrictions' ) );
141 namespaceRestrictionsWidget = OO.ui.infuse( $( '#mw-input-wpNamespaceRestrictions' ) );
142 editingRestrictionWidget.on( 'change', updateBlockOptions );
143 namespaceRestrictionsWidget.on( 'change', updateBlockOptions );
145 // Present for certain rights
146 hideUserWidget = infuseIfExists( $( '#mw-input-wpHideUser' ) );
148 // Present for certain global configs
149 preventTalkPageEditWidget = infuseIfExists( $( '#mw-input-wpDisableUTEdit' ) );
150 // Move up and always infuse when wgEnablePartialActionBlocks gets removed
151 partialActionsRestrictionsWidget = infuseIfExists( $( '.mw-block-action-restriction.oo-ui-checkboxMultiselectInputWidget' ) );
153 // When disabling checkboxes, preserve their selected state in case they are re-enabled
154 preserveSelectedStateOnDisable( enableAutoblockWidget );
155 preserveSelectedStateOnDisable( anonOnlyWidget );
156 preserveSelectedStateOnDisable( watchUserWidget );
157 preserveSelectedStateOnDisable( hideUserWidget );
158 preserveSelectedStateOnDisable( preventTalkPageEditWidget );
160 updateBlockOptions();