X-Git-Url: https://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2FSpecialWhatlinkshere.php;h=d51e13ad826942c493de0def25c0506649c3ecf9;hb=228f097d954469673634ea47c08ccc9adddca7dd;hp=dff036a1d0b7646720b4a18f96c7aa06aeb301d8;hpb=f9619da3f02b4759ae92250c483d4bf14dfd9ee8;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/SpecialWhatlinkshere.php b/includes/SpecialWhatlinkshere.php index dff036a1d0..d51e13ad82 100644 --- a/includes/SpecialWhatlinkshere.php +++ b/includes/SpecialWhatlinkshere.php @@ -1,5 +1,6 @@ request =& $request; + $this->request = $request; $this->skin = $wgUser->getSkin(); $this->par = $par; } @@ -33,33 +41,42 @@ class WhatLinksHerePage { function execute() { global $wgOut; - $this->limit = min( $this->request->getInt( 'limit', 50 ), 5000 ); - if ( $this->limit <= 0 ) { - $this->limit = 50; + $opts = new FormOptions(); + + $opts->add( 'target', '' ); + $opts->add( 'namespace', '', FormOptions::INTNULL ); + $opts->add( 'limit', 50 ); + $opts->add( 'from', 0 ); + $opts->add( 'back', 0 ); + $opts->add( 'hideredirs', false ); + $opts->add( 'hidetrans', false ); + $opts->add( 'hidelinks', false ); + $opts->add( 'hideimages', false ); + + $opts->fetchValuesFromRequest( $this->request ); + $opts->validateIntBounds( 'limit', 0, 5000 ); + if ( isset($this->par) ) { + $opts->setValue( 'target', $this->par ); } - $this->from = $this->request->getInt( 'from' ); - $this->back = $this->request->getInt( 'back' ); - $targetString = isset($this->par) ? $this->par : $this->request->getVal( 'target' ); + // Bind to member variable + $this->opts = $opts; - if (is_null($targetString)) { - $wgOut->showErrorPage( 'notargettitle', 'notargettext' ); - return; - } - - $this->target = Title::newFromURL( $targetString ); + $this->target = Title::newFromURL( $opts->getValue( 'target' ) ); if( !$this->target ) { - $wgOut->showErrorPage( 'notargettitle', 'notargettext' ); + $wgOut->addHTML( $this->whatlinkshereForm() ); return; } $this->selfTitle = Title::makeTitleSafe( NS_SPECIAL, 'Whatlinkshere/' . $this->target->getPrefixedDBkey() ); - $wgOut->setPagetitle( $this->target->getPrefixedText() ); + + $wgOut->setPageTitle( wfMsg( 'whatlinkshere-title', $this->target->getPrefixedText() ) ); $wgOut->setSubtitle( wfMsg( 'linklistsub' ) ); - $wgOut->addHTML( wfMsg( 'whatlinkshere-barrow' ) . ' ' .$this->skin->makeLinkObj($this->target, '', 'redirect=no' )."
\n"); + $wgOut->addHTML( wfMsgExt( 'whatlinkshere-barrow', array( 'escapenoentities') ) . ' ' .$this->skin->makeLinkObj($this->target, '', 'redirect=no' )."
\n"); - $this->showIndirectLinks( 0, $this->target, $this->limit, $this->from, $this->back ); + $this->showIndirectLinks( 0, $this->target, $opts->getValue( 'limit' ), + $opts->getValue( 'from' ), $opts->getValue( 'back' ) ); } /** @@ -71,18 +88,16 @@ class WhatLinksHerePage { * @private */ function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) { - global $wgOut; - $fname = 'WhatLinksHerePage::showIndirectLinks'; - $dbr = wfGetDB( DB_READ ); + global $wgOut, $wgMaxRedirectLinksRetrieved; + $dbr = wfGetDB( DB_SLAVE ); $options = array(); - $ns = $this->request->getIntOrNull( 'namespace' ); - if ( isset( $ns ) ) { - $options['namespace'] = $ns; - $this->setNamespace( $options['namespace'] ); - } else { - $options['namespace'] = ''; - } + $hidelinks = $this->opts->getValue( 'hidelinks' ); + $hideredirs = $this->opts->getValue( 'hideredirs' ); + $hidetrans = $this->opts->getValue( 'hidetrans' ); + $hideimages = $target->getNamespace() != NS_IMAGE || $this->opts->getValue( 'hideimages' ); + + $fetchlinks = !$hidelinks || !$hideredirs; // Make the query $plConds = array( @@ -90,6 +105,11 @@ class WhatLinksHerePage { 'pl_namespace' => $target->getNamespace(), 'pl_title' => $target->getDBkey(), ); + if( $hideredirs ) { + $plConds['page_is_redirect'] = 0; + } elseif( $hidelinks ) { + $plConds['page_is_redirect'] = 1; + } $tlConds = array( 'page_id=tl_from', @@ -97,75 +117,90 @@ class WhatLinksHerePage { 'tl_title' => $target->getDBkey(), ); - if ( $this->namespace !== null ){ - $plConds['page_namespace'] = (int)$this->namespace; - $tlConds['page_namespace'] = (int)$this->namespace; + $ilConds = array( + 'page_id=il_from', + 'il_to' => $target->getDBkey(), + ); + + $namespace = $this->opts->getValue( 'namespace' ); + if ( is_int($namespace) ){ + $plConds['page_namespace'] = $namespace; + $tlConds['page_namespace'] = $namespace; } if ( $from ) { - $offsetCond = "page_id >= $from"; - } else { - $offsetCond = false; + $tlConds[] = "tl_from >= $from"; + $plConds[] = "pl_from >= $from"; } - $options['ORDER BY'] = 'page_id'; // Read an extra row as an at-end check $queryLimit = $limit + 1; + + // enforce join order, sometimes namespace selector may + // trigger filesorts which are far less efficient than scanning many entries + $options[] = 'STRAIGHT_JOIN'; + $options['LIMIT'] = $queryLimit; - if ( $offsetCond ) { - $tlConds[] = $offsetCond; - $plConds[] = $offsetCond; - } $fields = array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ); - $plRes = $dbr->select( array( 'pagelinks', 'page' ), $fields, - $plConds, $fname, $options ); - $tlRes = $dbr->select( array( 'templatelinks', 'page' ), $fields, - $tlConds, $fname, $options ); - if ( !$dbr->numRows( $plRes ) && !$dbr->numRows( $tlRes ) ) { - if ( 0 == $level && !isset( $this->namespace ) ) { - // really no links to here - $wgOut->addWikiText( wfMsg( 'nolinkshere', $this->target->getPrefixedText() ) ); - } elseif ( 0 == $level && isset( $this->namespace ) ) { - // no links from requested namespace to here - $options = array(); // reinitialize for a further namespace search - $options['namespace'] = $this->namespace; - $options['target'] = $this->target->getPrefixedText(); - list( $options['limit'], $options['offset']) = wfCheckLimits(); - $wgOut->addHTML( $this->whatlinkshereForm( $options ) ); - $wgOut->addWikiText( wfMsg( 'nolinkshere-ns', $this->target->getPrefixedText() ) ); - } - return; + if( $fetchlinks ) { + $options['ORDER BY'] = 'pl_from'; + $plRes = $dbr->select( array( 'pagelinks', 'page' ), $fields, + $plConds, __METHOD__, $options ); } - $options = array(); - list( $options['limit'], $options['offset']) = wfCheckLimits(); - if ( ( $ns = $this->request->getVal( 'namespace', null ) ) !== null && $ns !== '' && ctype_digit($ns) ) { - $options['namespace'] = intval( $ns ); - $this->setNamespace( $options['namespace'] ); - } else { - $options['namespace'] = ''; - $this->setNamespace( null ); + if( !$hidetrans ) { + $options['ORDER BY'] = 'tl_from'; + $tlRes = $dbr->select( array( 'templatelinks', 'page' ), $fields, + $tlConds, __METHOD__, $options ); + } + + if( !$hideimages ) { + $options['ORDER BY'] = 'il_from'; + $ilRes = $dbr->select( array( 'imagelinks', 'page' ), $fields, + $ilConds, __METHOD__, $options ); + } + + if( ( !$fetchlinks || !$dbr->numRows( $plRes ) ) && ( $hidetrans || !$dbr->numRows( $tlRes ) ) && ( $hideimages || !$dbr->numRows( $ilRes ) ) ) { + if ( 0 == $level ) { + $wgOut->addHTML( $this->whatlinkshereForm() ); + $errMsg = is_int($namespace) ? 'nolinkshere-ns' : 'nolinkshere'; + $wgOut->addWikiMsg( $errMsg, $this->target->getPrefixedText() ); + // Show filters only if there are links + if( $hidelinks || $hidetrans || $hideredirs || $hideimages ) + $wgOut->addHTML( $this->getFilterPanel() ); + } + return; } - $options['offset'] = $this->request->getVal( 'offset' ); - /* Offset must be an integral. */ - if ( !strlen( $options['offset'] ) || !preg_match( '/^[0-9]+$/', $options['offset'] ) ) - $options['offset'] = ''; - $options['target'] = $this->target->getPrefixedDBkey(); // Read the rows into an array and remove duplicates // templatelinks comes second so that the templatelinks row overwrites the // pagelinks row, so we get (inclusion) rather than nothing - while ( $row = $dbr->fetchObject( $plRes ) ) { - $row->is_template = 0; - $rows[$row->page_id] = $row; + if( $fetchlinks ) { + while ( $row = $dbr->fetchObject( $plRes ) ) { + $row->is_template = 0; + $row->is_image = 0; + $rows[$row->page_id] = $row; + } + $dbr->freeResult( $plRes ); + + } + if( !$hidetrans ) { + while ( $row = $dbr->fetchObject( $tlRes ) ) { + $row->is_template = 1; + $row->is_image = 0; + $rows[$row->page_id] = $row; + } + $dbr->freeResult( $tlRes ); } - $dbr->freeResult( $plRes ); - while ( $row = $dbr->fetchObject( $tlRes ) ) { - $row->is_template = 1; - $rows[$row->page_id] = $row; + if( !$hideimages ) { + while ( $row = $dbr->fetchObject( $ilRes ) ) { + $row->is_template = 0; + $row->is_image = 1; + $rows[$row->page_id] = $row; + } + $dbr->freeResult( $ilRes ); } - $dbr->freeResult( $tlRes ); // Sort by key and then change the keys to 0-based indices ksort( $rows ); @@ -187,120 +222,186 @@ class WhatLinksHerePage { $prevId = $from; if ( $level == 0 ) { - $wgOut->addHTML( $this->whatlinkshereForm( $options ) ); - $wgOut->addWikiText( wfMsg( 'linkshere', $this->target->getPrefixedText() ) ); - } - $isredir = wfMsg( 'isredirect' ); - $istemplate = wfMsg( 'istemplate' ); + $wgOut->addHTML( $this->whatlinkshereForm( ) ); + $wgOut->addHTML( $this->getFilterPanel() ); + $wgOut->addWikiMsg( 'linkshere', $this->target->getPrefixedText() ); - if( $level == 0 ) { - $prevnext = $this->getPrevNext( $limit, $prevId, $nextId, $options['namespace'] ); + $prevnext = $this->getPrevNext( $prevId, $nextId ); $wgOut->addHTML( $prevnext ); } - $wgOut->addHTML( '\n" ); - if( $level == 0 ) { - $wgOut->addHTML( $prevnext ); + $suppressRedirect = $row->page_is_redirect ? 'redirect=no' : ''; + $link = $this->skin->makeKnownLinkObj( $nt, '', $suppressRedirect ); + + // Display properties (redirect or template) + $propsText = ''; + $props = array(); + if ( $row->page_is_redirect ) + $props[] = $msgcache['isredirect']; + if ( $row->is_template ) + $props[] = $msgcache['istemplate']; + if( $row->is_image ) + $props[] = $msgcache['isimage']; + + if ( count( $props ) ) { + $propsText = '(' . implode( $msgcache['semicolon-separator'], $props ) . ')'; } + + # Space for utilities links, with a what-links-here link provided + $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'] ); + $wlh = Xml::wrapClass( "($wlhLink)", 'mw-whatlinkshere-tools' ); + + return $notClose ? + Xml::openElement( 'li' ) . "$link $propsText $wlh\n" : + Xml::tags( 'li', null, "$link $propsText $wlh" ) . "\n"; + } + + protected function listEnd() { + return Xml::closeElement( 'ul' ); + } + + protected function wlhLink( Title $target, $text ) { + static $title = null; + if ( $title === null ) + $title = SpecialPage::getTitleFor( 'Whatlinkshere' ); + + $targetText = $target->getPrefixedUrl(); + return $this->skin->makeKnownLinkObj( $title, $text, 'target=' . $targetText ); } function makeSelfLink( $text, $query ) { return $this->skin->makeKnownLinkObj( $this->selfTitle, $text, $query ); } - function getPrevNext( $limit, $prevId, $nextId, $namespace ) { + function getPrevNext( $prevId, $nextId ) { global $wgLang; - $fmtLimit = $wgLang->formatNum( $limit ); + $currentLimit = $this->opts->getValue( 'limit' ); + $fmtLimit = $wgLang->formatNum( $currentLimit ); $prev = wfMsgExt( 'whatlinkshere-prev', array( 'parsemag', 'escape' ), $fmtLimit ); $next = wfMsgExt( 'whatlinkshere-next', array( 'parsemag', 'escape' ), $fmtLimit ); + $changed = $this->opts->getChangedValues(); + unset($changed['target']); // Already in the request title + if ( 0 != $prevId ) { - $prevLink = $this->makeSelfLink( $prev, "limit={$limit}&from={$this->back}&namespace={$namespace}" ); - } else { - $prevLink = $prev; + $overrides = array( 'from' => $this->opts->getValue( 'back' ) ); + $prev = $this->makeSelfLink( $prev, wfArrayToCGI( $overrides, $changed ) ); } if ( 0 != $nextId ) { - $nextLink = $this->makeSelfLink( $next, "limit={$limit}&from={$nextId}&back={$prevId}&namespace={$namespace}" ); - } else { - $nextLink = $next; + $overrides = array( 'from' => $nextId, 'back' => $prevId ); + $next = $this->makeSelfLink( $next, wfArrayToCGI( $overrides, $changed ) ); } - $nums = $this->numLink( 20, $prevId ) . ' | ' . - $this->numLink( 50, $prevId ) . ' | ' . - $this->numLink( 100, $prevId ) . ' | ' . - $this->numLink( 250, $prevId ) . ' | ' . - $this->numLink( 500, $prevId ); - return wfMsg( 'viewprevnext', $prevLink, $nextLink, $nums ); - } + $limitLinks = array(); + foreach ( $this->limits as $limit ) { + $prettyLimit = $wgLang->formatNum( $limit ); + $overrides = array( 'limit' => $limit ); + $limitLinks[] = $this->makeSelfLink( $prettyLimit, wfArrayToCGI( $overrides, $changed ) ); + } - function numLink( $limit, $from ) { - global $wgLang; - $query = "limit={$limit}&from={$from}"; - $fmtLimit = $wgLang->formatNum( $limit ); - return $this->makeSelfLink( $fmtLimit, $query ); + $nums = implode ( ' | ', $limitLinks ); + + return wfMsgHtml( 'viewprevnext', $prev, $next, $nums ); } - function whatlinkshereForm( $options ) { + function whatlinkshereForm() { global $wgScript, $wgTitle; - $options['title'] = $wgTitle->getPrefixedText(); + // We get nicer value from the title object + $this->opts->consumeValue( 'target' ); + // Reset these for new requests + $this->opts->consumeValues( array( 'back', 'from' ) ); + + $target = $this->target ? $this->target->getPrefixedText() : ''; + $namespace = $this->opts->consumeValue( 'namespace' ); + + # Build up the form + $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ); + + # Values that should not be forgotten + $f .= Xml::hidden( 'title', $wgTitle->getPrefixedText() ); + foreach ( $this->opts->getUnconsumedValues() as $name => $value ) { + $f .= Xml::hidden( $name, $value ); + } - $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => "$wgScript" ) ) . - '
' . - Xml::element( 'legend', array(), wfMsg( 'whatlinkshere' ) ); + $f .= Xml::openElement( 'fieldset' ); + $f .= Xml::element( 'legend', null, wfMsg( 'whatlinkshere' ) ); - foreach ( $options as $name => $value ) { - if( $name === 'namespace') continue; - $f .= "\t" . Xml::hidden( $name, $value ). "\n"; - } + # Target input + $f .= Xml::inputLabel( wfMsg( 'whatlinkshere-page' ), 'target', + 'mw-whatlinkshere-target', 40, $target ); + + $f .= ' '; + + # Namespace selector + $f .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' . + Xml::namespaceSelector( $namespace, '' ); + + # Submit + $f .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ); - $f .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' . - Xml::namespaceSelector( $options['namespace'], '' ) . - Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . - '
' . - Xml::closeElement( 'form' ) . "\n"; + # Close + $f .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n"; return $f; } - function setNamespace( $ns ) { - $this->namespace = $ns; + function getFilterPanel() { + $show = wfMsgHtml( 'show' ); + $hide = wfMsgHtml( 'hide' ); + + $changed = $this->opts->getChangedValues(); + unset($changed['target']); // Already in the request title + + $links = array(); + $types = array( 'hidetrans', 'hidelinks', 'hideredirs' ); + if( $this->target->getNamespace() == NS_IMAGE ) + $types[] = 'hideimages'; + foreach( $types as $type ) { + $chosen = $this->opts->getValue( $type ); + $msg = wfMsgHtml( "whatlinkshere-{$type}", $chosen ? $show : $hide ); + $overrides = array( $type => !$chosen ); + $links[] = $this->makeSelfLink( $msg, wfArrayToCGI( $overrides, $changed ) ); + } + return Xml::tags( 'fieldset', null, + Xml::element( 'legend', null, wfMsg( 'whatlinkshere-filters' ) ) . + implode( ' | ', $links ) + ); } - } - -?>