* @return mixed
*/
public function generateReason( &$hasHistory ) {
- return $this->mPage->getAutoDeleteReason( $hasHistory );
+ $title = $this->mPage->getTitle();
+ $handler = ContentHandler::getForTitle( $title );
+ return $handler->getAutoDeleteReason( $title, $hasHistory );
}
// ****** B/C functions for static methods ( __callStatic is PHP>=5.3 ) ****** //
* @param $newtext
* @param $flags
* @return string
+ * @deprecated since 1.20, use ContentHandler::getAutosummary() instead
*/
public static function getAutosummary( $oldtext, $newtext, $flags ) {
return WikiPage::getAutosummary( $oldtext, $newtext, $flags );
return $this->mModelName;
}
- public abstract function getSearchText( );
+ public abstract function getTextForSearchIndex( );
public abstract function getWikitextForTransclusion( );
+ public abstract function getTextForSummary( $maxlength = 250 );
+
/**
* Returns native represenation of the data. Interpretation depends on the data model used,
* as given by getDataModel().
*
+ * @return mixed the native representation of the content. Could be a string, a nested array
+ * structure, an object, a binary blob... anything, really.
*/
- public abstract function getNativeData( );
+ public abstract function getNativeData( ); #FIXME: review all calls carefully, caller must be aware of content model!
/**
* returns the content's nominal size in bogo-bytes.
*/
public abstract function getSize( ); #XXX: do we really need/want this here? we could just use the byte syse of the serialized form...
+ public function isEmpty() {
+ return $this->getSize() == 0;
+ }
+
/**
* Returns true if this content is countable as a "real" wiki page, provided
* that it's also in a countable location (e.g. a current revision in the main namespace).
public abstract function getParserOutput( Title $title = null, $revId = null, ParserOptions $options = NULL );
- public function getRedirectChain() {
+ public function getRedirectChain() { #TODO: document!
+ return null;
+ }
+
+ public function getRedirectTarget() {
return null;
}
public function isRedirect() {
- return false;
+ return $this->getRedirectTarget() != null;
}
/**
}
/**
- * Replaces a section of the content.
+ * Replaces a section of the content and returns a Content object with the section replaced.
*
* @param $section empty/null/false or a section number (0, 1, 2, T1, T2...), or "new"
* @param $with Content: new content of the section
# TODO: EditPage::getPreloadedText( $preload ) // $wgParser->getPreloadText
# TODO: tie into EditPage, make it use Content-objects throughout, make edit form aware of content model and format
+ # TODO: tie into WikiPage, make it use Content-objects throughout, especially in doEdit(), doDelete(), etc
# TODO: make model-aware diff view!
# TODO: handle ImagePage and CategoryPage
$this->mText = $text;
}
+ public function getTextForSummary( $maxlength = 250 ) {
+ global $wgContLang;
+
+ $text = $this->getNativeData();
+
+ $truncatedtext = $wgContLang->truncate(
+ preg_replace( "/[\n\r]/", ' ', $text ),
+ max( 0, $maxlength ) );
+
+ return $truncatedtext;
+ }
+
/**
* returns the content's nominal size in bogo-bytes.
*/
*
* @return String the raw text
*/
- public function getSearchText( ) { #FIXME: use!
+ public function getTextForSearchIndex( ) { #FIXME: use!
return $this->getNativeData();
}
return Title::newFromRedirectArray( $text );
}
- public function isRedirect() {
+ public function getRedirectTarget() {
$text = $this->getNativeData();
- return Title::newFromRedirect( $text ) !== null;
+ return Title::newFromRedirect( $text );
}
/**
}
}
+ public function getTextForSummary( $maxlength = 250 ) {
+ $truncatedtext = parent::getTextForSummary( $maxlength );
+
+ #clean up unfinished links
+ #XXX: make this optional? wasn't there in autosummary, but required for deletion summary.
+ $truncatedtext = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $truncatedtext );
+
+ return $truncatedtext;
+ }
+
}
class MessageContent extends TextContent {
return ContentHandler::getForModelName( $modelName );
}
+ /**
+ * @static
+ * @param $modelName String the name of the content model for which to get a handler. Use CONTENT_MODEL_XXX constants.
+ * @return ContentHandler
+ * @throws MWException
+ */
public static function getForModelName( $modelName ) {
global $wgContentHandlers;
return $this->mSupportedFormats[0];
}
+ /**
+ * @abstract
+ * @param Content $content
+ * @param null $format
+ * @return String
+ */
public abstract function serialize( Content $content, $format = null );
+ /**
+ * @abstract
+ * @param $blob String
+ * @param null $format
+ * @return Content
+ */
public abstract function unserialize( $blob, $format = null );
public abstract function emptyContent();
return false;
}
+ /**
+ * Return an applicable autosummary if one exists for the given edit.
+ *
+ * @param $oldContent Content: the previous text of the page.
+ * @param $newContent Content: The submitted text of the page.
+ * @param $flags Int bitmask: a bitmask of flags submitted for the edit.
+ *
+ * @return string An appropriate autosummary, or an empty string.
+ */
+ public function getAutosummary( Content $oldContent, Content $newContent, $flags ) {
+ global $wgContLang;
+
+ # Decide what kind of autosummary is needed.
+
+ # Redirect autosummaries
+ $ot = $oldContent->getRedirectTarget();
+ $rt = $newContent->getRedirectTarget();
+
+ if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
+
+ $truncatedtext = $newContent->getTextForSummary(
+ 250
+ - strlen( wfMsgForContent( 'autoredircomment' ) )
+ - strlen( $rt->getFullText() ) );
+
+ return wfMsgForContent( 'autoredircomment', $rt->getFullText(), $truncatedtext );
+ }
+
+ # New page autosummaries
+ if ( $flags & EDIT_NEW && $newContent->getSize() > 0 ) {
+ # If they're making a new article, give its text, truncated, in the summary.
+
+ $truncatedtext = $newContent->getTextForSummary(
+ 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) );
+
+ return wfMsgForContent( 'autosumm-new', $truncatedtext );
+ }
+
+ # Blanking autosummaries
+ if ( $oldContent->getSize() > 0 && $newContent->getSize() == 0 ) {
+ return wfMsgForContent( 'autosumm-blank' );
+ } elseif ( $oldContent->getSize() > 10 * $newContent->getSize() && $newContent->getSize() < 500 ) {
+ # Removing more than 90% of the article
+
+ $truncatedtext = $newContent->getTextForSummary(
+ 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) );
+
+ return wfMsgForContent( 'autosumm-replace', $truncatedtext );
+ }
+
+ # If we reach this point, there's no applicable autosummary for our case, so our
+ # autosummary is empty.
+ return '';
+ }
+
+ /**
+ * Auto-generates a deletion reason
+ *
+ * @param $title Title: the page's title
+ * @param &$hasHistory Boolean: whether the page has a history
+ * @return mixed String containing deletion reason or empty string, or boolean false
+ * if no revision occurred
+ */
+ public function getAutoDeleteReason( Title $title, &$hasHistory ) {
+ global $wgContLang;
+
+ $dbw = wfGetDB( DB_MASTER );
+
+ // Get the last revision
+ $rev = Revision::newFromTitle( $title );
+
+ if ( is_null( $rev ) ) {
+ return false;
+ }
+
+ // Get the article's contents
+ $content = $rev->getContent();
+ $blank = false;
+
+ // If the page is blank, use the text from the previous revision,
+ // which can only be blank if there's a move/import/protect dummy revision involved
+ if ( $content->getSize() == 0 ) {
+ $prev = $rev->getPrevious();
+
+ if ( $prev ) {
+ $content = $rev->getContent();
+ $blank = true;
+ }
+ }
+
+ // Find out if there was only one contributor
+ // Only scan the last 20 revisions
+ $res = $dbw->select( 'revision', 'rev_user_text',
+ array( 'rev_page' => $title->getArticleID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+ __METHOD__,
+ array( 'LIMIT' => 20 )
+ );
+
+ if ( $res === false ) {
+ // This page has no revisions, which is very weird
+ return false;
+ }
+
+ $hasHistory = ( $res->numRows() > 1 );
+ $row = $dbw->fetchObject( $res );
+
+ if ( $row ) { // $row is false if the only contributor is hidden
+ $onlyAuthor = $row->rev_user_text;
+ // Try to find a second contributor
+ foreach ( $res as $row ) {
+ if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
+ $onlyAuthor = false;
+ break;
+ }
+ }
+ } else {
+ $onlyAuthor = false;
+ }
+
+ // Generate the summary with a '$1' placeholder
+ if ( $blank ) {
+ // The current revision is blank and the one before is also
+ // blank. It's just not our lucky day
+ $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+ } else {
+ if ( $onlyAuthor ) {
+ $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+ } else {
+ $reason = wfMsgForContent( 'excontent', '$1' );
+ }
+ }
+
+ if ( $reason == '-' ) {
+ // Allow these UI messages to be blanked out cleanly
+ return '';
+ }
+
+ // Max content length = max comment length - length of the comment (excl. $1)
+ $text = $content->getTextForSummary( 255 - ( strlen( $reason ) - 2 ) );
+
+ // Now replace the '$1' placeholder
+ $reason = str_replace( '$1', $text, $reason );
+
+ return $reason;
+ }
+
+
#TODO: cover patch/undo just like merge3.
#TODO: how to handle extra message for JS/CSS previews??
return new WikitextContent("");
}
+
}
class JavaScriptContentHandler extends TextContentHandler {
# Provide autosummaries if one is not provided and autosummaries are enabled.
if ( $wgUseAutomaticEditSummaries && $flags & EDIT_AUTOSUMMARY && $summary == '' ) {
- $summary = self::getAutosummary( $oldtext, $text, $flags ); #FIXME: auto-summary from ContentHandler
+ $summary = self::getAutosummary( $oldtext, $text, $flags ); #FIXME: ContentHandler::getAutosummary()
}
$editInfo = $this->prepareTextForEdit( $text, null, $user );
* @param $newtext String: The submitted text of the page.
* @param $flags Int bitmask: a bitmask of flags submitted for the edit.
* @return string An appropriate autosummary, or an empty string.
+ * @deprecated since 1.20, use ContentHandler::getAutosummary() instead
*/
public static function getAutosummary( $oldtext, $newtext, $flags ) {
- global $wgContLang;
-
- # Decide what kind of autosummary is needed.
-
- # Redirect autosummaries
- $ot = Title::newFromRedirect( $oldtext );
- $rt = Title::newFromRedirect( $newtext );
-
- if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
- $truncatedtext = $wgContLang->truncate(
- str_replace( "\n", ' ', $newtext ),
- max( 0, 250
- - strlen( wfMsgForContent( 'autoredircomment' ) )
- - strlen( $rt->getFullText() )
- ) );
- return wfMsgForContent( 'autoredircomment', $rt->getFullText(), $truncatedtext );
- }
-
- # New page autosummaries
- if ( $flags & EDIT_NEW && strlen( $newtext ) ) {
- # If they're making a new article, give its text, truncated, in the summary.
-
- $truncatedtext = $wgContLang->truncate(
- str_replace( "\n", ' ', $newtext ),
- max( 0, 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) ) );
-
- return wfMsgForContent( 'autosumm-new', $truncatedtext );
- }
-
- # Blanking autosummaries
- if ( $oldtext != '' && $newtext == '' ) {
- return wfMsgForContent( 'autosumm-blank' );
- } elseif ( strlen( $oldtext ) > 10 * strlen( $newtext ) && strlen( $newtext ) < 500 ) {
- # Removing more than 90% of the article
-
- $truncatedtext = $wgContLang->truncate(
- $newtext,
- max( 0, 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) ) );
+ # NOTE: stub for backwards-compatibility. assumes the given text is wikitext. will break horribly if it isn't.
- return wfMsgForContent( 'autosumm-replace', $truncatedtext );
- }
+ $handler = ContentHandler::getForModelName( CONTENT_MODEL_WIKITEXT );
+ $oldContent = $handler->unserialize( $oldtext );
+ $newContent = $handler->unserialize( $newtext );
- # If we reach this point, there's no applicable autosummary for our case, so our
- # autosummary is empty.
- return '';
+ return $handler->getAutosummary( $oldContent, $newContent, $flags );
}
/**
* @param &$hasHistory Boolean: whether the page has a history
* @return mixed String containing deletion reason or empty string, or boolean false
* if no revision occurred
+ * @deprecated since 1.20, use ContentHandler::getAutoDeleteReason() instead
*/
public function getAutoDeleteReason( &$hasHistory ) {
- global $wgContLang;
-
- $dbw = wfGetDB( DB_MASTER );
- // Get the last revision
- $rev = Revision::newFromTitle( $this->getTitle() );
-
- if ( is_null( $rev ) ) {
- return false;
- }
-
- // Get the article's contents
- $contents = $rev->getText();
- $blank = false;
-
- // If the page is blank, use the text from the previous revision,
- // which can only be blank if there's a move/import/protect dummy revision involved
- if ( $contents == '' ) {
- $prev = $rev->getPrevious();
-
- if ( $prev ) {
- $contents = $prev->getText();
- $blank = true;
- }
- }
-
- // Find out if there was only one contributor
- // Only scan the last 20 revisions
- $res = $dbw->select( 'revision', 'rev_user_text',
- array( 'rev_page' => $this->getID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
- __METHOD__,
- array( 'LIMIT' => 20 )
- );
-
- if ( $res === false ) {
- // This page has no revisions, which is very weird
- return false;
- }
-
- $hasHistory = ( $res->numRows() > 1 );
- $row = $dbw->fetchObject( $res );
-
- if ( $row ) { // $row is false if the only contributor is hidden
- $onlyAuthor = $row->rev_user_text;
- // Try to find a second contributor
- foreach ( $res as $row ) {
- if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
- $onlyAuthor = false;
- break;
- }
- }
- } else {
- $onlyAuthor = false;
- }
-
- // Generate the summary with a '$1' placeholder
- if ( $blank ) {
- // The current revision is blank and the one before is also
- // blank. It's just not our lucky day
- $reason = wfMsgForContent( 'exbeforeblank', '$1' );
- } else {
- if ( $onlyAuthor ) {
- $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
- } else {
- $reason = wfMsgForContent( 'excontent', '$1' );
- }
- }
-
- if ( $reason == '-' ) {
- // Allow these UI messages to be blanked out cleanly
- return '';
- }
-
- // Replace newlines with spaces to prevent uglyness
- $contents = preg_replace( "/[\n\r]/", ' ', $contents );
- // Calculate the maximum amount of chars to get
- // Max content length = max comment length - length of the comment (excl. $1)
- $maxLength = 255 - ( strlen( $reason ) - 2 );
- $contents = $wgContLang->truncate( $contents, $maxLength );
- // Remove possible unfinished links
- $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
- // Now replace the '$1' placeholder
- $reason = str_replace( '$1', $contents, $reason );
+ #NOTE: stub for backwards-compatibility.
- return $reason;
+ $handler = ContentHandler::getForTitle( $this->getTitle() );
+ $handler->getAutoDeleteReason( $this->getTitle(), $hasHistory );
}
/**
// Need to pass a throwaway variable because generateReason expects
// a reference
$hasHistory = false;
- $reason = $page->getAutoDeleteReason( $hasHistory );
+ $reason = $page->getAutoDeleteReason( $hasHistory ); #FIXME: use ContentHandler::getAutoDeleteReason()
if ( $reason === false ) {
return array( array( 'cannotdelete', $title->getPrefixedText() ) );
}