| Index: trunk/phase3/maintenance/archives/patch-page_props.sql |
| — | — | @@ -0,0 +1,9 @@ |
| | 2 | +-- Name/value pairs indexed by page_id |
| | 3 | +CREATE TABLE /*$wgDBprefix*/page_props ( |
| | 4 | + pp_page int NOT NULL, |
| | 5 | + pp_propname varbinary(60) NOT NULL, |
| | 6 | + pp_value blob NOT NULL, |
| | 7 | + |
| | 8 | + PRIMARY KEY (pp_page,pp_propname) |
| | 9 | +); |
| | 10 | + |
| Property changes on: trunk/phase3/maintenance/archives/patch-page_props.sql |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 11 | + native |
| Index: trunk/phase3/maintenance/updaters.inc |
| — | — | @@ -39,6 +39,7 @@ |
| 40 | 40 | array( 'querycachetwo', 'patch-querycachetwo.sql' ), |
| 41 | 41 | array( 'redirect', 'patch-redirect.sql' ), |
| 42 | 42 | array( 'protected_titles', 'patch-protected_titles.sql' ), |
| | 43 | + array( 'page_props', 'patch-page_props.sql' ), |
| 43 | 44 | ); |
| 44 | 45 | |
| 45 | 46 | $wgNewFields = array( |
| Index: trunk/phase3/maintenance/tables.sql |
| — | — | @@ -1184,4 +1184,13 @@ |
| 1185 | 1185 | KEY pt_timestamp (pt_timestamp) |
| 1186 | 1186 | ) /*$wgDBTableOptions*/; |
| 1187 | 1187 | |
| | 1188 | +-- Name/value pairs indexed by page_id |
| | 1189 | +CREATE TABLE /*$wgDBprefix*/page_props ( |
| | 1190 | + pp_page int NOT NULL, |
| | 1191 | + pp_propname varbinary(60) NOT NULL, |
| | 1192 | + pp_value blob NOT NULL, |
| | 1193 | + |
| | 1194 | + PRIMARY KEY (pp_page,pp_propname) |
| | 1195 | +); |
| | 1196 | + |
| 1188 | 1197 | -- vim: sw=2 sts=2 et |
| Index: trunk/phase3/includes/ParserOutput.php |
| — | — | @@ -22,8 +22,9 @@ |
| 23 | 23 | $mHeadItems, # Items to put in the <head> section |
| 24 | 24 | $mOutputHooks, # Hook tags as per $wgParserOutputHooks |
| 25 | 25 | $mWarnings, # Warning text to be returned to the user. Wikitext formatted. |
| 26 | | - $mSections; # Table of contents |
| 27 | | - |
| | 26 | + $mSections, # Table of contents |
| | 27 | + $mProperties; # Name/value pairs to be cached in the DB |
| | 28 | + |
| 28 | 29 | /** |
| 29 | 30 | * Overridden title for display |
| 30 | 31 | */ |
| — | — | @@ -50,6 +51,7 @@ |
| 51 | 52 | $this->mTemplateIds = array(); |
| 52 | 53 | $this->mOutputHooks = array(); |
| 53 | 54 | $this->mWarnings = array(); |
| | 55 | + $this->mProperties = array(); |
| 54 | 56 | } |
| 55 | 57 | |
| 56 | 58 | function getText() { return $this->mText; } |
| — | — | @@ -183,7 +185,24 @@ |
| 184 | 186 | public function getFlag( $flag ) { |
| 185 | 187 | return isset( $this->mFlags[$flag] ); |
| 186 | 188 | } |
| 187 | | - |
| | 189 | + |
| | 190 | + /** |
| | 191 | + * Set a property to be cached in the DB |
| | 192 | + */ |
| | 193 | + public function setProperty( $name, $value ) { |
| | 194 | + $this->mProperties[$name] = $value; |
| | 195 | + } |
| | 196 | + |
| | 197 | + public function getProperty( $name ){ |
| | 198 | + return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false; |
| | 199 | + } |
| | 200 | + |
| | 201 | + public function getProperties() { |
| | 202 | + if ( !isset( $this->mProperties ) ) { |
| | 203 | + $this->mProperties = array(); |
| | 204 | + } |
| | 205 | + return $this->mProperties; |
| | 206 | + } |
| 188 | 207 | } |
| 189 | 208 | |
| 190 | 209 | |
| Index: trunk/phase3/includes/LinkBatch.php |
| — | — | @@ -73,12 +73,18 @@ |
| 74 | 74 | * Return an array mapping PDBK to ID |
| 75 | 75 | */ |
| 76 | 76 | function executeInto( &$cache ) { |
| 77 | | - $fname = 'LinkBatch::executeInto'; |
| 78 | | - wfProfileIn( $fname ); |
| 79 | | - // Do query |
| | 77 | + wfProfileIn( __METHOD__ ); |
| 80 | 78 | $res = $this->doQuery(); |
| | 79 | + $ids = $this->addResultToCache( $cache, $res ); |
| | 80 | + wfProfileOut( __METHOD__ ); |
| | 81 | + return $ids; |
| | 82 | + } |
| | 83 | + |
| | 84 | + /** |
| | 85 | + * Add a ResultWrapper containing IDs and titles to a LinkCache object |
| | 86 | + */ |
| | 87 | + function addResultToCache( $cache, $res ) { |
| 81 | 88 | if ( !$res ) { |
| 82 | | - wfProfileOut( $fname ); |
| 83 | 89 | return array(); |
| 84 | 90 | } |
| 85 | 91 | |
| — | — | @@ -92,7 +98,6 @@ |
| 93 | 99 | $ids[$title->getPrefixedDBkey()] = $row->page_id; |
| 94 | 100 | unset( $remaining[$row->page_namespace][$row->page_title] ); |
| 95 | 101 | } |
| 96 | | - $res->free(); |
| 97 | 102 | |
| 98 | 103 | // The remaining links in $data are bad links, register them as such |
| 99 | 104 | foreach ( $remaining as $ns => $dbkeys ) { |
| — | — | @@ -102,7 +107,6 @@ |
| 103 | 108 | $ids[$title->getPrefixedDBkey()] = 0; |
| 104 | 109 | } |
| 105 | 110 | } |
| 106 | | - wfProfileOut( $fname ); |
| 107 | 111 | return $ids; |
| 108 | 112 | } |
| 109 | 113 | |
| — | — | @@ -110,12 +114,10 @@ |
| 111 | 115 | * Perform the existence test query, return a ResultWrapper with page_id fields |
| 112 | 116 | */ |
| 113 | 117 | function doQuery() { |
| 114 | | - $fname = 'LinkBatch::doQuery'; |
| 115 | | - |
| 116 | 118 | if ( $this->isEmpty() ) { |
| 117 | 119 | return false; |
| 118 | 120 | } |
| 119 | | - wfProfileIn( $fname ); |
| | 121 | + wfProfileIn( __METHOD__ ); |
| 120 | 122 | |
| 121 | 123 | // Construct query |
| 122 | 124 | // This is very similar to Parser::replaceLinkHolders |
| — | — | @@ -123,22 +125,21 @@ |
| 124 | 126 | $page = $dbr->tableName( 'page' ); |
| 125 | 127 | $set = $this->constructSet( 'page', $dbr ); |
| 126 | 128 | if ( $set === false ) { |
| 127 | | - wfProfileOut( $fname ); |
| | 129 | + wfProfileOut( __METHOD__ ); |
| 128 | 130 | return false; |
| 129 | 131 | } |
| 130 | 132 | $sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE $set"; |
| 131 | 133 | |
| 132 | 134 | // Do query |
| 133 | | - $res = new ResultWrapper( $dbr, $dbr->query( $sql, $fname ) ); |
| 134 | | - wfProfileOut( $fname ); |
| | 135 | + $res = new ResultWrapper( $dbr, $dbr->query( $sql, __METHOD__ ) ); |
| | 136 | + wfProfileOut( __METHOD__ ); |
| 135 | 137 | return $res; |
| 136 | 138 | } |
| 137 | 139 | |
| 138 | 140 | /** |
| 139 | 141 | * Construct a WHERE clause which will match all the given titles. |
| 140 | | - * Give the appropriate table's field name prefix ('page', 'pl', etc). |
| 141 | 142 | * |
| 142 | | - * @param $prefix String: ?? |
| | 143 | + * @param string $prefix the appropriate table's field name prefix ('page', 'pl', etc) |
| 143 | 144 | * @return string |
| 144 | 145 | * @public |
| 145 | 146 | */ |
| Index: trunk/phase3/includes/Parser.php |
| — | — | @@ -98,7 +98,7 @@ |
| 99 | 99 | var $mInterwikiLinkHolders, $mLinkHolders; |
| 100 | 100 | var $mIncludeSizes, $mPPNodeCount, $mDefaultSort; |
| 101 | 101 | var $mTplExpandCache; // empty-frame expansion cache |
| 102 | | - var $mTplRedirCache, $mTplDomCache, $mHeadings; |
| | 102 | + var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores; |
| 103 | 103 | |
| 104 | 104 | # Temporary |
| 105 | 105 | # These are variables reset at least once per parse regardless of $clearState |
| — | — | @@ -147,51 +147,9 @@ |
| 148 | 148 | $this->mFirstCall = false; |
| 149 | 149 | |
| 150 | 150 | wfProfileIn( __METHOD__ ); |
| 151 | | - global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; |
| 152 | 151 | |
| 153 | 152 | $this->setHook( 'pre', array( $this, 'renderPreTag' ) ); |
| 154 | | - |
| 155 | | - # Syntax for arguments (see self::setFunctionHook): |
| 156 | | - # "name for lookup in localized magic words array", |
| 157 | | - # function callback, |
| 158 | | - # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...} |
| 159 | | - # instead of {{#int:...}}) |
| 160 | | - $this->setFunctionHook( 'int', array( 'CoreParserFunctions', 'intFunction' ), SFH_NO_HASH ); |
| 161 | | - $this->setFunctionHook( 'ns', array( 'CoreParserFunctions', 'ns' ), SFH_NO_HASH ); |
| 162 | | - $this->setFunctionHook( 'urlencode', array( 'CoreParserFunctions', 'urlencode' ), SFH_NO_HASH ); |
| 163 | | - $this->setFunctionHook( 'lcfirst', array( 'CoreParserFunctions', 'lcfirst' ), SFH_NO_HASH ); |
| 164 | | - $this->setFunctionHook( 'ucfirst', array( 'CoreParserFunctions', 'ucfirst' ), SFH_NO_HASH ); |
| 165 | | - $this->setFunctionHook( 'lc', array( 'CoreParserFunctions', 'lc' ), SFH_NO_HASH ); |
| 166 | | - $this->setFunctionHook( 'uc', array( 'CoreParserFunctions', 'uc' ), SFH_NO_HASH ); |
| 167 | | - $this->setFunctionHook( 'localurl', array( 'CoreParserFunctions', 'localurl' ), SFH_NO_HASH ); |
| 168 | | - $this->setFunctionHook( 'localurle', array( 'CoreParserFunctions', 'localurle' ), SFH_NO_HASH ); |
| 169 | | - $this->setFunctionHook( 'fullurl', array( 'CoreParserFunctions', 'fullurl' ), SFH_NO_HASH ); |
| 170 | | - $this->setFunctionHook( 'fullurle', array( 'CoreParserFunctions', 'fullurle' ), SFH_NO_HASH ); |
| 171 | | - $this->setFunctionHook( 'formatnum', array( 'CoreParserFunctions', 'formatnum' ), SFH_NO_HASH ); |
| 172 | | - $this->setFunctionHook( 'grammar', array( 'CoreParserFunctions', 'grammar' ), SFH_NO_HASH ); |
| 173 | | - $this->setFunctionHook( 'plural', array( 'CoreParserFunctions', 'plural' ), SFH_NO_HASH ); |
| 174 | | - $this->setFunctionHook( 'numberofpages', array( 'CoreParserFunctions', 'numberofpages' ), SFH_NO_HASH ); |
| 175 | | - $this->setFunctionHook( 'numberofusers', array( 'CoreParserFunctions', 'numberofusers' ), SFH_NO_HASH ); |
| 176 | | - $this->setFunctionHook( 'numberofarticles', array( 'CoreParserFunctions', 'numberofarticles' ), SFH_NO_HASH ); |
| 177 | | - $this->setFunctionHook( 'numberoffiles', array( 'CoreParserFunctions', 'numberoffiles' ), SFH_NO_HASH ); |
| 178 | | - $this->setFunctionHook( 'numberofadmins', array( 'CoreParserFunctions', 'numberofadmins' ), SFH_NO_HASH ); |
| 179 | | - $this->setFunctionHook( 'numberofedits', array( 'CoreParserFunctions', 'numberofedits' ), SFH_NO_HASH ); |
| 180 | | - $this->setFunctionHook( 'language', array( 'CoreParserFunctions', 'language' ), SFH_NO_HASH ); |
| 181 | | - $this->setFunctionHook( 'padleft', array( 'CoreParserFunctions', 'padleft' ), SFH_NO_HASH ); |
| 182 | | - $this->setFunctionHook( 'padright', array( 'CoreParserFunctions', 'padright' ), SFH_NO_HASH ); |
| 183 | | - $this->setFunctionHook( 'anchorencode', array( 'CoreParserFunctions', 'anchorencode' ), SFH_NO_HASH ); |
| 184 | | - $this->setFunctionHook( 'special', array( 'CoreParserFunctions', 'special' ) ); |
| 185 | | - $this->setFunctionHook( 'defaultsort', array( 'CoreParserFunctions', 'defaultsort' ), SFH_NO_HASH ); |
| 186 | | - $this->setFunctionHook( 'filepath', array( 'CoreParserFunctions', 'filepath' ), SFH_NO_HASH ); |
| 187 | | - $this->setFunctionHook( 'tag', array( 'CoreParserFunctions', 'tagObj' ), SFH_OBJECT_ARGS ); |
| 188 | | - |
| 189 | | - if ( $wgAllowDisplayTitle ) { |
| 190 | | - $this->setFunctionHook( 'displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH ); |
| 191 | | - } |
| 192 | | - if ( $wgAllowSlowParserFunctions ) { |
| 193 | | - $this->setFunctionHook( 'pagesinnamespace', array( 'CoreParserFunctions', 'pagesinnamespace' ), SFH_NO_HASH ); |
| 194 | | - } |
| 195 | | - |
| | 153 | + CoreParserFunctions::register( $this ); |
| 196 | 154 | $this->initialiseVariables(); |
| 197 | 155 | |
| 198 | 156 | wfRunHooks( 'ParserFirstCallInit', array( &$this ) ); |
| — | — | @@ -256,6 +214,7 @@ |
| 257 | 215 | $this->mPPNodeCount = 0; |
| 258 | 216 | $this->mDefaultSort = false; |
| 259 | 217 | $this->mHeadings = array(); |
| | 218 | + $this->mDoubleUnderscores = array(); |
| 260 | 219 | |
| 261 | 220 | # Fix cloning |
| 262 | 221 | if ( isset( $this->mPreprocessor ) && $this->mPreprocessor->parser !== $this ) { |
| — | — | @@ -991,8 +950,7 @@ |
| 992 | 951 | |
| 993 | 952 | $text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text ); |
| 994 | 953 | |
| 995 | | - $text = $this->stripToc( $text ); |
| 996 | | - $this->stripNoGallery( $text ); |
| | 954 | + $text = $this->doDoubleUnderscore( $text ); |
| 997 | 955 | $text = $this->doHeadings( $text ); |
| 998 | 956 | if($this->mOptions->getUseDynamicDates()) { |
| 999 | 957 | $df =& DateFormatter::getInstance(); |
| — | — | @@ -3302,32 +3260,11 @@ |
| 3303 | 3261 | } |
| 3304 | 3262 | |
| 3305 | 3263 | /** |
| 3306 | | - * Detect __NOGALLERY__ magic word and set a placeholder |
| | 3264 | + * Strip double-underscore items like __NOGALLERY__ and __NOTOC__ |
| | 3265 | + * Fills $this->mDoubleUnderscores, returns the modified text |
| 3307 | 3266 | */ |
| 3308 | | - function stripNoGallery( &$text ) { |
| 3309 | | - # if the string __NOGALLERY__ (not case-sensitive) occurs in the HTML, |
| 3310 | | - # do not add TOC |
| 3311 | | - $mw = MagicWord::get( 'nogallery' ); |
| 3312 | | - $this->mOutput->mNoGallery = $mw->matchAndRemove( $text ) ; |
| 3313 | | - } |
| 3314 | | - |
| 3315 | | - /** |
| 3316 | | - * Find the first __TOC__ magic word and set a <!--MWTOC--> |
| 3317 | | - * placeholder that will then be replaced by the real TOC in |
| 3318 | | - * ->formatHeadings, this works because at this points real |
| 3319 | | - * comments will have already been discarded by the sanitizer. |
| 3320 | | - * |
| 3321 | | - * Any additional __TOC__ magic words left over will be discarded |
| 3322 | | - * as there can only be one TOC on the page. |
| 3323 | | - */ |
| 3324 | | - function stripToc( $text ) { |
| 3325 | | - # if the string __NOTOC__ (not case-sensitive) occurs in the HTML, |
| 3326 | | - # do not add TOC |
| 3327 | | - $mw = MagicWord::get( 'notoc' ); |
| 3328 | | - if( $mw->matchAndRemove( $text ) ) { |
| 3329 | | - $this->mShowToc = false; |
| 3330 | | - } |
| 3331 | | - |
| | 3267 | + function doDoubleUnderscore( $text ) { |
| | 3268 | + // The position of __TOC__ needs to be recorded |
| 3332 | 3269 | $mw = MagicWord::get( 'toc' ); |
| 3333 | 3270 | if( $mw->match( $text ) ) { |
| 3334 | 3271 | $this->mShowToc = true; |
| — | — | @@ -3339,6 +3276,20 @@ |
| 3340 | 3277 | // Only keep the first one. |
| 3341 | 3278 | $text = $mw->replace( '', $text ); |
| 3342 | 3279 | } |
| | 3280 | + |
| | 3281 | + // Now match and remove the rest of them |
| | 3282 | + $mwa = MagicWord::getDoubleUnderscoreArray(); |
| | 3283 | + $this->mDoubleUnderscores = $mwa->matchAndRemove( $text ); |
| | 3284 | + |
| | 3285 | + if ( isset( $this->mDoubleUnderscores['nogallery'] ) ) { |
| | 3286 | + $this->mOutput->mNoGallery = true; |
| | 3287 | + } |
| | 3288 | + if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) { |
| | 3289 | + $this->mShowToc = false; |
| | 3290 | + } |
| | 3291 | + if ( isset( $this->mDoubleUnderscores['hiddencat'] ) ) { |
| | 3292 | + $this->mOutput->setProperty( 'hiddencat', 'y' ); |
| | 3293 | + } |
| 3343 | 3294 | return $text; |
| 3344 | 3295 | } |
| 3345 | 3296 | |
| — | — | @@ -3367,8 +3318,7 @@ |
| 3368 | 3319 | } |
| 3369 | 3320 | |
| 3370 | 3321 | # Inhibit editsection links if requested in the page |
| 3371 | | - $esw =& MagicWord::get( 'noeditsection' ); |
| 3372 | | - if( $esw->matchAndRemove( $text ) ) { |
| | 3322 | + if ( isset( $this->mDoubleUnderscores['noeditsection'] ) ) { |
| 3373 | 3323 | $showEditLink = 0; |
| 3374 | 3324 | } |
| 3375 | 3325 | |
| — | — | @@ -3384,14 +3334,13 @@ |
| 3385 | 3335 | |
| 3386 | 3336 | # Allow user to stipulate that a page should have a "new section" |
| 3387 | 3337 | # link added via __NEWSECTIONLINK__ |
| 3388 | | - $mw =& MagicWord::get( 'newsectionlink' ); |
| 3389 | | - if( $mw->matchAndRemove( $text ) ) |
| | 3338 | + if ( isset( $this->mDoubleUnderscores['newsectionlink'] ) ) { |
| 3390 | 3339 | $this->mOutput->setNewSection( true ); |
| | 3340 | + } |
| 3391 | 3341 | |
| 3392 | 3342 | # if the string __FORCETOC__ (not case-sensitive) occurs in the HTML, |
| 3393 | 3343 | # override above conditions and always show TOC above first header |
| 3394 | | - $mw =& MagicWord::get( 'forcetoc' ); |
| 3395 | | - if ($mw->matchAndRemove( $text ) ) { |
| | 3344 | + if ( isset( $this->mDoubleUnderscores['forcetoc'] ) ) { |
| 3396 | 3345 | $this->mShowToc = true; |
| 3397 | 3346 | $enoughToc = true; |
| 3398 | 3347 | } |
| Index: trunk/phase3/includes/OutputPage.php |
| — | — | @@ -270,18 +270,40 @@ |
| 271 | 271 | /** |
| 272 | 272 | * Add an array of categories, with names in the keys |
| 273 | 273 | */ |
| 274 | | - public function addCategoryLinks($categories) { |
| | 274 | + public function addCategoryLinks( $categories ) { |
| 275 | 275 | global $wgUser, $wgContLang; |
| 276 | 276 | |
| 277 | 277 | if ( !is_array( $categories ) ) { |
| 278 | 278 | return; |
| 279 | 279 | } |
| 280 | | - # Add the links to the link cache in a batch |
| | 280 | + if ( count( $categories ) == 0 ) { |
| | 281 | + return; |
| | 282 | + } |
| | 283 | + # Add the links to a LinkBatch |
| 281 | 284 | $arr = array( NS_CATEGORY => $categories ); |
| 282 | 285 | $lb = new LinkBatch; |
| 283 | 286 | $lb->setArray( $arr ); |
| 284 | | - $lb->execute(); |
| 285 | 287 | |
| | 288 | + # Fetch existence plus the hiddencat property |
| | 289 | + $dbr = wfGetDB( DB_SLAVE ); |
| | 290 | + $pageTable = $dbr->tableName( 'page' ); |
| | 291 | + $propsTable = $dbr->tableName( 'page_props' ); |
| | 292 | + $where = $lb->constructSet( 'page', $dbr ); |
| | 293 | + $sql = "SELECT page_id, page_namespace, page_title, pp_value FROM $pageTable LEFT JOIN $propsTable " . |
| | 294 | + " ON pp_page=page_id WHERE ($where) AND pp_propname='hiddencat'"; |
| | 295 | + $res = $dbr->query( $sql, __METHOD__ ); |
| | 296 | + |
| | 297 | + # Add the results to the link cache |
| | 298 | + $lb->addResultToCache( LinkCache::singleton(), $res ); |
| | 299 | + |
| | 300 | + # Remove categories with hiddencat |
| | 301 | + foreach ( $res as $row ) { |
| | 302 | + if ( isset( $row->pp_value ) ) { |
| | 303 | + unset( $categories[$row->page_title] ); |
| | 304 | + } |
| | 305 | + } |
| | 306 | + |
| | 307 | + # Add the remaining categories to the skin |
| 286 | 308 | $sk = $wgUser->getSkin(); |
| 287 | 309 | foreach ( $categories as $category => $unused ) { |
| 288 | 310 | $title = Title::makeTitleSafe( NS_CATEGORY, $category ); |
| — | — | @@ -389,11 +411,11 @@ |
| 390 | 412 | // Versioning... |
| 391 | 413 | $this->mTemplateIds += (array)$parserOutput->mTemplateIds; |
| 392 | 414 | |
| 393 | | - # Display title |
| | 415 | + // Display title |
| 394 | 416 | if( ( $dt = $parserOutput->getDisplayTitle() ) !== false ) |
| 395 | 417 | $this->setPageTitle( $dt ); |
| 396 | 418 | |
| 397 | | - # Hooks registered in the object |
| | 419 | + // Hooks registered in the object |
| 398 | 420 | global $wgParserOutputHooks; |
| 399 | 421 | foreach ( $parserOutput->getOutputHooks() as $hookInfo ) { |
| 400 | 422 | list( $hookName, $data ) = $hookInfo; |
| Index: trunk/phase3/includes/LinksUpdate.php |
| — | — | @@ -17,6 +17,7 @@ |
| 18 | 18 | $mExternals, //!< URLs of external links, array key only |
| 19 | 19 | $mCategories, //!< Map of category names to sort keys |
| 20 | 20 | $mInterlangs, //!< Map of language codes to titles |
| | 21 | + $mProperties, //!< Map of arbitrary name to value |
| 21 | 22 | $mDb, //!< Database connection reference |
| 22 | 23 | $mOptions, //!< SELECT options to be used (array) |
| 23 | 24 | $mRecursive; //!< Whether to queue jobs for recursive updates |
| — | — | @@ -51,6 +52,7 @@ |
| 52 | 53 | $this->mTemplates = $parserOutput->getTemplates(); |
| 53 | 54 | $this->mExternals = $parserOutput->getExternalLinks(); |
| 54 | 55 | $this->mCategories = $parserOutput->getCategories(); |
| | 56 | + $this->mProperties = $parserOutput->getProperties(); |
| 55 | 57 | |
| 56 | 58 | # Convert the format of the interlanguage links |
| 57 | 59 | # I didn't want to change it in the ParserOutput, because that array is passed all |
| — | — | @@ -85,8 +87,7 @@ |
| 86 | 88 | } |
| 87 | 89 | |
| 88 | 90 | function doIncrementalUpdate() { |
| 89 | | - $fname = 'LinksUpdate::doIncrementalUpdate'; |
| 90 | | - wfProfileIn( $fname ); |
| | 91 | + wfProfileIn( __METHOD__ ); |
| 91 | 92 | |
| 92 | 93 | # Page links |
| 93 | 94 | $existing = $this->getExistingLinks(); |
| — | — | @@ -126,13 +127,22 @@ |
| 127 | 128 | $categoryUpdates = array_diff_assoc( $existing, $this->mCategories ) + array_diff_assoc( $this->mCategories, $existing ); |
| 128 | 129 | $this->invalidateCategories( $categoryUpdates ); |
| 129 | 130 | |
| | 131 | + # Page properties |
| | 132 | + $existing = $this->getExistingProperties(); |
| | 133 | + $this->incrTableUpdate( 'page_props', 'pp', $this->getPropertyDeletions( $existing ), |
| | 134 | + $this->getPropertyInsertions( $existing ) ); |
| | 135 | + |
| | 136 | + # Invalidate the necessary pages |
| | 137 | + $changed = array_diff_assoc( $existing, $this->mProperties ) + array_diff_assoc( $this->mProperties, $existing ); |
| | 138 | + $this->invalidateProperties( $changed ); |
| | 139 | + |
| 130 | 140 | # Refresh links of all pages including this page |
| 131 | 141 | # This will be in a separate transaction |
| 132 | 142 | if ( $this->mRecursive ) { |
| 133 | 143 | $this->queueRecursiveJobs(); |
| 134 | 144 | } |
| 135 | 145 | |
| 136 | | - wfProfileOut( $fname ); |
| | 146 | + wfProfileOut( __METHOD__ ); |
| 137 | 147 | } |
| 138 | 148 | |
| 139 | 149 | /** |
| — | — | @@ -141,8 +151,7 @@ |
| 142 | 152 | * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php |
| 143 | 153 | */ |
| 144 | 154 | function doDumbUpdate() { |
| 145 | | - $fname = 'LinksUpdate::doDumbUpdate'; |
| 146 | | - wfProfileIn( $fname ); |
| | 155 | + wfProfileIn( __METHOD__ ); |
| 147 | 156 | |
| 148 | 157 | # Refresh category pages and image description pages |
| 149 | 158 | $existing = $this->getExistingCategories(); |
| — | — | @@ -156,6 +165,7 @@ |
| 157 | 166 | $this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' ); |
| 158 | 167 | $this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' ); |
| 159 | 168 | $this->dumbTableUpdate( 'langlinks', $this->getInterlangInsertions(), 'll_from' ); |
| | 169 | + $this->dumbTableUpdate( 'page_props', $this->getPropertyInsertions(), 'pp_page' ); |
| 160 | 170 | |
| 161 | 171 | # Update the cache of all the category pages and image description pages which were changed |
| 162 | 172 | $this->invalidateCategories( $categoryUpdates ); |
| — | — | @@ -167,7 +177,7 @@ |
| 168 | 178 | $this->queueRecursiveJobs(); |
| 169 | 179 | } |
| 170 | 180 | |
| 171 | | - wfProfileOut( $fname ); |
| | 181 | + wfProfileOut( __METHOD__ ); |
| 172 | 182 | } |
| 173 | 183 | |
| 174 | 184 | function queueRecursiveJobs() { |
| — | — | @@ -209,8 +219,6 @@ |
| 210 | 220 | * @param array $dbkeys |
| 211 | 221 | */ |
| 212 | 222 | function invalidatePages( $namespace, $dbkeys ) { |
| 213 | | - $fname = 'LinksUpdate::invalidatePages'; |
| 214 | | - |
| 215 | 223 | if ( !count( $dbkeys ) ) { |
| 216 | 224 | return; |
| 217 | 225 | } |
| — | — | @@ -227,7 +235,7 @@ |
| 228 | 236 | 'page_namespace' => $namespace, |
| 229 | 237 | 'page_title IN (' . $this->mDb->makeList( $dbkeys ) . ')', |
| 230 | 238 | 'page_touched < ' . $this->mDb->addQuotes( $now ) |
| 231 | | - ), $fname |
| | 239 | + ), __METHOD__ |
| 232 | 240 | ); |
| 233 | 241 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 234 | 242 | $ids[] = $row->page_id; |
| — | — | @@ -245,7 +253,7 @@ |
| 246 | 254 | array( |
| 247 | 255 | 'page_id IN (' . $this->mDb->makeList( $ids ) . ')', |
| 248 | 256 | 'page_touched < ' . $this->mDb->addQuotes( $now ) |
| 249 | | - ), $fname |
| | 257 | + ), __METHOD__ |
| 250 | 258 | ); |
| 251 | 259 | } |
| 252 | 260 | |
| — | — | @@ -258,13 +266,12 @@ |
| 259 | 267 | } |
| 260 | 268 | |
| 261 | 269 | function dumbTableUpdate( $table, $insertions, $fromField ) { |
| 262 | | - $fname = 'LinksUpdate::dumbTableUpdate'; |
| 263 | | - $this->mDb->delete( $table, array( $fromField => $this->mId ), $fname ); |
| | 270 | + $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ ); |
| 264 | 271 | if ( count( $insertions ) ) { |
| 265 | 272 | # The link array was constructed without FOR UPDATE, so there may be collisions |
| 266 | 273 | # This may cause minor link table inconsistencies, which is better than |
| 267 | 274 | # crippling the site with lock contention. |
| 268 | | - $this->mDb->insert( $table, $insertions, $fname, array( 'IGNORE' ) ); |
| | 275 | + $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) ); |
| 269 | 276 | } |
| 270 | 277 | } |
| 271 | 278 | |
| — | — | @@ -285,8 +292,12 @@ |
| 286 | 293 | * @private |
| 287 | 294 | */ |
| 288 | 295 | function incrTableUpdate( $table, $prefix, $deletions, $insertions ) { |
| 289 | | - $fname = 'LinksUpdate::incrTableUpdate'; |
| 290 | | - $where = array( "{$prefix}_from" => $this->mId ); |
| | 296 | + if ( $table == 'page_props' ) { |
| | 297 | + $fromField = 'pp_page'; |
| | 298 | + } else { |
| | 299 | + $fromField = "{$prefix}_from"; |
| | 300 | + } |
| | 301 | + $where = array( $fromField => $this->mId ); |
| 291 | 302 | if ( $table == 'pagelinks' || $table == 'templatelinks' ) { |
| 292 | 303 | $clause = $this->makeWhereFrom2d( $deletions, $prefix ); |
| 293 | 304 | if ( $clause ) { |
| — | — | @@ -297,6 +308,8 @@ |
| 298 | 309 | } else { |
| 299 | 310 | if ( $table == 'langlinks' ) { |
| 300 | 311 | $toField = 'll_lang'; |
| | 312 | + } elseif ( $table == 'page_props' ) { |
| | 313 | + $toField = 'pp_propname'; |
| 301 | 314 | } else { |
| 302 | 315 | $toField = $prefix . '_to'; |
| 303 | 316 | } |
| — | — | @@ -307,10 +320,10 @@ |
| 308 | 321 | } |
| 309 | 322 | } |
| 310 | 323 | if ( $where ) { |
| 311 | | - $this->mDb->delete( $table, $where, $fname ); |
| | 324 | + $this->mDb->delete( $table, $where, __METHOD__ ); |
| 312 | 325 | } |
| 313 | 326 | if ( count( $insertions ) ) { |
| 314 | | - $this->mDb->insert( $table, $insertions, $fname, 'IGNORE' ); |
| | 327 | + $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' ); |
| 315 | 328 | } |
| 316 | 329 | } |
| 317 | 330 | |
| — | — | @@ -429,6 +442,23 @@ |
| 430 | 443 | } |
| 431 | 444 | |
| 432 | 445 | /** |
| | 446 | + * Get an array of page property insertions |
| | 447 | + */ |
| | 448 | + function getPropertyInsertions( $existing = array() ) { |
| | 449 | + $diffs = array_diff_assoc( $this->mProperties, $existing ); |
| | 450 | + $arr = array(); |
| | 451 | + foreach ( $diffs as $name => $value ) { |
| | 452 | + $arr[] = array( |
| | 453 | + 'pp_page' => $this->mId, |
| | 454 | + 'pp_propname' => $name, |
| | 455 | + 'pp_value' => $value, |
| | 456 | + ); |
| | 457 | + } |
| | 458 | + return $arr; |
| | 459 | + } |
| | 460 | + |
| | 461 | + |
| | 462 | + /** |
| 433 | 463 | * Given an array of existing links, returns those links which are not in $this |
| 434 | 464 | * and thus should be deleted. |
| 435 | 465 | * @private |
| — | — | @@ -499,13 +529,20 @@ |
| 500 | 530 | } |
| 501 | 531 | |
| 502 | 532 | /** |
| | 533 | + * Get array of properties which should be deleted. |
| | 534 | + * @private |
| | 535 | + */ |
| | 536 | + function getPropertyDeletions( $existing ) { |
| | 537 | + return array_diff_assoc( $existing, $this->mProperties ); |
| | 538 | + } |
| | 539 | + |
| | 540 | + /** |
| 503 | 541 | * Get an array of existing links, as a 2-D array |
| 504 | 542 | * @private |
| 505 | 543 | */ |
| 506 | 544 | function getExistingLinks() { |
| 507 | | - $fname = 'LinksUpdate::getExistingLinks'; |
| 508 | 545 | $res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ), |
| 509 | | - array( 'pl_from' => $this->mId ), $fname, $this->mOptions ); |
| | 546 | + array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 510 | 547 | $arr = array(); |
| 511 | 548 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 512 | 549 | if ( !isset( $arr[$row->pl_namespace] ) ) { |
| — | — | @@ -522,9 +559,8 @@ |
| 523 | 560 | * @private |
| 524 | 561 | */ |
| 525 | 562 | function getExistingTemplates() { |
| 526 | | - $fname = 'LinksUpdate::getExistingTemplates'; |
| 527 | 563 | $res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ), |
| 528 | | - array( 'tl_from' => $this->mId ), $fname, $this->mOptions ); |
| | 564 | + array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 529 | 565 | $arr = array(); |
| 530 | 566 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 531 | 567 | if ( !isset( $arr[$row->tl_namespace] ) ) { |
| — | — | @@ -541,9 +577,8 @@ |
| 542 | 578 | * @private |
| 543 | 579 | */ |
| 544 | 580 | function getExistingImages() { |
| 545 | | - $fname = 'LinksUpdate::getExistingImages'; |
| 546 | 581 | $res = $this->mDb->select( 'imagelinks', array( 'il_to' ), |
| 547 | | - array( 'il_from' => $this->mId ), $fname, $this->mOptions ); |
| | 582 | + array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 548 | 583 | $arr = array(); |
| 549 | 584 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 550 | 585 | $arr[$row->il_to] = 1; |
| — | — | @@ -557,9 +592,8 @@ |
| 558 | 593 | * @private |
| 559 | 594 | */ |
| 560 | 595 | function getExistingExternals() { |
| 561 | | - $fname = 'LinksUpdate::getExistingExternals'; |
| 562 | 596 | $res = $this->mDb->select( 'externallinks', array( 'el_to' ), |
| 563 | | - array( 'el_from' => $this->mId ), $fname, $this->mOptions ); |
| | 597 | + array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 564 | 598 | $arr = array(); |
| 565 | 599 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 566 | 600 | $arr[$row->el_to] = 1; |
| — | — | @@ -573,9 +607,8 @@ |
| 574 | 608 | * @private |
| 575 | 609 | */ |
| 576 | 610 | function getExistingCategories() { |
| 577 | | - $fname = 'LinksUpdate::getExistingCategories'; |
| 578 | 611 | $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey' ), |
| 579 | | - array( 'cl_from' => $this->mId ), $fname, $this->mOptions ); |
| | 612 | + array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 580 | 613 | $arr = array(); |
| 581 | 614 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 582 | 615 | $arr[$row->cl_to] = $row->cl_sortkey; |
| — | — | @@ -590,15 +623,30 @@ |
| 591 | 624 | * @private |
| 592 | 625 | */ |
| 593 | 626 | function getExistingInterlangs() { |
| 594 | | - $fname = 'LinksUpdate::getExistingInterlangs'; |
| 595 | 627 | $res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ), |
| 596 | | - array( 'll_from' => $this->mId ), $fname, $this->mOptions ); |
| | 628 | + array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions ); |
| 597 | 629 | $arr = array(); |
| 598 | 630 | while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 599 | 631 | $arr[$row->ll_lang] = $row->ll_title; |
| 600 | 632 | } |
| 601 | 633 | return $arr; |
| 602 | 634 | } |
| | 635 | + |
| | 636 | + /** |
| | 637 | + * Get an array of existing categories, with the name in the key and sort key in the value. |
| | 638 | + * @private |
| | 639 | + */ |
| | 640 | + function getExistingProperties() { |
| | 641 | + $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ), |
| | 642 | + array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions ); |
| | 643 | + $arr = array(); |
| | 644 | + while ( $row = $this->mDb->fetchObject( $res ) ) { |
| | 645 | + $arr[$row->pp_propname] = $row->pp_value; |
| | 646 | + } |
| | 647 | + $this->mDb->freeResult( $res ); |
| | 648 | + return $arr; |
| | 649 | + } |
| | 650 | + |
| 603 | 651 | |
| 604 | 652 | /** |
| 605 | 653 | * Return the title object of the page being updated |
| — | — | @@ -606,5 +654,25 @@ |
| 607 | 655 | function getTitle() { |
| 608 | 656 | return $this->mTitle; |
| 609 | 657 | } |
| | 658 | + |
| | 659 | + /** |
| | 660 | + * Invalidate any necessary link lists related to page property changes |
| | 661 | + */ |
| | 662 | + function invalidateProperties( $changed ) { |
| | 663 | + global $wgPagePropLinkInvalidations; |
| | 664 | + |
| | 665 | + foreach ( $changed as $name => $value ) { |
| | 666 | + if ( isset( $wgPagePropLinkInvalidations[$name] ) ) { |
| | 667 | + $inv = $wgPagePropLinkInvalidations[$name]; |
| | 668 | + if ( !is_array( $inv ) ) { |
| | 669 | + $inv = array( $inv ); |
| | 670 | + } |
| | 671 | + foreach ( $inv as $table ) { |
| | 672 | + $update = new HTMLCacheUpdate( $this->mTitle, $table ); |
| | 673 | + $update->doUpdate(); |
| | 674 | + } |
| | 675 | + } |
| | 676 | + } |
| | 677 | + } |
| 610 | 678 | } |
| 611 | 679 | |
| Index: trunk/phase3/includes/MagicWord.php |
| — | — | @@ -140,7 +140,19 @@ |
| 141 | 141 | 'numberofadmins' => 3600, |
| 142 | 142 | ); |
| 143 | 143 | |
| | 144 | + static public $mDoubleUnderscoreIDs = array( |
| | 145 | + 'notoc', |
| | 146 | + 'nogallery', |
| | 147 | + 'forcetoc', |
| | 148 | + 'toc', |
| | 149 | + 'noeditsection', |
| | 150 | + 'newsectionlink', |
| | 151 | + 'hiddencat', |
| | 152 | + ); |
| | 153 | + |
| | 154 | + |
| 144 | 155 | static public $mObjects = array(); |
| | 156 | + static public $mDoubleUnderscoreArray = null; |
| 145 | 157 | |
| 146 | 158 | /**#@-*/ |
| 147 | 159 | |
| — | — | @@ -197,8 +209,15 @@ |
| 198 | 210 | return -1; |
| 199 | 211 | } |
| 200 | 212 | } |
| | 213 | + |
| | 214 | + /** Get a MagicWordArray of double-underscore entities */ |
| | 215 | + static function getDoubleUnderscoreArray() { |
| | 216 | + if ( is_null( self::$mDoubleUnderscoreArray ) ) { |
| | 217 | + self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs ); |
| | 218 | + } |
| | 219 | + return self::$mDoubleUnderscoreArray; |
| | 220 | + } |
| 201 | 221 | |
| 202 | | - |
| 203 | 222 | # Initialises this object with an ID |
| 204 | 223 | function load( $id ) { |
| 205 | 224 | global $wgContLang; |
| — | — | @@ -449,6 +468,7 @@ |
| 450 | 469 | var $names = array(); |
| 451 | 470 | var $hash; |
| 452 | 471 | var $baseRegex, $regex; |
| | 472 | + var $matches; |
| 453 | 473 | |
| 454 | 474 | function __construct( $names = array() ) { |
| 455 | 475 | $this->names = $names; |
| — | — | @@ -555,6 +575,8 @@ |
| 556 | 576 | |
| 557 | 577 | /** |
| 558 | 578 | * Parse a match array from preg_match |
| | 579 | + * Returns array(magic word ID, parameter value) |
| | 580 | + * If there is no parameter value, that element will be false. |
| 559 | 581 | */ |
| 560 | 582 | function parseMatch( $m ) { |
| 561 | 583 | reset( $m ); |
| — | — | @@ -613,4 +635,25 @@ |
| 614 | 636 | } |
| 615 | 637 | return false; |
| 616 | 638 | } |
| | 639 | + |
| | 640 | + /** |
| | 641 | + * Returns an associative array, ID => param value, for all items that match |
| | 642 | + * Removes the matched items from the input string (passed by reference) |
| | 643 | + */ |
| | 644 | + public function matchAndRemove( &$text ) { |
| | 645 | + $found = array(); |
| | 646 | + $regexes = $this->getRegex(); |
| | 647 | + foreach ( $regexes as $regex ) { |
| | 648 | + if ( $regex === '' ) { |
| | 649 | + continue; |
| | 650 | + } |
| | 651 | + preg_match_all( $regex, $text, $matches, PREG_SET_ORDER ); |
| | 652 | + foreach ( $matches as $m ) { |
| | 653 | + list( $name, $param ) = $this->parseMatch( $m ); |
| | 654 | + $found[$name] = $param; |
| | 655 | + } |
| | 656 | + $text = preg_replace( $regex, '', $text ); |
| | 657 | + } |
| | 658 | + return $found; |
| | 659 | + } |
| 617 | 660 | } |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -2937,3 +2937,11 @@ |
| 2938 | 2938 | * Hooks should return strings or false |
| 2939 | 2939 | */ |
| 2940 | 2940 | $wgExceptionHooks = array(); |
| | 2941 | + |
| | 2942 | +/** |
| | 2943 | + * Page property link table invalidation lists. |
| | 2944 | + * Should only be set by extensions. |
| | 2945 | + */ |
| | 2946 | +$wgPagePropLinkInvalidations = array( |
| | 2947 | + 'hiddencat' => 'categorylinks', |
| | 2948 | +); |
| Index: trunk/phase3/includes/CoreParserFunctions.php |
| — | — | @@ -5,6 +5,52 @@ |
| 6 | 6 | * @addtogroup Parser |
| 7 | 7 | */ |
| 8 | 8 | class CoreParserFunctions { |
| | 9 | + static function register( $parser ) { |
| | 10 | + global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; |
| | 11 | + |
| | 12 | + # Syntax for arguments (see self::setFunctionHook): |
| | 13 | + # "name for lookup in localized magic words array", |
| | 14 | + # function callback, |
| | 15 | + # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...} |
| | 16 | + # instead of {{#int:...}}) |
| | 17 | + |
| | 18 | + $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH ); |
| | 19 | + $parser->setFunctionHook( 'ns', array( __CLASS__, 'ns' ), SFH_NO_HASH ); |
| | 20 | + $parser->setFunctionHook( 'urlencode', array( __CLASS__, 'urlencode' ), SFH_NO_HASH ); |
| | 21 | + $parser->setFunctionHook( 'lcfirst', array( __CLASS__, 'lcfirst' ), SFH_NO_HASH ); |
| | 22 | + $parser->setFunctionHook( 'ucfirst', array( __CLASS__, 'ucfirst' ), SFH_NO_HASH ); |
| | 23 | + $parser->setFunctionHook( 'lc', array( __CLASS__, 'lc' ), SFH_NO_HASH ); |
| | 24 | + $parser->setFunctionHook( 'uc', array( __CLASS__, 'uc' ), SFH_NO_HASH ); |
| | 25 | + $parser->setFunctionHook( 'localurl', array( __CLASS__, 'localurl' ), SFH_NO_HASH ); |
| | 26 | + $parser->setFunctionHook( 'localurle', array( __CLASS__, 'localurle' ), SFH_NO_HASH ); |
| | 27 | + $parser->setFunctionHook( 'fullurl', array( __CLASS__, 'fullurl' ), SFH_NO_HASH ); |
| | 28 | + $parser->setFunctionHook( 'fullurle', array( __CLASS__, 'fullurle' ), SFH_NO_HASH ); |
| | 29 | + $parser->setFunctionHook( 'formatnum', array( __CLASS__, 'formatnum' ), SFH_NO_HASH ); |
| | 30 | + $parser->setFunctionHook( 'grammar', array( __CLASS__, 'grammar' ), SFH_NO_HASH ); |
| | 31 | + $parser->setFunctionHook( 'plural', array( __CLASS__, 'plural' ), SFH_NO_HASH ); |
| | 32 | + $parser->setFunctionHook( 'numberofpages', array( __CLASS__, 'numberofpages' ), SFH_NO_HASH ); |
| | 33 | + $parser->setFunctionHook( 'numberofusers', array( __CLASS__, 'numberofusers' ), SFH_NO_HASH ); |
| | 34 | + $parser->setFunctionHook( 'numberofarticles', array( __CLASS__, 'numberofarticles' ), SFH_NO_HASH ); |
| | 35 | + $parser->setFunctionHook( 'numberoffiles', array( __CLASS__, 'numberoffiles' ), SFH_NO_HASH ); |
| | 36 | + $parser->setFunctionHook( 'numberofadmins', array( __CLASS__, 'numberofadmins' ), SFH_NO_HASH ); |
| | 37 | + $parser->setFunctionHook( 'numberofedits', array( __CLASS__, 'numberofedits' ), SFH_NO_HASH ); |
| | 38 | + $parser->setFunctionHook( 'language', array( __CLASS__, 'language' ), SFH_NO_HASH ); |
| | 39 | + $parser->setFunctionHook( 'padleft', array( __CLASS__, 'padleft' ), SFH_NO_HASH ); |
| | 40 | + $parser->setFunctionHook( 'padright', array( __CLASS__, 'padright' ), SFH_NO_HASH ); |
| | 41 | + $parser->setFunctionHook( 'anchorencode', array( __CLASS__, 'anchorencode' ), SFH_NO_HASH ); |
| | 42 | + $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) ); |
| | 43 | + $parser->setFunctionHook( 'defaultsort', array( __CLASS__, 'defaultsort' ), SFH_NO_HASH ); |
| | 44 | + $parser->setFunctionHook( 'filepath', array( __CLASS__, 'filepath' ), SFH_NO_HASH ); |
| | 45 | + $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS ); |
| | 46 | + |
| | 47 | + if ( $wgAllowDisplayTitle ) { |
| | 48 | + $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH ); |
| | 49 | + } |
| | 50 | + if ( $wgAllowSlowParserFunctions ) { |
| | 51 | + $parser->setFunctionHook( 'pagesinnamespace', array( __CLASS__, 'pagesinnamespace' ), SFH_NO_HASH ); |
| | 52 | + } |
| | 53 | + } |
| | 54 | + |
| 9 | 55 | static function intFunction( $parser, $part1 = '' /*, ... */ ) { |
| 10 | 56 | if ( strval( $part1 ) !== '' ) { |
| 11 | 57 | $args = array_slice( func_get_args(), 2 ); |
| Index: trunk/phase3/languages/messages/MessagesEn.php |
| — | — | @@ -337,6 +337,7 @@ |
| 338 | 338 | 'defaultsort' => array( 1, 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ), |
| 339 | 339 | 'filepath' => array( 0, 'FILEPATH:' ), |
| 340 | 340 | 'tag' => array( 0, 'tag' ), |
| | 341 | + 'hiddencat' => array( 1, '__HIDDENCAT__' ), |
| 341 | 342 | ); |
| 342 | 343 | |
| 343 | 344 | /** |