f43d8d4962eccc030da2c177c1a8b7173f4fc6eb
4 if($wgUseTeX) include_once( "Math.php" );
7 var $mHeaders, $mCookies, $mMetatags, $mKeywords;
8 var $mLinktags, $mPagetitle, $mBodytext, $mDebugtext;
9 var $mHTMLtitle, $mRobotpolicy, $mIsarticle, $mPrintable;
10 var $mSubtitle, $mRedirect, $mAutonumber, $mHeadtext;
11 var $mLastModified, $mCategoryLinks;
13 var $mDTopen, $mLastSection; # Used for processing DL, PRE
14 var $mLanguageLinks, $mSupressQuickbar;
18 $this->mHeaders
= $this->mCookies
= $this->mMetatags
=
19 $this->mKeywords
= $this->mLinktags
= array();
20 $this->mHTMLtitle
= $this->mPagetitle
= $this->mBodytext
=
21 $this->mLastSection
= $this->mRedirect
= $this->mLastModified
=
22 $this->mSubtitle
= $this->mDebugtext
= $this->mRobotpolicy
= "";
23 $this->mIsarticle
= $this->mPrintable
= true;
24 $this->mSupressQuickbar
= $this->mDTopen
= $this->mPrintable
= false;
25 $this->mLanguageLinks
= array();
26 $this->mCategoryLinks
= array() ;
27 $this->mAutonumber
= 0;
30 function addHeader( $name, $val ) { array_push( $this->mHeaders
, "$name: $val" ) ; }
31 function addCookie( $name, $val ) { array_push( $this->mCookies
, array( $name, $val ) ); }
32 function redirect( $url ) { $this->mRedirect
= $url; }
34 # To add an http-equiv meta tag, precede the name with "http:"
35 function addMeta( $name, $val ) { array_push( $this->mMetatags
, array( $name, $val ) ); }
36 function addKeyword( $text ) { array_push( $this->mKeywords
, $text ); }
37 function addLink( $rel, $rev, $target ) { array_push( $this->mLinktags
, array( $rel, $rev, $target ) ); }
39 function checkLastModified ( $timestamp )
41 global $wgLang, $wgCachePages, $wgUser;
42 if( !$wgCachePages ) {
43 wfDebug( "CACHE DISABLED\n", false );
46 if( preg_match( '/MSIE ([1-4]|5\.0)/', $_SERVER["HTTP_USER_AGENT"] ) ) {
47 # IE 5.0 has probs with our caching
48 wfDebug( "-- bad client, not caching\n", false );
51 if( $wgUser->getOption( "nocache" ) ) {
52 wfDebug( "USER DISABLED CACHE\n", false );
56 $lastmod = gmdate( "D, j M Y H:i:s", wfTimestamp2Unix(
57 max( $timestamp, $wgUser->mTouched
) ) ) . " GMT";
59 if( $_SERVER["HTTP_IF_MODIFIED_SINCE"] != "" ) {
60 # IE sends sizes after the date for compressed pages:
61 # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
62 # this breaks strtotime().
63 $modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] );
64 $ismodsince = wfUnix2Timestamp( strtotime( $modsince ) );
65 wfDebug( "-- client send If-Modified-Since: " . $modsince . "\n", false );
66 wfDebug( "-- we might send Last-Modified : $lastmod\n", false );
68 if( ($ismodsince >= $timestamp ) and $wgUser->validateCache( $ismodsince ) ) {
69 # Make sure you're in a place you can leave when you call us!
70 header( "HTTP/1.0 304 Not Modified" );
71 header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
72 header( "Cache-Control: private, must-revalidate, max-age=0" );
73 header( "Last-Modified: {$lastmod}" );
74 wfDebug( "CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
77 wfDebug( "READY client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
78 $this->mLastModified
= $lastmod;
81 wfDebug( "We're confused.\n", false );
82 $this->mLastModified
= $lastmod;
86 function setRobotpolicy( $str ) { $this->mRobotpolicy
= $str; }
87 function setHTMLtitle( $name ) { $this->mHTMLtitle
= $name; }
88 function setPageTitle( $name ) { $this->mPagetitle
= $name; }
89 function getPageTitle() { return $this->mPagetitle
; }
90 function setSubtitle( $str ) { $this->mSubtitle
= $str; }
91 function getSubtitle() { return $this->mSubtitle
; }
92 function setArticleFlag( $v ) { $this->mIsarticle
= $v; }
93 function isArticle() { return $this->mIsarticle
; }
94 function setPrintable() { $this->mPrintable
= true; }
95 function isPrintable() { return $this->mPrintable
; }
97 function getLanguageLinks() {
98 global $wgUseNewInterlanguage, $wgTitle, $wgLanguageCode;
99 global $wgDBconnection, $wgDBname, $wgDBintlname;
101 if ( ! $wgUseNewInterlanguage )
102 return $this->mLanguageLinks
;
104 mysql_select_db( $wgDBintlname, $wgDBconnection ) or die(
105 htmlspecialchars(mysql_error()) );
108 $sql = "SELECT * FROM ilinks WHERE lang_from=\"" .
109 "{$wgLanguageCode}\" AND title_from=\"" . $wgTitle->getDBkey() . "\"";
110 $res = mysql_query( $sql, $wgDBconnection );
112 while ( $q = mysql_fetch_object ( $res ) ) {
113 $list[] = $q->lang_to
. ":" . $q->title_to
;
115 mysql_free_result( $res );
116 mysql_select_db( $wgDBname, $wgDBconnection ) or die(
117 htmlspecialchars(mysql_error()) );
122 function supressQuickbar() { $this->mSupressQuickbar
= true; }
123 function isQuickbarSupressed() { return $this->mSupressQuickbar
; }
125 function addHTML( $text ) { $this->mBodytext
.= $text; }
126 function addHeadtext( $text ) { $this->mHeadtext
.= $text; }
127 function debug( $text ) { $this->mDebugtext
.= $text; }
129 # First pass--just handle <nowiki> sections, pass the rest off
130 # to doWikiPass2() which does all the real work.
133 function addWikiText( $text, $linestart = true )
136 wfProfileIn( "OutputPage::addWikiText" );
137 $unique = "3iyZiyA7iMwg5rhxP0Dcc9oTnj8qD1jm1Sfv4";
138 $unique2 = "4LIQ9nXtiYFPCSfitVwDw7EYwQlL4GeeQ7qSO";
139 $unique3 = "fPaA8gDfdLBqzj68Yjg9Hil3qEF8JGO0uszIp";
150 while ( "" != $text ) {
151 $p = preg_split( "/<\\s*nowiki\\s*>/i", $text, 2 );
153 if ( ( count( $p ) < 2 ) ||
( "" == $p[1] ) ) { $text = ""; }
155 $q = preg_split( "/<\\/\\s*nowiki\\s*>/i", $p[1], 2 );
157 $nwlist[$nwsecs] = wfEscapeHTMLTagsOnly($q[0]);
158 $stripped .= $unique;
164 while ( "" != $stripped ) {
165 $p = preg_split( "/<\\s*math\\s*>/i", $stripped, 2 );
167 if ( ( count( $p ) < 2 ) ||
( "" == $p[1] ) ) { $stripped = ""; }
169 $q = preg_split( "/<\\/\\s*math\\s*>/i", $p[1], 2 );
171 $mathlist[$mathsecs] = renderMath($q[0]);
172 $stripped2 .= $unique2;
177 $stripped2 = $stripped;
180 while ( "" != $stripped2 ) {
181 $p = preg_split( "/<\\s*pre\\s*>/i", $stripped2, 2 );
183 if ( ( count( $p ) < 2 ) ||
( "" == $p[1] ) ) { $stripped2 = ""; }
185 $q = preg_split( "/<\\/\\s*pre\\s*>/i", $p[1], 2 );
187 $prelist[$presecs] = "<pre>". wfEscapeHTMLTagsOnly($q[0]). "</pre>";
188 $stripped3 .= $unique3;
193 $text = $this->doWikiPass2( $stripped3, $linestart );
195 $specialChars = array("\\", "$");
196 $escapedChars = array("\\\\", "\\$");
197 for ( $i = 1; $i <= $presecs; ++
$i ) {
198 $text = preg_replace( "/{$unique3}/", str_replace( $specialChars,
199 $escapedChars, $prelist[$i] ), $text, 1 );
202 for ( $i = 1; $i <= $mathsecs; ++
$i ) {
203 $text = preg_replace( "/{$unique2}/", str_replace( $specialChars,
204 $escapedChars, $mathlist[$i] ), $text, 1 );
207 for ( $i = 1; $i <= $nwsecs; ++
$i ) {
208 $text = preg_replace( "/{$unique}/", str_replace( $specialChars,
209 $escapedChars, $nwlist[$i] ), $text, 1 );
211 $this->addHTML( $text );
215 function sendCacheControl() {
217 if( $this->mLastModified
!= "" ) {
218 wfDebug( "** private caching; {$this->mLastModified} **\n", false );
219 header( "Cache-Control: private, must-revalidate, max-age=0" );
220 header( "Last-modified: {$this->mLastModified}" );
222 # We should put in Accept-Encoding, but IE chokes on anything but
223 # User-Agent in a Vary: header (at least through 6.0)
224 header( "Vary: User-Agent" );
227 wfDebug( "** no caching **\n", false );
228 header( "Cache-Control: no-cache" ); # Experimental - see below
229 header( "Pragma: no-cache" );
230 header( "Last-modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
232 header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
235 # Finally, all the text has been munged and accumulated into
236 # the object, let's actually output it:
240 global $wgUser, $wgLang, $wgDebugComments, $wgCookieExpiration;
241 global $wgInputEncoding, $wgOutputEncoding, $wgLanguageCode;
242 wfProfileIn( "OutputPage::output" );
243 $sk = $wgUser->getSkin();
245 wfProfileIn( "OutputPage::output-headers" );
246 $this->sendCacheControl();
248 header( "Content-type: text/html; charset={$wgOutputEncoding}" );
249 header( "Content-language: {$wgLanguageCode}" );
251 if ( "" != $this->mRedirect
) {
252 header( "Location: {$this->mRedirect}" );
257 $exp = time() +
$wgCookieExpiration;
258 foreach( $this->mCookies
as $name => $val ) {
259 setcookie( $name, $val, $exp, "/" );
263 wfProfileIn( "OutputPage::output-middle" );
265 $this->out( $this->headElement() );
267 $this->out( "\n<body" );
268 $ops = $sk->getBodyOptions();
269 foreach ( $ops as $name => $val ) {
270 $this->out( " $name='$val'" );
273 if ( $wgDebugComments ) {
274 $this->out( "<!-- Wiki debugging output:\n" .
275 $this->mDebugtext
. "-->\n" );
277 $this->out( $sk->beforeContent() );
280 wfProfileIn( "OutputPage::output-bodytext" );
281 $this->out( $this->mBodytext
);
283 wfProfileIn( "OutputPage::output-after" );
284 $this->out( $sk->afterContent() );
287 wfProfileOut(); # A hack - we can't report after here
288 $this->out( $this->reportTime() );
290 $this->out( "\n</body></html>" );
296 global $wgInputEncoding, $wgOutputEncoding, $wgLang;
297 if ( 0 == strcmp( $wgInputEncoding, $wgOutputEncoding ) ) {
300 $outs = $wgLang->iconv( $wgInputEncoding, $wgOutputEncoding, $ins );
301 if ( false === $outs ) { $outs = $ins; }
306 function setEncodings()
308 global $HTTP_SERVER_VARS, $wgInputEncoding, $wgOutputEncoding;
309 global $wgUser, $wgLang;
311 $wgInputEncoding = strtolower( $wgInputEncoding );
312 $s = $HTTP_SERVER_VARS['HTTP_ACCEPT_CHARSET'];
314 if( $wgUser->getOption( 'altencoding' ) ) {
315 $wgLang->setAltEncoding();
320 $wgOutputEncoding = strtolower( $wgOutputEncoding );
323 $a = explode( ",", $s );
327 foreach ( $a as $s ) {
328 if ( preg_match( "/(.*);q=(.*)/", $s, $m ) ) {
340 #if ( "*" == $bestset ) { $bestset = "iso-8859-1"; }
341 if ( "*" == $bestset ) { $bestset = $wgOutputEncoding; }
342 $wgOutputEncoding = strtolower( $bestset );
346 $wgOutputEncoding = $wgInputEncoding;
349 function reportTime()
351 global $wgRequestTime, $wgDebugLogFile, $HTTP_SERVER_VARS;
352 global $wgProfiling, $wgProfileStack, $wgUser;
354 list( $usec, $sec ) = explode( " ", microtime() );
355 $now = (float)$sec +
(float)$usec;
357 list( $usec, $sec ) = explode( " ", $wgRequestTime );
358 $start = (float)$sec +
(float)$usec;
359 $elapsed = $now - $start;
361 if ( "" != $wgDebugLogFile ) {
363 if( $wgProfiling and count( $wgProfileStack ) ) {
365 foreach( $wgProfileStack as $ile ) {
366 # "foo::bar 99 0.12345 1 0.23456 2"
367 if( preg_match( '/^(\S+)\s+([0-9]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)/', $ile, $m ) ) {
368 $thisstart = (float)$m[3] +
(float)$m[4] - $start;
369 $thisend = (float)$m[5] +
(float)$m[6] - $start;
370 $thiselapsed = $thisend - $thisstart;
371 $thispercent = $thiselapsed / $elapsed * 100.0;
373 $prof .= sprintf( "\tat %04.3f in %04.3f (%2.1f%%) - %s %s\n",
374 $thisstart, $thiselapsed, $thispercent,
375 str_repeat( "*", $m[2] ), $m[1] );
376 $lasttime = $thistime;
377 #$prof .= "\t(^ $ile)\n";
379 $prof .= "\t?broken? $ile\n";
384 if( $forward = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'] )
385 $forward = " forwarded for $forward";
386 if( $client = $HTTP_SERVER_VARS['HTTP_CLIENT_IP'] )
387 $forward .= " client IP $client";
388 if( $from = $HTTP_SERVER_VARS['HTTP_FROM'] )
389 $forward .= " from $from";
391 $forward = "\t(proxied via {$HTTP_SERVER_VARS['REMOTE_ADDR']}{$forward})";
392 if($wgUser->getId() == 0)
394 $log = sprintf( "%s\t%04.3f\t%s\n",
395 gmdate( "YmdHis" ), $elapsed,
396 urldecode( $HTTP_SERVER_VARS['REQUEST_URI'] . $forward ) );
397 error_log( $log . $prof, 3, $wgDebugLogFile );
399 $com = sprintf( "<!-- Time since request: %01.2f secs. -->",
404 # Note: these arguments are keys into wfMsg(), not text!
406 function errorpage( $title, $msg )
410 $this->mDebugtext
.= "Original title: " .
411 $wgTitle->getPrefixedText() . "\n";
412 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
413 $this->setPageTitle( wfMsg( $title ) );
414 $this->setRobotpolicy( "noindex,nofollow" );
415 $this->setArticleFlag( false );
417 $this->mBodytext
= "";
418 $this->addHTML( "<p>" . wfMsg( $msg ) . "\n" );
419 $this->returnToMain( false );
425 function sysopRequired()
429 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
430 $this->setPageTitle( wfMsg( "sysoptitle" ) );
431 $this->setRobotpolicy( "noindex,nofollow" );
432 $this->setArticleFlag( false );
433 $this->mBodytext
= "";
435 $sk = $wgUser->getSkin();
436 $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );
437 $text = str_replace( "$1", $ap, wfMsg( "sysoptext" ) );
438 $this->addHTML( $text );
439 $this->returnToMain();
442 function developerRequired()
446 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
447 $this->setPageTitle( wfMsg( "developertitle" ) );
448 $this->setRobotpolicy( "noindex,nofollow" );
449 $this->setArticleFlag( false );
450 $this->mBodytext
= "";
452 $sk = $wgUser->getSkin();
453 $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );
454 $text = str_replace( "$1", $ap, wfMsg( "developertext" ) );
455 $this->addHTML( $text );
456 $this->returnToMain();
459 function databaseError( $fname )
461 global $wgUser, $wgCommandLineMode;
463 $this->setPageTitle( wfMsg( "databaseerror" ) );
464 $this->setRobotpolicy( "noindex,nofollow" );
465 $this->setArticleFlag( false );
467 if ( $wgCommandLineMode ) {
468 $msg = wfMsg( "dberrortextcl" );
470 $msg = wfMsg( "dberrortextcl" );
472 $msg = str_replace( "$1", htmlspecialchars( wfLastDBquery() ), $msg );
473 $msg = str_replace( "$2", htmlspecialchars( $fname ), $msg );
474 $msg = str_replace( "$3", wfLastErrno(), $msg );
475 $msg = str_replace( "$4", htmlspecialchars( wfLastError() ), $msg );
477 if ( $wgCommandLineMode ) {
481 $sk = $wgUser->getSkin();
482 $shlink = $sk->makeKnownLink( wfMsg( "searchhelppage" ),
483 wfMsg( "searchingwikipedia" ) );
484 $msg = str_replace( "$5", $shlink, $msg );
486 $this->mBodytext
= $msg;
491 function readOnlyPage( $source = "" )
493 global $wgUser, $wgReadOnlyFile;
495 $this->setPageTitle( wfMsg( "readonly" ) );
496 $this->setRobotpolicy( "noindex,nofollow" );
497 $this->setArticleFlag( false );
499 $reason = implode( "", file( $wgReadOnlyFile ) );
500 $text = str_replace( "$1", $reason, wfMsg( "readonlytext" ) );
503 $rows = $wgUser->getOption( "rows" );
504 $cols = $wgUser->getOption( "cols" );
505 $text .= "</p>\n<textarea cols='$cols' rows='$rows' readonly>" .
506 htmlspecialchars( $source ) . "\n</textarea>";
509 $this->addHTML( $text );
510 $this->returnToMain( false );
513 function fatalError( $message )
515 $this->setPageTitle( wfMsg( "internalerror" ) );
516 $this->setRobotpolicy( "noindex,nofollow" );
517 $this->setArticleFlag( false );
519 $this->mBodytext
= $message;
524 function unexpectedValueError( $name, $val )
526 $msg = str_replace( "$1", $name, wfMsg( "unexpected" ) );
527 $msg = str_replace( "$2", $val, $msg );
528 $this->fatalError( $msg );
531 function fileCopyError( $old, $new )
533 $msg = str_replace( "$1", $old, wfMsg( "filecopyerror" ) );
534 $msg = str_replace( "$2", $new, $msg );
535 $this->fatalError( $msg );
538 function fileRenameError( $old, $new )
540 $msg = str_replace( "$1", $old, wfMsg( "filerenameerror" ) );
541 $msg = str_replace( "$2", $new, $msg );
542 $this->fatalError( $msg );
545 function fileDeleteError( $name )
547 $msg = str_replace( "$1", $name, wfMsg( "filedeleteerror" ) );
548 $this->fatalError( $msg );
551 function fileNotFoundError( $name )
553 $msg = str_replace( "$1", $name, wfMsg( "filenotfound" ) );
554 $this->fatalError( $msg );
557 function returnToMain( $auto = true )
559 global $wgUser, $wgOut, $returnto;
561 $sk = $wgUser->getSkin();
562 if ( "" == $returnto ) {
563 $returnto = wfMsg( "mainpage" );
565 $link = $sk->makeKnownLink( $returnto, "" );
567 $r = str_replace( "$1", $link, wfMsg( "returnto" ) );
569 $wgOut->addMeta( "http:Refresh", "10;url=" .
570 wfLocalUrlE( wfUrlencode( $returnto ) ) );
572 $wgOut->addHTML( "\n<p>$r\n" );
576 function categoryMagic ()
578 global $wgTitle , $wgUseCategoryMagic ;
579 if ( !isset ( $wgUseCategoryMagic ) ||
!$wgUseCategoryMagic ) return ;
580 $id = $wgTitle->getArticleID() ;
581 $cat = ucfirst ( wfMsg ( "category" ) ) ;
582 $ti = $wgTitle->getText() ;
583 $ti = explode ( ":" , $ti , 2 ) ;
584 if ( $cat != $ti[0] ) return "" ;
585 $r = "<br break=all>\n" ;
587 $articles = array() ;
588 $parents = array () ;
589 $children = array() ;
593 $sk = $wgUser->getSkin() ;
594 $sql = "SELECT l_from FROM links WHERE l_to={$id}" ;
595 $res = wfQuery ( $sql ) ;
596 while ( $x = wfFetchObject ( $res ) )
599 # $t->newFromDBkey ( $x->l_from ) ;
600 # $t = $t->getText() ;
602 $y = explode ( ":" , $t , 2 ) ;
603 if ( count ( $y ) == 2 && $y[0] == $cat )
605 array_push ( $children , $sk->makeLink ( $t , $y[1] ) ) ;
607 else array_push ( $articles , $sk->makeLink ( $t ) ) ;
609 wfFreeResult ( $res ) ;
612 if ( count ( $children ) > 0 )
614 asort ( $children ) ;
615 $r .= "<h2>".wfMsg("subcategories")."</h2>\n" ;
616 $r .= implode ( ", " , $children ) ;
620 if ( count ( $articles ) > 0 )
622 asort ( $articles ) ;
623 $h = str_replace ( "$1" , $ti[1] , wfMsg("category_header") ) ;
624 $r .= "<h2>{$h}</h2>\n" ;
625 $r .= implode ( ", " , $articles ) ;
633 function doTableStuff ( $t )
635 $t = explode ( "\n" , $t ) ;
636 $td = array () ; # Is currently a td tag open?
637 $tr = array () ; # Is currently a tr tag open?
638 foreach ( $t AS $k => $x )
641 if ( "{|" == substr ( $x , 0 , 2 ) )
643 $t[$k] = "<table " . substr ( $x , 3 ) . ">" ;
644 array_push ( $td , false ) ;
645 array_push ( $tr , false ) ;
647 else if ( count ( $td ) == 0 ) { } # Don't do any of the following
648 else if ( "|}" == substr ( $x , 0 , 2 ) )
651 if ( array_pop ( $tr ) ) $z = "</tr>" . $z ;
652 if ( array_pop ( $td ) ) $z = "</td>" . $z ;
655 else if ( "|_" == substr ( $x , 0 , 2 ) ) # Caption
657 $z = trim ( substr ( $x , 2 ) ) ;
658 $t[$k] = "<caption>{$z}</caption\n" ;
660 else if ( "|-" == substr ( $x , 0 , 2 ) ) # Allows for |---------------
663 if ( array_pop ( $tr ) ) $z = "</tr>" . $z ;
664 if ( array_pop ( $td ) ) $z = "</td>" . $z ;
666 array_push ( $tr , false ) ;
667 array_push ( $td , false ) ;
669 else if ( "|" == substr ( $x , 0 , 1 ) )
671 $after = substr ( $x , 1 ) ;
672 $after = explode ( "||" , $after ) ;
674 foreach ( $after AS $theline )
677 if ( !array_pop ( $tr ) ) $z = "<tr>\n" ;
678 array_push ( $tr , true ) ;
679 if ( array_pop ( $td ) ) $z = "</td>" . $z ;
680 $y = explode ( "|" , $theline , 2 ) ;
681 if ( count ( $y ) == 1 ) $y = "{$z}<td>{$y[0]}" ;
682 else $y = $y = "{$z}<td {$y[0]}>{$y[1]}" ;
684 array_push ( $td , true ) ;
688 $t = implode ( "\n" , $t ) ;
692 # Well, OK, it's actually about 14 passes. But since all the
693 # hard lifting is done inside PHP's regex code, it probably
694 # wouldn't speed things up much to add a real parser.
696 function doWikiPass2( $text, $linestart )
698 global $wgUser, $wgLang, $wgUseDynamicDates;
699 wfProfileIn( "OutputPage::doWikiPass2" );
701 $text = $this->removeHTMLtags( $text );
702 $text = $this->replaceVariables( $text );
704 $text = preg_replace( "/(^|\n)-----*/", "\\1<hr>", $text );
705 $text = str_replace ( "<HR>", "<hr>", $text );
707 $text = $this->doAllQuotes( $text );
708 $text = $this->doHeadings( $text );
709 $text = $this->doBlockLevels( $text, $linestart );
711 if($wgUseDynamicDates) {
712 $text = $wgLang->replaceDates( $text );
715 $text = $this->replaceExternalLinks( $text );
716 $text = $this->replaceInternalLinks ( $text );
717 $text = $this->doTableStuff ( $text ) ;
719 $text = $this->magicISBN( $text );
720 $text = $this->magicRFC( $text );
721 $text = $this->formatHeadings( $text );
723 $sk = $wgUser->getSkin();
724 $text = $sk->transformContent( $text );
725 $text .= $this->categoryMagic () ;
731 /* private */ function doAllQuotes( $text )
734 $lines = explode( "\r\n", $text );
735 foreach ( $lines as $line ) {
736 $outtext .= $this->doQuotes ( "", $line, "" ) . "\r\n";
741 /* private */ function doQuotes( $pre, $text, $mode )
743 if ( preg_match( "/^(.*)''(.*)$/sU", $text, $m ) ) {
744 $m1_strong = ($m[1] == "") ?
"" : "<strong>{$m[1]}</strong>";
745 $m1_em = ($m[1] == "") ?
"" : "<em>{$m[1]}</em>";
746 if ( substr ($m[2], 0, 1) == "'" ) {
747 $m[2] = substr ($m[2], 1);
749 return $this->doQuotes ( $m[1], $m[2], ($m[1] == "") ?
"both" : "emstrong" );
750 } else if ($mode == "strong") {
751 return $m1_strong . $this->doQuotes ( "", $m[2], "" );
752 } else if (($mode == "emstrong") ||
($mode == "both")) {
753 return $this->doQuotes ( "", $pre.$m1_strong.$m[2], "em" );
754 } else if ($mode == "strongem") {
755 return "<strong>{$pre}{$m1_em}</strong>" . $this->doQuotes ( "", $m[2], "em" );
757 return $m[1] . $this->doQuotes ( "", $m[2], "strong" );
760 if ($mode == "strong") {
761 return $this->doQuotes ( $m[1], $m[2], ($m[1] == "") ?
"both" : "strongem" );
762 } else if ($mode == "em") {
763 return $m1_em . $this->doQuotes ( "", $m[2], "" );
764 } else if ($mode == "emstrong") {
765 return "<em>{$pre}{$m1_strong}</em>" . $this->doQuotes ( "", $m[2], "strong" );
766 } else if (($mode == "strongem") ||
($mode == "both")) {
767 return $this->doQuotes ( "", $pre.$m1_em.$m[2], "strong" );
769 return $m[1] . $this->doQuotes ( "", $m[2], "em" );
773 $text_strong = ($text == "") ?
"" : "<strong>{$text}</strong>";
774 $text_em = ($text == "") ?
"" : "<em>{$text}</em>";
777 } else if ($mode == "em") {
778 return $pre . $text_em;
779 } else if ($mode == "strong") {
780 return $pre . $text_strong;
781 } else if ($mode == "strongem") {
782 return (($pre == "") && ($text == "")) ?
"" : "<strong>{$pre}{$text_em}</strong>";
784 return (($pre == "") && ($text == "")) ?
"" : "<em>{$pre}{$text_strong}</em>";
789 /* private */ function doHeadings( $text )
791 for ( $i = 6; $i >= 1; --$i ) {
792 $h = substr( "======", 0, $i );
793 $text = preg_replace( "/^{$h}([^=]+){$h}(\\s|$)/m",
794 "<h{$i}>\\1</h{$i}>\\2", $text );
799 # Note: we have to do external links before the internal ones,
800 # and otherwise take great care in the order of things here, so
801 # that we don't end up interpreting some URLs twice.
803 /* private */ function replaceExternalLinks( $text )
805 wfProfileIn( "OutputPage::replaceExternalLinks" );
806 $text = $this->subReplaceExternalLinks( $text, "http", true );
807 $text = $this->subReplaceExternalLinks( $text, "https", true );
808 $text = $this->subReplaceExternalLinks( $text, "ftp", false );
809 $text = $this->subReplaceExternalLinks( $text, "gopher", false );
810 $text = $this->subReplaceExternalLinks( $text, "news", false );
811 $text = $this->subReplaceExternalLinks( $text, "mailto", false );
816 /* private */ function subReplaceExternalLinks( $s, $protocol, $autonumber )
818 global $wgUser, $printable;
819 global $wgAllowExternalImages;
822 $unique = "4jzAfzB8hNvf4sqyO9Edd8pSmk9rE2in0Tgw3";
823 $uc = "A-Za-z0-9_\\/~%\\-+&*#?!=()@\\x80-\\xFF";
825 # this is the list of separators that should be ignored if they
826 # are the last character of an URL but that should be included
827 # if they occur within the URL, e.g. "go to www.foo.com, where .."
828 # in this case, the last comma should not become part of the URL,
829 # but in "www.foo.com/123,2342,32.htm" it should.
831 $fnc = "A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF";
832 $images = "gif|png|jpg|jpeg";
834 # PLEASE NOTE: The curly braces { } are not part of the regex,
835 # they are interpreted as part of the string (used to tell PHP
836 # that the content of the string should be inserted there).
837 $e1 = "/(^|[^\\[])({$protocol}:)([{$uc}{$sep}]+)\\/([{$fnc}]+)\\." .
838 "((?i){$images})([^{$uc}]|$)/";
840 $e2 = "/(^|[^\\[])({$protocol}:)(([".$uc."]|[".$sep."][".$uc."])+)([^". $uc . $sep. "]|[".$sep."]|$)/";
841 $sk = $wgUser->getSkin();
843 if ( $autonumber and $wgAllowExternalImages) { # Use img tags only for HTTP urls
844 $s = preg_replace( $e1, "\\1" . $sk->makeImage( "{$unique}:\\3" .
845 "/\\4.\\5", "\\4.\\5" ) . "\\6", $s );
847 $s = preg_replace( $e2, "\\1" . "<a href=\"{$unique}:\\3\"" .
848 $sk->getExternalLinkAttributes( "{$unique}:\\3", wfEscapeHTML(
849 "{$unique}:\\3" ) ) . ">" . wfEscapeHTML( "{$unique}:\\3" ) .
851 $s = str_replace( $unique, $protocol, $s );
853 $a = explode( "[{$protocol}:", " " . $s );
854 $s = array_shift( $a );
855 $s = substr( $s, 1 );
857 $e1 = "/^([{$uc}"."{$sep}]+)](.*)\$/sD";
858 $e2 = "/^([{$uc}"."{$sep}]+)\\s+([^\\]]+)](.*)\$/sD";
860 foreach ( $a as $line ) {
861 if ( preg_match( $e1, $line, $m ) ) {
862 $link = "{$protocol}:{$m[1]}";
864 if ( $autonumber ) { $text = "[" . ++
$this->mAutonumber
. "]"; }
865 else { $text = wfEscapeHTML( $link ); }
866 } else if ( preg_match( $e2, $line, $m ) ) {
867 $link = "{$protocol}:{$m[1]}";
871 $s .= "[{$protocol}:" . $line;
874 if ( $printable == "yes") $paren = " (<i>" . htmlspecialchars ( $link ) . "</i>)";
876 $la = $sk->getExternalLinkAttributes( $link, $text );
877 $s .= "<a href='{$link}'{$la}>{$text}</a>{$paren}{$trail}";
883 /* private */ function replaceInternalLinks( $s )
885 global $wgTitle, $wgUser, $wgLang;
886 global $wgLinkCache, $wgInterwikiMagic, $wgUseCategoryMagic;
887 global $wgNamespacesWithSubpages, $wgLanguageCode;
888 wfProfileIn( $fname = "OutputPage::replaceInternalLinks" );
890 wfProfileIn( "$fname-setup" );
891 $tc = Title
::legalChars() . "#";
892 $sk = $wgUser->getSkin();
894 $a = explode( "[[", " " . $s );
895 $s = array_shift( $a );
896 $s = substr( $s, 1 );
898 $e1 = "/^([{$tc}]+)\\|([^]]+)]](.*)\$/sD";
899 $e2 = "/^([{$tc}]+)]](.*)\$/sD";
902 foreach ( $a as $line ) {
903 wfProfileIn( "$fname-loop" );
904 if ( preg_match( $e1, $line, $m ) ) { # page with alternate text
909 } else if ( preg_match( $e2, $line, $m ) ) { # page with normal text
915 else { # Invalid form; output directly
920 if(substr($m[1],0,1)=="/") { # subpage
921 if(substr($m[1],-1,1)=="/") { # / at end means we don't want the slash to be shown
922 $m[1]=substr($m[1],1,strlen($m[1])-2);
926 $noslash=substr($m[1],1);
928 if($wgNamespacesWithSubpages[$wgTitle->getNamespace()]) { # subpages allowed here
929 $link = $wgTitle->getPrefixedText(). "/" . trim($noslash);
932 } # this might be changed for ugliness reasons
934 $link = $noslash; # no subpage allowed, use standard link
936 } else { # no subpage
940 if ( preg_match( "/^((?:i|x|[a-z]{2,3})(?:-[a-z0-9]+)?|[A-Za-z\\x80-\\xff]+):(.*)\$/", $link, $m ) ) {
941 $pre = strtolower( $m[1] );
943 if ( $wgLang->getNsIndex( $pre ) ==
944 Namespace::getImage() ) {
945 $nt = Title
::newFromText( $suf );
946 $name = $nt->getDBkey();
947 if ( "" == $text ) { $text = $nt->GetText(); }
949 $wgLinkCache->addImageLink( $name );
950 $s .= $sk->makeImageLink( $name,
951 wfImageUrl( $name ), $text );
953 } else if ( "media" == $pre ) {
954 $nt = Title
::newFromText( $suf );
955 $name = $nt->getDBkey();
956 if ( "" == $text ) { $text = $nt->GetText(); }
958 $wgLinkCache->addImageLink( $name );
959 $s .= $sk->makeMediaLink( $name,
960 wfImageUrl( $name ), $text );
962 } else if ( isset($wgUseCategoryMagic) && $wgUseCategoryMagic && $pre == wfMsg ( "category" ) ) {
963 $l = $sk->makeLink ( $pre.":".ucfirst($m[2]) , ucfirst ( $m[2] ) ) ;
964 array_push ( $this->mCategoryLinks
, $l ) ;
967 $l = $wgLang->getLanguageName( $pre );
968 if ( "" == $l or !$wgInterwikiMagic or
969 Namespace::isTalk( $wgTitle->getNamespace() ) ) {
970 if ( "" == $text ) { $text = $link; }
971 $s .= $sk->makeLink( $link, $text, "", $trail );
972 } else if ( $pre != $wgLanguageCode ) {
973 array_push( $this->mLanguageLinks
, "$pre:$suf" );
977 # } else if ( 0 == strcmp( "##", substr( $link, 0, 2 ) ) ) {
978 # $link = substr( $link, 2 );
979 # $s .= "<a name=\"{$link}\">{$text}</a>{$trail}";
981 if ( "" == $text ) { $text = $link; }
982 $s .= $sk->makeLink( $link, $text, "", $trail );
990 # Some functions here used by doBlockLevels()
992 /* private */ function closeParagraph()
995 if ( 0 != strcmp( "p", $this->mLastSection
) &&
996 0 != strcmp( "", $this->mLastSection
) ) {
997 $result = "</" . $this->mLastSection
. ">";
999 $this->mLastSection
= "";
1002 # getCommon() returns the length of the longest common substring
1003 # of both arguments, starting at the beginning of both.
1005 /* private */ function getCommon( $st1, $st2 )
1007 $fl = strlen( $st1 );
1008 $shorter = strlen( $st2 );
1009 if ( $fl < $shorter ) { $shorter = $fl; }
1011 for ( $i = 0; $i < $shorter; ++
$i ) {
1012 if ( $st1{$i} != $st2{$i} ) { break; }
1016 # These next three functions open, continue, and close the list
1017 # element appropriate to the prefix character passed into them.
1019 /* private */ function openList( $char )
1021 $result = $this->closeParagraph();
1023 if ( "*" == $char ) { $result .= "<ul><li>"; }
1024 else if ( "#" == $char ) { $result .= "<ol><li>"; }
1025 else if ( ":" == $char ) { $result .= "<dl><dd>"; }
1026 else if ( ";" == $char ) {
1027 $result .= "<dl><dt>";
1028 $this->mDTopen
= true;
1030 else { $result = "<!-- ERR 1 -->"; }
1035 /* private */ function nextItem( $char )
1037 if ( "*" == $char ||
"#" == $char ) { return "</li><li>"; }
1038 else if ( ":" == $char ||
";" == $char ) {
1040 if ( $this->mDTopen
) { $close = "</dt>"; }
1041 if ( ";" == $char ) {
1042 $this->mDTopen
= true;
1043 return $close . "<dt>";
1045 $this->mDTopen
= false;
1046 return $close . "<dd>";
1049 return "<!-- ERR 2 -->";
1052 /* private */function closeList( $char )
1054 if ( "*" == $char ) { return "</li></ul>"; }
1055 else if ( "#" == $char ) { return "</li></ol>"; }
1056 else if ( ":" == $char ) {
1057 if ( $this->mDTopen
) {
1058 $this->mDTopen
= false;
1059 return "</dt></dl>";
1061 return "</dd></dl>";
1064 return "<!-- ERR 3 -->";
1067 /* private */ function doBlockLevels( $text, $linestart )
1069 wfProfileIn( "OutputPage::doBlockLevels" );
1070 # Parsing through the text line by line. The main thing
1071 # happening here is handling of block-level elements p, pre,
1072 # and making lists from lines starting with * # : etc.
1074 $a = explode( "\n", $text );
1075 $text = $lastPref = "";
1076 $this->mDTopen
= $inBlockElem = false;
1078 if ( ! $linestart ) { $text .= array_shift( $a ); }
1079 foreach ( $a as $t ) {
1080 if ( "" != $text ) { $text .= "\n"; }
1083 $opl = strlen( $lastPref );
1084 $npl = strspn( $t, "*#:;" );
1085 $pref = substr( $t, 0, $npl );
1086 $pref2 = str_replace( ";", ":", $pref );
1087 $t = substr( $t, $npl );
1089 if ( 0 != $npl && 0 == strcmp( $lastPref, $pref2 ) ) {
1090 $text .= $this->nextItem( substr( $pref, -1 ) );
1092 if ( ";" == substr( $pref, -1 ) ) {
1093 $cpos = strpos( $t, ":" );
1094 if ( ! ( false === $cpos ) ) {
1095 $term = substr( $t, 0, $cpos );
1096 $text .= $term . $this->nextItem( ":" );
1097 $t = substr( $t, $cpos +
1 );
1100 } else if (0 != $npl ||
0 != $opl) {
1101 $cpl = $this->getCommon( $pref, $lastPref );
1103 while ( $cpl < $opl ) {
1104 $text .= $this->closeList( $lastPref{$opl-1} );
1107 if ( $npl <= $cpl && $cpl > 0 ) {
1108 $text .= $this->nextItem( $pref{$cpl-1} );
1110 while ( $npl > $cpl ) {
1111 $char = substr( $pref, $cpl, 1 );
1112 $text .= $this->openList( $char );
1114 if ( ";" == $char ) {
1115 $cpos = strpos( $t, ":" );
1116 if ( ! ( false === $cpos ) ) {
1117 $term = substr( $t, 0, $cpos );
1118 $text .= $term . $this->nextItem( ":" );
1119 $t = substr( $t, $cpos +
1 );
1126 if ( 0 == $npl ) { # No prefix--go to paragraph mode
1128 "/(<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6)/i", $t ) ) {
1129 $text .= $this->closeParagraph();
1130 $inBlockElem = true;
1132 if ( ! $inBlockElem ) {
1133 if ( " " == $t{0} ) {
1134 $newSection = "pre";
1135 # $t = wfEscapeHTML( $t );
1137 else { $newSection = "p"; }
1139 if ( 0 == strcmp( "", trim( $oLine ) ) ) {
1140 $text .= $this->closeParagraph();
1141 $text .= "<" . $newSection . ">";
1142 } else if ( 0 != strcmp( $this->mLastSection
,
1144 $text .= $this->closeParagraph();
1145 if ( 0 != strcmp( "p", $newSection ) ) {
1146 $text .= "<" . $newSection . ">";
1149 $this->mLastSection
= $newSection;
1151 if ( $inBlockElem &&
1152 preg_match( "/(<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6)/i", $t ) ) {
1153 $inBlockElem = false;
1159 $text .= $this->closeList( $pref2{$npl-1} );
1162 if ( "" != $this->mLastSection
) {
1163 if ( "p" != $this->mLastSection
) {
1164 $text .= "</" . $this->mLastSection
. ">";
1166 $this->mLastSection
= "";
1172 /* private */ function replaceVariables( $text )
1175 wfProfileIn( "OutputPage:replaceVariables" );
1177 /* As with sigs, use server's local time --
1178 ensure this is appropriate for your audience! */
1180 $mw =& MagicWord
::get( MAG_CURRENTMONTH
);
1181 $text = $mw->replace( $v, $text );
1183 $v = $wgLang->getMonthName( date( "n" ) );
1184 $mw =& MagicWord
::get( MAG_CURRENTMONTHNAME
);
1185 $text = $mw->replace( $v, $text );
1187 $v = $wgLang->getMonthNameGen( date( "n" ) );
1188 $mw =& MagicWord
::get( MAG_CURRENTMONTHNAMEGEN
);
1189 $text = $mw->replace( $v, $text );
1192 $mw = MagicWord
::get( MAG_CURRENTDAY
);
1193 $text = $mw->replace( $v, $text );
1195 $v = $wgLang->getWeekdayName( date( "w" )+
1 );
1196 $mw =& MagicWord
::get( MAG_CURRENTDAYNAME
);
1197 $text = $mw->replace( $v, $text );
1200 $mw =& MagicWord
::get( MAG_CURRENTYEAR
);
1201 $text = $mw->replace( $v, $text );
1203 $v = $wgLang->time( wfTimestampNow(), false );
1204 $mw =& MagicWord
::get( MAG_CURRENTTIME
);
1205 $text = $mw->replace( $v, $text );
1207 $mw =& MagicWord
::get( MAG_NUMBEROFARTICLES
);
1208 if ( $mw->match( $text ) ) {
1209 $v = wfNumberOfArticles();
1210 $text = $mw->replace( $v, $text );
1216 /* private */ function removeHTMLtags( $text )
1218 wfProfileIn( "OutputPage::removeHTMLtags" );
1219 $htmlpairs = array( # Tags that must be closed
1220 "b", "i", "u", "font", "big", "small", "sub", "sup", "h1",
1221 "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s",
1222 "strike", "strong", "tt", "var", "div", "center",
1223 "blockquote", "ol", "ul", "dl", "table", "caption", "pre",
1224 "ruby", "rt" , "rb" , "rp"
1226 $htmlsingle = array(
1227 "br", "p", "hr", "li", "dt", "dd"
1229 $htmlnest = array( # Tags that can be nested--??
1230 "table", "tr", "td", "th", "div", "blockquote", "ol", "ul",
1231 "dl", "font", "big", "small", "sub", "sup"
1233 $tabletags = array( # Can only appear inside table
1237 $htmlsingle = array_merge( $tabletags, $htmlsingle );
1238 $htmlelements = array_merge( $htmlsingle, $htmlpairs );
1240 $htmlattrs = array( # Allowed attributes--no scripting, etc.
1241 "title", "align", "lang", "dir", "width", "height",
1242 "bgcolor", "clear", /* BR */ "noshade", /* HR */
1243 "cite", /* BLOCKQUOTE, Q */ "size", "face", "color",
1244 /* FONT */ "type", "start", "value", "compact",
1245 /* For various lists, mostly deprecated but safe */
1246 "summary", "width", "border", "frame", "rules",
1247 "cellspacing", "cellpadding", "valign", "char",
1248 "charoff", "colgroup", "col", "span", "abbr", "axis",
1249 "headers", "scope", "rowspan", "colspan", /* Tables */
1250 "id", "class", "name", "style" /* For CSS */
1253 # Remove HTML comments
1254 $text = preg_replace( "/<!--.*-->/sU", "", $text );
1256 $bits = explode( "<", $text );
1257 $text = array_shift( $bits );
1258 $tagstack = array(); $tablestack = array();
1260 foreach ( $bits as $x ) {
1261 $prev = error_reporting( E_ALL
& ~
( E_NOTICE | E_WARNING
) );
1262 preg_match( "/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/",
1264 list( $qbar, $slash, $t, $params, $brace, $rest ) = $regs;
1265 error_reporting( $prev );
1268 if ( in_array( $t = strtolower( $t ), $htmlelements ) ) {
1272 if ( ! in_array( $t, $htmlsingle ) &&
1273 ( $ot = array_pop( $tagstack ) ) != $t ) {
1274 array_push( $tagstack, $ot );
1277 if ( $t == "table" ) {
1278 $tagstack = array_pop( $tablestack );
1283 # Keep track for later
1284 if ( in_array( $t, $tabletags ) &&
1285 ! in_array( "table", $tagstack ) ) {
1287 } else if ( in_array( $t, $tagstack ) &&
1288 ! in_array ( $t , $htmlnest ) ) {
1290 } else if ( ! in_array( $t, $htmlsingle ) ) {
1291 if ( $t == "table" ) {
1292 array_push( $tablestack, $tagstack );
1293 $tagstack = array();
1295 array_push( $tagstack, $t );
1297 # Strip non-approved attributes from the tag
1298 $newparams = preg_replace(
1299 "/(\\w+)(\\s*=\\s*([^\\s\">]+|\"[^\">]*\"))?/e",
1300 "(in_array(strtolower(\"\$1\"),\$htmlattrs)?(\"\$1\".((\"x\$3\" != \"x\")?\"=\$3\":'')):'')",
1304 $rest = str_replace( ">", ">", $rest );
1305 $text .= "<$slash$t$newparams$brace$rest";
1309 $text .= "<" . str_replace( ">", ">", $x);
1311 # Close off any remaining tags
1312 while ( $t = array_pop( $tagstack ) ) {
1314 if ( $t == "table" ) { $tagstack = array_pop( $tablestack ); }
1323 * This function accomplishes several tasks:
1324 * 1) Auto-number headings if that option is enabled
1325 * 2) Add an [edit] link to sections for logged in users who have enabled the option
1326 * 3) Add a Table of contents on the top for users who have enabled the option
1327 * 4) Auto-anchor headings
1329 * It loops through all headlines, collects the necessary data, then splits up the
1330 * string and re-inserts the newly formatted headlines.
1333 /* private */ function formatHeadings( $text )
1335 global $wgUser,$wgArticle,$wgTitle,$wpPreview;
1336 $nh=$wgUser->getOption( "numberheadings" );
1337 $st=$wgUser->getOption( "showtoc" );
1338 if(!$wgTitle->userCanEdit()) {
1342 $es=$wgUser->getID() && $wgUser->getOption( "editsection" );
1343 $esr=$wgUser->getID() && $wgUser->getOption( "editsectiononrightclick" );
1345 # if the string __NOTOC__ (not case-sensitive) occurs in the HTML, do not
1347 $mw =& MagicWord
::get( MAG_NOTOC
);
1348 $st = ! $mw->matchAndRemove( $text );
1350 # never add the TOC to the Main Page. This is an entry page that should not
1351 # be more than 1-2 screens large anyway
1352 if($wgTitle->getPrefixedText()==wfMsg("mainpage")) {$st=0;}
1354 # We need this to perform operations on the HTML
1355 $sk=$wgUser->getSkin();
1357 # Get all headlines for numbering them and adding funky stuff like [edit]
1359 preg_match_all("/<H([1-6])(.*?>)(.*?)<\/H[1-6]>/i",$text,$matches);
1364 # Ugh .. the TOC should have neat indentation levels which can be
1365 # passed to the skin functions. These are determined here
1366 foreach($matches[3] as $headline) {
1367 if($level) { $prevlevel=$level;}
1368 $level=$matches[1][$c];
1369 if(($nh||
$st) && $prevlevel && $level>$prevlevel) {
1371 $h[$level]=0; // reset when we enter a new level
1372 $toc.=$sk->tocIndent($level-$prevlevel);
1373 $toclevel+
=$level-$prevlevel;
1376 if(($nh||
$st) && $level<$prevlevel) {
1377 $h[$level+
1]=0; // reset when we step back a level
1378 $toc.=$sk->tocUnindent($prevlevel-$level);
1379 $toclevel-=$prevlevel-$level;
1382 $h[$level]++
; // count number of headlines for each level
1385 for($i=1;$i<=$level;$i++
) {
1387 if($dot) {$numbering.=".";}
1395 $canonized_headline=preg_replace("/<.*?>/","",$headline); // strip out HTML
1396 $tocline=$canonized_headline;
1397 $canonized_headline=str_replace('"',"",$canonized_headline);
1398 $canonized_headline=str_replace(" ","_",trim($canonized_headline));
1399 $refer[$c]=$canonized_headline;
1400 $refers[$canonized_headline]++
; // count how many in assoc. array so we can track dupes in anchors
1401 $refcount[$c]=$refers[$canonized_headline];
1403 $tocline=$numbering ." ". $tocline;
1405 $headline=$numbering . " " . $headline; // the two are different if the line contains a link
1408 $anchor=$canonized_headline;
1409 if($refcount[$c]>1) {$anchor.="_".$refcount[$c];}
1411 $toc.=$sk->tocLine($anchor,$tocline,$toclevel);
1413 if($es && !isset($wpPreview)) {
1414 $head[$c].=$sk->editSectionLink($c+
1);
1416 $head[$c].="<H".$level.$matches[2][$c]
1417 ."<a name=\"".$anchor."\">"
1421 if($esr && !isset($wpPreview)) {
1422 $head[$c]=$sk->editSectionScript($c+
1,$head[$c]);
1431 $toc.=$sk->tocUnindent($toclevel);
1432 $toc=$sk->tocTable($toc);
1435 // split up and insert constructed headlines
1437 $blocks=preg_split("/<H[1-6].*?>.*?<\/H[1-6]>/i",$text);
1441 foreach($blocks as $block) {
1442 if(($es) && !isset($wpPreview) && $c>0 && $i==0) {
1443 # This is the [edit] link that appears for the top block of text when
1444 # section editing is enabled
1445 $full.=$sk->editSectionLink(0);
1448 if($st && $toclines>3 && !$i) {
1449 # Let's add a top anchor just in case we want to link to the top of the page
1450 $full="<a name=\"top\"></a>".$full.$toc;
1459 /* private */ function magicISBN( $text )
1463 $a = split( "ISBN ", " $text" );
1464 if ( count ( $a ) < 2 ) return $text;
1465 $text = substr( array_shift( $a ), 1);
1466 $valid = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1468 foreach ( $a as $x ) {
1469 $isbn = $blank = "" ;
1470 while ( " " == $x{0} ) {
1472 $x = substr( $x, 1 );
1474 while ( strstr( $valid, $x{0} ) != false ) {
1476 $x = substr( $x, 1 );
1478 $num = str_replace( "-", "", $isbn );
1479 $num = str_replace( " ", "", $num );
1482 $text .= "ISBN $blank$x";
1484 $text .= "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
1485 "Booksources"), "isbn={$num}" ) . "\" CLASS=\"internal\">ISBN $isbn</a>";
1492 /* private */ function magicRFC( $text )
1497 /* private */ function headElement()
1499 global $wgDocType, $wgDTD, $wgUser, $wgLanguageCode, $wgOutputEncoding, $wgLang;
1501 $ret = "<!DOCTYPE HTML PUBLIC \"$wgDocType\"\n \"$wgDTD\">\n";
1503 if ( "" == $this->mHTMLtitle
) {
1504 $this->mHTMLtitle
= $this->mPagetitle
;
1506 $rtl = $wgLang->isRTL() ?
" dir='RTL'" : "";
1507 $ret .= "<html lang=\"$wgLanguageCode\"$rtl><head><title>{$this->mHTMLtitle}</title>\n";
1508 array_push( $this->mMetatags
, array( "http:Content-type", "text/html; charset={$wgOutputEncoding}" ) );
1509 foreach ( $this->mMetatags
as $tag ) {
1510 if ( 0 == strcasecmp( "http:", substr( $tag[0], 0, 5 ) ) ) {
1512 $tag[0] = substr( $tag[0], 5 );
1516 $ret .= "<meta $a=\"{$tag[0]}\" content=\"{$tag[1]}\">\n";
1518 $p = $this->mRobotpolicy
;
1519 if ( "" == $p ) { $p = "index,follow"; }
1520 $ret .= "<meta name=\"robots\" content=\"$p\">\n";
1522 if ( count( $this->mKeywords
) > 0 ) {
1523 $ret .= "<meta name=\"keywords\" content=\"" .
1524 implode( ",", $this->mKeywords
) . "\">\n";
1526 foreach ( $this->mLinktags
as $tag ) {
1528 if ( "" != $tag[0] ) { $ret .= "rel=\"{$tag[0]}\" "; }
1529 if ( "" != $tag[1] ) { $ret .= "rev=\"{$tag[1]}\" "; }
1530 $ret .= "href=\"{$tag[2]}\">\n";
1532 $sk = $wgUser->getSkin();
1533 $ret .= $sk->getHeadScripts();
1534 $ret .= $sk->getUserStyles();
1536 $ret .= "</head>\n";