return $wgLegalTitleChars;
}
- /**
- * Returns a simple regex that will match on characters and sequences invalid in titles.
- * Note that this doesn't pick up many things that could be wrong with titles, but that
- * replacing this regex with something valid will make many titles valid.
- *
- * @deprecated since 1.25, use MediaWikiTitleCodec::getTitleInvalidRegex() instead
- *
- * @return string Regex string
- */
- static function getTitleInvalidRegex() {
- wfDeprecated( __METHOD__, '1.25' );
- return MediaWikiTitleCodec::getTitleInvalidRegex();
- }
-
/**
* Utility method for converting a character sequence from bytes to Unicode.
*
*/
public function getNsText() {
if ( $this->isExternal() ) {
- // This probably shouldn't even happen,
- // but for interwiki transclusion it sometimes does.
- // Use the canonical namespaces if possible to try to
- // resolve a foreign namespace.
- if ( MWNamespace::exists( $this->mNamespace ) ) {
- return MWNamespace::getCanonicalName( $this->mNamespace );
+ // This probably shouldn't even happen, except for interwiki transclusion.
+ // If possible, use the canonical name for the foreign namespace.
+ $nsText = MWNamespace::getCanonicalName( $this->mNamespace );
+ if ( $nsText !== false ) {
+ return $nsText;
}
}
}
/**
- * Could this page contain custom CSS or JavaScript for the global UI.
- * This is generally true for pages in the MediaWiki namespace having CONTENT_MODEL_CSS
- * or CONTENT_MODEL_JAVASCRIPT.
+ * Could this MediaWiki namespace page contain custom CSS, JSON, or JavaScript for the
+ * global UI. This is generally true for pages in the MediaWiki namespace having
+ * CONTENT_MODEL_CSS, CONTENT_MODEL_JSON, or CONTENT_MODEL_JAVASCRIPT.
*
- * This method does *not* return true for per-user JS/CSS. Use isCssJsSubpage()
+ * This method does *not* return true for per-user JS/JSON/CSS. Use isUserConfigPage()
* for that!
*
- * Note that this method should not return true for pages that contain and
- * show "inactive" CSS or JS.
+ * Note that this method should not return true for pages that contain and show
+ * "inactive" CSS, JSON, or JS.
*
* @return bool
- * @todo FIXME: Rename to isSiteConfigPage() and remove deprecated hook
+ * @since 1.31
+ */
+ public function isSiteConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_CSS )
+ || $this->hasContentModel( CONTENT_MODEL_JSON )
+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+ )
+ );
+ }
+
+ /**
+ * @return bool
+ * @deprecated Since 1.31; use ::isSiteConfigPage() instead (which also checks for JSON pages)
*/
public function isCssOrJsPage() {
- $isCssOrJsPage = NS_MEDIAWIKI == $this->mNamespace
- && ( $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) );
+ wfDeprecated( __METHOD__, '1.31' );
+ return ( NS_MEDIAWIKI == $this->mNamespace
+ && ( $this->hasContentModel( CONTENT_MODEL_CSS )
+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ) );
+ }
- return $isCssOrJsPage;
+ /**
+ * Is this a "config" (.css, .json, or .js) sub-page of a user page?
+ *
+ * @return bool
+ * @since 1.31
+ */
+ public function isUserConfigPage() {
+ return (
+ NS_USER == $this->mNamespace
+ && $this->isSubpage()
+ && (
+ $this->hasContentModel( CONTENT_MODEL_CSS )
+ || $this->hasContentModel( CONTENT_MODEL_JSON )
+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+ )
+ );
}
/**
- * Is this a .css or .js subpage of a user page?
* @return bool
- * @todo FIXME: Rename to isUserConfigPage()
+ * @deprecated Since 1.31; use ::isUserConfigPage() instead (which also checks for JSON pages)
*/
public function isCssJsSubpage() {
+ wfDeprecated( __METHOD__, '1.31' );
return ( NS_USER == $this->mNamespace && $this->isSubpage()
&& ( $this->hasContentModel( CONTENT_MODEL_CSS )
|| $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ) );
}
/**
- * Trim down a .css or .js subpage title to get the corresponding skin name
+ * Trim down a .css, .json, or .js subpage title to get the corresponding skin name
*
- * @return string Containing skin name from .css or .js subpage title
+ * @return string Containing skin name from .css, .json, or .js subpage title
+ * @since 1.31
*/
- public function getSkinFromCssJsSubpage() {
+ public function getSkinFromConfigSubpage() {
$subpage = explode( '/', $this->mTextform );
$subpage = $subpage[count( $subpage ) - 1];
$lastdot = strrpos( $subpage, '.' );
if ( $lastdot === false ) {
- return $subpage; # Never happens: only called for names ending in '.css' or '.js'
+ return $subpage; # Never happens: only called for names ending in '.css'/'.json'/'.js'
}
return substr( $subpage, 0, $lastdot );
}
/**
- * Is this a .css subpage of a user page?
+ * @deprecated Since 1.31; use ::getSkinFromConfigSubpage() instead
+ * @return string Containing skin name from .css, .json, or .js subpage title
+ */
+ public function getSkinFromCssJsSubpage() {
+ wfDeprecated( __METHOD__, '1.31' );
+ return $this->getSkinFromConfigSubpage();
+ }
+
+ /**
+ * Is this a CSS "config" sub-page of a user page?
*
* @return bool
+ * @since 1.31
+ */
+ public function isUserCssConfigPage() {
+ return (
+ NS_USER == $this->mNamespace
+ && $this->isSubpage()
+ && $this->hasContentModel( CONTENT_MODEL_CSS )
+ );
+ }
+
+ /**
+ * @deprecated Since 1.31; use ::isUserCssConfigPage()
+ * @return bool
*/
public function isCssSubpage() {
- return ( NS_USER == $this->mNamespace && $this->isSubpage()
- && $this->hasContentModel( CONTENT_MODEL_CSS ) );
+ wfDeprecated( __METHOD__, '1.31' );
+ return $this->isUserCssConfigPage();
}
/**
- * Is this a .js subpage of a user page?
+ * Is this a JSON "config" sub-page of a user page?
*
* @return bool
+ * @since 1.31
+ */
+ public function isUserJsonConfigPage() {
+ return (
+ NS_USER == $this->mNamespace
+ && $this->isSubpage()
+ && $this->hasContentModel( CONTENT_MODEL_JSON )
+ );
+ }
+
+ /**
+ * Is this a JS "config" sub-page of a user page?
+ *
+ * @return bool
+ * @since 1.31
+ */
+ public function isUserJsConfigPage() {
+ return (
+ NS_USER == $this->mNamespace
+ && $this->isSubpage()
+ && $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+ );
+ }
+
+ /**
+ * @deprecated Since 1.31; use ::isUserJsConfigPage()
+ * @return bool
*/
public function isJsSubpage() {
- return ( NS_USER == $this->mNamespace && $this->isSubpage()
- && $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) );
+ wfDeprecated( __METHOD__, '1.31' );
+ return $this->isUserJsConfigPage();
}
/**
}
/**
- * Check CSS/JS sub-page permissions
+ * Check CSS/JSON/JS sub-page permissions
*
* @param string $action The action to check
* @param User $user User to check
*
* @return array List of errors
*/
- private function checkCSSandJSPermissions( $action, $user, $errors, $rigor, $short ) {
- # Protect css/js subpages of user pages
+ private function checkUserConfigPermissions( $action, $user, $errors, $rigor, $short ) {
+ # Protect css/json/js subpages of user pages
# XXX: this might be better using restrictions
+
if ( $action != 'patrol' ) {
if ( preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
- if ( $this->isCssSubpage() && !$user->isAllowedAny( 'editmyusercss', 'editusercss' ) ) {
+ if (
+ $this->isUserCssConfigPage()
+ && !$user->isAllowedAny( 'editmyusercss', 'editusercss' )
+ ) {
$errors[] = [ 'mycustomcssprotected', $action ];
- } elseif ( $this->isJsSubpage() && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' ) ) {
+ } elseif (
+ $this->isUserJsonConfigPage()
+ && !$user->isAllowedAny( 'editmyuserjson', 'edituserjson' )
+ ) {
+ $errors[] = [ 'mycustomjsonprotected', $action ];
+ } elseif (
+ $this->isUserJsConfigPage()
+ && !$user->isAllowedAny( 'editmyuserjs', 'edituserjs' )
+ ) {
$errors[] = [ 'mycustomjsprotected', $action ];
}
} else {
- if ( $this->isCssSubpage() && !$user->isAllowed( 'editusercss' ) ) {
+ if (
+ $this->isUserCssConfigPage()
+ && !$user->isAllowed( 'editusercss' )
+ ) {
$errors[] = [ 'customcssprotected', $action ];
- } elseif ( $this->isJsSubpage() && !$user->isAllowed( 'edituserjs' ) ) {
+ } elseif (
+ $this->isUserJsonConfigPage()
+ && !$user->isAllowed( 'edituserjson' )
+ ) {
+ $errors[] = [ 'customjsonprotected', $action ];
+ } elseif (
+ $this->isUserJsConfigPage()
+ && !$user->isAllowed( 'edituserjs' )
+ ) {
$errors[] = [ 'customjsprotected', $action ];
}
}
* @return array List of errors
*/
private function checkCascadingSourcesRestrictions( $action, $user, $errors, $rigor, $short ) {
- if ( $rigor !== 'quick' && !$this->isCssJsSubpage() ) {
+ if ( $rigor !== 'quick' && !$this->isUserConfigPage() ) {
# We /could/ use the protection level on the source page, but it's
# fairly ugly as we have to establish a precedence hierarchy for pages
# included by multiple cascade-protected pages. So just restrict
'checkReadPermissions',
'checkUserBlock', // for wgBlockDisablesLogin
];
- # Don't call checkSpecialsAndNSPermissions or checkCSSandJSPermissions
+ # Don't call checkSpecialsAndNSPermissions or checkUserConfigPermissions
# here as it will lead to duplicate error messages. This is okay to do
# since anywhere that checks for create will also check for edit, and
# those checks are called for edit.
'checkQuickPermissions',
'checkPermissionHooks',
'checkSpecialsAndNSPermissions',
- 'checkCSSandJSPermissions',
+ 'checkUserConfigPermissions',
'checkPageRestrictions',
'checkCascadingSourcesRestrictions',
'checkActionPermissions',
}
// If we are looking at a css/js user subpage, purge the action=raw.
- if ( $this->isJsSubpage() ) {
+ if ( $this->isUserJsConfigPage() ) {
$urls[] = $this->getInternalURL( 'action=raw&ctype=text/javascript' );
- } elseif ( $this->isCssSubpage() ) {
+ } elseif ( $this->isUserJsonConfigPage() ) {
+ $urls[] = $this->getInternalURL( 'action=raw&ctype=application/json' );
+ } elseif ( $this->isUserCssConfigPage() ) {
$urls[] = $this->getInternalURL( 'action=raw&ctype=text/css' );
}
return $authors;
}
$dbr = wfGetDB( DB_REPLICA );
- $res = $dbr->select( 'revision', 'DISTINCT rev_user_text',
+ $revQuery = Revision::getQueryInfo();
+ $authors = $dbr->selectFieldValues(
+ $revQuery['tables'],
+ $revQuery['fields']['rev_user_text'],
[
'rev_page' => $this->getArticleID(),
"rev_timestamp $old_cmp " . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
"rev_timestamp $new_cmp " . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) )
], __METHOD__,
- [ 'LIMIT' => $limit + 1 ] // add one so caller knows it was truncated
+ [ 'DISTINCT', 'LIMIT' => $limit + 1 ], // add one so caller knows it was truncated
+ $revQuery['joins']
);
- foreach ( $res as $row ) {
- $authors[] = $row->rev_user_text;
- }
return $authors;
}
*/
public function getNamespaceKey( $prepend = 'nstab-' ) {
global $wgContLang;
- // Gets the subject namespace if this title
- $namespace = MWNamespace::getSubject( $this->getNamespace() );
- // Checks if canonical namespace name exists for namespace
- if ( MWNamespace::exists( $this->getNamespace() ) ) {
- // Uses canonical namespace name
- $namespaceKey = MWNamespace::getCanonicalName( $namespace );
- } else {
- // Uses text of namespace
+ // Gets the subject namespace of this title
+ $subjectNS = MWNamespace::getSubject( $this->getNamespace() );
+ // Prefer canonical namespace name for HTML IDs
+ $namespaceKey = MWNamespace::getCanonicalName( $subjectNS );
+ if ( $namespaceKey === false ) {
+ // Fallback to localised text
$namespaceKey = $this->getSubjectNsText();
}
// Makes namespace key lowercase