r53099 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r53098‎ | r53099 | r53100 >
Date:04:47, 11 July 2009
Author:mrzman
Status:deferred
Tags:
Comment:
Change name for consistency
Modified paths:
  • /trunk/extensions/Index (deleted) (history)
  • /trunk/extensions/IndexFunction (added) (history)

Diff [purge]

Index: trunk/extensions/IndexFunction/IndexFunction_body.php
@@ -0,0 +1,211 @@
 2+<?php
 3+
 4+class IndexFunction {
 5+
 6+ // Utility function to get the target pageid for a possible index-title
 7+ static function getIndexTarget( Title $title ) {
 8+ $ns = $title->getNamespace();
 9+ $t = $title->getDBkey();
 10+ $dbr = wfGetDB( DB_SLAVE );
 11+ $res = $dbr->select( 'indexes', 'in_from',
 12+ array( 'in_namespace' => $ns, 'in_title' => $t ),
 13+ __METHOD__
 14+ );
 15+ return $res;
 16+ }
 17+
 18+ // Makes "Go" searches for an index title go directly to their target
 19+ static function redirectSearch( $term, &$title ) {
 20+ $title = Title::newFromText( $term );
 21+ if ( is_null($title) ) {
 22+ return true;
 23+ }
 24+ $res = self::getIndexTarget( $title );
 25+ if ( $res->numRows() == 0 ) {
 26+ return true;
 27+ } elseif ( $res->numRows() > 1 ) {
 28+ global $wgOut;
 29+ $title = SpecialPage::getTitleFor( 'Index', $title->getPrefixedText() );
 30+ $wgOut->redirect( $title->getLocalURL() );
 31+ return true;
 32+ }
 33+ $res = $res->fetchRow();
 34+ $title = Title::newFromId( $res );
 35+ return false;
 36+ }
 37+
 38+ // Make indexes work like redirects
 39+ static function doRedirect( &$title, &$request,& $ignoreRedirect, &$target, &$article ) {
 40+ if ( $article->exists() ) {
 41+ return true;
 42+ }
 43+ $res = self::getIndexTarget( $title );
 44+ if ( $res->numRows() == 0 ) {
 45+ return true;
 46+ } elseif ( $res->numRows() > 1 ) {
 47+ global $wgOut;
 48+ $t = SpecialPage::getTitleFor( 'Index', $title->getPrefixedText() );
 49+ $wgOut->redirect( $t->getLocalURL() );
 50+ return true;
 51+ } else {
 52+ $res = $res->fetchRow();
 53+ $redir = Title::newFromID( $res );
 54+ }
 55+ $target = $redir;
 56+ $article->mIsRedirect = true;
 57+ $ignoreRedirect = false;
 58+ return true;
 59+ }
 60+
 61+ // Turn links to indexes into blue links
 62+ static function blueLinkIndexes( $skin, $target, $options, &$text, &$attribs, &$ret ) {
 63+ if ( in_array( 'known', $options ) ) {
 64+ return true;
 65+ }
 66+ $res = self::getIndexTarget( $target );
 67+ if ( $res->numRows() == 0 ) {
 68+ return true;
 69+ }
 70+ $attribs['class'] = str_replace( 'new', 'mw-index', $attribs['class'] );
 71+ $attribs['href'] = $target->getLinkUrl();
 72+ $attribs['title'] = $target->getEscapedText();
 73+ return true;
 74+ }
 75+
 76+ // Register the function name
 77+ static function addIndexFunction( &$magicWords, $langCode ) {
 78+ $magicWords['index-func'] = array( 0, 'index' );
 79+ return true;
 80+ }
 81+
 82+ // Function called to render the parser function
 83+ // Output is an empty string unless there are errors
 84+ static function indexRender( &$parser ) {
 85+ if ( !isset($parser->mOutput->mIndexes) ) {
 86+ $parser->mOutput->mIndexes = array();
 87+ }
 88+ wfLoadExtensionMessages( 'IndexFunction' );
 89+ static $indexCount = 0;
 90+ static $indexes = array();
 91+ $args = func_get_args();
 92+ unset( $args[0] );
 93+ if ( $parser->mOptions->getIsPreview() ) {
 94+ # This is kind of hacky, but it seems that we only
 95+ # know if its a preview during parse, not when its
 96+ # done, which is when it matters for this
 97+ $parser->mOutput->setProperty( 'preview', 1 );
 98+ }
 99+ $errors = array();
 100+ $pageid = $parser->mTitle->getArticleID();
 101+ foreach ( $args as $name ) {
 102+ $t = Title::newFromText( $name );
 103+ if( is_null( $t ) ) {
 104+ $errors[] = wfMsg( 'indexfunc-badtitle', $name );
 105+ continue;
 106+ }
 107+ $ns = $t->getNamespace();
 108+ $dbkey = $t->getDBkey();
 109+ $entry = array( $ns, $dbkey );
 110+ if ( in_array( $entry, $indexes ) ) {
 111+ continue;
 112+ }
 113+ if ( $t->exists() ) {
 114+ $errors[] = wfMsg( 'indexfunc-index-exists', $name );
 115+ continue;
 116+ }
 117+ $indexCount++;
 118+ $parser->mOutput->mIndexes[$indexCount] = $entry;
 119+ }
 120+ if ( !$errors ) {
 121+ return '';
 122+ }
 123+ $out = Xml::openElement( 'ul', array( 'class'=>'error' ) );
 124+ foreach( $errors as $e ) {
 125+ $out .= Xml::element( 'li', null, $e );
 126+ }
 127+ $out .= Xml::closeElement( 'ul' );
 128+ return $out;
 129+ }
 130+
 131+ // Called after parse, updates the index table
 132+ static function doIndexes( &$out, &$parseroutput ) {
 133+ global $wgTitle;
 134+ if ( !isset($parseroutput->mIndexes) ) {
 135+ return true;
 136+ }
 137+ if ( $parseroutput->getProperty( 'preview' ) ) {
 138+ return true;
 139+ }
 140+ $pageid = $wgTitle->getArticleID();
 141+ $dbw = wfGetDB( DB_MASTER );
 142+ $res = $dbw->select( 'indexes',
 143+ array( 'in_namespace', 'in_title' ),
 144+ array( 'in_from' => $pageid ),
 145+ __METHOD__
 146+ );
 147+ $current = array();
 148+ foreach( $res as $row ) {
 149+ $current[] = array( $row->in_namespace, $row->in_title );
 150+ }
 151+ $toAdd = wfArrayDiff2( $parseroutput->mIndexes, $current );
 152+ $toRem = wfArrayDiff2( $current, $parseroutput->mIndexes );
 153+ if ( true ) {
 154+ $dbw->begin( __METHOD__ );
 155+ if ( $toRem ) {
 156+ $delCond = "in_from = $pageid AND (";
 157+ $parts = array();
 158+ # Looking at Database::delete, it seems to turn arrays into AND statements
 159+ # but we need to chain together groups of ANDs with ORs
 160+ foreach ( $toRem as $entry ) {
 161+ $parts[] = "(in_namespace = " . $entry[0] . " AND in_title = " . $dbw->addQuotes($entry[1]) . ")";
 162+ }
 163+ $delCond .= implode( ' OR ', $parts ) . ")";
 164+ $dbw->delete( 'indexes', array($delCond), __METHOD__ );
 165+ }
 166+ if ( $toAdd ) {
 167+ $ins = array();
 168+ foreach ( $toAdd as $entry ) {
 169+ $ins[] = array( 'in_from' => $pageid, 'in_namespace' => $entry[0], 'in_title' => $entry[1] );
 170+ }
 171+ $dbw->insert( 'indexes', $ins, __METHOD__ );
 172+ }
 173+ $dbw->commit( __METHOD__ );
 174+ }
 175+ return true;
 176+ }
 177+
 178+ // When deleting a page, delete all rows from the index table that point to it
 179+ static function onDelete( &$article, &$user, $reason, $id ) {
 180+ $dbw = wfGetDB( DB_MASTER );
 181+ $dbw->delete( 'indexes', array( 'in_from'=>$id ), __METHOD__ );
 182+ return true;
 183+ }
 184+
 185+ // When creating an article, delete its title from the index table
 186+ static function onCreate( &$article, &$user, &$text, &$summary, &$minoredit, &$watchthis, &$sectionanchor, &$flags, &$revision ) {
 187+ $t = $article->mTitle;
 188+ $ns = $t->getNamespace();
 189+ $dbkey = $t->getDBkey();
 190+ $dbw = wfGetDB( DB_MASTER );
 191+ $dbw->delete( 'indexes',
 192+ array( 'in_namespace'=>$ns, 'in_title'=>$dbkey ),
 193+ __METHOD__ );
 194+ return true;
 195+ }
 196+
 197+ // Show a warning when editing an index-title
 198+ static function editWarning( $editpage ) {
 199+ $t = $editpage->mTitle;
 200+ $target = self::getIndexTarget( $t );
 201+ if ( $target->numRows() != 1 ) { # FIXME
 202+ return true;
 203+ }
 204+ $target = $target->fetchRow();
 205+ $page = Title::newFromID( $target['in_from'] );
 206+ wfLoadExtensionMessages( 'IndexFunction' );
 207+ $warn = wfMsgExt( 'indexfunc-editwarn', array( 'parse' ), $page->getPrefixedText() );
 208+ $editpage->editFormTextBeforeContent .= "<span class='error'>$warn</span>";
 209+ return true;
 210+ }
 211+}
 212+
Index: trunk/extensions/IndexFunction/IndexFunction.i18n.php
@@ -0,0 +1,22 @@
 2+<?php
 3+
 4+$messages = array();
 5+
 6+$messages['en'] = array(
 7+ 'indexfunc-desc' => 'Parser function to create automatic redirects and disambiguation pages',
 8+
 9+ 'indexfunc-badtitle' => 'Invalid title: "$1"',
 10+ 'indexfunc-editwarn' => 'Warning: This title is an index title for [[$1]].
 11+Be sure the page you are about to create does not already exist under a different title.
 12+If you create this page, remove this title from the <nowiki>{{#index:}}</nowiki> on $1.',
 13+ 'indexfunc-index-exists' => 'The page "$1" already exists',
 14+ 'indexfunc-index-taken' => '"$1" is already used as an index by "$2"',
 15+
 16+ 'index' => 'Index',
 17+ 'index-legend' => 'Search the index',
 18+ 'index-search' => 'Search: ',
 19+ 'index-submit' => 'Submit',
 20+ 'index-disambig-start' => "'''$1''' may refer to several pages:",
 21+ 'index-exclude-categories' => '', # List of categories to exclude from the auto-disambig pages
 22+ 'index-missing-param' => 'This page cannot be used with no parameters',
 23+);
Index: trunk/extensions/IndexFunction/IndexFunction.php
@@ -0,0 +1,53 @@
 2+<?php
 3+
 4+$wgExtensionCredits['other'][] = array(
 5+ 'path' => __FILE__,
 6+ 'name' => 'IndexFunction',
 7+ 'author' =>'Alex Zaddach',
 8+ 'url' => 'http://www.mediawiki.org/wiki/Extension:IndexFunction',
 9+ 'descriptionmsg' => 'indexfunc-desc',
 10+ 'description' => 'Parser function to create automatic redirects and disambiguation pages'
 11+);
 12+
 13+$dir = dirname(__FILE__) . '/';
 14+
 15+# Register function
 16+$wgHooks['ParserFirstCallInit'][] = 'efIndexSetup';
 17+$wgHooks['LanguageGetMagic'][] = 'IndexFunction::addIndexFunction';
 18+# Add to database
 19+$wgHooks['OutputPageParserOutput'][] = 'IndexFunction::doIndexes';
 20+# Make links to indexes blue
 21+$wgHooks['LinkEnd'][] = 'IndexFunction::blueLinkIndexes';
 22+# Make links to indexes redirect
 23+$wgHooks['InitializeArticleMaybeRedirect'][] = 'IndexFunction::doRedirect';
 24+# Make "go" searches for indexes redirect
 25+$wgHooks['SearchGetNearMatch'][] = 'IndexFunction::redirectSearch';
 26+# Remove things from the index table when a page is deleted
 27+$wgHooks['ArticleDeleteComplete'][] = 'IndexFunction::onDelete';
 28+# Remove things from the index table when creating a new page
 29+$wgHooks['ArticleInsertComplete'][] = 'IndexFunction::onCreate';
 30+# Show a warning when editing an index title
 31+$wgHooks['EditPage::showEditForm:initial'][] = 'IndexFunction::editWarning';
 32+
 33+$wgHooks['LoadExtensionSchemaUpdates'][] = 'efIndexUpdateSchema';
 34+
 35+# Setup the special page
 36+$wgSpecialPages['Index'] = 'SpecialIndex';
 37+$wgAutoloadClasses['SpecialIndex'] = $dir . 'SpecialIndex.php';
 38+
 39+$wgExtensionMessagesFiles['IndexFunction'] = $dir . 'IndexFunction.i18n.php';
 40+$wgAutoloadClasses['IndexFunction'] = $dir . 'IndexFunction_body.php';
 41+
 42+function efIndexSetup( &$parser ) {
 43+ $parser->setFunctionHook( 'index-func', array( 'IndexFunction', 'indexRender' ) );
 44+ return true;
 45+}
 46+
 47+function efIndexUpdateSchema() {
 48+ global $wgExtNewTables;
 49+ $wgExtNewTables[] = array(
 50+ 'indexes',
 51+ dirname( __FILE__ ) . '/indexes.sql' );
 52+ return true;
 53+}
 54+
Index: trunk/extensions/IndexFunction/indexes.sql
@@ -0,0 +1,12 @@
 2+CREATE TABLE /*$wgDBprefix*/indexes (
 3+ -- The pageid of the page containing the parser function
 4+ in_from int unsigned NOT NULL default 0,
 5+
 6+ -- The NS/title that should redirect to the page
 7+ in_namespace int NOT NULL default 0,
 8+ in_title varchar(255) binary NOT NULL default '',
 9+
 10+ KEY (in_from),
 11+ KEY in_target (in_namespace, in_title)
 12+) ENGINE=InnoDB;
 13+
Index: trunk/extensions/IndexFunction/SpecialIndex.php
@@ -0,0 +1,167 @@
 2+<?php
 3+
 4+class SpecialIndex extends SpecialPage {
 5+ function __construct() {
 6+ parent::__construct( 'Index' );
 7+ wfLoadExtensionMessages('IndexFunction');
 8+ }
 9+
 10+ function execute( $par ) {
 11+ global $wgOut;
 12+
 13+ $this->setHeaders();
 14+ if ($par) {
 15+ $t1 = Title::newFromText( $par );
 16+ $this->showDabPage( $t1 );
 17+ } else {
 18+ $wgOut->addWikiMsg( 'index-missing-param' );
 19+ }
 20+ # Will eventually be some sort of a search form
 21+
 22+ //$form = Xml::openElement( 'fieldset' ) .
 23+ // Xml::element( 'legend', array(), wfMsgHtml( 'index-legend' ) ) .
 24+ // Xml::openElement( 'form', array( 'method'=>'GET' ) ) .
 25+
 26+ // Xml::label( wfMsg( 'index-search' ), 'mw-index-searchtext' ) .
 27+ // Xml::input( 'searchtext', 100, false, array( 'id' => 'mw-index-searchtext' ) ) .
 28+ // '<br />' .
 29+ // Xml::submitButton( wfMsg( 'index-submit' ) ) .
 30+
 31+ // Xml::closeElement( 'form' ) .
 32+ // Xml::closeElement( 'fieldset' );
 33+
 34+ //$wgOut->addHTML( $form );
 35+
 36+ }
 37+
 38+ function showDabPage( Title $t1 ) {
 39+ global $wgOut, $wgUser;
 40+ $sk = $wgUser->getSkin();
 41+ $wgOut->setPagetitle( $t1->getPrefixedText() );
 42+ $wgOut->addWikiMsg( 'index-disambig-start', $t1->getPrefixedText() );
 43+ $dbr = wfGetDB( DB_SLAVE );
 44+ $pages = $dbr->select( array('page', 'indexes'),
 45+ array( 'page_id', 'page_namespace', 'page_title' ),
 46+ array( 'in_namespace'=>$t1->getNamespace(), 'in_title'=>$t1->getDBkey() ),
 47+ __METHOD__,
 48+ array('ORDER BY'=> 'page_namespace, page_title'),
 49+ array( 'indexes' => array('JOIN', 'in_from=page_id') )
 50+ );
 51+
 52+ $list = array();
 53+ foreach( $pages as $row ) {
 54+ $t = Title::newFromRow( $row );
 55+ $list[strval($row->page_id)] = array( 'title' => $t, 'cats' => array() );
 56+ }
 57+ $keys = array_keys( $list );
 58+ $set = '(' . implode(',', $keys) . ')';
 59+
 60+ $excludecats = wfMsg('index-exclude-categories');
 61+ if ($excludecats) {
 62+ $excludecats = str_replace(' ', '_', $excludecats);
 63+ $excludecats = explode( '\n', $excludecats );
 64+ foreach( $excludecats as $index => $cat ) {
 65+ $excludecats[$index] = $dbr->addQuotes( $cat );
 66+ }
 67+ $excludecats = 'AND cl_to NOT IN (' . implode(',', $excludecats) . ')';
 68+ } else {
 69+ $excludecats = '';
 70+ }
 71+
 72+ $categories = $dbr->select( 'categorylinks',
 73+ array('cl_from', 'cl_to'),
 74+ "cl_from IN $set $excludecats",
 75+ __METHOD__,
 76+ array('ORDER BY' => 'cl_from')
 77+ );
 78+ $groups = array();
 79+ $catlist = array();
 80+ foreach( $categories as $row ) {
 81+ $ct = Title::newFromText( $row->cl_to, NS_CATEGORY );
 82+ $textform = $ct->getText();
 83+ $list[strval($row->cl_from)]['cats'][] = $textform;
 84+ if ( array_key_exists( $textform, $catlist ) ) {
 85+ $catlist[$textform][] = strval($row->cl_from);
 86+ } else {
 87+ $catlist[$textform] = array ( strval($row->cl_from) );
 88+ }
 89+ }
 90+ if (count($catlist) > 2) {
 91+ while (true) {
 92+ arsort($catlist);
 93+ $group = reset( $catlist );
 94+ if (count($group) == 0) {
 95+ break;
 96+ }
 97+ $keys = array_keys($catlist, $group);
 98+ $heading = $keys[0];
 99+ $grouphtml = Xml::element('h2', null, $heading);
 100+ $grouphtml .= Xml::openElement( 'ul' );
 101+ foreach( $group as $pageid ) {
 102+ $t = $list[$pageid]['title'];
 103+ $cats = $list[$pageid]['cats'];
 104+ $link = $sk->link( $t, null, array(), array(), array( 'known', 'noclasses' ) );
 105+ $grouphtml .= Xml::tags( 'li', array(), $link . '&nbsp;&ndash&nbsp;' . implode( ', ', $cats ) );
 106+ unset( $list[$pageid] );
 107+ ksort($list);
 108+ foreach($catlist as $remaining) {
 109+ $key = array_search( $pageid, $remaining );
 110+ if ( $key !== false ) {
 111+ $masterkeys = array_keys($catlist, $remaining);
 112+ $heading = $masterkeys[0];
 113+ unset($catlist[$heading][$key]);
 114+ sort($catlist[$heading]);
 115+ }
 116+ }
 117+ }
 118+ $grouphtml .= Xml::closeElement( 'ul' );
 119+ $groups[] = $grouphtml;
 120+ unset( $catlist[$heading] );
 121+ if (count($catlist) == 0) {
 122+ break;
 123+ }
 124+ }
 125+ if (count($list) != 0) { //Pages w/ no cats
 126+ $grouphtml = Xml::openElement( 'ul' );
 127+ foreach( $list as $pageid => $info ) {
 128+ $link = $sk->link( $info['title'], null, array(), array(), array( 'known', 'noclasses' ) );
 129+ $grouphtml .= Xml::tags( 'li', array(), $link );
 130+ }
 131+ $grouphtml .= Xml::closeElement('ul');
 132+ $groups = array_merge( array($grouphtml), $groups);
 133+ }
 134+ $out = implode( "\n", $groups );
 135+ } else {
 136+ $out = Xml::openElement( 'ul' );
 137+ foreach( $list as $pageid => $info ) {
 138+ $link = $sk->link( $info['title'], null, array(), array(), array( 'known', 'noclasses' ) );
 139+ if ( $info['cats'] ) {
 140+ $line = $link . '&nbsp;&ndash&nbsp;' . implode( ', ', $info['cats'] );
 141+ $line = Xml::tags( 'li', array(), $line );
 142+ } else {
 143+ $line = Xml::tags( 'li', array(), $link );
 144+ }
 145+ $out .= $line;
 146+ }
 147+ $out .= Xml::closeElement('ul');
 148+ }
 149+
 150+ $wgOut->addHtml($out);
 151+ //$wgOut->addHTML( Xml::openElement( 'ul' ) );
 152+ # TODO: Group into sections based on most used categories.
 153+ # When iterating over the category results above, use another array
 154+ # to record the most frequently used ones and add some h2's in the
 155+ # list for some (all?)
 156+ //foreach( $list as $pageid => $info ) {
 157+ // $link = $sk->link( $info['title'], null, array(), array(), array( 'known', 'noclasses' ) );
 158+ // if ( $info['cats'] ) {
 159+ // $line = $link . '&nbsp;&ndash&nbsp;' . implode( ', ', $info['cats'] );
 160+ // } else {
 161+ // $line = $link;
 162+ // }
 163+ // $wgOut->addHtml( Xml::tags( 'li', array(), $line) );
 164+ //}
 165+ //$wgOut->addHTML( Xml::closeElement('ul') );
 166+ }
 167+}
 168+

Status & tagging log