X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FEditPage.php;h=1eb87ab93731602cc582a042bb240d5c0a568206;hb=25d66ab5d4f2d16261ca6b0df08fcc29be0a2f0b;hp=d9959ae39f973197ce733b93a9256ba7dfeb830b;hpb=680704d114e4aa787c7a2431653ed9f2cb52415e;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/EditPage.php b/includes/EditPage.php index d9959ae39f..1eb87ab937 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1,126 +1,302 @@ 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" ); + $this->editForm( 'preview' ); + } else if ( $this->diff ) { + $this->editForm( 'diff' ); } else { $wgOut->readOnlyPage( $this->mArticle->getContent( true ) ); } return; } if ( $this->save ) { - $this->editForm( "save" ); + $this->editForm( 'save' ); } else if ( $this->preview ) { - $this->editForm( "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; + global $wgSpamRegex, $wgFilterCallback; $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")); + $wgOut->addWikiText(wfmsg('newarticletext')); } - if( Namespace::isTalk( $this->mTitle->getNamespace() ) ) { - $wgOut->addWikiText(wfmsg("talkpagetext")); + if( $this->mTitle->isTalkPage() ) { + $wgOut->addWikiText(wfmsg('talkpagetext')); } # Attempt submission here. This will check for edit conflicts, @@ -128,18 +304,26 @@ class EditPage { # that edit() already checked just in case someone tries to sneak # in the back door with a hand-edited submission URL. - if ( "save" == $formtype ) { + 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 ) ) { - sleep(10); - $wgOut->redirect( $this->mTitle->getFullURL() ); - return; + if ( $wgSpamRegex && preg_match( $wgSpamRegex, $this->textbox1, $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; } @@ -149,30 +333,45 @@ class EditPage { } # If article is new, insert it. - $aid = $this->mTitle->getArticleID(); + $aid = $this->mTitle->getArticleID( GAID_FOR_UPDATE ); if ( 0 == $aid ) { # Don't save a new article if it's blank. - if ( ( "" == $this->textbox1 ) || - ( wfMsg( "newarticletext" ) == $this->textbox1 ) ) { + if ( ( '' == $this->textbox1 ) || + ( wfMsg( 'newarticletext' ) == $this->textbox1 ) ) { $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; } # Article exists. Check for edit conflict. $this->mArticle->clear(); # Force reload of dates, etc. + $this->mArticle->forUpdate( true ); # Lock the article - if( ( $this->section != "new" ) && + if( ( $this->section != 'new' ) && ($this->mArticle->getTimestamp() != $this->edittime ) ) { $isConflict = true; } $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 ) ) { @@ -185,7 +384,7 @@ class EditPage { // Successful merge! Maybe we should tell the user the good news? $isConflict = false; } else { - $this->section = ""; + $this->section = ''; $this->textbox1 = $text; } } @@ -193,134 +392,155 @@ 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 $hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches ); # we can't deal with anchors, includes, html etc in the header for now, # headline would need to be parsed to improve this - if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) { - global $wgInputEncoding; - $headline = do_html_entity_decode( $matches[2], ENT_COMPAT, $wgInputEncoding ); - # strip out HTML, will be useful when - # $headline = preg_replace( "/<.*?" . ">/","",$headline ); - $headline = trim( $headline ); - $sectionanchor = '#'.preg_replace("/[ \\?&\\/<>\\(\\)\\[\\]=,+']+/", '_', urlencode( $headline ) ); + #if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) { + if($hasmatch and strlen($matches[2]) > 0) { + $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 = ""; + $this->summary = ''; $this->proxyCheck(); } - $wgOut->setRobotpolicy( "noindex,nofollow" ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); # Enabled article-related sidebar, toplinks, etc. $wgOut->setArticleRelated( true ); if ( $isConflict ) { - $s = wfMsg( "editconflict", $this->mTitle->getPrefixedText() ); + $s = wfMsg( 'editconflict', $this->mTitle->getPrefixedText() ); $wgOut->setPageTitle( $s ); - $wgOut->addHTML( wfMsg( "explainconflict" ) ); + $wgOut->addHTML( wfMsg( 'explainconflict' ) ); $this->textbox2 = $this->textbox1; $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"); + if( $this->section != '' ) { + if( $this->section == 'new' ) { + $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" ) ); + $wgOut->addHTML( wfMsg( 'editingold' ) ); } } if( wfReadOnly() ) { - $wgOut->addHTML( "" . - wfMsg( "readonlywarning" ) . + $wgOut->addHTML( '' . + wfMsg( 'readonlywarning' ) . "" ); - } else if ( $isCssJsSubpage and "preview" != $formtype) { - $wgOut->addHTML( wfMsg( "usercssjsyoucanpreview" )); + } else if ( $isCssJsSubpage and 'preview' != $formtype) { + $wgOut->addHTML( wfMsg( 'usercssjsyoucanpreview' )); } - if( $this->mTitle->isProtected() ) { - $wgOut->addHTML( "" . wfMsg( "protectedpagewarning" ) . + if( $this->mTitle->isProtected('edit') ) { + $wgOut->addHTML( '' . wfMsg( 'protectedpagewarning' ) . "
\n" ); } $kblength = (int)(strlen( $this->textbox1 ) / 1024); if( $kblength > 29 ) { - $wgOut->addHTML( "" . - wfMsg( "longpagewarning", $kblength ) - . "" ); + $wgOut->addHTML( '' . + wfMsg( 'longpagewarning', $wgLang->formatNum( $kblength ) ) + . '' ); } - $rows = $wgUser->getOption( "rows" ); - $cols = $wgUser->getOption( "cols" ); + $rows = $wgUser->getOption( 'rows' ); + $cols = $wgUser->getOption( 'cols' ); - $ew = $wgUser->getOption( "editwidth" ); + $ew = $wgUser->getOption( 'editwidth' ); if ( $ew ) $ew = " style=\"width:100%\""; - else $ew = "" ; + else $ew = ''; - $q = "action=submit"; + $q = 'action=submit'; #if ( "no" == $redirect ) { $q .= "&redirect=no"; } $action = $this->mTitle->escapeLocalURL( $q ); - $summary = wfMsg( "summary" ); - $subject = wfMsg("subject"); - $minor = wfMsg( "minoredit" ); - $watchthis = wfMsg ("watchthis"); - $save = wfMsg( "savearticle" ); - $prev = wfMsg( "showpreview" ); - - $cancel = $sk->makeKnownLink( $this->mTitle->getPrefixedURL(), - wfMsg( "cancel" ) ); - $edithelpurl = $sk->makeUrl( wfMsg( "edithelppage" )); - $edithelp = ''. - wfMsg( "edithelp" ).''; - $copywarn = wfMsg( "copyrightwarning", $sk->makeKnownLink( - wfMsg( "copyrightpage" ) ) ); - - if( $wgUser->getOption("showtoolbar") and !$isCssJsSubpage ) { + $summary = wfMsg('summary'); + $subject = wfMsg('subject'); + $minor = wfMsg('minoredit'); + $watchthis = wfMsg ('watchthis'); + $save = wfMsg('savearticle'); + $prev = wfMsg('showpreview'); + $diff = wfMsg('showdiff'); + + $cancel = $sk->makeKnownLink( $this->mTitle->getPrefixedText(), + wfMsg('cancel') ); + $edithelpurl = $sk->makeUrl( wfMsg( 'edithelppage' )); + $edithelp = ''. + htmlspecialchars( wfMsg( 'edithelp' ) ).' '. + htmlspecialchars( wfMsg( 'newwindow' ) ); + + global $wgRightsText; + $copywarn = "
\n" . + wfMsg( $wgRightsText ? 'copyrightwarning' : 'copyrightwarning2', + '[[' . wfMsgForContent( 'copyrightpage' ) . ']]', + $wgRightsText ) . "\n
"; + + if( $wgUser->getOption('showtoolbar') and !$isCssJsSubpage ) { # prepare toolbar for edit buttons - $toolbar = $sk->getEditToolbar(); + $toolbar = $this->getEditToolbar(); } else { - $toolbar = ""; + $toolbar = ''; } // activate checkboxes if user wants them to be always active - if( !$this->preview ) { - if( $wgUser->getOption( "watchdefault" ) ) $this->watchthis = true; - if( $wgUser->getOption( "minordefault" ) ) $this->minoredit = true; + if( !$this->preview && !$this->diff ) { + if( $wgUser->getOption( 'watchdefault' ) ) $this->watchthis = true; + if( $wgUser->getOption( 'minordefault' ) ) $this->minoredit = true; // activate checkbox also if user is already watching the page, // require wpWatchthis to be unset so that second condition is not @@ -328,154 +548,287 @@ class EditPage { if( !$this->watchthis && $this->mTitle->userIsWatching() ) $this->watchthis = true; } - $minoredithtml = ""; + $minoredithtml = ''; - if ( 0 != $wgUser->getID() || $wgAllowAnonymousMinor ) { + if ( $wgUser->isLoggedIn() || $wgAllowAnonymousMinor ) { $minoredithtml = - "minoredit?" checked='checked'":""). - " accesskey='".wfMsg('accesskey-minoredit')."' id='wpMinoredit' />". - ""; + "minoredit?" checked='checked'":""). + " accesskey='".wfMsg('accesskey-minoredit')."' id='wpMinoredit' />". + ""; } - $watchhtml = ""; + $watchhtml = ''; - if ( 0 != $wgUser->getID() ) { + if ( $wgUser->isLoggedIn() ) { $watchhtml = "watchthis?" checked='checked'":""). - " accesskey='".wfMsg('accesskey-watch')."' id='wpWatchthis' />". - ""; - } - - $checkboxhtml = $minoredithtml . $watchhtml . "
"; - - if ( "preview" == $formtype) { - $previewhead="

" . wfMsg( "preview" ) . "

\n

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

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

" . wfMsg( "previewconflict" ) . - "

\n"; - } - $previewtext = wfUnescapeHTML( $this->textbox1 ); - - $parserOptions = ParserOptions::newFromUser( $wgUser ); - $parserOptions->setUseCategoryMagic( false ); - $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( $previewtext ) ."\n\n", - $wgTitle, $parserOptions ); - $previewHTML = $parserOutput->mText; + " accesskey='".wfMsg('accesskey-watch')."' id='wpWatchthis' />". + ""; + } - if($wgUser->getOption("previewontop")) { - $wgOut->addHTML($previewhead); - $wgOut->addHTML($previewHTML); - } + $checkboxhtml = $minoredithtml . $watchhtml . '
'; + + $wgOut->addHTML( '
' ); + if ( 'preview' == $formtype) { + $previewOutput = $this->getPreviewText( $isConflict, $isCssJsSubpage ); + if ( $wgUser->getOption('previewontop' ) ) { + $wgOut->addHTML( $previewOutput ); + $wgOut->addHTML( "
\n" ); + } + } + $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 - if( $this->section == "new" ) { - $commentsubject="{$subject}:
"; - $editsummary = ""; + $summarytext = htmlspecialchars( $wgContLang->recodeForEdit( $this->summary ) ); # FIXME + if( $this->section == 'new' ) { + $commentsubject="{$subject}:
"; + $editsummary = ''; + } else { + $commentsubject = ''; + $editsummary="{$summary}:
"; + } + + 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 + $templates = ''; + $articleTemplates = $this->mArticle->getUsedTemplates(); + if ( count( $articleTemplates ) > 0 ) { + $templates = '
'. wfMsg( 'templatesused' ) . '
    '; + foreach ( $articleTemplates as $tpl ) { + if ( $titleObj = Title::makeTitle( NS_TEMPLATE, $tpl ) ) { + $templates .= '
  • ' . $sk->makeLinkObj( $titleObj ) . '
  • '; + } + } + $templates .= '
'; + } + + 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 { - $commentsubject = ""; - $editsummary="{$summary}:
"; + $liveOnclick = ''; } - - if( !$this->preview ) { - # Don't select the edit box on preview; this interferes with seeing what's going on. - $wgOut->setOnloadHandler( "document.editform.wpTextbox1.focus()" ); + + 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 . "" ; } - $wgOut->addHTML( " + else $metadata = "" ; + + + $wgOut->addHTML( << +
{$commentsubject} - +{$metadata}
{$editsummary} {$checkboxhtml} - -  + -{$cancel} | {$edithelp} -

{$copywarn} + +{$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" ); DifferenceEngine::showDiff( $this->textbox2, $this->textbox1, wfMsg( "yourtext" ), wfMsg( "storedversion" ) ); $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 getDiffText() { } - function blockedIPpage() - { - global $wgOut, $wgUser, $wgLang, $wgIP; + /** + * @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"; + } - $wgOut->setPageTitle( wfMsg( "blockedtitle" ) ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); + $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' ); $wgOut->setArticleRelated( false ); $id = $wgUser->blockedBy(); $reason = $wgUser->blockedFor(); - $ip = $wgIP; + $ip = $wgIP; - $name = User::whoIs( $id ); - $link = "[[" . $wgLang->getNsText( Namespace::getUser() ) . + if ( is_numeric( $id ) ) { + $name = User::whoIs( $id ); + } else { + $name = $id; + } + $link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]"; - $wgOut->addWikiText( wfMsg( "blockedtext", $link, $reason, $ip, $name ) ); + $wgOut->addWikiText( wfMsg( 'blockedtext', $link, $reason, $ip, $name ) ); $wgOut->returnToMain( false ); } + /** + * @todo document + */ + function userNotLoggedInPage() { + global $wgOut; + + $wgOut->setPageTitle( wfMsg( 'whitelistedittitle' ) ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->setArticleRelated( false ); + $wgOut->addWikiText( wfMsg( 'whitelistedittext' ) ); + $wgOut->returnToMain( false ); + } - function userNotLoggedInPage() + /** + * @todo document + */ + function spamPage ( $match = false ) { - global $wgOut, $wgUser, $wgLang; - - $wgOut->setPageTitle( wfMsg( "whitelistedittitle" ) ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); + global $wgOut; + $wgOut->setPageTitle( wfMsg( 'spamprotectiontitle' ) ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->setArticleRelated( false ); - $wgOut->addWikiText( wfMsg( "whitelistedittext" ) ); + $wgOut->addWikiText( wfMsg( 'spamprotectiontext' ) ); + 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; @@ -486,7 +839,7 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . # Get MemCached key $skip = false; if ( $wgUseMemCached ) { - $mcKey = "$wgDBname:proxy:ip:$wgIP"; + $mcKey = $wgDBname.':proxy:ip:'.$wgIP; $mcValue = $wgMemc->get( $mcKey ); if ( $mcValue ) { $skip = true; @@ -495,12 +848,12 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . # Fork the processes if ( !$skip ) { - $title = Title::makeTitle( NS_SPECIAL, "Blockme" ); + $title = Title::makeTitle( NS_SPECIAL, 'Blockme' ); $iphash = md5( $wgIP . $wgProxyKey ); - $url = $title->getFullURL( "ip=$iphash" ); + $url = $title->getFullURL( 'ip='.$iphash ); foreach ( $wgProxyPorts as $port ) { - $params = implode( " ", array( + $params = implode( ' ', array( escapeshellarg( $wgProxyScriptPath ), escapeshellarg( $wgIP ), escapeshellarg( $port ), @@ -515,25 +868,208 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . } } - /* private */ function mergeChangesInto( &$text ){ - $oldDate = $this->edittime; - $res = wfQuery("SELECT cur_text FROM cur WHERE cur_id=" . - $this->mTitle->getArticleID() . " FOR UPDATE", DB_WRITE); - $obj = wfFetchObject($res); - - $yourtext = $obj->cur_text; - $ns = $this->mTitle->getNamespace(); - $title = wfStrencode( $this->mTitle->getDBkey() ); - $res = wfQuery("SELECT old_text FROM old WHERE old_namespace = $ns AND ". - "old_title = '{$title}' AND old_timestamp = '{$oldDate}'", DB_WRITE); - $obj = wfFetchObject($res); - if(wfMerge($obj->old_text, $text, $yourtext, $result)){ + /** + * @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; return true; } else { 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 ); + } + } ?>