Loudblog PHP Cross Reference Blogging Systems

Source: /loudblog/inc/markuphelp/textile.php - 948 lines - 31437 bytes - Summary - Text - Print

Description: Example: get XHTML from a given Textile-markup string ($string)

   1  <?php
   2  
   3  /**
   4   * Example: get XHTML from a given Textile-markup string ($string)
   5   *
   6   *        $textile = new Textile;
   7   *        echo $textile->TextileThis($string);
   8   *
   9   */
  10  
  11  /*
  12  
  13  _____________
  14  T E X T I L E
  15  
  16  A Humane Web Text Generator
  17  
  18  Version 2.0 beta
  19  
  20  Copyright (c) 2003-2004, Dean Allen <dean@textism.com>
  21  All rights reserved.
  22  
  23  Thanks to Carlo Zottmann <carlo@g-blog.net> for refactoring 
  24  Textile's procedural code into a class framework
  25  
  26  _____________
  27  L I C E N S E
  28  
  29  Redistribution and use in source and binary forms, with or without
  30  modification, are permitted provided that the following conditions are met:
  31  
  32  * Redistributions of source code must retain the above copyright notice,
  33    this list of conditions and the following disclaimer.
  34  
  35  * Redistributions in binary form must reproduce the above copyright notice,
  36    this list of conditions and the following disclaimer in the documentation
  37    and/or other materials provided with the distribution.
  38  
  39  * Neither the name Textile nor the names of its contributors may be used to
  40    endorse or promote products derived from this software without specific
  41    prior written permission.
  42  
  43  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  44  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  45  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  46  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  47  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  48  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  49  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  50  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  51  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  52  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  53  POSSIBILITY OF SUCH DAMAGE.
  54  
  55  _________
  56  U S A G E
  57  
  58  Block modifier syntax:
  59  
  60      Header: h(1-6).
  61      Paragraphs beginning with 'hn. ' (where n is 1-6) are wrapped in header tags.
  62      Example: h1. Header... -> <h1>Header...</h1>
  63  
  64      Paragraph: p. (also applied by default)
  65      Example: p. Text -> <p>Text</p>
  66  
  67      Blockquote: bq.
  68      Example: bq. Block quotation... -> <blockquote>Block quotation...</blockquote>
  69  
  70      Blockquote with citation: bq.:http://citation.url
  71      Example: bq.:http://textism.com/ Text...
  72      ->    <blockquote cite="http://textism.com">Text...</blockquote>
  73  
  74      Footnote: fn(1-100).
  75      Example: fn1. Footnote... -> <p id="fn1">Footnote...</p>
  76  
  77      Numeric list: #, ##
  78      Consecutive paragraphs beginning with # are wrapped in ordered list tags.
  79      Example: <ol><li>ordered list</li></ol>
  80  
  81      Bulleted list: *, **
  82      Consecutive paragraphs beginning with * are wrapped in unordered list tags.
  83      Example: <ul><li>unordered list</li></ul>
  84  
  85  Phrase modifier syntax:
  86  
  87             _emphasis_   ->   <em>emphasis</em>
  88             __italic__   ->   <i>italic</i>
  89               *strong*   ->   <strong>strong</strong>
  90               **bold**   ->   <b>bold</b>
  91           ??citation??   ->   <cite>citation</cite>
  92         -deleted text-   ->   <del>deleted</del>
  93        +inserted text+   ->   <ins>inserted</ins>
  94          ^superscript^   ->   <sup>superscript</sup>
  95            ~subscript~   ->   <sub>subscript</sub>
  96                 @code@   ->   <code>computer code</code>
  97            %(bob)span%   ->   <span class="bob">span</span>
  98  
  99          ==notextile==   ->   leave text alone (do not format)
 100  
 101         "linktext":url   ->   <a href="url">linktext</a>
 102   "linktext(title)":url  ->   <a href="url" title="title">linktext</a>
 103  
 104             !imageurl!   ->   <img src="imageurl" />
 105    !imageurl(alt text)!  ->   <img src="imageurl" alt="alt text" />
 106      !imageurl!:linkurl  ->   <a href="linkurl"><img src="imageurl" /></a>
 107  
 108  ABC(Always Be Closing)  ->   <acronym title="Always Be Closing">ABC</acronym>
 109  
 110  
 111  Table syntax:
 112  
 113      Simple tables:
 114  
 115          |a|simple|table|row|
 116          |And|Another|table|row|
 117  
 118          |_. A|_. table|_. header|_.row|
 119          |A|simple|table|row|
 120  
 121      Tables with attributes:
 122  
 123          table{border:1px solid black}.
 124          {background:#ddd;color:red}. |{}| | | |
 125  
 126  
 127  Applying Attributes:
 128  
 129      Most anywhere Textile code is used, attributes such as arbitrary css style,
 130      css classes, and ids can be applied. The syntax is fairly consistent.
 131  
 132      The following characters quickly alter the alignment of block elements:
 133  
 134          <  ->  left align    ex. p<. left-aligned para
 135          >  ->  right align       h3>. right-aligned header 3
 136          =  ->  centred           h4=. centred header 4
 137          <> ->  justified         p<>. justified paragraph
 138  
 139      These will change vertical alignment in table cells:
 140  
 141          ^  ->  top         ex. |^. top-aligned table cell|
 142          -  ->  middle          |-. middle aligned|
 143          ~  ->  bottom          |~. bottom aligned cell|
 144  
 145      Plain (parentheses) inserted between block syntax and the closing dot-space
 146      indicate classes and ids:
 147  
 148          p(hector). paragraph -> <p class="hector">paragraph</p>
 149  
 150          p(#fluid). paragraph -> <p id="fluid">paragraph</p>
 151  
 152          (classes and ids can be combined)
 153          p(hector#fluid). paragraph -> <p class="hector" id="fluid">paragraph</p>
 154  
 155      Curly {brackets} insert arbitrary css style
 156  
 157          p{line-height:18px}. paragraph -> <p style="line-height:18px">paragraph</p>
 158  
 159          h3{color:red}. header 3 -> <h3 style="color:red">header 3</h3>
 160  
 161      Square [brackets] insert language attributes
 162  
 163          p[no]. paragraph -> <p lang="no">paragraph</p>
 164  
 165          %[fr]phrase% -> <span lang="fr">phrase</span>
 166  
 167      Usually Textile block element syntax requires a dot and space before the block
 168      begins, but since lists don't, they can be styled just using braces
 169  
 170          #{color:blue} one  ->  <ol style="color:blue">
 171          # big                   <li>one</li>
 172          # list                  <li>big</li>
 173                                  <li>list</li>
 174                                 </ol>
 175  
 176      Using the span tag to style a phrase
 177  
 178          It goes like this, %{color:red}the fourth the fifth%
 179                -> It goes like this, <span style="color:red">the fourth the fifth</span>
 180  
 181  */
 182  
 183  class Textile
 184  {
 185      var $hlgn;
 186      var $vlgn;
 187      var $clas;
 188      var $lnge;
 189      var $styl;
 190      var $cspn;
 191      var $rspn;
 192      var $a;
 193      var $s;
 194      var $c;
 195      var $pnct;
 196      var $rel;
 197  
 198  // -------------------------------------------------------------
 199      function Textile()
 200      {
 201          $this->hlgn = "(?:\<(?!>)|(?<!<)\>|\<\>|\=|[()]+)";
 202          $this->vlgn = "[\-^~]";
 203          $this->clas = "(?:\([^)]+\))";
 204          $this->lnge = "(?:\[[^]]+\])";
 205          $this->styl = "(?:\{[^}]+\})";
 206          $this->cspn = "(?:\\\\\d+)";
 207          $this->rspn = "(?:\/\d+)";
 208          $this->a = "(?:{$this->hlgn}?{$this->vlgn}?|{$this->vlgn}?{$this->hlgn}?)";
 209          $this->s = "(?:{$this->cspn}?{$this->rspn}?|{$this->rspn}?{$this->cspn}?)";
 210          $this->c = "(?:{$this->clas}?{$this->styl}?{$this->lnge}?|{$this->styl}?{$this->lnge}?{$this->clas}?|{$this->lnge}?{$this->styl}?{$this->clas}?)";
 211          $this->pnct = '[\!"#\$%&\'()\*\+,\-\./:;<=>\?@\[\\\]\^_`{\|}\~]';
 212  
 213      }
 214  
 215  // -------------------------------------------------------------
 216      function TextileThis($text, $lite='', $encode='', $noimage='', $strict='', $rel='')
 217      {
 218          if (get_magic_quotes_gpc())
 219              $text = stripslashes($text);
 220  
 221          if ($rel)
 222             $this->rel = ' rel="'.$rel.'" ';
 223  
 224          $text = $this->incomingEntities($text);
 225          $text = $this->encodeEntities($text);
 226          
 227          if ($encode) {
 228              $text = str_replace("x%x%", "&#38;", $text);
 229              return $text;
 230          } else {
 231          
 232              if(!$strict) {
 233                  $text = $this->fixEntities($text);
 234                  $text = $this->cleanWhiteSpace($text);
 235              }
 236      
 237              $text = $this->getRefs($text);
 238      
 239              $text = $this->noTextile($text);
 240              $text = $this->links($text);
 241              if (!$noimage) {
 242                  $text = $this->image($text);
 243              }
 244              $text = $this->code($text);
 245              $text = $this->span($text);
 246              $text = $this->superscript($text);
 247              $text = $this->footnoteRef($text);
 248              $text = $this->glyphs($text);
 249              $text = $this->retrieve($text);
 250      
 251              if (!$lite) {
 252                  $text = $this->lists($text);
 253                  $text = $this->table($text);
 254                  $text = $this->block($text);
 255              }
 256  
 257                  // clean up <notextile>
 258              $text = preg_replace('/<\/?notextile>/', "", $text);
 259      
 260                  // turn the temp char back to an ampersand entity
 261              $text = str_replace("x%x%", "&#38;", $text);
 262      
 263                  // just to be tidy
 264              $text = str_replace("<br />", "<br />\n", $text);
 265      
 266              return $text;
 267            }
 268      }
 269  
 270  // -------------------------------------------------------------
 271      function pba($in, $element = "") // "parse block attributes"
 272      {
 273          $style = '';
 274          $class = '';
 275          $lang = '';
 276          $colspan = '';
 277          $rowspan = '';
 278          $id = '';
 279          $atts = '';
 280  
 281          if (!empty($in)) {
 282              $matched = $in;
 283              if ($element == 'td') {
 284                  if (preg_match("/\\\\(\d+)/", $matched, $csp)) $colspan = $csp[1];
 285                  if (preg_match("/\/(\d+)/", $matched, $rsp)) $rowspan = $rsp[1];
 286  
 287                  if (preg_match("/($this->vlgn)/", $matched, $vert))
 288                      $style[] = "vertical-align:" . $this->vAlign($vert[1]) . ";";
 289              }
 290  
 291              if (preg_match("/\{([^}]*)\}/", $matched, $sty)) {
 292                  $style[] = $sty[1] . ';';
 293                  $matched = str_replace($sty[0], '', $matched);
 294              }
 295  
 296              if (preg_match("/\[([^)]+)\]/U", $matched, $lng)) {
 297                  $lang = $lng[1];
 298                  $matched = str_replace($lng[0], '', $matched);
 299              }
 300  
 301              if (preg_match("/\(([^()]+)\)/U", $matched, $cls)) {
 302                  $class = $cls[1];
 303                  $matched = str_replace($cls[0], '', $matched);
 304              }
 305  
 306              if (preg_match("/([(]+)/", $matched, $pl)) {
 307                  $style[] = "padding-left:" . strlen($pl[1]) . "em;";
 308                  $matched = str_replace($pl[0], '', $matched);
 309              }
 310  
 311              if (preg_match("/([)]+)/", $matched, $pr)) {
 312                  // $this->dump($pr);
 313                  $style[] = "padding-right:" . strlen($pr[1]) . "em;";
 314                  $matched = str_replace($pr[0], '', $matched);
 315              }
 316  
 317              if (preg_match("/($this->hlgn)/", $matched, $horiz))
 318                  $style[] = "text-align:" . $this->hAlign($horiz[1]) . ";";
 319  
 320              if (preg_match("/^(.*)#(.*)$/", $class, $ids)) {
 321                  $id = $ids[2];
 322                  $class = $ids[1];
 323              }
 324  
 325              return join('',array(
 326                  ($style)   ? ' style="'   . join("", $style) .'"':'',
 327                  ($class)   ? ' class="'   . $class           .'"':'',
 328                  ($lang)    ? ' lang="'    . $lang            .'"':'',
 329                  ($id)      ? ' id="'      . $id              .'"':'',
 330                  ($colspan) ? ' colspan="' . $colspan         .'"':'',
 331                  ($rowspan) ? ' rowspan="' . $rowspan         .'"':''
 332              ));
 333          }
 334          return '';
 335      }
 336  
 337  // -------------------------------------------------------------
 338      function table($text)
 339      {
 340          $text = $text . "\n\n";
 341          return preg_replace_callback("/^(?:table(_?{$this->s}{$this->a}{$this->c})\. ?\n)?^({$this->a}{$this->c}\.? ?\|.*\|)\n\n/smU", 
 342             array(&$this, "fTable"), $text);
 343      }
 344  
 345  // -------------------------------------------------------------
 346      function fTable($matches)
 347      {
 348          $tatts = $this->pba($matches[1], 'table');
 349  
 350          foreach(preg_split("/\|$/m", $matches[2], -1, PREG_SPLIT_NO_EMPTY) as $row) {
 351              if (preg_match("/^($this->a$this->c\. )(.*)/m", $row, $rmtch)) {
 352                  $ratts = $this->pba($rmtch[1], 'tr');
 353                  $row = $rmtch[2];
 354              } else $ratts = '';
 355  
 356              foreach(explode("|", $row) as $cell) {
 357                  $ctyp = "d";
 358                  if (preg_match("/^_/", $cell)) $ctyp = "h";
 359                  if (preg_match("/^(_?$this->s$this->a$this->c\. )(.*)/", $cell, $cmtch)) {
 360                      $catts = $this->pba($cmtch[1], 'td');
 361                      $cell = $cmtch[2];
 362                  } else $catts = '';
 363  
 364                  if (trim($cell) != '')
 365                      $cells[] = "\t\t\t<t$ctyp$catts>$cell</t$ctyp>";
 366              }
 367              $rows[] = "\t\t<tr$ratts>\n" . join("\n", $cells) . "\n\t\t</tr>";
 368              unset($cells, $catts);
 369          }
 370          return "\t<table$tatts>\n" . join("\n", $rows) . "\n\t</table>\n\n";
 371      }
 372  
 373  // -------------------------------------------------------------
 374      function lists($text)
 375      {
 376          return preg_replace_callback("/^([#*]+$this->c .*)$(?![^#*])/smU", array(&$this, "fList"), $text);
 377      }
 378  
 379  // -------------------------------------------------------------
 380      function fList($m)
 381      {
 382          $text = explode("\n", $m[0]);
 383          foreach($text as $line) {
 384              $nextline = next($text);
 385              if (preg_match("/^([#*]+)($this->a$this->c) (.*)$/s", $line, $m)) {
 386                  list(, $tl, $atts, $content) = $m;
 387                  $nl = preg_replace("/^([#*]+)\s.*/", "$1", $nextline);
 388                  if (!isset($lists[$tl])) {
 389                      $lists[$tl] = true;
 390                      $atts = $this->pba($atts);
 391                      $line = "\t<" . $this->lT($tl) . "l$atts>\n\t<li>" . $content;
 392                  } else {
 393                      $line = "\t\t<li>" . $content;
 394                  }
 395  
 396                  if ($nl === $tl) {
 397                      $line .= "</li>";
 398                  } elseif($nl=="*" or $nl=="#") {
 399                      $line .= "</li>\n\t</".$this->lT($tl)."l>\n\t</li>";
 400                      unset($lists[$tl]);
 401                  }
 402                  if (!$nl) {
 403                      foreach($lists as $k => $v) {
 404                          $line .= "</li>\n\t</" . $this->lT($k) . "l>";
 405                          unset($lists[$k]);
 406                      }
 407                  }
 408              }
 409              $out[] = $line;
 410          }
 411          return join("\n", $out);
 412      }
 413  
 414  // -------------------------------------------------------------
 415      function lT($in)
 416      {
 417          return preg_match("/^#+/", $in) ? 'o' : 'u';
 418      }
 419  
 420  // -------------------------------------------------------------
 421      function block($text)
 422      {
 423          $pre = $php = false;
 424          $find = array('bq', 'h[1-6]', 'fn\d+', 'p');
 425  
 426          $text = preg_replace("/(.+)\n(?![#*\s|])/",
 427              "$1<br />", $text);
 428  
 429          $text = explode("\n", $text);
 430          array_push($text, " ");
 431  
 432          foreach($text as $line) {
 433              if (preg_match('/<pre>/i', $line)) {
 434                  $pre = true;
 435              }
 436              elseif (preg_match('/<txp:php>/i', $line)) {
 437                  $php = true;
 438              }
 439  
 440  
 441              foreach($find as $tag) {
 442                  $line = ($pre == false and $php == false)
 443                  ? preg_replace_callback("/^($tag)($this->a$this->c)\.(?::(\S+))? (.*)$/",
 444                      array(&$this, "fBlock"), $line)
 445                  : $line;
 446              }
 447  
 448              $line = (!$php) ? preg_replace('/^(?!\t|<\/?pre|<\/?code|$| )(.*)/', "\t<p>$1</p>", $line) : $line;
 449  
 450              $line = ($pre or $php) ? str_replace("<br />", "\n", $line):$line;
 451              if (preg_match('/<\/pre>/i', $line)) {
 452                  $pre = false;
 453              }
 454              elseif (preg_match('/<\/txp:php>/i', $line)) {
 455          $php = false;
 456              }
 457  
 458              $out[] = $line;
 459          }
 460          return join("\n", $out);
 461      }
 462  
 463  // -------------------------------------------------------------
 464      function fBlock($m)
 465      {
 466          // $this->dump($m);
 467          list(, $tag, $atts, $cite, $content) = $m;
 468  
 469          $atts = $this->pba($atts);
 470  
 471          if (preg_match("/fn(\d+)/", $tag, $fns)) {
 472              $tag = 'p';
 473              $atts .= ' id="fn' . $fns[1] . '"';
 474              $content = '<sup>' . $fns[1] . '</sup> ' . $content;
 475          }
 476  
 477          $start = "\t<$tag";
 478          $end = "</$tag>";
 479  
 480          if ($tag == "bq") {
 481              $cite = $this->checkRefs($cite);
 482              $cite = ($cite != '') ? ' cite="' . $cite . '"' : '';
 483              $start = "\t<blockquote$cite>\n\t\t<p";
 484              $end = "</p>\n\t</blockquote>";
 485          }
 486  
 487          return "$start$atts>$content$end";
 488      }
 489  
 490  // -------------------------------------------------------------
 491      function span($text)
 492      {
 493          $qtags = array('\*','\*\*','\?\?','-','__','_','%','\+','~');
 494  
 495          foreach($qtags as $f) {
 496              $text = preg_replace_callback("/
 497                  (?<=^|\s|[[:punct:]]|[{([])
 498                  ($f)
 499                  ($this->c)
 500                  (?::(\S+))?
 501                  ([\w<&].*[\w])
 502                  ([[:punct:];]*)
 503                  $f
 504                  (?=[])}]|[[:punct:]]+|\s|$)
 505              /xmU", array(&$this, "fSpan"), $text);
 506          }
 507          return $text;
 508      }
 509  
 510  // -------------------------------------------------------------
 511      function fSpan($m)
 512      {
 513          $qtags = array(
 514              '*'  => 'strong',
 515              '**' => 'b',
 516              '??' => 'cite',
 517              '_'  => 'em',
 518              '__' => 'i',
 519              '-'  => 'del',
 520              '%'  => 'span',
 521              '+'  => 'ins',
 522              '~'  => 'sub'
 523          );
 524  
 525          list(, $tag, $atts, $cite, $content, $end) = $m;
 526          $tag = $qtags[$tag];
 527          $atts = $this->pba($atts);
 528          $atts .= ($cite != '') ? 'cite="' . $cite . '"' : '';
 529  
 530          $out = "<$tag$atts>$content$end</$tag>";
 531  
 532  //        $this->dump($out);
 533  
 534          return $out;
 535      
 536      }
 537  
 538  // -------------------------------------------------------------
 539      function links($text)
 540      {
 541          return preg_replace_callback('/
 542              ([\s[{(]|[[:punct:]])?       # $pre
 543              "                            # start
 544              (' . $this->c . ')           # $atts
 545              ([^"]+)                      # $text
 546              \s?
 547              (?:\(([^)]+)\)(?="))?        # $title
 548              ":
 549              (\S+\b)                      # $url
 550              (\/)?                        # $slash
 551              ([^\w\/;]*)                  # $post
 552              (?=\s|$)
 553          /Ux', array(&$this, "fLink"), $text);
 554      }
 555  
 556  // -------------------------------------------------------------
 557      function fLink($m)
 558      {
 559          list(, $pre, $atts, $text, $title, $url, $slash, $post) = $m;
 560  
 561          $url = $this->checkRefs($url);
 562  
 563          $atts = $this->pba($atts);
 564          $atts .= ($title != '') ? ' title="' . $title . '"' : '';
 565  
 566          $atts = ($atts) ? $this->shelve($atts) : '';
 567  
 568          $out = $pre . '<a href="' . $url . $slash . '"' . $atts . $this->rel . '>' . $text . '</a>' . $post;
 569  
 570          // $this->dump($out);
 571          return $out;
 572  
 573      }
 574  
 575  // -------------------------------------------------------------
 576      function getRefs($text)
 577      {
 578          return preg_replace_callback("/(?<=^|\s)\[(.+)\]((?:http:\/\/|\/)\S+)(?=\s|$)/U",
 579              array(&$this, "refs"), $text);
 580      }
 581      // -------------------------------------------------------------
 582  
 583  function refs($m)
 584      {
 585          list(, $flag, $url) = $m;
 586          $this->urlrefs[$flag] = $url;
 587          return '';
 588      }
 589  
 590  // -------------------------------------------------------------
 591      function checkRefs($text)
 592      {
 593          return (isset($this->urlrefs[$text])) ? $this->urlrefs[$text] : $text;
 594      }
 595  
 596  // -------------------------------------------------------------
 597      function image($text)
 598      {
 599          return preg_replace_callback("/
 600              \!                 # opening !
 601              (\<|\=|\>)?        # optional alignment atts
 602              ($this->c)         # optional style,class atts
 603              (?:\. )?           # optional dot-space
 604              ([^\s(!]+)         # presume this is the src
 605              \s?                # optional space
 606              (?:\(([^\)]+)\))?  # optional title
 607              \!                 # closing
 608              (?::(\S+))?        # optional href
 609              (?=\s|$)           # lookahead: space or end of string
 610          /Ux", array(&$this, "fImage"), $text);
 611      }
 612  
 613  // -------------------------------------------------------------
 614      function fImage($m)
 615      {
 616          list(, $algn, $atts, $url) = $m;
 617          $atts  = $this->pba($atts);
 618          $atts .= ($algn != '')  ? ' align="' . $this->iAlign($algn) . '"' : '';
 619          $atts .= (isset($m[4])) ? ' title="' . $m[4] . '"' : '';
 620          $atts .= (isset($m[4])) ? ' alt="'   . $m[4] . '"' : ' alt=""';
 621          $size = @getimagesize($url);
 622          if ($size) $atts .= " $size[3]";
 623  
 624          $href = (isset($m[5])) ? $this->checkRefs($m[5]) : '';
 625          $url = $this->checkRefs($url);
 626  
 627          $out = array(
 628              ($href) ? '<a href="' . $href . '">' : '',
 629              '<img src="' . $url . '"' . $atts . ' />',
 630              ($href) ? '</a>' : ''
 631          );
 632  
 633          return join('',$out);
 634      }
 635  
 636  // -------------------------------------------------------------
 637      function code($text)
 638      {
 639          return preg_replace_callback("/
 640              (?:^|(?<=[\s\(])|([[{]))        # before
 641              @                               
 642              (?:\|(\w+)\|)?                  # lang
 643              (.+)                            # code
 644              @                               
 645              (?:$|([\]}])|
 646              (?=[[:punct:]]{1,2}|
 647              \s|$))                           # after
 648          /Ux", array(&$this, "fCode"), $text);
 649      }
 650  
 651  // -------------------------------------------------------------
 652      function fCode($m)
 653      {
 654          @list(, $before, $lang, $code, $after) = $m;
 655          $lang = ($lang) ? ' language="' . $lang . '"' : '';
 656          return $before . '<code' . $lang . '>' . $code . '</code>' . $after;
 657      }
 658  
 659  // -------------------------------------------------------------
 660      function shelve($val)
 661      {
 662          $this->shelf[] = $val;
 663          return ' <' . count($this->shelf) . '>';
 664      }
 665  
 666  // -------------------------------------------------------------
 667      function retrieve($text)
 668      {
 669          $i = 0;
 670          if (isset($this->shelf) && is_array($this->shelf)) {
 671              foreach($this->shelf as $r) {
 672                  $i++;
 673                  $text = str_replace("<$i>", $r, $text);
 674              }
 675          }
 676          return $text;
 677      }
 678  
 679  // -------------------------------------------------------------
 680      function incomingEntities($text)
 681      {
 682          return preg_replace("/&(?![#a-z0-9]+;)/i", "x%x%", $text);
 683      }
 684  
 685  // -------------------------------------------------------------
 686      function encodeEntities($text)
 687      {
 688          return (function_exists('mb_encode_numericentity'))
 689          ?    $this->encode_high($text)
 690          :    htmlentities($text, ENT_NOQUOTES, "utf-8");
 691      }
 692  
 693  // -------------------------------------------------------------
 694      function fixEntities($text)
 695      {
 696          /*  de-entify any remaining angle brackets or ampersands */
 697          return str_replace(array("&gt;", "&lt;", "&amp;"),
 698              array(">", "<", "&"), $text);
 699      }
 700  
 701  // -------------------------------------------------------------
 702      function cleanWhiteSpace($text)
 703      {
 704          $out = str_replace(array("\r\n", "\t"), array("\n", ''), $text);
 705          $out = preg_replace("/\n{3,}/", "\n\n", $out);
 706          $out = preg_replace("/\n *\n/", "\n\n", $out);
 707          $out = preg_replace('/"$/', "\" ", $out);
 708          return $out;
 709      }
 710  
 711  // -------------------------------------------------------------
 712      function noTextile($text)
 713      {
 714          return preg_replace('/(^|\s)==(.*)==(\s|$)?/msU',
 715              '$1<notextile>$2</notextile>$3', $text);
 716      }
 717  
 718  // -------------------------------------------------------------
 719      function superscript($text)
 720      {
 721          return preg_replace('/\^(.*)\^/mU', '<sup>$1</sup>', $text);
 722      }
 723  
 724  // -------------------------------------------------------------
 725      function footnoteRef($text)
 726      {
 727          return preg_replace('/\b\[([0-9]+)\](\s)?/U',
 728              '<sup><a href="#fn$1">$1</a></sup>$2', $text);
 729      }
 730  
 731  // -------------------------------------------------------------
 732      function glyphs($text)
 733      {
 734          // fix: hackish
 735          $text = preg_replace('/"\z/', "\" ", $text);
 736          $pnc = '[[:punct:]]';
 737  
 738          $glyph_search = array(
 739              '/([^\s[{(>_*])?\'(?(1)|(?=\s|s\b|'.$pnc.'))/',      //  single closing
 740              '/\'/',                                              //  single opening
 741              '/([^\s[{(>_*])?"(?(1)|(?=\s|'.$pnc.'))/',           //  double closing
 742              '/"/',                                               //  double opening
 743              '/\b( )?\.{3}/',                                     //  ellipsis
 744              '/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/',        //  3+ uppercase acronym
 745              '/\s?--\s?/',                                        //  em dash
 746              '/\s-\s/',                                           //  en dash
 747              '/(\d+) ?x ?(\d+)/',                                 //  dimension sign
 748              '/\b ?[([]TM[])]/i',                                 //  trademark
 749              '/\b ?[([]R[])]/i',                                  //  registered
 750              '/\b ?[([]C[])]/i');                                 //  copyright
 751  
 752          $glyph_replace = array('$1&#8217;$2',   //  single closing
 753              '&#8216;',                          //  single opening
 754              '$1&#8221;',                        //  double closing
 755              '&#8220;',                          //  double opening
 756              '$1&#8230;',                        //  ellipsis
 757              '<acronym title="$2">$1</acronym>', //  3+ uppercase acronym
 758              '&#8212;',                          //  em dash
 759              ' &#8211; ',                        //  en dash
 760              '$1&#215;$2',                       //  dimension sign
 761              '&#8482;',                          //  trademark
 762              '&#174;',                           //  registered
 763              '&#169;');                          //  copyright
 764  
 765          $codepre = false;
 766          /*  if no html, do a simple search and replace... */
 767          if (!preg_match("/<.*>/", $text)) {
 768              $text = preg_replace($glyph_search, $glyph_replace, $text);
 769              return $text;
 770          }
 771          else {
 772              $text = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
 773              foreach($text as $line) {
 774                  $offtags = ('code|pre|kbd|notextile|txp:php');
 775  
 776                  /*  matches are off if we're between <code>, <pre> etc. */
 777                  if (preg_match('/<(' . $offtags . ')>/i', $line)) $codepre = true;
 778                  if (preg_match('/<\/(' . $offtags . ')>/i', $line)) $codepre = false;
 779  
 780                  if (!preg_match("/<.*>/", $line) && $codepre == false) {
 781                      $line = preg_replace($glyph_search, $glyph_replace, $line);
 782                  }
 783  
 784                  /* do htmlspecial if between <code> */
 785                  if ($codepre == true) {
 786                      $line = htmlspecialchars($line, ENT_NOQUOTES, "UTF-8");
 787                      $line = preg_replace('/&lt;(\/?' . $offtags . ')&gt;/', "<$1>", $line);
 788                      $line = str_replace("&amp;#","&#",$line);
 789                  }
 790  
 791                  $glyph_out[] = $line;
 792              }
 793              return join('', $glyph_out);
 794          }
 795      }
 796  
 797  // -------------------------------------------------------------
 798      function iAlign($in)
 799      {
 800          $vals = array(
 801              '<' => 'left',
 802              '=' => 'center',
 803              '>' => 'right');
 804          return (isset($vals[$in])) ? $vals[$in] : '';
 805      }
 806  
 807  // -------------------------------------------------------------
 808      function hAlign($in)
 809      {
 810          $vals = array(
 811              '<'  => 'left',
 812              '='  => 'center',
 813              '>'  => 'right',
 814              '<>' => 'justify');
 815          return (isset($vals[$in])) ? $vals[$in] : '';
 816      }
 817  
 818  // -------------------------------------------------------------
 819      function vAlign($in)
 820      {
 821          $vals = array(
 822              '^' => 'top',
 823              '-' => 'middle',
 824              '~' => 'bottom');
 825          return (isset($vals[$in])) ? $vals[$in] : '';
 826      }
 827  
 828  // -------------------------------------------------------------
 829      function encode_high($text, $charset = "UTF-8")
 830      {
 831          return mb_encode_numericentity($text, $this->cmap(), $charset);
 832      }
 833  
 834  // -------------------------------------------------------------
 835      function decode_high($text, $charset = "UTF-8")
 836      {
 837          return mb_decode_numericentity($text, $this->cmap(), $charset);
 838      }
 839  
 840  // -------------------------------------------------------------
 841      function cmap()
 842      {
 843          $f = 0xffff;
 844          $cmap = array(
 845              160,  383,  0, $f,
 846              402,  402,  0, $f,
 847              913,  929,  0, $f,
 848              931,  937,  0, $f,
 849              945,  969,  0, $f,
 850              977,  978,  0, $f,
 851              982,  982,  0, $f,
 852              8226, 8226, 0, $f,
 853              8230, 8230, 0, $f,
 854              8242, 8243, 0, $f,
 855              8254, 8254, 0, $f,
 856              8260, 8260, 0, $f,
 857              8465, 8465, 0, $f,
 858              8472, 8472, 0, $f,
 859              8476, 8476, 0, $f,
 860              8482, 8482, 0, $f,
 861              8501, 8501, 0, $f,
 862              8592, 8596, 0, $f,
 863              8629, 8629, 0, $f,
 864              8656, 8660, 0, $f,
 865              8704, 8704, 0, $f,
 866              8706, 8707, 0, $f,
 867              8709, 8709, 0, $f,
 868              8711, 8713, 0, $f,
 869              8715, 8715, 0, $f,
 870              8719, 8719, 0, $f,
 871              8721, 8722, 0, $f,
 872              8727, 8727, 0, $f,
 873              8730, 8730, 0, $f,
 874              8733, 8734, 0, $f,
 875              8736, 8736, 0, $f,
 876              8743, 8747, 0, $f,
 877              8756, 8756, 0, $f,
 878              8764, 8764, 0, $f,
 879              8773, 8773, 0, $f,
 880              8776, 8776, 0, $f,
 881              8800, 8801, 0, $f,
 882              8804, 8805, 0, $f,
 883              8834, 8836, 0, $f,
 884              8838, 8839, 0, $f,
 885              8853, 8853, 0, $f,
 886              8855, 8855, 0, $f,
 887              8869, 8869, 0, $f,
 888              8901, 8901, 0, $f,
 889              8968, 8971, 0, $f,
 890              9001, 9002, 0, $f,
 891              9674, 9674, 0, $f,
 892              9824, 9824, 0, $f,
 893              9827, 9827, 0, $f,
 894              9829, 9830, 0, $f,
 895              338,  339,  0, $f,
 896              352,  353,  0, $f,
 897              376,  376,  0, $f,
 898              710,  710,  0, $f,
 899              732,  732,  0, $f,
 900              8194, 8195, 0, $f,
 901              8201, 8201, 0, $f,
 902              8204, 8207, 0, $f,
 903              8211, 8212, 0, $f,
 904              8216, 8218, 0, $f,
 905              8218, 8218, 0, $f,
 906              8220, 8222, 0, $f,
 907              8224, 8225, 0, $f,
 908              8240, 8240, 0, $f,
 909              8249, 8250, 0, $f,
 910              8364, 8364, 0, $f);
 911          return $cmap;
 912      }
 913  
 914  // -------------------------------------------------------------
 915      function textile_popup_help($name, $helpvar, $windowW, $windowH)
 916      {
 917          return ' <a target="_blank" href="http://www.textpattern.com/help/?item=' . $helpvar . '" onclick="window.open(this.href, \'popupwindow\', \'width=' . $windowW . ',height=' . $windowH . ',scrollbars,resizable\'); return false;">' . $name . '</a><br />';
 918  
 919          return $out;
 920      }
 921  
 922  // -------------------------------------------------------------
 923      function txtgps($thing)
 924      {
 925          if (isset($_POST[$thing])) {
 926              if (get_magic_quotes_gpc()) {
 927                  return stripslashes($_POST[$thing]);
 928              }
 929              else {
 930                  return $_POST[$thing];
 931              }
 932          }
 933          else {
 934              return '';
 935          }
 936      }
 937      
 938  // -------------------------------------------------------------
 939      function dump()
 940      {
 941          foreach (func_get_args() as $a)
 942              echo "\n<pre>",(is_array($a)) ? print_r($a) : $a, "</pre>\n";
 943      }
 944  
 945  
 946  } // end class
 947  
 948  ?>

title

Description

title

Description

title

Description

title

title

Body