X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FEditPage.php;h=1eb87ab93731602cc582a042bb240d5c0a568206;hb=25d66ab5d4f2d16261ca6b0df08fcc29be0a2f0b;hp=83f303463725d4b6b1d3126083712be20f74df96;hpb=dac2ca94f4e408fa951a490d3fb759daec961d7b;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/EditPage.php b/includes/EditPage.php index 83f3034637..1eb87ab937 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1,53 +1,170 @@ mArticle =& $article; global $wgTitle; $this->mTitle =& $wgTitle; } - # This is the function that gets called for "action=edit". - - function edit() + /** + * This is the function that extracts metadata from the article body on the first view. + * To turn the feature on, set $wgUseMetadataEdit = true ; in LocalSettings + * and set $wgMetadataWhitelist to the *full* title of the template whitelist + */ + function extractMetaDataFromArticle () { + global $wgUseMetadataEdit , $wgMetadataWhitelist , $wgLang ; + $this->mMetaData = '' ; + if ( !$wgUseMetadataEdit ) return ; + if ( $wgMetadataWhitelist == "" ) return ; + $s = '' ; + $t = $this->mArticle->getContent ( true ) ; + + # MISSING : filtering + + # Categories and language links + $t = explode ( "\n" , $t ) ; + $catlow = strtolower ( $wgLang->getNsText ( NS_CATEGORY ) ) ; + $cat = $ll = array() ; + foreach ( $t AS $key => $x ) + { + $y = trim ( strtolower ( $x ) ) ; + while ( substr ( $y , 0 , 2 ) == "[[" ) + { + $y = explode ( "]]" , trim ( $x ) ) ; + $first = array_shift ( $y ) ; + $first = explode ( ":" , $first ) ; + $ns = array_shift ( $first ) ; + $ns = trim ( str_replace ( '[' , '' , $ns ) ) ; + if ( strlen ( $ns ) == 2 OR strtolower ( $ns ) == $catlow ) + { + $add = '[[' . $ns . ':' . implode ( ':' , $first ) . ']]' ; + if ( strtolower ( $ns ) == $catlow ) $cat[] = $add ; + else $ll[] = $add ; + $x = implode ( ']]' , $y ) ; + $t[$key] = $x ; + $y = trim ( strtolower ( $x ) ) ; + } + } + } + if ( count ( $cat ) ) $s .= implode ( ' ' , $cat ) . "\n" ; + if ( count ( $ll ) ) $s .= implode ( ' ' , $ll ) . "\n" ; + $t = implode ( "\n" , $t ) ; + + # Load whitelist + $sat = array () ; # stand-alone-templates; must be lowercase + $wl_title = Title::newFromText ( $wgMetadataWhitelist ) ; + $wl_article = new Article ( $wl_title ) ; + $wl = explode ( "\n" , $wl_article->getContent(true) ) ; + foreach ( $wl AS $x ) + { + $isentry = false ; + $x = trim ( $x ) ; + while ( substr ( $x , 0 , 1 ) == '*' ) + { + $isentry = true ; + $x = trim ( substr ( $x , 1 ) ) ; + } + if ( $isentry ) + { + $sat[] = strtolower ( $x ) ; + } + + } + + # Templates, but only some + $t = explode ( '{{' , $t ) ; + $tl = array () ; + foreach ( $t AS $key => $x ) + { + $y = explode ( '}}' , $x , 2 ) ; + if ( count ( $y ) == 2 ) + { + $z = $y[0] ; + $z = explode ( '|' , $z ) ; + $tn = array_shift ( $z ) ; + if ( in_array ( strtolower ( $tn ) , $sat ) ) + { + $tl[] = '{{' . $y[0] . '}}' ; + $t[$key] = $y[1] ; + $y = explode ( '}}' , $y[1] , 2 ) ; + } + else $t[$key] = '{{' . $x ; + } + else if ( $key != 0 ) $t[$key] = '{{' . $x ; + else $t[$key] = $x ; + } + if ( count ( $tl ) ) $s .= implode ( ' ' , $tl ) ; + $t = implode ( '' , $t ) ; + + $t = str_replace ( "\n\n\n" , "\n" , $t ) ; + $this->mArticle->mContent = $t ; + $this->mMetaData = $s ; + } + + /** + * This is the function that gets called for "action=edit". + */ + function edit() { global $wgOut, $wgUser, $wgWhitelistEdit, $wgRequest; // this is not an article $wgOut->setArticleFlag(false); $this->importFormData( $wgRequest ); + + if( $this->live ) { + $this->livePreview(); + return; + } if ( ! $this->mTitle->userCanEdit() ) { $wgOut->readOnlyPage( $this->mArticle->getContent( true ), true ); return; } - if ( $wgUser->isBlocked() ) { + if ( !$this->preview && !$this->diff && $wgUser->isBlocked( !$this->save ) ) { + # When previewing, don't check blocked state - will get caught at save time. + # Also, check when starting edition is done against slave to improve performance. $this->blockedIPpage(); return; } - if ( !$wgUser->getID() && $wgWhitelistEdit ) { + if ( $wgUser->isAnon() && $wgWhitelistEdit ) { $this->userNotLoggedInPage(); return; } if ( wfReadOnly() ) { if( $this->save || $this->preview ) { $this->editForm( 'preview' ); + } else if ( $this->diff ) { + $this->editForm( 'diff' ); } else { $wgOut->readOnlyPage( $this->mArticle->getContent( true ) ); } @@ -57,56 +174,113 @@ class EditPage { $this->editForm( 'save' ); } else if ( $this->preview ) { $this->editForm( 'preview' ); + } else if ( $this->diff ) { + $this->editForm( 'diff' ); } else { # First time through - $this->editForm( 'initial' ); + if( $wgUser->getOption('previewonfirst') ) { + $this->editForm( 'preview', true ); + } else { + $this->extractMetaDataFromArticle () ; + $this->editForm( 'initial', true ); + } } } + /** + * @todo document + */ function importFormData( &$request ) { - # These fields need to be checked for encoding. - # Also remove trailing whitespace, but don't remove _initial_ - # whitespace from the text boxes. This may be significant formatting. - $this->textbox1 = rtrim( $request->getText( 'wpTextbox1' ) ); - $this->textbox2 = rtrim( $request->getText( 'wpTextbox2' ) ); - $this->summary = trim( $request->getText( 'wpSummary' ) ); - - $this->edittime = $request->getVal( 'wpEdittime' ); - if( !preg_match( '/^\d{14}$/', $this->edittime )) $this->edittime = ''; - - $this->preview = $request->getCheck( 'wpPreview' ); - $this->save = $request->wasPosted() && !$this->preview; - $this->minoredit = $request->getCheck( 'wpMinoredit' ); - $this->watchthis = $request->getCheck( 'wpWatchthis' ); + if( $request->wasPosted() ) { + # These fields need to be checked for encoding. + # Also remove trailing whitespace, but don't remove _initial_ + # whitespace from the text boxes. This may be significant formatting. + $this->textbox1 = rtrim( $request->getText( 'wpTextbox1' ) ); + $this->textbox2 = rtrim( $request->getText( 'wpTextbox2' ) ); + $this->mMetaData = rtrim( $request->getText( 'metadata' ) ); + $this->summary = trim( $request->getText( 'wpSummary' ) ); + + $this->edittime = $request->getVal( 'wpEdittime' ); + if( is_null( $this->edittime ) ) { + # If the form is incomplete, force to preview. + $this->preview = true; + } else { + if( $this->tokenOk( $request ) ) { + # Some browsers will not report any submit button + # if the user hits enter in the comment box. + # The unmarked state will be assumed to be a save, + # if the form seems otherwise complete. + $this->preview = $request->getCheck( 'wpPreview' ); + $this->diff = $request->getCheck( 'wpDiff' ); + } else { + # Page might be a hack attempt posted from + # an external site. Preview instead of saving. + $this->preview = true; + } + } + $this->save = ! ( $this->preview OR $this->diff ); + if( !preg_match( '/^\d{14}$/', $this->edittime )) { + $this->edittime = null; + } + + $this->minoredit = $request->getCheck( 'wpMinoredit' ); + $this->watchthis = $request->getCheck( 'wpWatchthis' ); + } else { + # Not a posted form? Start with nothing. + $this->textbox1 = ''; + $this->textbox2 = ''; + $this->mMetaData = ''; + $this->summary = ''; + $this->edittime = ''; + $this->preview = false; + $this->save = false; + $this->diff = false; + $this->minoredit = false; + $this->watchthis = false; + } $this->oldid = $request->getInt( 'oldid' ); # Section edit can come from either the form or a link $this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) ); + + $this->live = $request->getCheck( 'live' ); } - # Since there is only one text field on the edit form, - # pressing will cause the form to be submitted, but - # the submit button value won't appear in the query, so we - # Fake it here before going back to edit(). This is kind of - # ugly, but it helps some old URLs to still work. - - function submit() - { - if( !$this->preview ) $this->save = true; - + /** + * Make sure the form isn't faking a user's credentials. + * + * @param WebRequest $request + * @return bool + * @access private + */ + function tokenOk( &$request ) { + global $wgUser; + if( $wgUser->isAnon() ) { + # Anonymous users may not have a session + # open. Don't tokenize. + return true; + } else { + return $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) ); + } + } + + function submit() { $this->edit(); } - # The edit form is self-submitting, so that when things like - # preview and edit conflicts occur, we get the same form back - # with the extra stuff added. Only when the final submission - # is made and all is well do we actually save and redirect to - # the newly-edited page. - - function editForm( $formtype ) - { + /** + * The edit form is self-submitting, so that when things like + * preview and edit conflicts occur, we get the same form back + * with the extra stuff added. Only when the final submission + * is made and all is well do we actually save and redirect to + * the newly-edited page. + * + * @param string $formtype Type of form either : save, initial, diff or preview + * @param bool $firsttime True to load form data from db + */ + function editForm( $formtype, $firsttime = false ) { global $wgOut, $wgUser; - global $wgLang, $wgParser, $wgTitle; + global $wgLang, $wgContLang, $wgParser, $wgTitle; global $wgAllowAnonymousMinor; global $wgWhitelistEdit; global $wgSpamRegex, $wgFilterCallback; @@ -114,13 +288,14 @@ class EditPage { $sk = $wgUser->getSkin(); $isConflict = false; // css / js subpages of user pages get a special treatment - $isCssJsSubpage = (Namespace::getUser() == $wgTitle->getNamespace() and preg_match("/\\.(css|js)$/", $wgTitle->getText() )); + $isCssJsSubpage = $wgTitle->isCssJsSubpage(); + if(!$this->mTitle->getArticleID()) { # new article $wgOut->addWikiText(wfmsg('newarticletext')); } - if( Namespace::isTalk( $this->mTitle->getNamespace() ) ) { + if( $this->mTitle->isTalkPage() ) { $wgOut->addWikiText(wfmsg('talkpagetext')); } @@ -130,20 +305,25 @@ class EditPage { # in the back door with a hand-edited submission URL. if ( 'save' == $formtype ) { + # Reintegrate metadata + if ( $this->mMetaData != '' ) $this->textbox1 .= "\n" . $this->mMetaData ; + $this->mMetaData = '' ; + # Check for spam if ( $wgSpamRegex && preg_match( $wgSpamRegex, $this->textbox1, $matches ) ) { - $this->spamPage ( $matches ); + $this->spamPage ( $matches[0] ); return; } if ( $wgFilterCallback && $wgFilterCallback( $this->mTitle, $this->textbox1, $this->section ) ) { # Error messages or other handling should be performed by the filter function return; } - if ( $wgUser->isBlocked() ) { + if ( $wgUser->isBlocked( false ) ) { + # Check block state against master, thus 'false'. $this->blockedIPpage(); return; } - if ( !$wgUser->getID() && $wgWhitelistEdit ) { + if ( $wgUser->isAnon() && $wgWhitelistEdit ) { $this->userNotLoggedInPage(); return; } @@ -161,7 +341,15 @@ class EditPage { $wgOut->redirect( $this->mTitle->getFullURL() ); return; } - $this->mArticle->insertNewArticle( $this->textbox1, $this->summary, $this->minoredit, $this->watchthis ); + if (wfRunHooks('ArticleSave', array(&$this->mArticle, &$wgUser, &$this->textbox1, + &$this->summary, &$this->minoredit, &$this->watchthis, NULL))) + { + $this->mArticle->insertNewArticle( $this->textbox1, $this->summary, + $this->minoredit, $this->watchthis ); + wfRunHooks('ArticleSaveComplete', array(&$this->mArticle, &$wgUser, $this->textbox1, + $this->summary, $this->minoredit, + $this->watchthis, NULL)); + } return; } @@ -176,8 +364,14 @@ class EditPage { } $userid = $wgUser->getID(); - $text = $this->mArticle->getTextOfLastEditWithSectionReplacedOrAdded( - $this->section, $this->textbox1, $this->summary); + if ( $isConflict) { + $text = $this->mArticle->getTextOfLastEditWithSectionReplacedOrAdded( + $this->section, $this->textbox1, $this->summary, $this->edittime); + } + else { + $text = $this->mArticle->getTextOfLastEditWithSectionReplacedOrAdded( + $this->section, $this->textbox1, $this->summary); + } # Suppress edit conflict with self if ( ( 0 != $userid ) && ( $this->mArticle->getUser() == $userid ) ) { @@ -198,7 +392,11 @@ class EditPage { if ( ! $isConflict ) { # All's well $sectionanchor = ''; - if( $this->section != '' ) { + if( $this->section == 'new' ) { + if( $this->summary != '' ) { + $sectionanchor = $this->sectionAnchor( $this->summary ); + } + } elseif( $this->section != '' ) { # Try to get a section anchor from the section source, redirect to edited section if header found # XXX: might be better to integrate this into Article::getTextOfLastEditWithSectionReplacedOrAdded # for duplicate heading checking and maybe parsing @@ -207,31 +405,32 @@ class EditPage { # headline would need to be parsed to improve this #if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) { if($hasmatch and strlen($matches[2]) > 0) { - global $wgInputEncoding; - $headline = do_html_entity_decode( $matches[2], ENT_COMPAT, $wgInputEncoding ); - # strip out HTML - $headline = preg_replace( "/<.*?" . ">/","",$headline ); - $headline = trim( $headline ); - $sectionanchor = '#'.urlencode( str_replace(' ', '_', $headline ) ); - $replacearray = array( - '%3A' => ':', - '%' => '.' - ); - $sectionanchor = str_replace(array_keys($replacearray),array_values($replacearray),$sectionanchor); + $sectionanchor = $this->sectionAnchor( $matches[2] ); } } - - # update the article here - if($this->mArticle->updateArticle( $text, $this->summary, $this->minoredit, $this->watchthis, '', $sectionanchor )) - return; - else - $isConflict = true; + + if (wfRunHooks('ArticleSave', array(&$this->mArticle, &$wgUser, &$text, + &$this->summary, &$this->minoredit, + &$this->watchthis, &$sectionanchor))) + { + # update the article here + if($this->mArticle->updateArticle( $text, $this->summary, $this->minoredit, + $this->watchthis, '', $sectionanchor )) + { + wfRunHooks('ArticleSaveComplete', array(&$this->mArticle, &$wgUser, $text, + $this->summary, $this->minoredit, + $this->watchthis, $sectionanchor)); + return; + } + else + $isConflict = true; + } } } # First time through: get contents, set time for conflict # checking, etc. - if ( 'initial' == $formtype ) { + if ( 'initial' == $formtype || $firsttime ) { $this->edittime = $this->mArticle->getTimestamp(); $this->textbox1 = $this->mArticle->getContent( true ); $this->summary = ''; @@ -251,24 +450,29 @@ class EditPage { $this->textbox1 = $this->mArticle->getContent( true ); $this->edittime = $this->mArticle->getTimestamp(); } else { - $s = wfMsg( 'editing', $this->mTitle->getPrefixedText() ); if( $this->section != '' ) { if( $this->section == 'new' ) { - $s.=wfMsg('commentedit'); + $s = wfMsg('editingcomment', $this->mTitle->getPrefixedText() ); } else { - $s.=wfMsg('sectionedit'); + $s = wfMsg('editingsection', $this->mTitle->getPrefixedText() ); } if(!$this->preview) { - $sectitle=preg_match("/^=+(.*?)=+/mi", - $this->textbox1, - $matches); - if( !empty( $matches[1] ) ) { - $this->summary = "/* ". trim($matches[1])." */ "; + preg_match( "/^(=+)(.+)\\1/mi", + $this->textbox1, + $matches ); + if( !empty( $matches[2] ) ) { + $this->summary = "/* ". trim($matches[2])." */ "; } } + } else { + $s = wfMsg( 'editing', $this->mTitle->getPrefixedText() ); } $wgOut->setPageTitle( $s ); + if ( !$this->checkUnicodeCompliantBrowser() ) { + $this->mArticle->setOldSubtitle(); + $wgOut->addWikiText( wfMsg( 'nonunicodebrowser') ); + } if ( $this->oldid ) { $this->mArticle->setOldSubtitle(); $wgOut->addHTML( wfMsg( 'editingold' ) ); @@ -282,7 +486,7 @@ class EditPage { } else if ( $isCssJsSubpage and 'preview' != $formtype) { $wgOut->addHTML( wfMsg( 'usercssjsyoucanpreview' )); } - if( $this->mTitle->isProtected() ) { + if( $this->mTitle->isProtected('edit') ) { $wgOut->addHTML( '' . wfMsg( 'protectedpagewarning' ) . "
\n" ); } @@ -311,6 +515,7 @@ class EditPage { $watchthis = wfMsg ('watchthis'); $save = wfMsg('savearticle'); $prev = wfMsg('showpreview'); + $diff = wfMsg('showdiff'); $cancel = $sk->makeKnownLink( $this->mTitle->getPrefixedText(), wfMsg('cancel') ); @@ -322,18 +527,18 @@ class EditPage { global $wgRightsText; $copywarn = "
\n" . wfMsg( $wgRightsText ? 'copyrightwarning' : 'copyrightwarning2', - '[[' . wfMsg( 'copyrightpage' ) . ']]', + '[[' . wfMsgForContent( 'copyrightpage' ) . ']]', $wgRightsText ) . "\n
"; if( $wgUser->getOption('showtoolbar') and !$isCssJsSubpage ) { # prepare toolbar for edit buttons - $toolbar = $sk->getEditToolbar(); + $toolbar = $this->getEditToolbar(); } else { $toolbar = ''; } // activate checkboxes if user wants them to be always active - if( !$this->preview ) { + if( !$this->preview && !$this->diff ) { if( $wgUser->getOption( 'watchdefault' ) ) $this->watchthis = true; if( $wgUser->getOption( 'minordefault' ) ) $this->minoredit = true; @@ -345,7 +550,7 @@ class EditPage { $minoredithtml = ''; - if ( 0 != $wgUser->getID() || $wgAllowAnonymousMinor ) { + if ( $wgUser->isLoggedIn() || $wgAllowAnonymousMinor ) { $minoredithtml = "minoredit?" checked='checked'":""). " accesskey='".wfMsg('accesskey-minoredit')."' id='wpMinoredit' />". @@ -354,7 +559,7 @@ class EditPage { $watchhtml = ''; - if ( 0 != $wgUser->getID() ) { + if ( $wgUser->isLoggedIn() ) { $watchhtml = "watchthis?" checked='checked'":""). " accesskey='".wfMsg('accesskey-watch')."' id='wpWatchthis' />". ""; @@ -362,47 +567,37 @@ class EditPage { $checkboxhtml = $minoredithtml . $watchhtml . '
'; + $wgOut->addHTML( '
' ); if ( 'preview' == $formtype) { - $previewhead='

' . wfMsg( 'preview' ) . "

\n

" . - wfMsg( 'note' ) . wfMsg( 'previewnote' ) . "

\n"; - if ( $isConflict ) { - $previewhead.='

' . wfMsg( 'previewconflict' ) . - "

\n"; + $previewOutput = $this->getPreviewText( $isConflict, $isCssJsSubpage ); + if ( $wgUser->getOption('previewontop' ) ) { + $wgOut->addHTML( $previewOutput ); + $wgOut->addHTML( "
\n" ); } - - $parserOptions = ParserOptions::newFromUser( $wgUser ); - $parserOptions->setEditSection( false ); - $parserOptions->setEditSectionOnRightClick( false ); - - # don't parse user css/js, show message about preview - # XXX: stupid php bug won't let us use $wgTitle->isCssJsSubpage() here - - if ( $isCssJsSubpage ) { - if(preg_match("/\\.css$/", $wgTitle->getText() ) ) { - $previewtext = wfMsg('usercsspreview'); - } else if(preg_match("/\\.js$/", $wgTitle->getText() ) ) { - $previewtext = wfMsg('userjspreview'); - } - $parserOutput = $wgParser->parse( $previewtext , $wgTitle, $parserOptions ); - $wgOut->addHTML( $parserOutput->mText ); - } else { - $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $this->textbox1 ) ."\n\n", - $wgTitle, $parserOptions ); - $previewHTML = $parserOutput->mText; - - if($wgUser->getOption('previewontop')) { - $wgOut->addHTML($previewhead); - $wgOut->addHTML($previewHTML); - } - $wgOut->addCategoryLinks($parserOutput->getCategoryLinks()); - $wgOut->addLanguageLinks($parserOutput->getLanguageLinks()); + } + $wgOut->addHTML( '
' ); + if ( 'diff' == $formtype ) { + $wgOut->addHTML( '
' ); + require_once( 'DifferenceEngine.php' ); + $oldtext = $this->mArticle->getContent( true ); + $newtext = $this->textbox1; + $oldtitle = wfMsg( 'currentrev' ); + $newtitle = wfMsg( 'yourtext' ); + + if ( $oldtext != wfMsg( 'noarticletext' ) || $newtext != '' ) { + $difftext = DifferenceEngine::getDiff( $oldtext, $newtext, $oldtitle, $newtitle ); + } + if ( $wgUser->getOption('previewontop' ) ) { + $wgOut->addHTML( $difftext ); $wgOut->addHTML( "
\n" ); } + $wgOut->addHTML( '
' ); } + # if this is a comment, show a subject line at the top, which is also the edit summary. # Otherwise, show a summary field at the bottom - $summarytext = htmlspecialchars( $wgLang->recodeForEdit( $this->summary ) ); # FIXME + $summarytext = htmlspecialchars( $wgContLang->recodeForEdit( $this->summary ) ); # FIXME if( $this->section == 'new' ) { $commentsubject="{$subject}:
"; $editsummary = ''; @@ -411,52 +606,96 @@ class EditPage { $editsummary="{$summary}:
"; } - if( !$this->preview ) { + if( !$this->preview && !$this->diff ) { # Don't select the edit box on preview; this interferes with seeing what's going on. $wgOut->setOnloadHandler( 'document.editform.wpTextbox1.focus()' ); } # Prepare a list of templates used by this page - $db =& wfGetDB( DB_SLAVE ); - $cur = $db->tableName( 'cur' ); - $links = $db->tableName( 'links' ); - $id = $this->mTitle->getArticleID(); - $sql = "SELECT cur_namespace,cur_title,cur_id ". - "FROM $cur,$links WHERE l_to=cur_id AND l_from={$id} and cur_namespace=".NS_TEMPLATE; - $res = $db->query( $sql, "EditPage::editform" ); - - if ( $db->numRows( $res ) ) { + $templates = ''; + $articleTemplates = $this->mArticle->getUsedTemplates(); + if ( count( $articleTemplates ) > 0 ) { $templates = '
'. wfMsg( 'templatesused' ) . ''; - } else { - $templates = ''; } - $wgOut->addHTML( " + + global $wgLivePreview, $wgStylePath; + /** + * Live Preview lets us fetch rendered preview page content and + * add it to the page without refreshing the whole page. + * Set up the button for it; if not supported by the browser + * it will fall through to the normal form submission method. + */ + if( $wgLivePreview ) { + $wgOut->addHTML( '' . "\n" ); + $liveAction = $wgTitle->getLocalUrl( 'action=submit&wpPreview=true&live=true' ); + $liveOnclick = 'onclick="return !livePreview('. + 'getElementById(\'wikiPreview\'),' . + 'editform.wpTextbox1.value,' . + htmlspecialchars( '"' . $liveAction . '"' ) . ')"'; + } else { + $liveOnclick = ''; + } + + global $wgUseMetadataEdit ; + if ( $wgUseMetadataEdit ) + { + $metadata = $this->mMetaData ; + $metadata = htmlspecialchars( $wgContLang->recodeForEdit( $metadata ) ) ; + $helppage = Title::newFromText ( wfmsg("metadata_page") ) ; + $top = str_replace ( "$1" , $helppage->getInternalURL() , wfmsg("metadata") ) ; + $metadata = $top . "" ; + } + else $metadata = "" ; + + + $wgOut->addHTML( << +
{$commentsubject} - +{$metadata}
{$editsummary} {$checkboxhtml} -  + + {$cancel} | {$edithelp}{$templates}" ); $wgOut->addWikiText( $copywarn ); $wgOut->addHTML( " section ) . "\" name=\"wpSection\" /> edittime}\" name=\"wpEdittime\" />\n" ); + if ( $wgUser->isLoggedIn() ) { + /** + * To make it harder for someone to slip a user a page + * which submits an edit form to the wiki without their + * knowledge, a random token is associated with the login + * session. If it's not passed back with the submission, + * we won't save the page, or render user JavaScript and + * CSS previews. + */ + $token = htmlspecialchars( $wgUser->editToken() ); + $wgOut->addHTML( " +\n" ); + } + + if ( $isConflict ) { require_once( "DifferenceEngine.php" ); $wgOut->addHTML( "

" . wfMsg( "yourdiff" ) . "

\n" ); @@ -465,20 +704,74 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $wgOut->addHTML( "

" . wfMsg( "yourtext" ) . "

" ); } $wgOut->addHTML( "
\n" ); - if($formtype =="preview" && !$wgUser->getOption("previewontop")) { - $wgOut->addHTML($previewhead); - $wgOut->addHTML($previewHTML); + if ( $formtype == 'preview' && !$wgUser->getOption( 'previewontop' ) ) { + $wgOut->addHTML( '
' . $previewOutput . '
' ); + } + if ( $formtype == 'diff' && !$wgUser->getOption( 'previewontop' ) ) { + $wgOut->addHTML( '
' . $difftext . '
' ); } } - function blockedIPpage() - { - global $wgOut, $wgUser, $wgLang, $wgIP; + function getDiffText() { + } + + /** + * @todo document + */ + function getPreviewText( $isConflict, $isCssJsSubpage ) { + global $wgOut, $wgUser, $wgTitle, $wgParser, $wgAllowDiffPreview, $wgEnableDiffPreviewPreference; + $previewhead = '

' . htmlspecialchars( wfMsg( 'preview' ) ) . "

\n" . + "

" . htmlspecialchars( wfMsg( 'previewnote' ) ) . "

\n"; + if ( $isConflict ) { + $previewhead.='

' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . + "

\n"; + } + + $parserOptions = ParserOptions::newFromUser( $wgUser ); + $parserOptions->setEditSection( false ); + + # don't parse user css/js, show message about preview + # XXX: stupid php bug won't let us use $wgTitle->isCssJsSubpage() here + + if ( $isCssJsSubpage ) { + if(preg_match("/\\.css$/", $wgTitle->getText() ) ) { + $previewtext = wfMsg('usercsspreview'); + } else if(preg_match("/\\.js$/", $wgTitle->getText() ) ) { + $previewtext = wfMsg('userjspreview'); + } + $parserOutput = $wgParser->parse( $previewtext , $wgTitle, $parserOptions ); + $wgOut->addHTML( $parserOutput->mText ); + return $previewhead; + } else { + # if user want to see preview when he edit an article + if( $wgUser->getOption('previewonfirst') and ($this->textbox1 == '')) { + $this->textbox1 = $this->mArticle->getContent(true); + } + + $toparse = $this->textbox1 ; + if ( $this->mMetaData != "" ) $toparse .= "\n" . $this->mMetaData ; + + $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $toparse ) ."\n\n", + $wgTitle, $parserOptions ); + + $previewHTML = $parserOutput->mText; + + $wgOut->addCategoryLinks($parserOutput->getCategoryLinks()); + $wgOut->addLanguageLinks($parserOutput->getLanguageLinks()); + return $previewhead . $previewHTML; + } + } + + /** + * @todo document + */ + function blockedIPpage() { + global $wgOut, $wgUser, $wgContLang, $wgIP; $wgOut->setPageTitle( wfMsg( 'blockedtitle' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); @@ -493,18 +786,18 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . } else { $name = $id; } - $link = '[[' . $wgLang->getNsText( Namespace::getUser() ) . + $link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]"; $wgOut->addWikiText( wfMsg( 'blockedtext', $link, $reason, $ip, $name ) ); $wgOut->returnToMain( false ); } - - - function userNotLoggedInPage() - { - global $wgOut, $wgUser, $wgLang; + /** + * @todo document + */ + function userNotLoggedInPage() { + global $wgOut; $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); @@ -514,7 +807,10 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $wgOut->returnToMain( false ); } - function spamPage ( $matches = array() ) + /** + * @todo document + */ + function spamPage ( $match = false ) { global $wgOut; $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) ); @@ -522,16 +818,17 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $wgOut->setArticleRelated( false ); $wgOut->addWikiText( wfMsg( 'spamprotectiontext' ) ); - if ( isset ( $matches[0] ) ) { - $wgOut->addWikiText( wfMsg( 'spamprotectionmatch', "{$matches[0]}" ) ); + if ( $match ) { + $wgOut->addWikiText( wfMsg( 'spamprotectionmatch', "{$match}" ) ); } $wgOut->returnToMain( false ); } - # Forks processes to scan the originating IP for an open proxy server - # MemCached can be used to skip IPs that have already been scanned - function proxyCheck() - { + /** + * Forks processes to scan the originating IP for an open proxy server + * MemCached can be used to skip IPs that have already been scanned + */ + function proxyCheck() { global $wgBlockOpenProxies, $wgProxyPorts, $wgProxyScriptPath; global $wgIP, $wgUseMemCached, $wgMemc, $wgDBname, $wgProxyMemcExpiry; @@ -571,22 +868,17 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . } } - /* private */ function mergeChangesInto( &$text ){ - $fname = 'EditPage::mergeChangesInto'; - $oldDate = $this->edittime; - $dbw =& wfGetDB( DB_MASTER ); - $obj = $dbw->getArray( 'cur', array( 'cur_text' ), array( 'cur_id' => $this->mTitle->getArticleID() ), - $fname, 'FOR UPDATE' ); - - $yourtext = $obj->cur_text; - $ns = $this->mTitle->getNamespace(); - $title = $this->mTitle->getDBkey(); - $obj = $dbw->getArray( 'old', - array( 'old_text','old_flags'), - array( 'old_namespace' => $ns, 'old_title' => $title, - 'old_timestamp' => $dbw->timestamp($oldDate)), - $fname ); - $oldText = Article::getRevisionText( $obj ); + /** + * @access private + * @todo document + */ + function mergeChangesInto( &$text ){ + $yourtext = $this->mArticle->fetchRevisionText(); + + $db =& wfGetDB( DB_SLAVE ); + $oldText = $this->mArticle->fetchRevisionText( + $db->timestamp( $this->edittime ), + 'rev_timestamp' ); if(wfMerge($oldText, $text, $yourtext, $result)){ $text = $result; @@ -595,6 +887,189 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . return false; } } + + + function checkUnicodeCompliantBrowser() { + global $wgBrowserBlackList; + $currentbrowser = $_SERVER["HTTP_USER_AGENT"]; + foreach ( $wgBrowserBlackList as $browser ) { + if ( preg_match($browser, $currentbrowser) ) { + return false; + } + } + return true; + } + + /** + * Format an anchor fragment as it would appear for a given section name + * @param string $text + * @return string + * @access private + */ + function sectionAnchor( $text ) { + global $wgInputEncoding; + $headline = do_html_entity_decode( $text, ENT_COMPAT, $wgInputEncoding ); + # strip out HTML + $headline = preg_replace( '/<.*?' . '>/', '', $headline ); + $headline = trim( $headline ); + $sectionanchor = '#' . urlencode( str_replace( ' ', '_', $headline ) ); + $replacearray = array( + '%3A' => ':', + '%' => '.' + ); + return str_replace( + array_keys( $replacearray ), + array_values( $replacearray ), + $sectionanchor ); + } + + /** + * Shows a bulletin board style toolbar for common editing functions. + * It can be disabled in the user preferences. + * The necessary JavaScript code can be found in style/wikibits.js. + */ + function getEditToolbar() { + global $wgStylePath, $wgLang, $wgMimeType; + + /** + * toolarray an array of arrays which each include the filename of + * the button image (without path), the opening tag, the closing tag, + * and optionally a sample text that is inserted between the two when no + * selection is highlighted. + * The tip text is shown when the user moves the mouse over the button. + * + * Already here are accesskeys (key), which are not used yet until someone + * can figure out a way to make them work in IE. However, we should make + * sure these keys are not defined on the edit page. + */ + $toolarray=array( + array( 'image'=>'button_bold.png', + 'open' => "\'\'\'", + 'close' => "\'\'\'", + 'sample'=> wfMsg('bold_sample'), + 'tip' => wfMsg('bold_tip'), + 'key' => 'B' + ), + array( 'image'=>'button_italic.png', + 'open' => "\'\'", + 'close' => "\'\'", + 'sample'=> wfMsg('italic_sample'), + 'tip' => wfMsg('italic_tip'), + 'key' => 'I' + ), + array( 'image'=>'button_link.png', + 'open' => '[[', + 'close' => ']]', + 'sample'=> wfMsg('link_sample'), + 'tip' => wfMsg('link_tip'), + 'key' => 'L' + ), + array( 'image'=>'button_extlink.png', + 'open' => '[', + 'close' => ']', + 'sample'=> wfMsg('extlink_sample'), + 'tip' => wfMsg('extlink_tip'), + 'key' => 'X' + ), + array( 'image'=>'button_headline.png', + 'open' => "\\n== ", + 'close' => " ==\\n", + 'sample'=> wfMsg('headline_sample'), + 'tip' => wfMsg('headline_tip'), + 'key' => 'H' + ), + array( 'image'=>'button_image.png', + 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":", + 'close' => ']]', + 'sample'=> wfMsg('image_sample'), + 'tip' => wfMsg('image_tip'), + 'key' => 'D' + ), + array( 'image' => 'button_media.png', + 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':', + 'close' => ']]', + 'sample'=> wfMsg('media_sample'), + 'tip' => wfMsg('media_tip'), + 'key' => 'M' + ), + array( 'image' => 'button_math.png', + 'open' => "\\", + 'close' => "\\", + 'sample'=> wfMsg('math_sample'), + 'tip' => wfMsg('math_tip'), + 'key' => 'C' + ), + array( 'image' => 'button_nowiki.png', + 'open' => "\\", + 'close' => "\\", + 'sample'=> wfMsg('nowiki_sample'), + 'tip' => wfMsg('nowiki_tip'), + 'key' => 'N' + ), + array( 'image' => 'button_sig.png', + 'open' => '--~~~~', + 'close' => '', + 'sample'=> '', + 'tip' => wfMsg('sig_tip'), + 'key' => 'Y' + ), + array( 'image' => 'button_hr.png', + 'open' => "\\n----\\n", + 'close' => '', + 'sample'=> '', + 'tip' => wfMsg('hr_tip'), + 'key' => 'R' + ) + ); + $toolbar =""; + return $toolbar; + } + + /** + * Output preview text only. This can be sucked into the edit page + * via JavaScript, and saves the server time rendering the skin as + * well as theoretically being more robust on the client (doesn't + * disturb the edit box's undo history, won't eat your text on + * failure, etc). + * + * @todo This doesn't include category or interlanguage links. + * Would need to enhance it a bit, maybe wrap them in XML + * or something... that might also require more skin + * initialization, so check whether that's a problem. + */ + function livePreview() { + global $wgOut; + $wgOut->disable(); + header( 'Content-type: text/xml' ); + header( 'Cache-control: no-cache' ); + # FIXME + echo $this->getPreviewText( false, false ); + } + } ?>