r107363 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r107362‎ | r107363 | r107364 >
Date:06:51, 27 December 2011
Author:bawolff
Status:deferred
Tags:
Comment:
Make this extension work correctly on preview

Making this work on preview was rather convoluted, ugly and fragile.
If anyone has a better way of doing that please let me know.
Modified paths:
  • /trunk/extensions/PageInCat/PageInCat.i18n.php (modified) (history)
  • /trunk/extensions/PageInCat/PageInCat.php (modified) (history)
  • /trunk/extensions/PageInCat/PageInCat_body.php (modified) (history)

Diff [purge]

Index: trunk/extensions/PageInCat/PageInCat.i18n.php
@@ -11,14 +11,19 @@
1212 $messages['en'] = array(
1313 'pageincat-desc' => 'Adds a parser function <code><nowiki>{{#incat:...}}</nowiki></code> to determine if the current page is in a specified category',
1414 'pageincat-wrong-warn' => '\'\'\'Warning:\'\'\' The {{PLURAL:$2|category $1 was|categories $1 were}} detected incorrectly by <code><nowiki>{{#incat:...}}</nowiki></code>, and as a result this preview may be incorrect. The saved version of this page should be displayed in the correct manner.',
 15+ 'pageincat-very-wrong-warn' => '\'\'\'Warning:\'\'\' The {{PLURAL:$2|category $1 was|categories $1 were}} detected incorrectly by <code><nowiki>{{#incat:...}}</nowiki></code>, and as a result this preview may be incorrect. This can be caused by including categories inside of <code><nowiki>{{#incat:...}}</nowiki></code> statements, and may result in inconsistant display.',
1516 );
1617
1718 /** Message documentation (Message documentation) */
1819 $messages['qqq'] = array(
19 - 'pageincat-wrong-warn' => 'Warning displayed during preview when editing a page if #incat parser function acted incorrectly (Acting incorrectly means acting as if page was not in category, but page actually is) . This can happen during preview, since the categories from the last saved revision are used instead of the categories specified in the page text. Once page is saved, the correct categories should be used. This error can also be caused by conditional category inclusion (<code><nowiki>{{#ifpageincat:Foo||[[category:Foo]]}}</nowiki></code>
 20+ 'pageincat-wrong-warn' => 'Warning displayed during preview when editing a page if #incat parser function acted incorrectly (Acting incorrectly means acting as if page was not in category, but page actually is). This can happen during preview, since the categories from the last saved revision are used instead of the categories specified in the page text. Once page is saved, the correct categories should be used. This error can also be caused by conditional category inclusion (<code><nowiki>{{#ifpageincat:Foo||[[category:Foo]]}}</nowiki></code>. See also {{msg-mw|pageincat-very-wrong-warn}}.
2021
2122 *$1 is the list of categories (in a localized comma seperated list with the last two items separated by {{msg-mw|and}}. The individual category names will be italicized).
2223 *$2 is how many categories',
 24+ 'pageincat-very-wrong-warn' => 'Warning displayed during preview when editing a page if #incat parser function acted incorrectly (Acting incorrectly means acting as if page was not in category, but page actually is) . This can happen if someone does something like \'\'put this page in category foo only if its not in category foo\'\' or more generally when people include category links inside <code>#incat</code> functions. Compare this to {{msg-mw|pageincat-wrong-warn}}. Generally this error message can happen when support for checking actual categories in the preview is enabled (but the category functions still behave incorrectly), the other error message will be triggered when such support is disabled.
 25+
 26+*$1 is the list of categories (in a localized comma seperated list with the last two items separated by {{msg-mw|and}}. The individual category names will be italicized).
 27+*$2 is how many categories',
2328 );
2429
2530 /** German (Deutsch)
Index: trunk/extensions/PageInCat/PageInCat.php
@@ -1,7 +1,7 @@
22 <?php
33 /**
44 * Extension to add parserfunction {{#incat:foo|yes|no}}
5 - * Note, this might give wrong results on preview, but should work once page is saved.
 5+ *
66 * @author Brian Wolff <bawolff+ext _at_ gmail _dot_ com>
77 *
88 * Copyright © Brian Wolff 2011.
@@ -31,7 +31,7 @@
3232 'path' => __FILE__,
3333 'name' => 'PageInCat',
3434 'descriptionmsg' => 'pageincat-desc',
35 - 'version' => 1.1,
 35+ 'version' => 2,
3636 'url' => 'https://mediawiki.org/wiki/Extension:PageInCat',
3737 'author' => '[https://mediawiki.org/wiki/User:Bawolff Brian Wolff]',
3838 );
@@ -46,3 +46,10 @@
4747 $wgHooks['ParserFirstCallInit'][] = 'PageInCat::register';
4848 $wgHooks['ParserClearState'][] = 'PageInCat::onClearState';
4949 $wgHooks['ParserAfterTidy'][] = 'PageInCat::onParserAfterTidy';
 50+$wgHooks['EditPageGetPreviewText'][] = 'PageInCat::onEditPageGetPreviewText';
 51+$wgHooks['ParserBeforeInternalParse'][] = 'PageInCat::onParserBeforeInternalParse';
 52+
 53+# Double parse previews so that #incat: uses the categories
 54+# in the edit box, instead of from the previous version of the page.
 55+# A bit hacky, and will double the time it takes to render a preview.
 56+$wgPageInCatUseAccuratePreview = true;
Index: trunk/extensions/PageInCat/PageInCat_body.php
@@ -1,6 +1,15 @@
22 <?php
33 class PageInCat {
44
 5+ /**
 6+ * Really hacky array for categories of page
 7+ * that we are previewing. See onEditPageGetPreviewText
 8+ * method. Each key is an md5sum of page text, and each key
 9+ * is an array of categories
 10+ */
 11+ public static $categoriesForPreview = array();
 12+
 13+
514 /**
615 * Register the parser hook.
716 * @param $parser Parser
@@ -43,24 +52,32 @@
4453 if ( !$catTitle ) return false;
4554 $catDBkey = $catTitle->getDBkey();
4655
 56+ if ( !isset( $parser->pageInCat_cache ) ) {
 57+ $parser->pageInCat_cache = array();
 58+ } else {
 59+ if ( isset( $parser->pageInCat_cache[$catDBkey] ) ) {
 60+ # been there done that, return cached value
 61+ return $parser->pageInCat_cache[$catDBkey];
 62+ } elseif( isset( $parser->pageInCat_onlyCache ) && $parser->pageInCat_onlyCache ) {
 63+ # All categories have been preloaded into cache, so
 64+ # we must have hit a cat not in page.
 65+ # Mark it so can be checked for correctness later.
 66+ $parser->PageInCat_cache[$catDBkey] = false;
 67+ return false;
 68+ }
 69+ }
 70+
4771 $pageId = $page->getArticleId();
4872 if ( !$pageId ) {
4973 // page hasn't yet been saved (preview)
5074 // add to the cache list so the other hook
5175 // will warn about incorrect value.
 76+ // Important to do this after checking cache
 77+ // in case categories were pre-loaded during preview.
5278 $parser->pageInCat_cache[$catDBkey] = false;
5379 return false;
5480 }
5581
56 - if ( !isset( $parser->pageInCat_cache ) ) {
57 - $parser->pageInCat_cache = array();
58 - } else {
59 - if ( isset( $parser->pageInCat_cache[$catDBkey] ) ) {
60 - # been there done that, return cached value
61 - return $parser->pageInCat_cache[$catDBkey];
62 - }
63 - }
64 -
6582 if ( !$parser->incrementExpensiveFunctionCount() ) {
6683 # expensive function limit reached.
6784 return false;
@@ -112,6 +129,7 @@
113130 */
114131 public static function onClearState( Parser $parser ) {
115132 $parser->pageInCat_cache = array();
 133+ $parser->pageInCat_onlyCache = false;
116134 return true;
117135 }
118136
@@ -163,7 +181,20 @@
164182 if ( count( $catList ) !== 0 ) {
165183 # We have at least 1 category that was treated
166184 # incorrectly by {{#incat:
167 - $msg = wfMessage( 'pageincat-wrong-warn' )
 185+ if ( isset( $parser->pageInCat_onlyCache ) && $parser->pageInCat_onlyCache ) {
 186+ # categories already preloaded, so not a preview thing
 187+ # yes, creativity in message name is apparently not my strong suit.
 188+ $msgName = 'pageincat-very-wrong-warn';
 189+ } else {
 190+ # Categories were not pre-loaded, so used last saved revision
 191+ # which is most likely source of errors.
 192+ # Generally triggered by $wgPageInCatUseAccuratePreview = false;
 193+ # but can also be triggered if the pre-loading mechanism fails
 194+ # (extensions hooking into ParserBeforeStrip for example)
 195+ $msgName = 'pageincat-wrong-warn';
 196+ }
 197+
 198+ $msg = wfMessage( $msgName )
168199 ->params( $wgLang->listToText( $catList ) )
169200 ->numParams( count( $catList ) )
170201 ->text();
@@ -174,4 +205,105 @@
175206 return true;
176207 }
177208
 209+ /**
 210+ * Hook called just before rendering preview. Used to determine current categories
 211+ *
 212+ * This is hacky... Basically double parse the page, so we can determine categories.
 213+ * Store the retrieved categories in a static member of this class because I can't
 214+ * figure out a better way to get the data where it needs to be.
 215+ * See $categoriesForPreview member variable.
 216+ *
 217+ * Have I mentioned this is ugly, icky and hacky?
 218+ *
 219+ * @todo Find a non-ugly way of doing this (is that possible?)
 220+ *
 221+ * @param $editPage EditPage
 222+ * @param $text String wikitext to be parsed
 223+ * @return boolean true
 224+ */
 225+ public static function onEditPageGetPreviewText( EditPage $editPage, $text ) {
 226+ global $wgPageInCatUseAccuratePreview;
 227+ if ( !$wgPageInCatUseAccuratePreview ) return true; // disable this hacky mess ;)
 228+
 229+ global $wgParser; // we are not parsing anything yet, so should be safe.
 230+ $curUser = RequestContext::getMain()->getUser(); // aka $wgUser in disguise
 231+
 232+ # This is copied from EditPage.php
 233+ # Most of these options don't matter, but thought I'd make it as close to
 234+ # EditPage.php as possible
 235+ $parserOptions = ParserOptions::newFromUser( $curUser );
 236+ $parserOptions->setEditSection( false );
 237+ $parserOptions->setTidy( true );
 238+ # Don't set as preview so other hook isn't triggered (Talk about being hacky!)
 239+ # $parserOptions->setIsPreview( true );
 240+ # $parserOptions->setIsSectionPreview( !is_null($editPage->section) && $editPage->section !== '' );
 241+ $parserOptions->enableLimitReport();
 242+
 243+ // I suppose I should be using $editPage->getTitle() but that's new in 1.19
 244+ $toparse = $wgParser->preSaveTransform( $text, $editPage->mTitle, $curUser, $parserOptions );
 245+ $hash = md5( $toparse, true );
 246+ $parserOutput = $wgParser->parse( $toparse, $editPage->mTitle, $parserOptions );
 247+
 248+ if ( count( self::$categoriesForPreview ) > 10 ) {
 249+ # Really this should never have more than 1 element
 250+ # since we should do a preview directly after this
 251+ # and delete the sole element. But good to be paranoid,
 252+ # especially given how fragile this solution is.
 253+ wfDebug( __METHOD__ . ' self::$categoriesForPreview grew too big.' );
 254+ self::$categoriesForPreview = array();
 255+ }
 256+ self::$categoriesForPreview[$hash] = $parserOutput->getCategoryLinks();
 257+ return true;
 258+ }
 259+
 260+ /**
 261+ * Insert categories from previous pre-preview parse into parser.
 262+ *
 263+ * See onEditPageGetPreviewText. This is rather fragile/scary.
 264+ * If anyone has a suggestion for how to do this better, please let me know.
 265+ *
 266+ * @param $parser Parser
 267+ * @param $pstText String text to parse, all pst'd. In theory untouched but
 268+ * various hooks could have touched it, which would make this all fail.
 269+ * @param $stripState StripState $parser->mStripState - I really don't need this
 270+ * @return boolean true
 271+ */
 272+ public static function onParserBeforeInternalParse( Parser $parser, $pstText, $stripState ) {
 273+ global $wgPageInCatUseAccuratePreview;
 274+ if ( !$wgPageInCatUseAccuratePreview ) {
 275+ // Disabled
 276+ return true;
 277+ }
 278+
 279+ if ( !$parser->getOptions()->getIsPreview() ) {
 280+ // We only do stuff on preview
 281+ return true;
 282+ }
 283+
 284+ $hash = md5( $pstText, true );
 285+
 286+ if ( !isset( self::$categoriesForPreview[$hash] ) ) {
 287+ # This probably shouldn't happen
 288+ wfDebug( __METHOD__ . ' Could not find relavent cat list.' );
 289+ return true;
 290+ }
 291+
 292+ if ( !isset( $parser->pageInCat_cache ) ) {
 293+ $parser->pageInCat_cache = array();
 294+ } elseif ( count( $parser->pageInCat_cache ) !== 0 ) {
 295+ # being paranoid
 296+ wfDebug( __METHOD__ . ' $parser->pageInCat_cache not empty!' );
 297+ $parser->pageInCat_cache = array();
 298+ }
 299+
 300+ foreach( self::$categoriesForPreview[$hash] as $catName ) {
 301+ $parser->pageInCat_cache[$catName] = true;
 302+ }
 303+ // Assume anything not in the cache is false.
 304+ $parser->pageInCat_onlyCache = true;
 305+ unset( self::$categoriesForPreview[$hash] );
 306+
 307+ return true;
 308+ }
 309+
178310 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r107366follow-up r107363. Spelling mistake in messages and comments + add one wfProf...bawolff07:31, 27 December 2011

Status & tagging log