b2evolution

Multilingual multiuser multiblog engine

b2evolution Technical Documentation (0.9.x) [ class tree: plugins ] [ index: plugins ] [ all elements ]

Source for file _textile.renderer.php

Documentation is available at _textile.renderer.php

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

Documentation generated on Tue, 20 May 2008 01:55:49 +0200 by phpDocumentor 1.4.2