r113018 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r113017‎ | r113018 | r113019 >
Date:11:53, 5 March 2012
Author:daniel
Status:deferred
Tags:
Comment:
integration with Title and Revision (work in progress)
Modified paths:
  • /branches/Wikidata/phase3/includes/Article.php (modified) (history)
  • /branches/Wikidata/phase3/includes/Content.php (added) (history)
  • /branches/Wikidata/phase3/includes/ContentHandler.php (modified) (history)
  • /branches/Wikidata/phase3/includes/DefaultSettings.php (modified) (history)
  • /branches/Wikidata/phase3/includes/Defines.php (modified) (history)
  • /branches/Wikidata/phase3/includes/EditPage.php (modified) (history)
  • /branches/Wikidata/phase3/includes/Revision.php (modified) (history)
  • /branches/Wikidata/phase3/includes/Title.php (modified) (history)
  • /branches/Wikidata/phase3/includes/WikiPage.php (modified) (history)
  • /branches/Wikidata/phase3/includes/parser/ParserOutput.php (modified) (history)

Diff [purge]

Index: branches/Wikidata/phase3/includes/Defines.php
@@ -249,3 +249,12 @@
250250 define( 'PROTO_CURRENT', null );
251251 define( 'PROTO_CANONICAL', 1 );
252252 define( 'PROTO_INTERNAL', 2 );
 253+
 254+/**
 255+ * Content model names, used by Content and ContentHandler
 256+ */
 257+define('CONTENT_MODEL_WIKITEXT', 'wikitext');
 258+define('CONTENT_MODEL_JAVASCRIPT', 'javascript');
 259+define('CONTENT_MODEL_CSS', 'css');
 260+define('CONTENT_MODEL_TEXT', 'text');
 261+
Index: branches/Wikidata/phase3/includes/Article.php
@@ -37,7 +37,7 @@
3838 */
3939 public $mParserOptions;
4040
41 - var $mContent; // !<
 41+ var $mContent; // !< #FIXME: use Content object!
4242 var $mContentLoaded = false; // !<
4343 var $mOldId; // !<
4444
@@ -557,6 +557,7 @@
558558
559559 # Pages containing custom CSS or JavaScript get special treatment
560560 if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) {
 561+ #FIXME: use Content object instead!
561562 wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
562563 $this->showCssOrJsPage();
563564 $outputDone = true;
@@ -694,17 +695,18 @@
695696 * This is hooked by SyntaxHighlight_GeSHi to do syntax highlighting of these
696697 * page views.
697698 */
698 - protected function showCssOrJsPage() {
 699+ protected function showCssOrJsPage() { #FIXME: deprecate, keep for BC
699700 global $wgOut;
700701
701702 $dir = $this->getContext()->getLanguage()->getDir();
702703 $lang = $this->getContext()->getLanguage()->getCode();
703704
704705 $wgOut->wrapWikiMsg( "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
705 - 'clearyourcache' );
 706+ 'clearyourcache' ); #FIXME: get this from handler
706707
707708 // Give hooks a chance to customise the output
708709 if ( wfRunHooks( 'ShowRawCssJs', array( $this->mContent, $this->getTitle(), $wgOut ) ) ) {
 710+ #FIXME: use content object instead
709711 // Wrap the whole lot in a <pre> and don't parse
710712 $m = array();
711713 preg_match( '!\.(css|js)$!u', $this->getTitle()->getText(), $m );
Index: branches/Wikidata/phase3/includes/parser/ParserOutput.php
@@ -30,7 +30,7 @@
3131 */
3232 function setCacheTime( $t ) { return wfSetVar( $this->mCacheTime, $t ); }
3333
34 - /**
 34+ /**abstract
3535 * Sets the number of seconds after which this object should expire.
3636 * This value is used with the ParserCache.
3737 * If called with a value greater than the value provided at any previous call,
Index: branches/Wikidata/phase3/includes/Content.php
@@ -0,0 +1,166 @@
 2+<?php
 3+
 4+/**
 5+ * A content object represents page content, e.g. the text to show on a page.
 6+ *
 7+ */
 8+abstract class Content {
 9+
 10+ public function __construct( Title $title, $revId, $modelName ) {
 11+ $this->mModelName = $modelName;
 12+ $this->mTitle = $title;
 13+ $this->mRevId = $revId;
 14+ }
 15+
 16+ public function getModelName() {
 17+ return $this->mModelName;
 18+ }
 19+
 20+ public function getTitle() {
 21+ return $this->mTitle;
 22+ }
 23+
 24+ public function getRevId() {
 25+ return $this->mRevId;
 26+ }
 27+
 28+ public abstract function getSearchText( $obj );
 29+
 30+ public abstract function getWikitextForTransclusion( $obj );
 31+
 32+ public abstract function getParserOutput( ParserOptions $options = NULL );
 33+
 34+ public abstract function getRawData( );
 35+
 36+ public function getHtml( ParserOptions $options ) {
 37+ $po = $this->getParserOutput( $options );
 38+ return $po->getText();
 39+ }
 40+
 41+ public function getIndexUpdateJobs( ParserOptions $options , $recursive = true ) {
 42+ $po = $this->getParserOutput( $options );
 43+ $update = new LinksUpdate( $this->mTitle, $po, $recursive );
 44+ return $update;
 45+ }
 46+
 47+ #XXX: is the native model for wikitext a string or the parser output? parse early or parse late?
 48+}
 49+
 50+class TextContent extends Content {
 51+ public function __construct( $text, Title $title, $revId, $modelName ) {
 52+ parent::__construct($title, $revId, $modelName);
 53+
 54+ $this->mText = $text;
 55+ }
 56+
 57+ public function getSearchText( $obj ) {
 58+ return $this->getRawData();
 59+ }
 60+
 61+ public function getWikitextForTransclusion( $obj ) {
 62+ return $this->getRawData();
 63+ }
 64+
 65+
 66+ public function getParserOutput( ParserOptions $options = null ) {
 67+ # generic implementation, relying on $this->getHtml()
 68+
 69+ $html = $this->getHtml( $options );
 70+ $po = new ParserOutput( $html );
 71+
 72+ #TODO: cache settings, etc?
 73+
 74+ return $po;
 75+ }
 76+
 77+ public function getHtml( ParserOptions $options ) {
 78+ $html = "";
 79+ $html .= "<pre class=\"mw-code\" dir=\"ltr\">\n";
 80+ $html .= htmlspecialchars( $this->getRawData() );
 81+ $html .= "\n</pre>\n";
 82+
 83+ return $html;
 84+ }
 85+
 86+
 87+ public function getRawData( ) {
 88+ global $wgParser, $wgUser;
 89+
 90+ $text = $this->mText;
 91+ return $text;
 92+ }
 93+
 94+}
 95+
 96+class WikitextContent extends TextContent {
 97+ public function __construct( $text, Title $title, $revId = null) {
 98+ parent::__construct($text, $title, $revId, CONTENT_MODEL_WIKITEXT);
 99+
 100+ $this->mDefaultParserOptions = null;
 101+ }
 102+
 103+ public function getDefaultParserOptions() {
 104+ global $wgUser, $wgContLang;
 105+
 106+ if ( !$this->mDefaultParserOptions ) {
 107+ #TODO: use static member?!
 108+ $this->mDefaultParserOptions = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
 109+ }
 110+
 111+ return $this->mDefaultParserOptions;
 112+ }
 113+
 114+ public function getParserOutput( ParserOptions $options = null ) {
 115+ global $wgParser;
 116+
 117+ #TODO: quick local cache: if $options is NULL, use ->mParserOutput!
 118+ #FIXME: need setParserOutput, so we can use stuff from the parser cache??
 119+ #FIXME: ...or we somehow need to know the parser cache key??
 120+
 121+ if ( !$options ) {
 122+ $options = $this->getDefaultParserOptions();
 123+ }
 124+
 125+ $po = $wgParser->parse( $this->mText, $this->getTitle(), $options );
 126+
 127+ return $po;
 128+ }
 129+
 130+}
 131+
 132+
 133+class JavaScriptContent extends TextContent {
 134+ public function __construct( $text, Title $title, $revId = null ) {
 135+ parent::__construct($text, $title, $revId, CONTENT_MODEL_JAVASCRIPT);
 136+ }
 137+
 138+ public function getHtml( ParserOptions $options ) {
 139+ $html = "";
 140+ $html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n";
 141+ $html .= htmlspecialchars( $this->getRawData() );
 142+ $html .= "\n</pre>\n";
 143+
 144+ return $html;
 145+ }
 146+
 147+}
 148+
 149+class CssContent extends TextContent {
 150+ public function __construct( $text, Title $title, $revId = null ) {
 151+ parent::__construct($text, $title, $revId, CONTENT_MODEL_CSS);
 152+ }
 153+
 154+ public function getHtml( ParserOptions $options ) {
 155+ $html = "";
 156+ $html .= "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n";
 157+ $html .= htmlspecialchars( $this->getRawData() );
 158+ $html .= "\n</pre>\n";
 159+
 160+ return $html;
 161+ }
 162+}
 163+
 164+#TODO: MultipartMultipart < WikipageContent (Main + Links + X)
 165+#TODO: LinksContent < LanguageLinksContent, CategoriesContent
 166+#EXAMPLE: CoordinatesContent
 167+#EXAMPLE: WikidataContent
Index: branches/Wikidata/phase3/includes/ContentHandler.php
@@ -12,7 +12,90 @@
1313 *
1414 */
1515 abstract class ContentHandler {
16 -
 16+
 17+ public static function getDefaultModelFor( Title $title ) {
 18+ global $wgNamespaceContentModels;
 19+
 20+ # NOTE: this method must not rely on $title->getContentModelName() directly or indirectly,
 21+ # because it is used to initialized the mContentModelName memebr.
 22+
 23+ $ns = $title->getNamespace();
 24+
 25+ $ext = false;
 26+ $m = null;
 27+ $model = null;
 28+
 29+ if ( !empty( $wgNamespaceContentModels[ $ns ] ) ) {
 30+ $model = $wgNamespaceContentModels[ $ns ];
 31+ }
 32+
 33+ # hook can determin default model
 34+ if ( !wfRunHooks( 'DefaultModelFor', array( $title, &$model ) ) ) { #FIXME: document new hook!
 35+ if ( $model ) return $model;
 36+ }
 37+
 38+ # Could this page contain custom CSS or JavaScript, based on the title?
 39+ $isCssOrJsPage = ( NS_MEDIAWIKI == $ns && preg_match( "!\.(css|js)$!u", $title->getText(), $m ) );
 40+ if ( $isCssOrJsPage ) $ext = $m[1];
 41+
 42+ # hook can force js/css
 43+ wfRunHooks( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage, &$ext ) ); #FIXME: add $ext to hook interface spec
 44+
 45+ # Is this a .css subpage of a user page?
 46+ $isJsCssSubpage = ( NS_USER == $ns && !$isCssOrJsPage && preg_match( "/\\/.*\\.(js|css)$/", $title->getText(), $m ) );
 47+ if ( $isJsCssSubpage ) $ext = $m[1];
 48+
 49+ # is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
 50+ $isWikitext = ( $model == CONTENT_MODEL_WIKITEXT || $model === null );
 51+ $isWikitext = ( $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage );
 52+
 53+ # hook can override $isWikitext
 54+ wfRunHooks( 'TitleIsWikitextPage', array( $title, &$isWikitext ) );
 55+
 56+ if ( !$isWikitext ) {
 57+
 58+ if ( $ext == 'js' )
 59+ return CONTENT_MODEL_JAVASCRIPT;
 60+ else if ( $ext == 'css' )
 61+ return CONTENT_MODEL_CSS;
 62+
 63+ if ( $model )
 64+ return $model;
 65+ else
 66+ return CONTENT_MODEL_TEXT;
 67+ }
 68+
 69+ # we established that is must be wikitext
 70+ return CONTENT_MODEL_WIKITEXT;
 71+ }
 72+
 73+ public static function getForTitle( Title $title ) {
 74+ $modelName = $title->getContentModelName();
 75+ return ContenteHandler::getForModelName( $modelName );
 76+ }
 77+
 78+ public static function getForContent( Content $content ) {
 79+ $modelName = $content->getModelName();
 80+ return ContenteHandler::getForModelName( $modelName );
 81+ }
 82+
 83+ public static function getForModelName( $modelName ) {
 84+ global $wgContentHandlers;
 85+
 86+ if ( empty( $wgContentHandlers[$modelName] ) ) {
 87+ #FIXME: hook here!
 88+ throw new MWException( "No handler for model $modelName registered in \$wgContentHandlers" );
 89+ }
 90+
 91+ if ( is_string( $wgContentHandlers[$modelName] ) ) {
 92+ $class = $wgContentHandlers[$modelName];
 93+ $wgContentHandlers[$modelName] = new $class( $modelName );
 94+ }
 95+
 96+ return $wgContentHandlers[$modelName];
 97+ }
 98+
 99+
17100 public function __construct( $modelName, $formats ) {
18101 $this->mModelName = $modelName;
19102 $this->mSupportedFormats = $formats;
@@ -62,7 +145,7 @@
63146 # returns a ParserOutput instance!
64147 # are parser options, generic?!
65148
66 - public function doPreSaveTransform( $title, $obj );
 149+ public abstract function doPreSaveTransform( $title, $obj );
67150
68151 # TODO: getPreloadText()
69152 # TODO: preprocess()
Index: branches/Wikidata/phase3/includes/EditPage.php
@@ -2552,6 +2552,7 @@
25532553 # don't parse non-wikitext pages, show message about preview
25542554 # XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago?
25552555
 2556+ #FIXME: get appropriate content handler!
25562557 if ( $this->isCssJsSubpage || !$this->mTitle->isWikitextPage() ) {
25572558 if( $this->mTitle->isCssJsSubpage() ) {
25582559 $level = 'user';
@@ -2564,6 +2565,7 @@
25652566 # Used messages to make sure grep find them:
25662567 # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview
25672568 if( $level ) {
 2569+ #FIXME: move this crud into ContentHandler class!
25682570 if (preg_match( "/\\.css$/", $this->mTitle->getText() ) ) {
25692571 $previewtext = "<div id='mw-{$level}csspreview'>\n" . wfMsg( "{$level}csspreview" ) . "\n</div>";
25702572 $class = "mw-code mw-css";
Index: branches/Wikidata/phase3/includes/Revision.php
@@ -20,6 +20,8 @@
2121 protected $mTextRow;
2222 protected $mTitle;
2323 protected $mCurrent;
 24+ protected $mContentModelName;
 25+ protected $mContentType;
2426
2527 const DELETED_TEXT = 1;
2628 const DELETED_COMMENT = 2;
@@ -125,6 +127,8 @@
126128 'deleted' => $row->ar_deleted,
127129 'len' => $row->ar_len,
128130 'sha1' => isset( $row->ar_sha1 ) ? $row->ar_sha1 : null,
 131+ 'content_model' => isset( $row->ar_content_model ) ? $row->ar_content_model : null,
 132+ 'content_type' => isset( $row->ar_content_type ) ? $row->ar_content_type : null,
129133 );
130134 if ( isset( $row->ar_text ) && !$row->ar_text_id ) {
131135 // Pre-1.5 ar_text row
@@ -412,6 +416,18 @@
413417 $this->mTitle = null;
414418 }
415419
 420+ if( !isset( $row->rev_content_model ) || is_null( $row->rev_content_model ) ) {
 421+ $this->mContentModelName = null; # determine on demand if needed
 422+ } else {
 423+ $this->mContentModelName = strval( $row->rev_content_model );
 424+ }
 425+
 426+ if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) {
 427+ $this->mContentType = null; # determine on demand if needed
 428+ } else {
 429+ $this->mContentType = strval( $row->rev_content_type );
 430+ }
 431+
416432 // Lazy extraction...
417433 $this->mText = null;
418434 if( isset( $row->old_text ) ) {
@@ -445,6 +461,15 @@
446462 $this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null;
447463 $this->mSha1 = isset( $row['sha1'] ) ? strval( $row['sha1'] ) : null;
448464
 465+ $this->mContentModelName = isset( $row['content_model'] ) ? strval( $row['content_model'] ) : null;
 466+ $this->mContentType = isset( $row['content_type'] ) ? strval( $row['content_type'] ) : null;
 467+
 468+ if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) {
 469+ $this->mContentType = null; # determine on demand if needed
 470+ } else {
 471+ $this->mContentType = $row->rev_content_type;
 472+ }
 473+
449474 // Enforce spacing trimming on supplied text
450475 $this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null;
451476 $this->mText = isset( $row['text'] ) ? rtrim( strval( $row['text'] ) ) : null;
@@ -460,6 +485,9 @@
461486 if ( $this->mSha1 === null ) {
462487 $this->mSha1 = is_null( $this->mText ) ? null : self::base36Sha1( $this->mText );
463488 }
 489+
 490+ $this->getContentModelName(); # force lazy init
 491+ $this->getContentType(); # force lazy init
464492 } else {
465493 throw new MWException( 'Revision constructor passed invalid row format.' );
466494 }
@@ -723,17 +751,48 @@
724752 * @param $user User object to check for, only if FOR_THIS_USER is passed
725753 * to the $audience parameter
726754 * @return String
 755+ * @deprectaed in 1.20, use getContent() instead
727756 */
728 - public function getText( $audience = self::FOR_PUBLIC, User $user = null ) {
729 - if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) {
730 - return '';
731 - } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT, $user ) ) {
732 - return '';
733 - } else {
734 - return $this->getRawText();
735 - }
 757+ public function getText( $audience = self::FOR_PUBLIC, User $user = null ) { #FIXME: deprecated, replace usage!
 758+ wfDeprecated( __METHOD__, '1.20' );
 759+ $content = $this->getContent();
 760+
 761+ if ( $content == null ) {
 762+ return ""; # not allowed
 763+ }
 764+
 765+ if ( $content instanceof TextContent ) {
 766+ #FIXME: or check by model name? or define $content->allowRawData()?
 767+ return $content->getRawData();
 768+ }
 769+
 770+ #TODO: log this failure!
 771+ return null;
736772 }
737773
 774+ /**
 775+ * Fetch revision content if it's available to the specified audience.
 776+ * If the specified audience does not have the ability to view this
 777+ * revision, null will be returned.
 778+ *
 779+ * @param $audience Integer: one of:
 780+ * Revision::FOR_PUBLIC to be displayed to all users
 781+ * Revision::FOR_THIS_USER to be displayed to $wgUser
 782+ * Revision::RAW get the text regardless of permissions
 783+ * @param $user User object to check for, only if FOR_THIS_USER is passed
 784+ * to the $audience parameter
 785+ * @return Content
 786+ */
 787+ public function getContent( $audience = self::FOR_PUBLIC, User $user = null ) {
 788+ if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) {
 789+ return null;
 790+ } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT, $user ) ) {
 791+ return null;
 792+ } else {
 793+ return $this->getContentInternal();
 794+ }
 795+ }
 796+
738797 /**
739798 * Alias for getText(Revision::FOR_THIS_USER)
740799 *
@@ -750,14 +809,55 @@
751810 *
752811 * @return String
753812 */
754 - public function getRawText() {
755 - if( is_null( $this->mText ) ) {
756 - // Revision text is immutable. Load on demand:
757 - $this->mText = $this->loadText();
758 - }
759 - return $this->mText;
 813+ public function getRawText() { #FIXME: deprecated, replace usage!
 814+ return $this->getText( self::RAW );
760815 }
761816
 817+ protected function getContentInternal() {
 818+ if( is_null( $this->mContent ) ) {
 819+ // Revision is immutable. Load on demand:
 820+
 821+ $handler = $this->getContentHandler();
 822+ $type = $this->getContentType();
 823+
 824+ if( is_null( $this->mText ) ) {
 825+ // Load text on demand:
 826+ $this->mText = $this->loadText();
 827+ }
 828+
 829+ $this->mContent = $handler->unserialize( $this->mText, $type );
 830+ }
 831+
 832+ return $this->mContent;
 833+ }
 834+
 835+ public function getContentModelName() {
 836+ if ( !$this->mContentModelName ) {
 837+ $title = $this->getTitle(); #XXX: never null?
 838+ $this->mContentModelName = $title->getContentModelName();
 839+ }
 840+
 841+ return $this->mContentModelName;
 842+ }
 843+
 844+ public function getContentType() {
 845+ if ( !$this->mContentType ) {
 846+ $handler = $this->getContentHandler();
 847+ $this->mContentType = $handler->getDefaultFormat();
 848+ }
 849+
 850+ return $this->mContentType;
 851+ }
 852+
 853+ public function getContentHandler() {
 854+ if ( !$this->mContentHandler ) {
 855+ $m = $this->getModelName();
 856+ $this->mContentHandler = ContentHandler::getForModelName( $m );
 857+ }
 858+
 859+ return $this->mContentHandler;
 860+ }
 861+
762862 /**
763863 * @return String
764864 */
@@ -996,7 +1096,9 @@
9971097 : $this->mParentId,
9981098 'rev_sha1' => is_null( $this->mSha1 )
9991099 ? Revision::base36Sha1( $this->mText )
1000 - : $this->mSha1
 1100+ : $this->mSha1,
 1101+ 'rev_content_model' => $this->getContentModelName(),
 1102+ 'rev_content_type' => $this->getContentType(),
10011103 ), __METHOD__
10021104 );
10031105
@@ -1096,7 +1198,8 @@
10971199
10981200 $current = $dbw->selectRow(
10991201 array( 'page', 'revision' ),
1100 - array( 'page_latest', 'rev_text_id', 'rev_len', 'rev_sha1' ),
 1202+ array( 'page_latest', 'rev_text_id', 'rev_len', 'rev_sha1',
 1203+ 'rev_content_model', 'rev_content_type' ),
11011204 array(
11021205 'page_id' => $pageId,
11031206 'page_latest=rev_id',
@@ -1111,7 +1214,9 @@
11121215 'text_id' => $current->rev_text_id,
11131216 'parent_id' => $current->page_latest,
11141217 'len' => $current->rev_len,
1115 - 'sha1' => $current->rev_sha1
 1218+ 'sha1' => $current->rev_sha1,
 1219+ 'content_model' => $current->rev_content_model,
 1220+ 'content_type' => $current->rev_content_type
11161221 ) );
11171222 } else {
11181223 $revision = null;
Index: branches/Wikidata/phase3/includes/Title.php
@@ -272,12 +272,17 @@
273273 if ( isset( $row->page_is_redirect ) )
274274 $this->mRedirect = (bool)$row->page_is_redirect;
275275 if ( isset( $row->page_latest ) )
276 - $this->mLatestID = (int)$row->page_latest;
 276+ $this->mLatestID = (int)$row->page_latest; # FIXME: whene3ver page_latest is updated, also update page_content_model
 277+ if ( isset( $row->page_content_model ) )
 278+ $this->mContentModelName = $row->page_content_model;
 279+ else
 280+ $this->mContentModelName = null; # initialized lazily in getContentModelName()
277281 } else { // page not found
278282 $this->mArticleID = 0;
279283 $this->mLength = 0;
280284 $this->mRedirect = false;
281285 $this->mLatestID = 0;
 286+ $this->mContentModelName = null; # initialized lazily in getContentModelName()
282287 }
283288 }
284289
@@ -303,6 +308,7 @@
304309 $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
305310 $t->mUrlform = wfUrlencode( $t->mDbkeyform );
306311 $t->mTextform = str_replace( '_', ' ', $title );
 312+ $t->mContentModelName = null; # initialized lazily in getContentModelName()
307313 return $t;
308314 }
309315
@@ -688,6 +694,29 @@
689695 return $this->mNamespace;
690696 }
691697
 698+ /**
 699+ * Get the page's content model name
 700+ *
 701+ * @return Integer: Namespace index
 702+ */
 703+ public function getContentModelName() {
 704+ if ( empty( $this->mContentModelName ) ) {
 705+ $this->mContentModelName = ContentHandler::getDefaultModelFor( $this );
 706+ }
 707+
 708+ return $this->mContentModelName;
 709+ }
 710+
 711+ /**
 712+ * Conveniance method for checking a title's content model name
 713+ *
 714+ * @param $name
 715+ * @return true if $this->getContentModelName() == $name
 716+ */
 717+ public function hasContentModel( $name ) {
 718+ return $this->getContentModelName() == $name;
 719+ }
 720+
692721 /**
693722 * Get the namespace text
694723 *
@@ -937,9 +966,7 @@
938967 * @return Bool
939968 */
940969 public function isWikitextPage() {
941 - $retval = !$this->isCssOrJsPage() && !$this->isCssJsSubpage();
942 - wfRunHooks( 'TitleIsWikitextPage', array( $this, &$retval ) );
943 - return $retval;
 970+ return $this->hasContentModel( CONTENT_MODEL_WIKITEXT );
944971 }
945972
946973 /**
@@ -949,10 +976,8 @@
950977 * @return Bool
951978 */
952979 public function isCssOrJsPage() {
953 - $retval = $this->mNamespace == NS_MEDIAWIKI
954 - && preg_match( '!\.(?:css|js)$!u', $this->mTextform ) > 0;
955 - wfRunHooks( 'TitleIsCssOrJsPage', array( $this, &$retval ) );
956 - return $retval;
 980+ return $this->hasContentModel( CONTENT_MODEL_CSS )
 981+ || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT );
957982 }
958983
959984 /**
@@ -960,7 +985,8 @@
961986 * @return Bool
962987 */
963988 public function isCssJsSubpage() {
964 - return ( NS_USER == $this->mNamespace and preg_match( "/\\/.*\\.(?:css|js)$/", $this->mTextform ) );
 989+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
 990+ && $this->isCssOrJsPage() );
965991 }
966992
967993 /**
@@ -983,7 +1009,8 @@
9841010 * @return Bool
9851011 */
9861012 public function isCssSubpage() {
987 - return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.css$/", $this->mTextform ) );
 1013+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
 1014+ && $this->hasContentModel( CONTENT_MODEL_CSS ) );
9881015 }
9891016
9901017 /**
@@ -992,7 +1019,8 @@
9931020 * @return Bool
9941021 */
9951022 public function isJsSubpage() {
996 - return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.js$/", $this->mTextform ) );
 1023+ return ( NS_USER == $this->mNamespace && $this->isSubpage()
 1024+ && $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) );
9971025 }
9981026
9991027 /**
Index: branches/Wikidata/phase3/includes/WikiPage.php
@@ -800,7 +800,7 @@
801801 && $parserOptions->getStubThreshold() == 0
802802 && $this->mTitle->exists()
803803 && ( $oldid === null || $oldid === 0 || $oldid === $this->getLatest() )
804 - && $this->mTitle->isWikitextPage();
 804+ && $this->mTitle->isWikitextPage(); #FIXME: ask ContentHandler if cachable!
805805 }
806806
807807 /**
Index: branches/Wikidata/phase3/includes/DefaultSettings.php
@@ -637,6 +637,17 @@
638638 );
639639
640640 /**
 641+ * Plugins for page content model handling.
 642+ * Each entry in the array maps a model name type to a class name
 643+ */
 644+$wgContentHandlers = array(
 645+ CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler', // the usual case
 646+ CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler', // dumb version, no syntax highlighting
 647+ CONTENT_MODEL_CSS => 'CssContentHandler', // dumb version, no syntax highlighting
 648+ CONTENT_MODEL_TEXT => 'TextContentHandler', // dumb plain text in <pre>
 649+);
 650+
 651+/**
641652 * Resizing can be done using PHP's internal image libraries or using
642653 * ImageMagick or another third-party converter, e.g. GraphicMagick.
643654 * These support more file formats than PHP, which only supports PNG,

Status & tagging log