From 807c3afaa73bb15a699980c61305a650770f7ab3 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sat, 13 Sep 2008 05:33:24 +0000 Subject: [PATCH] (bug 12650) Make it possible to enter separate expiry times for each restriction type. --- RELEASE-NOTES | 2 + includes/Article.php | 48 ++++--- includes/DefaultSettings.php | 2 +- includes/LogPage.php | 10 +- includes/ProtectionForm.php | 191 +++++++++++++------------- includes/Title.php | 18 +-- includes/specials/SpecialMovepage.php | 4 + languages/messages/MessagesEn.php | 1 + skins/common/protect.js | 111 ++++++++++++++- 9 files changed, 251 insertions(+), 136 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index dff4659e89..5d202fa73b 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -124,6 +124,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * (bug 15551) Deletion log excerpt is now shown whenever a user vists a deleted page, even if they are unable to edit it. * Added Wantedfiles special pages, allowing users to find image links with no image. +* (bug 12650) It is now possible to set different expiration times for different + restriction types on the protection form. === Bug fixes in 1.14 === diff --git a/includes/Article.php b/includes/Article.php index 1735c9e1d7..b6033d1180 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -1798,7 +1798,7 @@ class Article { * @param string $reason * @return bool true on success */ - function updateRestrictions( $limit = array(), $reason = '', $cascade = 0, $expiry = null ) { + function updateRestrictions( $limit = array(), $reason = '', $cascade = 0, $expiry = array() ) { global $wgUser, $wgRestrictionTypes, $wgContLang; $id = $this->mTitle->getArticleID(); @@ -1816,15 +1816,17 @@ class Article { # FIXME: Same limitations as described in ProtectionForm.php (line 37); # we expect a single selection, but the schema allows otherwise. $current = array(); - foreach( $wgRestrictionTypes as $action ) + $updated = Article::flattenRestrictions( $limit ); + $changed = false; + foreach( $wgRestrictionTypes as $action ) { $current[$action] = implode( '', $this->mTitle->getRestrictions( $action ) ); + $changed = ($changed || ($this->mTitle->mRestrictionsExpiry[$action] != $expiry[$action]) ); + } $current = Article::flattenRestrictions( $current ); - $updated = Article::flattenRestrictions( $limit ); - $changed = ( $current != $updated ); + $changed = ($changed || ( $current != $updated ) ); $changed = $changed || ($updated && $this->mTitle->areRestrictionsCascading() != $cascade); - $changed = $changed || ($updated && $this->mTitle->mRestrictionsExpiry != $expiry); $protect = ( $updated != '' ); # If nothing's changed, do nothing @@ -1832,14 +1834,6 @@ class Article { if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser, $limit, $reason ) ) ) { $dbw = wfGetDB( DB_MASTER ); - - $encodedExpiry = Block::encodeExpiry($expiry, $dbw ); - - $expiry_description = ''; - if( $encodedExpiry != 'infinity' ) { - $expiry_description = ' (' . wfMsgForContent( 'protect-expiring', - $wgContLang->timeanddate( $expiry, false, false ) ).')'; - } # Prepare a null revision to be added to the history $modified = $current != '' && $protect; @@ -1859,7 +1853,6 @@ class Article { break; } } - $cascade_description = ''; if( $cascade ) { $cascade_description = ' ['.wfMsgForContent('protect-summary-cascade').']'; @@ -1869,10 +1862,23 @@ class Article { $comment .= ": $reason"; $editComment = $comment; - if( $protect ) - $editComment .= " [$updated]"; - if( $expiry_description && $protect ) - $editComment .= "$expiry_description"; + $encodedExpiry = array(); + $protect_description = ''; + foreach( $limit as $action => $restrictions ) { + $encodedExpiry[$action] = Block::encodeExpiry($expiry[$action], $dbw ); + if ($restrictions != '') { + $protect_description .= "[$action=$restrictions] ("; + if( $encodedExpiry[$action] != 'infinity' ) { + $protect_description .= wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry[$action], false, false ) ); + } else { + $protect_description .= wfMsgForContent( 'protect-expiry-indefinite' ); + } + $protect_description .= ') '; + } + } + + if( $protect_description && $protect ) + $editComment .= "($protect_description)"; if( $cascade ) $editComment .= "$cascade_description"; # Update restrictions table @@ -1880,8 +1886,8 @@ class Article { if ($restrictions != '' ) { $dbw->replace( 'page_restrictions', array(array('pr_page', 'pr_type')), array( 'pr_page' => $id, 'pr_type' => $action - , 'pr_level' => $restrictions, 'pr_cascade' => $cascade ? 1 : 0 - , 'pr_expiry' => $encodedExpiry ), __METHOD__ ); + , 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0 + , 'pr_expiry' => $encodedExpiry[$action] ), __METHOD__ ); } else { $dbw->delete( 'page_restrictions', array( 'pr_page' => $id, 'pr_type' => $action ), __METHOD__ ); @@ -1910,7 +1916,7 @@ class Article { # Update the protection log $log = new LogPage( 'protect' ); if( $protect ) { - $params = array($updated,$encodedExpiry,$cascade ? 'cascade' : ''); + $params = array($protect_description,$cascade ? 'cascade' : ''); $log->addEntry( $modified ? 'modify' : 'protect', $this->mTitle, trim( $reason), $params ); } else { $log->addEntry( 'unprotect', $this->mTitle, $reason ); diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 81d5a10f39..c017c35d39 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -1383,7 +1383,7 @@ $wgCacheEpoch = '20030516000000'; * to ensure that client-side caches don't keep obsolete copies of global * styles. */ -$wgStyleVersion = '176'; +$wgStyleVersion = '177'; # Server-side caching: diff --git a/includes/LogPage.php b/includes/LogPage.php index 7ace1ac0c5..2b821e9f4f 100644 --- a/includes/LogPage.php +++ b/includes/LogPage.php @@ -203,13 +203,9 @@ class LogPage { } $params[2] = isset( $params[2] ) ? self::formatBlockFlags( $params[2], is_null( $skin ) ) : ''; - } else if ( $type == 'protect' && count($params) == 4 ) { - $details .= " [{$params[1]}]"; // the restrictions - if( $params[2] != 'infinity' ) { - $details .= ' (' . wfMsgForContent( 'protect-expiring', - $wgContLang->timeanddate( $params[2], false, false ) ).')'; - } - if( $params[3] ) { + } else if ( $type == 'protect' && count($params) == 3 ) { + $details .= " {$params[1]}"; // restrictions and expiries + if( $params[2] ) { $details .= ' ['.wfMsg('protect-summary-cascade').']'; } } diff --git a/includes/ProtectionForm.php b/includes/ProtectionForm.php index 222851c190..617b953f43 100644 --- a/includes/ProtectionForm.php +++ b/includes/ProtectionForm.php @@ -25,8 +25,10 @@ class ProtectionForm { var $mRestrictions = array(); var $mReason = ''; + var $mReasonList = ''; var $mCascade = false; - var $mExpiry = null; + var $mExpiry =array(); + var $mExpiryList = array(); var $mPermErrors = array(); var $mApplicableTypes = array(); @@ -44,18 +46,17 @@ class ProtectionForm { // Fixme: this form currently requires individual selections, // but the db allows multiples separated by commas. $this->mRestrictions[$action] = implode( '', $this->mTitle->getRestrictions( $action ) ); + + if ( $this->mTitle->mRestrictionsExpiry[$action] == 'infinity' ) { + $this->mExpiry[$action] = 'infinite'; + } else if ( strlen($this->mTitle->mRestrictionsExpiry[$action]) == 0 ) { + $this->mExpiry[$action] = ''; + } else { + // FIXME: this format is not user friendly + $this->mExpiry[$action] = wfTimestamp( TS_ISO_8601, $this->mTitle->mRestrictionsExpiry[$action] ); + } } - $this->mCascade = $this->mTitle->areRestrictionsCascading(); - - if ( $this->mTitle->mRestrictionsExpiry == 'infinity' ) { - $this->mExpiry = 'infinite'; - } else if ( strlen($this->mTitle->mRestrictionsExpiry) == 0 ) { - $this->mExpiry = ''; - } else { - // FIXME: this format is not user friendly - $this->mExpiry = wfTimestamp( TS_ISO_8601, $this->mTitle->mRestrictionsExpiry ); - } } // The form will be available in read-only to show levels. @@ -67,14 +68,15 @@ class ProtectionForm { $this->mReason = $wgRequest->getText( 'mwProtect-reason' ); $this->mReasonList = $wgRequest->getText( 'wpProtectReasonList' ); $this->mCascade = $wgRequest->getBool( 'mwProtect-cascade', $this->mCascade ); - // Let dropdown have 'infinite' for unprotected pages - if( !($expiry = $wgRequest->getText( 'mwProtect-expiry' )) && $this->mExpiry != 'infinite' ) { - $expiry = $this->mExpiry; - } - $this->mExpiry = $expiry; - $this->mExpiryList = $wgRequest->getText( 'wpProtectExpiryList', $this->mExpiry ? '' : 'infinite' ); - + foreach( $this->mApplicableTypes as $action ) { + // Let dropdown have 'infinite' for unprotected pages + if( !($expiry[$action] = $wgRequest->getText( "mwProtect-expiry-$action" )) && $this->mExpiry[$action] != 'infinite' ) { + $expiry[$action] = $this->mExpiry[$action]; + } + $this->mExpiry[$action] = $expiry[$action]; + $this->mExpiryList[$action] = $wgRequest->getText( "wpProtectExpiryList-$action", $this->mExpiry[$action] ? '' : 'infinite' ); + $val = $wgRequest->getVal( "mwProtect-level-$action" ); if( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) { // Prevent users from setting levels that they cannot later unset @@ -175,32 +177,35 @@ class ProtectionForm { } elseif ( $reasonstr == 'other' ) { $reasonstr = $this->mReason; } - # Custom expiry takes precedence - if ( strlen( $this->mExpiry ) == 0 ) { - $this->mExpiry = strlen($this->mExpiryList) ? $this->mExpiryList : 'infinite'; - } - - if ( $this->mExpiry == 'infinite' || $this->mExpiry == 'indefinite' ) { - $expiry = Block::infinity(); - } else { - # Convert GNU-style date, on error returns -1 for PHP <5.1 and false for PHP >=5.1 - $expiry = strtotime( $this->mExpiry ); - - if ( $expiry < 0 || $expiry === false ) { - $this->show( wfMsg( 'protect_expiry_invalid' ) ); - return false; + $expiry = array(); + foreach( $this->mApplicableTypes as $action ) { + # Custom expiry takes precedence + if ( strlen( $wgRequest->getText( "mwProtect-expiry-$action" ) ) == 0 ) { + $this->mExpiry[$action] = strlen($wgRequest->getText( "wpProtectExpiryList-$action")) ? $wgRequest->getText( "wpProtectExpiryList-$action") : 'infinite'; + } else { + $this->mExpiry[$action] = $wgRequest->getText( "mwProtect-expiry-$action" ); } + if ( $this->mExpiry[$action] == 'infinite' || $this->mExpiry[$action] == 'indefinite' ) { + $expiry[$action] = Block::infinity(); + } else { + # Convert GNU-style date, on error returns -1 for PHP <5.1 and false for PHP >=5.1 + $expiry[$action] = strtotime( $this->mExpiry[$action] ); + + if ( $expiry[$action] < 0 || $expiry[$action] === false ) { + $this->show( wfMsg( 'protect_expiry_invalid' ) ); + return false; + } - // Fixme: non-qualified absolute times are not in users specified timezone - // and there isn't notice about it in the ui - $expiry = wfTimestamp( TS_MW, $expiry ); + // Fixme: non-qualified absolute times are not in users specified timezone + // and there isn't notice about it in the ui + $expiry[$action] = wfTimestamp( TS_MW, $expiry[$action] ); - if ( $expiry < wfTimestampNow() ) { - $this->show( wfMsg( 'protect_expiry_old' ) ); - return false; + if ( $expiry[$action] < wfTimestampNow() ) { + $this->show( wfMsg( 'protect_expiry_old' ) ); + return false; + } } } - # They shouldn't be able to do this anyway, but just to make sure, ensure that cascading restrictions aren't being applied # to a semi-protected page. global $wgGroupPermissions; @@ -214,7 +219,7 @@ class ProtectionForm { if ($this->mTitle->exists()) { $ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $reasonstr, $this->mCascade, $expiry ); } else { - $ok = $this->mTitle->updateTitleProtection( $this->mRestrictions['create'], $reasonstr, $expiry ); + $ok = $this->mTitle->updateTitleProtection( $this->mRestrictions['create'], $reasonstr, $expiry['create'] ); } if( !$ok ) { @@ -238,8 +243,6 @@ class ProtectionForm { function buildForm() { global $wgUser; - $mProtectexpiry = Xml::label( wfMsg( 'protectexpiry' ), 'mwProtectExpiryList' ); - $mProtectother = Xml::label( wfMsg( 'protect-othertime' ), 'expires' ); $mProtectreasonother = Xml::label( wfMsg( 'protectcomment' ), 'wpProtectReasonList' ); $mProtectreason = Xml::label( wfMsg( 'protect-otherreason' ), 'mwProtect-reason' ); @@ -257,10 +260,9 @@ class ProtectionForm { $out .= Xml::openElement( 'fieldset' ) . Xml::element( 'legend', null, wfMsg( 'protect-legend' ) ) . Xml::openElement( 'table', array( 'id' => 'mwProtectSet' ) ) . - Xml::openElement( 'tbody' ) . - "\n"; + Xml::openElement( 'tbody' ); - foreach( $this->mRestrictions as $action => $required ) { + foreach( $this->mRestrictions as $action => $selected ) { /* Not all languages have V_x <-> N_x relation */ $msg = wfMsg( 'restriction-' . $action ); if( wfEmptyMsg( 'restriction-' . $action, $msg ) ) { @@ -269,32 +271,53 @@ class ProtectionForm { $label = Xml::element( 'label', array( 'for' => "mwProtect-level-$action" ), $msg ); - $out .= "$label"; - } - $out .= " - \n"; - foreach( $this->mRestrictions as $action => $selected ) { - $out .= "" . - $this->buildSelector( $action, $selected ) . - ""; - } - $out .= "\n"; - - $scExpiryOptions = wfMsgForContent( 'ipboptions' ); // FIXME: use its own message - - $showProtectOptions = ($scExpiryOptions !== '-' && !$this->disabled); - if( !$showProtectOptions ) - $mProtectother = $mProtectexpiry; - - $expiryFormOptions = Xml::option( wfMsg( 'protect-othertime-op' ), 'wpProtectExpiryList' ); - foreach( explode(',', $scExpiryOptions) as $option ) { - if ( strpos($option, ":") === false ) $option = "$option:$option"; - list($show, $value) = explode(":", $option); - $show = htmlspecialchars($show); - $value = htmlspecialchars($value); - $expiryFormOptions .= Xml::option( $show, $value, $this->mExpiryList === $value ? true : false ) . "\n"; + $out .= "$label"; + $out .= "" . + $this->buildSelector( $action, $selected ) . + ""; + $scExpiryOptions = wfMsgForContent( 'ipboptions' ); // FIXME: use its own message + + $showProtectOptions = ($scExpiryOptions !== '-' && !$this->disabled); + + $mProtectexpiry = Xml::label( wfMsg( 'protectexpiry' ), "mwProtectExpiryList-$action" ); + $mProtectother = Xml::label( wfMsg( 'protect-othertime' ), "mwProtect-$action-expires" ); + $expiryFormOptions = Xml::option( wfMsg( 'protect-othertime-op' ), "wpProtectExpiryList-$action" ); + foreach( explode(',', $scExpiryOptions) as $option ) { + if ( strpos($option, ":") === false ) $option = "$option:$option"; + list($show, $value) = explode(":", $option); + $show = htmlspecialchars($show); + $value = htmlspecialchars($value); + $expiryFormOptions .= Xml::option( $show, $value, $this->mExpiryList[$action] === $value ? true : false ) . "\n"; + } + # Add expiry dropdown + if( $showProtectOptions && !$this->disabled ) { + $out .= " + + + {$mProtectexpiry} + + " . + Xml::tags( 'select', + array( + 'id' => "mwProtectExpiryList-$action", + 'name' => "wpProtectExpiryList-$action", + 'onchange' => "protectExpiryListUpdate(this)", + 'tabindex' => '2' ) + $this->disabledAttrib, + $expiryFormOptions ) . + " + "; + } + # Add custom expiry field + $attribs = array( 'id' => "mwProtect-$action-expires", 'onkeyup' => 'protectExpiryUpdate(this)' ) + $this->disabledAttrib; + $out .= " + " . + $mProtectother . + ' + ' . + Xml::input( "mwProtect-expiry-$action", 60, $this->mExpiry[$action], $attribs ) . + ' + '; } - $reasonDropDown = Xml::listDropDown( 'wpProtectReasonList', wfMsgForContent( 'protect-dropdown' ), wfMsgForContent( 'protect-otherreason-op' ), '', 'mwProtect-reason', 4 ); @@ -314,34 +337,6 @@ class ProtectionForm { " \n"; } - # Add expiry dropdown - if( $showProtectOptions && !$this->disabled ) { - $out .= " - - - {$mProtectexpiry} - - " . - Xml::tags( 'select', - array( - 'id' => 'mwProtectExpiryList', - 'name' => 'wpProtectExpiryList', - 'onchange' => "document.getElementById('expires').value='';", - 'tabindex' => '2' ) + $this->disabledAttrib, - $expiryFormOptions ) . - " - "; - } - # Add custom expiry field - $attribs = array( 'id' => 'expires' ) + $this->disabledAttrib; - $out .= " - " . - $mProtectother . - ' - ' . - Xml::input( 'mwProtect-expiry', 60, $this->mExpiry, $attribs ) . - ' - '; # Add manual and custom reason field/selects if( !$this->disabled ) { $out .= " diff --git a/includes/Title.php b/includes/Title.php index fae7775ad9..209d2f1568 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -56,7 +56,7 @@ class Title { var $mRestrictions = array(); ///< Array of groups allowed to edit this article var $mOldRestrictions = false; var $mCascadeRestriction; ///< Cascade restrictions on this page to included templates and images? - var $mRestrictionsExpiry; ///< When do the restrictions on this page expire? + var $mRestrictionsExpiry = array(); ///< When do the restrictions on this page expire? var $mHasCascadingRestrictions; ///< Are cascading restrictions in effect on this page? var $mCascadeSources; ///< Where are the cascading restrictions coming from on this page? var $mRestrictionsLoaded = false; ///< Boolean for initialisation on demand @@ -1368,7 +1368,7 @@ class Title { global $wgUser,$wgContLang; if ($create_perm == implode(',',$this->getRestrictions('create')) - && $expiry == $this->mRestrictionsExpiry) { + && $expiry == $this->mRestrictionsExpiry['create']) { // No change return true; } @@ -1383,7 +1383,10 @@ class Title { if ( $encodedExpiry != 'infinity' ) { $expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ) ).')'; } - + else { + $expiry_description .= ' (' . wfMsgForContent( 'protect-expiry-indefinite' ).')'; + } + # Update protection table if ($create_perm != '' ) { $dbw->replace( 'protected_titles', array(array('pt_namespace', 'pt_title')), @@ -1740,7 +1743,6 @@ class Title { } else { $this->mHasCascadingRestrictions = $sources; } - return array( $sources, $pagerestrictions ); } @@ -1762,10 +1764,10 @@ class Title { foreach( $wgRestrictionTypes as $type ){ $this->mRestrictions[$type] = array(); + $this->mRestrictionsExpiry[$type] = Block::decodeExpiry(''); } $this->mCascadeRestriction = false; - $this->mRestrictionsExpiry = Block::decodeExpiry(''); # Backwards-compatibility: also load the restrictions from the page record (old format). @@ -1809,7 +1811,7 @@ class Title { // Only apply the restrictions if they haven't expired! if ( !$expiry || $expiry > $now ) { - $this->mRestrictionsExpiry = $expiry; + $this->mRestrictionsExpiry[$row->pr_type] = $expiry; $this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) ); $this->mCascadeRestriction |= $row->pr_cascade; @@ -1850,13 +1852,13 @@ class Title { if (!$expiry || $expiry > $now) { // Apply the restrictions - $this->mRestrictionsExpiry = $expiry; + $this->mRestrictionsExpiry['create'] = $expiry; $this->mRestrictions['create'] = explode(',', trim($pt_create_perm) ); } else { // Get rid of the old restrictions Title::purgeExpiredRestrictions(); } } else { - $this->mRestrictionsExpiry = Block::decodeExpiry(''); + $this->mRestrictionsExpiry['create'] = Block::decodeExpiry(''); } $this->mRestrictionsLoaded = true; } diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php index 4f3ae34f97..a912f84b18 100644 --- a/includes/specials/SpecialMovepage.php +++ b/includes/specials/SpecialMovepage.php @@ -292,6 +292,10 @@ class MovePageForm { $error = $ot->moveTo( $nt, true, $this->reason ); if ( $error !== true ) { + if (isset($error[0][0]) && $error[0][0] = 'cascadeprotected') { + $wgOut->showPermissionsErrorPage($error, 'move'); + return; + } # FIXME: showForm() should handle multiple errors call_user_func_array(array($this, 'showForm'), $error[0]); return; diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index f10350938b..859e6c6fa1 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -2315,6 +2315,7 @@ You can change this page's protection level, but it will not affect the cascadin 'protect-level-sysop' => 'Sysops only', 'protect-summary-cascade' => 'cascading', 'protect-expiring' => 'expires $1 (UTC)', +'protect-expiry-indefinite' => 'indefinite', 'protect-cascade' => 'Protect pages included in this page (cascading protection)', 'protect-cantedit' => 'You cannot change the protection levels of this page, because you do not have permission to edit it.', 'protect-othertime' => 'Other time:', diff --git a/skins/common/protect.js b/skins/common/protect.js index 863b95bd80..7541533d58 100644 --- a/skins/common/protect.js +++ b/skins/common/protect.js @@ -100,6 +100,40 @@ function protectLevelsUpdate(source) { setCascadeCheckbox(); } +/** + * When protection levels are locked together, update the + * expiries when one changes + * + * @param Element source expiry input that changed + */ + +function protectExpiryUpdate(source) { + if( !protectUnchained() ) { + var expiry = source.value; + expiryForInputs(function(set) { + set.value = expiry; + }); + } +} + +/** + * When protection levels are locked together, update the + * expiry lists when one changes and clear the custom inputs + * + * @param Element source expiry selector that changed + */ +function protectExpiryListUpdate(source) { + if( !protectUnchained() ) { + var expiry = source.value; + expiryListForInputs(function(set) { + set.value = expiry; + }); + expiryForInputs(function(set) { + set.value = ''; + }); + } +} + /** * Update chain status and enable/disable various bits of the UI * when the user changes the "unlock move permissions" checkbox @@ -200,7 +234,64 @@ function protectSelectors() { } /** - * Enable/disable protection selectors + * Apply a callback to each expiry input + * + * @param callable func Callback function + */ +function expiryForInputs(func) { + var inputs = expiryInputs(); + for (var i = 0; i < inputs.length; i++) { + func(inputs[i]); + } +} + +/** + * Get a list of all expiry inputs on the page + * + * @return Array + */ +function expiryInputs() { + var all = document.getElementsByTagName("input"); + var ours = new Array(); + for (var i = 0; i < all.length; i++) { + var set = all[i]; + if (set.name.match(/^mwProtect-expiry-/)) { + ours[ours.length] = set; + } + } + return ours; +} + +/** + * Apply a callback to each expiry selector list + * @param callable func Callback function + */ +function expiryListForInputs(func) { + var inputs = expiryListInputs(); + for (var i = 0; i < inputs.length; i++) { + func(inputs[i]); + } +} + +/** + * Get a list of all expiry selector lists on the page + * + * @return Array + */ +function expiryListInputs() { + var all = document.getElementsByTagName("select"); + var ours = new Array(); + for (var i = 0; i < all.length; i++) { + var set = all[i]; + if (set.id.match(/^mwProtectExpiryList-/)) { + ours[ours.length] = set; + } + } + return ours; +} + +/** + * Enable/disable protection selectors and expiry inputs * * @param boolean val Enable? */ @@ -215,4 +306,22 @@ function protectEnable(val) { set.style.visible = val ? "visible" : "hidden"; } }); + first = true; + expiryForInputs(function(set) { + if (first) { + first = false; + } else { + set.disabled = !val; + set.style.visible = val ? "visible" : "hidden"; + } + }); + first = true; + expiryListForInputs(function(set) { + if (first) { + first = false; + } else { + set.disabled = !val; + set.style.visible = val ? "visible" : "hidden"; + } + }); } -- 2.20.1