Add support for enabling and displaying global interwikis

This effectively merges Extension:ShoutWikiInterwikiMagic into Interwiki
to add support for global interwikis, allowing sysadmins to set
$wgInterwikiCentralDB to a central wiki database from which to pull global
interwikis, which will be used alongside any locally-defined prefixes.

It also separates out the display of global, local, and language
interwikis into their own sections, improving the display even for
local-only projects.

Bug: 68241
Change-Id: I54c072c65f10dd0ad5f815c2649e7ce9ed1e7b58
This commit is contained in:
isarra 2014-07-19 17:40:44 +00:00
parent 6e13591eb7
commit ca46fc0350
4 changed files with 168 additions and 23 deletions

46
Interwiki.php Normal file → Executable file
View file

@ -10,6 +10,8 @@
* @version 3.0
* @author Stephanie Amanda Stevens <phroziac@gmail.com>
* @author Robin Pepermans (SPQRobin) <robinp.1273@gmail.com>
* @author Jack Phoenix <jack@shoutwiki.com>
* @author Calimonius the Estrange <isarra@shoutwiki.com>
* @copyright Copyright © 2005-2007 Stephanie Amanda Stevens
* @copyright Copyright © 2007-2011 Robin Pepermans (SPQRobin)
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
@ -26,6 +28,9 @@ if ( !defined( 'MEDIAWIKI' ) ) {
// the addition of a log for interwiki link changes.
$wgInterwikiViewOnly = false;
// Name of a database where global interwikis will be stored.
$wgInterwikiCentralDB = null;
// Extension credits for Special:Version
$wgExtensionCredits['specialpage'][] = array(
'path' => __FILE__,
@ -38,9 +43,11 @@ $wgExtensionCredits['specialpage'][] = array(
'Platonides',
'Raimond Spekking',
'Sam Reed',
'Jack Phoenix',
'Calimonius the Estrange',
'...'
),
'version' => '2.3 20140327',
'version' => '3.0 20140719',
'url' => 'https://www.mediawiki.org/wiki/Extension:Interwiki',
'descriptionmsg' => 'interwiki-desc',
);
@ -66,6 +73,9 @@ $wgAutoloadClasses['InterwikiLogFormatter'] = $dir . 'Interwiki_body.php';
$wgSpecialPages['Interwiki'] = 'SpecialInterwiki';
$wgSpecialPageGroups['Interwiki'] = 'wiki';
$wgHooks['InterwikiLoadPrefix'][] = 'wfGlobalInterwikis';
function setupInterwikiExtension() {
global $wgInterwikiViewOnly;
@ -77,9 +87,41 @@ function setupInterwikiExtension() {
// Set up the new log type - interwiki actions are logged to this new log
$wgLogTypes[] = 'interwiki';
# interwiki, iw_add, iw_delete, iw_edit
// interwiki, iw_add, iw_delete, iw_edit
$wgLogActionsHandlers['interwiki/*'] = 'InterwikiLogFormatter';
}
return true;
}
function wfGlobalInterwikis( $prefix, &$iwData ) {
global $wgInterwikiCentralDB;
// docs/hooks.txt says: Return true without providing an interwiki to continue interwiki search.
if ( $wgInterwikiCentralDB === null || $wgInterwikiCentralDB === wfWikiId() ) {
// No global set or this is global, nothing to add
return true;
}
if ( !Language::fetchLanguageName( $prefix ) ) {
// Check if prefix exists locally and skip
foreach ( Interwiki::getAllPrefixes( null ) as $id => $localPrefixInfo ) {
if ( $prefix === $localPrefixInfo['iw_prefix'] ) {
return true;
}
}
$dbr = wfGetDB( DB_SLAVE, array(), $wgInterwikiCentralDB );
$res = $dbr->selectRow(
'interwiki',
'*',
array( 'iw_prefix' => $prefix ),
__METHOD__
);
if ( !$res ) {
return true;
}
// Excplicitly make this an array since it's expected to be one
$iwData = (array)$res;
// At this point, we can safely return false because we know that we have something
return false;
}
return true;
}

View file

@ -212,7 +212,7 @@ class SpecialInterwiki extends SpecialPage {
}
function doSubmit() {
global $wgContLang, $wgMemc;
global $wgMemc, $wgContLang;
$request = $this->getRequest();
$prefix = $request->getVal( 'wpInterwikiPrefix' );
@ -295,47 +295,130 @@ class SpecialInterwiki extends SpecialPage {
}
function showList() {
global $wgInterwikiCentralDB;
$canModify = $this->canModify();
// Page intro content
$this->getOutput()->addWikiMsg( 'interwiki_intro' );
// Make collapsible.
$this->getOutput()->addHTML(
Html::openElement(
'div', array(
'class' => 'mw-collapsible mw-collapsed',
'class' => 'mw-collapsible mw-collapsed mw-interwiki-legend',
'data-collapsetext' => $this->msg( 'interwiki-legend-hide' )->escaped(),
'data-expandtext' => $this->msg('interwiki-legend-show' )->escaped()
) ) );
$this->getOutput()->addWikiMsg( 'interwiki_legend' );
$this->getOutput()->addHTML( Html::closeElement( 'div' ) ); // end collapsible.
$this->getOutput()->addHTML( '<div style="clear:both"></div>' );
if ( $canModify ) {
$this->getOutput()->addWikiMsg( 'interwiki_intro_footer' );
$addtext = $this->msg( 'interwiki_addtext' )->escaped();
$addlink = Linker::linkKnown( $this->getPageTitle( 'add' ), $addtext );
$this->getOutput()->addHTML( '<p class="mw-interwiki-addlink">' . $addlink . '</p>' );
}
// Build lists
if ( !method_exists( 'Interwiki', 'getAllPrefixes' ) ) {
// version 2.0 is not backwards compatible (but still display nice error)
// version 2.0 is not backwards compatible (but will still display a nice error)
$this->error( 'interwiki_error' );
return;
}
$iwPrefixes = Interwiki::getAllPrefixes( null );
if ( !is_array( $iwPrefixes ) || count( $iwPrefixes ) === 0 ) {
// If the interwiki table is empty, display an error message
$this->error( 'interwiki_error' );
return;
$iwGlobalPrefixes = array();
if ( $wgInterwikiCentralDB !== null && $wgInterwikiCentralDB !== wfWikiId() ) {
// Fetch list from global table
$dbrCentralDB = wfGetDB( DB_SLAVE, array(), $wgInterwikiCentralDB );
$res = $dbrCentralDB->select( 'interwiki', '*', false, __METHOD__ );
$retval = array();
foreach ( $res as $row ) {
$row = (array)$row;
if ( !Language::fetchLanguageName( $row['iw_prefix'] ) ) {
$retval[] = $row;
}
}
$iwGlobalPrefixes = $retval;
}
// Split out language links
$iwLocalPrefixes = array();
$iwLanguagePrefixes = array();
foreach ( $iwPrefixes as $iwPrefix ) {
if ( Language::fetchLanguageName( $iwPrefix['iw_prefix'] ) ) {
$iwLanguagePrefixes[] = $iwPrefix;
} else {
$iwLocalPrefixes[] = $iwPrefix;
}
}
// Add general description and 'add' link
if ( $canModify ) {
$this->getOutput()->addWikiMsg( 'interwiki_intro_footer' );
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$addtext = $this->msg( 'interwiki-addtext-local' )->escaped();
} else {
$addtext = $this->msg( 'interwiki_addtext' )->escaped();
}
$addlink = Linker::linkKnown( $this->getPageTitle( 'add' ), $addtext );
$this->getOutput()->addHTML( '<p class="mw-interwiki-addlink">' . $addlink . '</p>' );
}
if ( !is_array( $iwPrefixes ) || count( $iwPrefixes ) === 0 ) {
if ( !is_array( $iwGlobalPrefixes ) || count( $iwGlobalPrefixes ) === 0 ) {
// If the interwiki table(s) are empty, display an error message
$this->error( 'interwiki_error' );
return;
}
}
// Add the global table
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-global">' .
$this->msg( 'interwiki-global-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-global-description' );
// $canModify is false here because this is just a display of remote data
$this->makeTable( false, $iwGlobalPrefixes );
}
// Add the local table
if ( count( $iwLocalPrefixes ) !== 0 ) {
if ( count( $iwGlobalPrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-local">' .
$this->msg( 'interwiki-local-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-local-description' );
} else {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-local">' .
$this->msg( 'interwiki-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-description' );
}
$this->makeTable( $canModify, $iwLocalPrefixes );
}
// Add the language table
if ( count( $iwLanguagePrefixes ) !== 0 ) {
$this->getOutput()->addHTML(
'<h2 id="interwikitable-language">' .
$this->msg( 'interwiki-language-links' )->parse() .
'</h2>'
);
$this->getOutput()->addWikiMsg( 'interwiki-language-description' );
$this->makeTable( $canModify, $iwLanguagePrefixes );
}
}
function makeTable( $canModify, $iwPrefixes ) {
// Output the existing Interwiki prefixes table header
$out = '';
$out .= Html::openElement(
'table',
array( 'class' => 'mw-interwikitable wikitable sortable body' )
) . "\n";
$out .= Html::openElement( 'tr', array( 'id' => 'interwikitable-header' ) ) .
$out .= Html::openElement( 'tr', array( 'class' => 'interwikitable-header' ) ) .
Html::element( 'th', null, $this->msg( 'interwiki_prefix' )->text() ) .
Html::element( 'th', null, $this->msg( 'interwiki_url' )->text() ) .
Html::element( 'th', null, $this->msg( 'interwiki_local' )->text() ) .

View file

@ -3,7 +3,8 @@
"authors": [
"Stephanie Amanda Stevens",
"SPQRobin",
"Purodha"
"Purodha",
"Isarra"
]
},
"interwiki": "View and edit interwiki data",
@ -38,7 +39,8 @@
"interwiki_deleting": "You are deleting prefix \"$1\".",
"interwiki_deleted": "Prefix \"$1\" was successfully removed from the interwiki table.",
"interwiki_delfailed": "Prefix \"$1\" could not be removed from the interwiki table.",
"interwiki_addtext": "Add an interwiki prefix",
"interwiki_addtext": "Add an interwiki or language prefix",
"interwiki-addtext-local": "Add a local interwiki or language prefix",
"interwiki_addintro": "You are adding a new interwiki prefix.\nRemember that it cannot contain spaces ( ), colons (:), ampersands (&), or equal signs (=).",
"interwiki_addbutton": "Add",
"interwiki_added": "Prefix \"$1\" was successfully added to the interwiki table.",
@ -58,5 +60,13 @@
"log-description-interwiki": "This is a log of changes to the [[Special:Interwiki|interwiki table]].",
"logentry-interwiki-interwiki": "",
"right-interwiki": "Edit interwiki data",
"action-interwiki": "change this interwiki entry"
"action-interwiki": "change this interwiki entry",
"interwiki-global-links": "Global interwiki prefixes",
"interwiki-global-description": "These prefixes are inherited from a global configuration, and can only be edited on the source wiki.",
"interwiki-local-links": "Local interwiki prefixes",
"interwiki-local-description": "These prefixes exist locally. Any duplicates with the global configuration will override the global definiton.",
"interwiki-links": "Interwiki prefixes",
"interwiki-description": "",
"interwiki-language-links": "Interlanguage prefixes",
"interwiki-language-description": "These prefixes match defined language codes, and will be used to create the 'in other languages' listing when added to a page."
}

View file

@ -12,7 +12,8 @@
"SPQRobin",
"Shirayuki",
"Siebrand",
"Umherirrender"
"Umherirrender",
"Isarra"
]
},
"interwiki": "{{doc-special|Interwiki}}",
@ -48,6 +49,7 @@
"interwiki_deleted": "Used as success message. Parameters:\n* $1 - interwiki prefix",
"interwiki_delfailed": "Error message when removing an interwiki table entry fails. Parameters:\n* $1 is an interwiki prefix.",
"interwiki_addtext": "Link description to open form to add an interwiki prefix.",
"interwiki-addtext-local": "Link description for wikis with global interwikis to open form to add a local interwiki prefix.",
"interwiki_addintro": "Form information when adding an interwiki prefix.",
"interwiki_addbutton": "This message is the text of the button to submit the interwiki prefix you are adding.\n\n{{Identical|Add}}",
"interwiki_added": "Success message after adding an interwiki prefix. Parameters:\n* $1 is the added interwiki prefix.",
@ -67,5 +69,13 @@
"log-description-interwiki": "Part of the interwiki extension. Summary shown on [[Special:Log/interwiki]].",
"logentry-interwiki-interwiki": "{{notranslate}}",
"right-interwiki": "{{doc-right|interwiki}}",
"action-interwiki": "{{doc-action|interwiki}}"
"action-interwiki": "{{doc-action|interwiki}}",
"interwiki-global-links": "Used on [[Special:Interwiki]] as header text for global interwiki prefix table",
"interwiki-global-description": "Appears under the interwiki-global-links header on [[Special:Interwiki]]; explains the distinction between global and local tables",
"interwiki-local-links": "Used on [[Special:Interwiki]] as header text for local interwiki prefix table if a global table is also present",
"interwiki-local-description": "Appears under the interwiki-local-links header on [[Special:Interwiki]]Used on [[Special:Interwiki]]; explains what the local table does",
"interwiki-links": "Used on [[Special:Interwiki]] as header text for interwiki prefix table if no global table is present",
"interwiki-description": "{{notranslate}}\nAppears under the interwiki-links header on [[Special:Interwiki]]",
"interwiki-language-links": "Used on [[Special:Interwiki]] as header text for interwiki language prefix table",
"interwiki-language-description": "Appears under the interwiki-language-links header on [[Special:Interwiki]]; explains what interlanguage links do"
}