missing parentheses
[lhc/web/wiklou.git] / includes / Parser.php
index 9efab38..c345e28 100644 (file)
@@ -220,8 +220,12 @@ class Parser
 
                $text = Parser::extractTags("math", $text, $math_content, $uniq_prefix);
                foreach( $math_content as $marker => $content ){
-                       if( $render && $this->mOptions->getUseTeX() ){
-                               $math_content[$marker] = renderMath( $content );
+                       if( $render ) {
+                               if( $this->mOptions->getUseTeX() ) {
+                                       $math_content[$marker] = renderMath( $content );
+                               } else {
+                                       $math_content[$marker] = "<math>$content<math>";
+                               }
                        } else {
                                $math_content[$marker] = "<math>$content</math>";
                        }
@@ -312,18 +316,11 @@ class Parser
                $data = array () ;
                $id = $this->mTitle->getArticleID() ;
 
-               # For existing categories
-               if( $id ) {
-                       $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,links WHERE l_to={$id} AND l_from=cur_id";
-                       $res = wfQuery ( $sql, DB_READ ) ;
-                       while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
-               } else {
-                       # For non-existing categories
-                       $t = wfStrencode( $this->mTitle->getPrefixedDBKey() );
-                       $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,brokenlinks WHERE bl_to='$t' AND bl_from=cur_id" ;
-                       $res = wfQuery ( $sql, DB_READ ) ;
-                       while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
-               }
+               # FIXME: add limits
+               $t = wfStrencode( $this->mTitle->getDBKey() );
+               $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,categorylinks WHERE cl_to='$t' AND cl_from=cur_id ORDER BY cl_sortkey" ;
+               $res = wfQuery ( $sql, DB_READ ) ;
+               while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
 
                # For all pages that link to this category
                foreach ( $data AS $x )
@@ -341,18 +338,14 @@ class Parser
                wfFreeResult ( $res ) ;
 
                # Showing subcategories
-               if ( count ( $children ) > 0 )
-               {
-                       asort ( $children ) ;
+               if ( count ( $children ) > 0 ) {
                        $r .= "<h2>".wfMsg("subcategories")."</h2>\n" ;
                        $r .= implode ( ", " , $children ) ;
                }
 
                # Showing pages in this category
-               if ( count ( $articles ) > 0 )
-               {
+               if ( count ( $articles ) > 0 ) {
                        $ti = $this->mTitle->getText() ;
-                       asort ( $articles ) ;
                        $h =  wfMsg( "category_header", $ti );
                        $r .= "<h2>{$h}</h2>\n" ;
                        $r .= implode ( ", " , $articles ) ;
@@ -543,7 +536,7 @@ class Parser
                return $t ;
        }
 
-       function internalParse( $text, $linestart, $args = array() )
+       function internalParse( $text, $linestart, $args = array(), $isMain=true )
        {
                $fname = "Parser::internalParse";
                wfProfileIn( $fname );
@@ -561,14 +554,14 @@ class Parser
                $text = $this->replaceExternalLinks( $text );
                $text = $this->doTokenizedParser ( $text );
                $text = $this->doTableStuff ( $text ) ;
-               $text = $this->formatHeadings( $text );
+               $text = $this->formatHeadings( $text, $isMain );
                $sk =& $this->mOptions->getSkin();
                $text = $sk->transformContent( $text );
 
                if ( !isset ( $this->categoryMagicDone ) ) {
-                  $text .= $this->categoryMagic () ;
-                  $this->categoryMagicDone = true ;
-                  }
+                       $text .= $this->categoryMagic () ;
+                       $this->categoryMagicDone = true ;
+               }
 
                wfProfileOut( $fname );
                return $text;
@@ -671,6 +664,21 @@ class Parser
                return $s;
        }
 
+       /* private */ function handle4Quotes( &$state, $token )
+       {
+               /* This one makes some assumptions. 
+                * '''Caesar''''s army  => <strong>Caesar</strong>'s army
+                * ''''Caesar'''' was a roman emperor => '<strong>Caesar</strong>' was a roman emperor
+                * These assumptions might be wrong, but any other assumption might be wrong, too.
+                * So here we go */
+               if ( $state["strong"] !== false ) {
+                       return $this->handle3Quotes( $state, $token ) . "'";
+               } else {
+                       return "'" . $this->handle3Quotes( $state, $token );
+               }
+       }
+
+
        /* private */ function handle3Quotes( &$state, $token )
        {
                if ( $state["strong"] !== false ) {
@@ -684,7 +692,7 @@ class Parser
                        $state["strong"] = FALSE;
                } else {
                        $s = "<strong>";
-                       $state["strong"] = isset($token["pos"]) ? $token["pos"] : true;
+                       $state["strong"] = $token["pos"];
                }
                return $s;
        }
@@ -702,7 +710,7 @@ class Parser
                        $state["em"] = FALSE;
                } else {
                        $s = "<em>";
-                       $state["em"] = isset($token["pos"]) ? $token["pos"] : true;
+                       $state["em"] = $token["pos"];
 
                }
                return $s;
@@ -728,7 +736,7 @@ class Parser
                        $state["em"] = $token["pos"];
                } else { # not $em and not $strong
                        $s .= "<strong><em>";
-                       $state["strong"] = $state["em"] = isset($token["pos"]) ? $token["pos"] : true;
+                       $state["strong"] = $state["em"] = $token["pos"];
                }
                return $s;
        }
@@ -826,7 +834,7 @@ class Parser
                                        $txt = "\n<hr />\n";
                                        break;
                                case "'''":
-                                       # This and the three next ones handle quotes
+                                       # This and the four next ones handle quotes
                                        $txt = $this->handle3Quotes( $state, $token );
                                        break;
                                case "''":
@@ -835,10 +843,26 @@ class Parser
                                case "'''''":
                                        $txt = $this->handle5Quotes( $state, $token );
                                        break;
+                               case "''''":
+                                       $txt = $this->handle4Quotes( $state, $token );
+                                       break;
                                case "":
                                        # empty token
                                        $txt="";
                                        break;
+                               case "h": 
+                                       #heading- used to close all unbalanced bold or em tags in this section
+                                       $txt = '';
+                                       if( $state['em'] !== false and 
+                                       ( $state['strong'] === false or $state['em'] > $state['strong'] ) )
+                                       { 
+                                               $s .= '</em>';
+                                               $state['em'] = false;
+                                       }
+                                       if ( $state['strong'] !== false ) $txt .= '</strong>';
+                                       if ( $state['em'] !== false ) $txt .= '</em>';
+                                       $state['strong'] = $state['em'] = false;
+                                       break;
                                case "RFC ":
                                        if ( $tagIsOpen ) {
                                                $txt = "RFC ";
@@ -882,6 +906,19 @@ class Parser
                                $s .= $txt;
                        }
                } #end while
+
+               # make 100% sure all strong and em tags are closed
+               # doBlockLevels often messes the last bit up though, but invalid nesting is better than unclosed tags
+               # tidy solves this though
+               if( $state['em'] !== false and 
+               ( $state['strong'] === false or $state['em'] > $state['strong'] ) )
+               { 
+                       $s .= '</em>';
+                       $state['em'] = false;
+               }
+               if ( $state['strong'] !== false ) $s .= '</strong>';
+               if ( $state['em'] !== false ) $s .= '</em>';
+
                if ( count( $tokenStack ) != 0 )
                {
                        # still objects on stack. opened [[ tag without closing ]] tag.
@@ -973,7 +1010,8 @@ class Parser
                } else {
                        $link = substr( $m[1], 1 );
                }
-               if( "" == $text )
+               $wasblank = ( "" == $text );
+               if( $wasblank )
                        $text = $link;
 
                $nt = Title::newFromText( $link );
@@ -997,7 +1035,13 @@ class Parser
                        if ( $ns == $category ) {
                                $t = $nt->getText() ;
                                $nnt = Title::newFromText ( Namespace::getCanonicalName($category).":".$t ) ;
+                               
+                               $wgLinkCache->suspend(); # Don't save in links/brokenlinks
                                $t = $sk->makeLinkObj( $nnt, $t, "", "" , $prefix );
+                               $wgLinkCache->resume();
+                               
+                               $sortkey = $wasblank ? $this->mTitle->getPrefixedText() : $text;
+                               $wgLinkCache->addCategoryLinkObj( $nt, $sortkey );
                                $this->mOutput->mCategoryLinks[] = $t ;
                                $s .= $prefix . $trail ;
                                return $s ;
@@ -1208,7 +1252,7 @@ class Parser
                                                $inBlockElem = true;
                                        }
                                } else if ( !$inBlockElem ) {
-                                       if ( " " == $t{0} ) {
+                                       if ( " " == $t{0} and trim($t) != '' ) {
                                                // pre
                                                if ($this->mLastSection != 'pre') {
                                                        $paragraphStack = false;
@@ -1503,7 +1547,8 @@ class Parser
 
                        # Run full parser on the included text
                        $text = $this->strip( $text, $this->mStripState );
-                       $text = $this->internalParse( $text, (bool)$newline, $assocArgs );
+                       $text = $this->internalParse( $text, (bool)$newline, $assocArgs, false );
+                       if(!empty($newline)) $text = "\n".$text;
 
                        # Add the result to the strip state for re-inclusion after
                        # the rest of the processing
@@ -1540,26 +1585,34 @@ class Parser
        # Cleans up HTML, removes dangerous tags and attributes
        /* private */ function removeHTMLtags( $text )
        {
-               global $wgUseTidy;
+               global $wgUseTidy, $wgUserHtml;
                $fname = "Parser::removeHTMLtags";
                wfProfileIn( $fname );
-               $htmlpairs = array( # Tags that must be closed
-                       "b", "del", "i", "ins", "u", "font", "big", "small", "sub", "sup", "h1",
-                       "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s",
-                       "strike", "strong", "tt", "var", "div", "center",
-                       "blockquote", "ol", "ul", "dl", "table", "caption", "pre",
-                       "ruby", "rt" , "rb" , "rp", "p"
-               );
-               $htmlsingle = array(
-                       "br", "hr", "li", "dt", "dd"
-               );
-               $htmlnest = array( # Tags that can be nested--??
-                       "table", "tr", "td", "th", "div", "blockquote", "ol", "ul",
-                       "dl", "font", "big", "small", "sub", "sup"
-               );
-               $tabletags = array( # Can only appear inside table
-                       "td", "th", "tr"
-               );
+               
+               if( $wgUserHtml ) {
+                       $htmlpairs = array( # Tags that must be closed
+                               "b", "del", "i", "ins", "u", "font", "big", "small", "sub", "sup", "h1",
+                               "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s",
+                               "strike", "strong", "tt", "var", "div", "center",
+                               "blockquote", "ol", "ul", "dl", "table", "caption", "pre",
+                               "ruby", "rt" , "rb" , "rp", "p"
+                       );
+                       $htmlsingle = array(
+                               "br", "hr", "li", "dt", "dd"
+                       );
+                       $htmlnest = array( # Tags that can be nested--??
+                               "table", "tr", "td", "th", "div", "blockquote", "ol", "ul",
+                               "dl", "font", "big", "small", "sub", "sup"
+                       );
+                       $tabletags = array( # Can only appear inside table
+                               "td", "th", "tr"
+                       );
+               } else {
+                       $htmlpairs = array();
+                       $htmlsingle = array();
+                       $htmlnest = array();
+                       $tabletags = array();
+               }
 
                $htmlsingle = array_merge( $tabletags, $htmlsingle );
                $htmlelements = array_merge( $htmlsingle, $htmlpairs );
@@ -1660,8 +1713,10 @@ class Parser
  *
  */
 
-       /* private */ function formatHeadings( $text )
+       /* private */ function formatHeadings( $text, $isMain=true )
        {
+               global $wgInputEncoding;
+               
                $doNumberHeadings = $this->mOptions->getNumberHeadings();
                $doShowToc = $this->mOptions->getShowToc();
                if( !$this->mTitle->userCanEdit() ) {
@@ -1762,7 +1817,9 @@ class Parser
                        # strip out HTML
                        $canonized_headline = preg_replace( "/<.*?" . ">/","",$canonized_headline );
                        $tocline = trim( $canonized_headline );
-                       $canonized_headline = preg_replace("/[ \\?&\\/<>\\(\\)\\[\\]=,+']+/", '_', html_entity_decode( $tocline));
+                       $canonized_headline = preg_replace("/[ \\?&\\/<>\\(\\)\\[\\]=,+']+/", '_', urlencode( do_html_entity_decode( $tocline, ENT_COMPAT, $wgInputEncoding ) ) );
+                       # strip out urlencoded &nbsp; (inserted for french spaces, e.g. first space in 'something : something')
+                       $canonized_headline = str_replace('%C2%A0','_', $canonized_headline);
                        $refer[$headlineCount] = $canonized_headline;
 
                        # count how many in assoc. array so we can track dupes in anchors
@@ -1828,7 +1885,7 @@ class Parser
                                # $full .= $sk->editSectionLink(0);
                        }
                        $full .= $block;
-                       if( $doShowToc && !$i) {
+                       if( $doShowToc && !$i && $isMain) {
                        # Top anchor now in skin
                                $full = $full.$toc;
                        }