4 * Example: get XHTML from a given Textile-markup string ($string)
6 * $textile = new Textile;
7 * echo $textile->TextileThis($string);
12 $HeadURL: http://svn.textpattern.com/development/4.0/textpattern/lib/classTextile.php $
13 $LastChangedRevision: 1072 $
21 A Humane Web Text Generator
25 Copyright (c) 2003-2004, Dean Allen <dean@textism.com>
28 Thanks to Carlo Zottmann <carlo@g-blog.net> for refactoring
29 Textile's procedural code into a class framework
34 Redistribution and use in source and binary forms, with or without
35 modification, are permitted provided that the following conditions are met:
37 * Redistributions of source code must retain the above copyright notice,
38 this list of conditions and the following disclaimer.
40 * Redistributions in binary form must reproduce the above copyright notice,
41 this list of conditions and the following disclaimer in the documentation
42 and/or other materials provided with the distribution.
44 * Neither the name Textile nor the names of its contributors may be used to
45 endorse or promote products derived from this software without specific
46 prior written permission.
48 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
49 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
52 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 POSSIBILITY OF SUCH DAMAGE.
63 Block modifier syntax:
66 Paragraphs beginning with 'hn. ' (where n is 1-6) are wrapped in header tags.
67 Example: h1. Header... -> <h1>Header...</h1>
69 Paragraph: p. (also applied by default)
70 Example: p. Text -> <p>Text</p>
73 Example: bq. Block quotation... -> <blockquote>Block quotation...</blockquote>
75 Blockquote with citation: bq.:http://citation.url
76 Example: bq.:http://textism.com/ Text...
77 -> <blockquote cite="http://textism.com">Text...</blockquote>
80 Example: fn1. Footnote... -> <p id="fn1">Footnote...</p>
83 Consecutive paragraphs beginning with # are wrapped in ordered list tags.
84 Example: <ol><li>ordered list</li></ol>
87 Consecutive paragraphs beginning with * are wrapped in unordered list tags.
88 Example: <ul><li>unordered list</li></ul>
90 Phrase modifier syntax:
92 _emphasis_ -> <em>emphasis</em>
93 __italic__ -> <i>italic</i>
94 *strong* -> <strong>strong</strong>
95 **bold** -> <b>bold</b>
96 ??citation?? -> <cite>citation</cite>
97 -deleted text- -> <del>deleted</del>
98 +inserted text+ -> <ins>inserted</ins>
99 ^superscript^ -> <sup>superscript</sup>
100 ~subscript~ -> <sub>subscript</sub>
101 @code@ -> <code>computer code</code>
102 %(bob)span% -> <span class="bob">span</span>
104 ==notextile== -> leave text alone (do not format)
106 "linktext":url -> <a href="url">linktext</a>
107 "linktext(title)":url -> <a href="url" title="title">linktext</a>
109 !imageurl! -> <img src="imageurl" />
110 !imageurl(alt text)! -> <img src="imageurl" alt="alt text" />
111 !imageurl!:linkurl -> <a href="linkurl"><img src="imageurl" /></a>
113 ABC(Always Be Closing) -> <acronym title="Always Be Closing">ABC</acronym>
121 |And|Another|table|row|
123 |_. A|_. table|_. header|_.row|
126 Tables with attributes:
128 table{border:1px solid black}.
129 {background:#ddd;color:red}. |{}| | | |
134 Most anywhere Textile code is used, attributes such as arbitrary css style,
135 css classes, and ids can be applied. The syntax is fairly consistent.
137 The following characters quickly alter the alignment of block elements:
139 < -> left align ex. p<. left-aligned para
140 > -> right align h3>. right-aligned header 3
141 = -> centred h4=. centred header 4
142 <> -> justified p<>. justified paragraph
144 These will change vertical alignment in table cells:
146 ^ -> top ex. |^. top-aligned table cell|
147 - -> middle |-. middle aligned|
148 ~ -> bottom |~. bottom aligned cell|
150 Plain (parentheses) inserted between block syntax and the closing dot-space
151 indicate classes and ids:
153 p(hector). paragraph -> <p class="hector">paragraph</p>
155 p(#fluid). paragraph -> <p id="fluid">paragraph</p>
157 (classes and ids can be combined)
158 p(hector#fluid). paragraph -> <p class="hector" id="fluid">paragraph</p>
160 Curly {brackets} insert arbitrary css style
162 p{line-height:18px}. paragraph -> <p style="line-height:18px">paragraph</p>
164 h3{color:red}. header 3 -> <h3 style="color:red">header 3</h3>
166 Square [brackets] insert language attributes
168 p[no]. paragraph -> <p lang="no">paragraph</p>
170 %[fr]phrase% -> <span lang="fr">phrase</span>
172 Usually Textile block element syntax requires a dot and space before the block
173 begins, but since lists don't, they can be styled just using braces
175 #{color:blue} one -> <ol style="color:blue">
181 Using the span tag to style a phrase
183 It goes like this, %{color:red}the fourth the fifth%
184 -> It goes like this, <span style="color:red">the fourth the fifth</span>
204 // -------------------------------------------------------------
207 $this->hlgn
= "(?:\<(?!>)|(?<!<)\>|\<\>|\=|[()]+)";
208 $this->vlgn
= "[\-^~]";
209 $this->clas
= "(?:\([^)]+\))";
210 $this->lnge
= "(?:\[[^]]+\])";
211 $this->styl
= "(?:\{[^}]+\})";
212 $this->cspn
= "(?:\\\\\d+)";
213 $this->rspn
= "(?:\/\d+)";
214 $this->a
= "(?:{$this->hlgn}?{$this->vlgn}?|{$this->vlgn}?{$this->hlgn}?)";
215 $this->s
= "(?:{$this->cspn}?{$this->rspn}?|{$this->rspn}?{$this->cspn}?)";
216 $this->c
= "(?:{$this->clas}?{$this->styl}?{$this->lnge}?|{$this->styl}?{$this->lnge}?{$this->clas}?|{$this->lnge}?{$this->styl}?{$this->clas}?)";
217 $this->pnct
= '[\!"#\$%&\'()\*\+,\-\./:;<=>\?@\[\\\]\^_`{\|}\~]';
221 // -------------------------------------------------------------
222 function TextileThis($text, $lite='', $encode='', $noimage='', $strict='', $rel='')
225 $this->rel
= ' rel="'.$rel.'" ';
227 $text = $this->incomingEntities($text);
230 $text = str_replace("x%x%", "&", $text);
235 $text = $this->fixEntities($text);
236 $text = $this->cleanWhiteSpace($text);
239 $text = $this->getRefs($text);
241 $text = $this->noTextile($text);
242 $text = $this->links($text);
244 $text = $this->image($text);
246 $text = $this->code($text);
247 $text = $this->span($text);
248 $text = $this->superscript($text);
249 $text = $this->footnoteRef($text);
250 $text = $this->glyphs($text);
251 $text = $this->retrieve($text);
254 $text = $this->lists($text);
255 $text = $this->table($text);
256 $text = $this->block($text);
259 // clean up <notextile>
260 $text = preg_replace('/<\/?notextile>/', "", $text);
262 // turn the temp char back to an ampersand entity
263 $text = str_replace("x%x%", "&", $text);
266 $text = str_replace("<br />", "<br />\n", $text);
272 // -------------------------------------------------------------
273 function pba($in, $element = "") // "parse block attributes"
285 if ($element == 'td') {
286 if (preg_match("/\\\\(\d+)/", $matched, $csp)) $colspan = $csp[1];
287 if (preg_match("/\/(\d+)/", $matched, $rsp)) $rowspan = $rsp[1];
289 if (preg_match("/($this->vlgn)/", $matched, $vert))
290 $style[] = "vertical-align:" . $this->vAlign($vert[1]) . ";";
293 if (preg_match("/\{([^}]*)\}/", $matched, $sty)) {
294 $style[] = $sty[1] . ';';
295 $matched = str_replace($sty[0], '', $matched);
298 if (preg_match("/\[([^)]+)\]/U", $matched, $lng)) {
300 $matched = str_replace($lng[0], '', $matched);
303 if (preg_match("/\(([^()]+)\)/U", $matched, $cls)) {
305 $matched = str_replace($cls[0], '', $matched);
308 if (preg_match("/([(]+)/", $matched, $pl)) {
309 $style[] = "padding-left:" . strlen($pl[1]) . "em;";
310 $matched = str_replace($pl[0], '', $matched);
313 if (preg_match("/([)]+)/", $matched, $pr)) {
315 $style[] = "padding-right:" . strlen($pr[1]) . "em;";
316 $matched = str_replace($pr[0], '', $matched);
319 if (preg_match("/($this->hlgn)/", $matched, $horiz))
320 $style[] = "text-align:" . $this->hAlign($horiz[1]) . ";";
322 if (preg_match("/^(.*)#(.*)$/", $class, $ids)) {
327 return join('',array(
328 ($style) ?
' style="' . join("", $style) .'"':'',
329 ($class) ?
' class="' . $class .'"':'',
330 ($lang) ?
' lang="' . $lang .'"':'',
331 ($id) ?
' id="' . $id .'"':'',
332 ($colspan) ?
' colspan="' . $colspan .'"':'',
333 ($rowspan) ?
' rowspan="' . $rowspan .'"':''
339 // -------------------------------------------------------------
340 function table($text)
342 $text = $text . "\n\n";
343 return preg_replace_callback("/^(?:table(_?{$this->s}{$this->a}{$this->c})\. ?\n)?^({$this->a}{$this->c}\.? ?\|.*\|)\n\n/smU",
344 array(&$this, "fTable"), $text);
347 // -------------------------------------------------------------
348 function fTable($matches)
350 $tatts = $this->pba($matches[1], 'table');
352 foreach(preg_split("/\|$/m", $matches[2], -1, PREG_SPLIT_NO_EMPTY
) as $row) {
353 if (preg_match("/^($this->a$this->c\. )(.*)/m", $row, $rmtch)) {
354 $ratts = $this->pba($rmtch[1], 'tr');
358 foreach(explode("|", $row) as $cell) {
360 if (preg_match("/^_/", $cell)) $ctyp = "h";
361 if (preg_match("/^(_?$this->s$this->a$this->c\. )(.*)/", $cell, $cmtch)) {
362 $catts = $this->pba($cmtch[1], 'td');
366 if (trim($cell) != '')
367 $cells[] = "\t\t\t<t$ctyp$catts>$cell</t$ctyp>";
369 $rows[] = "\t\t<tr$ratts>\n" . join("\n", $cells) . "\n\t\t</tr>";
370 unset($cells, $catts);
372 return "\t<table$tatts>\n" . join("\n", $rows) . "\n\t</table>\n\n";
375 // -------------------------------------------------------------
376 function lists($text)
378 return preg_replace_callback("/^([#*]+$this->c .*)$(?![^#*])/smU", array(&$this, "fList"), $text);
381 // -------------------------------------------------------------
384 $text = explode("\n", $m[0]);
385 foreach($text as $line) {
386 $nextline = next($text);
387 if (preg_match("/^([#*]+)($this->a$this->c) (.*)$/s", $line, $m)) {
388 list(, $tl, $atts, $content) = $m;
389 $nl = preg_replace("/^([#*]+)\s.*/", "$1", $nextline);
390 if (!isset($lists[$tl])) {
392 $atts = $this->pba($atts);
393 $line = "\t<" . $this->lT($tl) . "l$atts>\n\t\t<li>" . $content;
395 $line = "\t\t<li>" . $content;
398 if(strlen($nl) <= strlen($tl)) $line .= "</li>";
399 foreach(array_reverse($lists) as $k => $v) {
400 if(strlen($k) > strlen($nl)) {
401 $line .= "\n\t</" . $this->lT($k) . "l>";
410 return join("\n", $out);
413 // -------------------------------------------------------------
416 return preg_match("/^#+/", $in) ?
'o' : 'u';
419 // -------------------------------------------------------------
420 function block($text)
422 $pre = $php = $txp = false
;
423 $find = array('bq', 'h[1-6]', 'fn\d+', 'p');
425 $text = preg_replace("/(.+)\n(?![#*\s|])/",
428 $text = explode("\n", $text);
429 array_push($text, " ");
431 foreach($text as $line) {
432 if (preg_match('/<pre>/i', $line)) {
435 elseif (preg_match('/<txp:php>/i', $line)) {
438 elseif (preg_match('/^\s*<txp:/i', $line)) {
443 foreach($find as $tag) {
444 $line = ($pre == false
and $php == false
and $txp == false
)
445 ?
preg_replace_callback("/^($tag)($this->a$this->c)\.(?::(\S+))? (.*)$/",
446 array(&$this, "fBlock"), $line)
450 $line = (!$php and !$txp) ?
preg_replace('/^(?!\t|<\/?pre|<\/?code|$| )(.*)/', "\t<p>$1</p>", $line) : $line;
452 $line = ($pre or $php) ?
str_replace("<br />", "\n", $line):$line;
453 if (preg_match('/<\/pre>/i', $line)) {
456 elseif (preg_match('/<\/txp:php>/i', $line)) {
459 if ($txp == true
) $txp = false
;
462 return join("\n", $out);
465 // -------------------------------------------------------------
469 list(, $tag, $atts, $cite, $content) = $m;
471 $atts = $this->pba($atts);
473 if (preg_match("/fn(\d+)/", $tag, $fns)) {
475 $fnid = empty($this->fn
[$fns[1]]) ?
$fns[1] : $this->fn
[$fns[1]];
476 $atts .= ' id="fn' . $fnid . '"';
477 $content = '<sup>' . $fns[1] . '</sup> ' . $content;
484 $cite = $this->checkRefs($cite);
485 $cite = ($cite != '') ?
' cite="' . $cite . '"' : '';
486 $start = "\t<blockquote$cite>\n\t\t<p";
487 $end = "</p>\n\t</blockquote>";
490 return "$start$atts>$content$end";
493 // -------------------------------------------------------------
496 $qtags = array('\*\*','\*','\?\?','-','__','_','%','\+','~');
498 foreach($qtags as $f) {
499 $text = preg_replace_callback("/
500 (?<=^|\s|[[:punct:]]|[{([])
507 (?=[])}]|[[:punct:]]+|\s|$)
508 /xmU", array(&$this, "fSpan"), $text);
513 // -------------------------------------------------------------
528 list(, $tag, $atts, $cite, $content, $end) = $m;
530 $atts = $this->pba($atts);
531 $atts .= ($cite != '') ?
'cite="' . $cite . '"' : '';
533 $out = "<$tag$atts>$content$end</$tag>";
535 // $this->dump($out);
541 // -------------------------------------------------------------
542 function links($text)
544 return preg_replace_callback('/
545 ([\s[{(]|[[:punct:]])? # $pre
547 (' . $this->c
. ') # $atts
550 (?:\(([^)]+)\)(?="))? # $title
556 /Ux', array(&$this, "fLink"), $text);
559 // -------------------------------------------------------------
562 list(, $pre, $atts, $text, $title, $url, $slash, $post) = $m;
564 $url = $this->checkRefs($url);
566 $atts = $this->pba($atts);
567 $atts .= ($title != '') ?
'title="' . $title . '"' : '';
569 $atts = ($atts) ?
$this->shelve($atts) : '';
571 $parts = parse_url($url);
572 if (empty($parts['host']) and preg_match('/^\w/', @$parts['path']))
575 $out = $pre . '<a href="' . $url . $slash . '"' . $atts . $this->rel
. '>' . $text . '</a>' . $post;
577 // $this->dump($out);
582 // -------------------------------------------------------------
583 function getRefs($text)
585 return preg_replace_callback("/(?<=^|\s)\[(.+)\]((?:http:\/\/|\/)\S+)(?=\s|$)/U",
586 array(&$this, "refs"), $text);
588 // -------------------------------------------------------------
592 list(, $flag, $url) = $m;
593 $this->urlrefs
[$flag] = $url;
597 // -------------------------------------------------------------
598 function checkRefs($text)
600 return (isset($this->urlrefs
[$text])) ?
$this->urlrefs
[$text] : $text;
603 // -------------------------------------------------------------
604 function image($text)
606 return preg_replace_callback("/
608 (\<|\=|\>)? # optional alignment atts
609 ($this->c) # optional style,class atts
610 (?:\. )? # optional dot-space
611 ([^\s(!]+) # presume this is the src
613 (?:\(([^\)]+)\))? # optional title
615 (?::(\S+))? # optional href
616 (?=\s|$) # lookahead: space or end of string
617 /Ux", array(&$this, "fImage"), $text);
620 // -------------------------------------------------------------
623 list(, $algn, $atts, $url) = $m;
624 $atts = $this->pba($atts);
625 $atts .= ($algn != '') ?
' align="' . $this->iAlign($algn) . '"' : '';
626 $atts .= (isset($m[4])) ?
' title="' . $m[4] . '"' : '';
627 $atts .= (isset($m[4])) ?
' alt="' . $m[4] . '"' : ' alt=""';
628 $size = @getimagesize
($url);
629 if ($size) $atts .= " $size[3]";
631 $href = (isset($m[5])) ?
$this->checkRefs($m[5]) : '';
632 $url = $this->checkRefs($url);
634 $parts = parse_url($url);
635 if (empty($parts['host']) and preg_match('/^\w/', @$parts['path']))
639 ($href) ?
'<a href="' . $href . '">' : '',
640 '<img src="' . $url . '"' . $atts . ' />',
641 ($href) ?
'</a>' : ''
644 return join('',$out);
647 // -------------------------------------------------------------
650 return preg_replace_callback("/
651 (?:^|(?<=[\s\(])|([[{])) # before
653 (?:\|(\w+)\|)? # lang
659 /Ux", array(&$this, "fCode"), $text);
662 // -------------------------------------------------------------
665 @list
(, $before, $lang, $code, $after) = $m;
666 $lang = ($lang) ?
' language="' . $lang . '"' : '';
667 return $before . '<code' . $lang . '>' . $code . '</code>' . $after;
670 // -------------------------------------------------------------
671 function shelve($val)
673 $this->shelf
[] = $val;
674 return ' <' . count($this->shelf
) . '>';
677 // -------------------------------------------------------------
678 function retrieve($text)
681 if (isset($this->shelf
) && is_array($this->shelf
)) {
682 foreach($this->shelf
as $r) {
684 $text = str_replace("<$i>", $r, $text);
690 // -------------------------------------------------------------
691 function incomingEntities($text)
693 return preg_replace("/&(?![#a-z0-9]+;)/i", "x%x%", $text);
696 // -------------------------------------------------------------
697 function encodeEntities($text)
699 return (function_exists('mb_encode_numericentity'))
700 ?
$this->encode_high($text)
701 : htmlentities($text, ENT_NOQUOTES
, "utf-8");
704 // -------------------------------------------------------------
705 function fixEntities($text)
707 /* de-entify any remaining angle brackets or ampersands */
708 return str_replace(array(">", "<", "&"),
709 array(">", "<", "&"), $text);
712 // -------------------------------------------------------------
713 function cleanWhiteSpace($text)
715 $out = str_replace(array("\r\n", "\t"), array("\n", ''), $text);
716 $out = preg_replace("/\n{3,}/", "\n\n", $out);
717 $out = preg_replace("/\n *\n/", "\n\n", $out);
718 $out = preg_replace('/"$/', "\" ", $out);
722 // -------------------------------------------------------------
723 function noTextile($text)
725 $text = preg_replace_callback('/(^|\s)<notextile>(.*)<\/notextile>(\s|$)?/msU',
726 array(&$this, "fTextile"), $text);
727 return preg_replace_callback('/(^|\s)==(.*)==(\s|$)?/msU',
728 array(&$this, "fTextile"), $text);
731 // -------------------------------------------------------------
732 function fTextile($m)
749 @list
(, $before, $notextile, $after) = $m;
750 $notextile = str_replace(array_keys($modifiers), array_values($modifiers), $notextile);
751 return $before . '<notextile>' . $notextile . '</notextile>' . $after;
754 // -------------------------------------------------------------
755 function superscript($text)
757 return preg_replace('/\^(.*)\^/mU', '<sup>$1</sup>', $text);
760 // -------------------------------------------------------------
761 function footnoteRef($text)
763 return preg_replace('/\b\[([0-9]+)\](\s)?/Ue',
764 '$this->footnoteID(\'\1\',\'\2\')', $text);
767 // -------------------------------------------------------------
768 function footnoteID($id, $t)
770 if (empty($this->fn
[$id]))
771 $this->fn
[$id] = uniqid(rand());
772 $fnid = $this->fn
[$id];
773 return '<sup><a href="#fn'.$fnid.'">'.$id.'</a></sup>'.$t;
776 // -------------------------------------------------------------
777 function glyphs($text)
780 $text = preg_replace('/"\z/', "\" ", $text);
781 $pnc = '[[:punct:]]';
783 $glyph_search = array(
784 '/([^\s[{(>_*])?\'(?(1)|(?=\s|s\b|'.$pnc.'))/', // single closing
785 '/\'/', // single opening
786 '/([^\s[{(>_*])?"(?(1)|(?=\s|'.$pnc.'))/', // double closing
787 '/"/', // double opening
788 '/\b( )?\.{3}/', // ellipsis
789 '/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/', // 3+ uppercase acronym
790 '/\s?--\s?/', // em dash
791 '/\s-\s/', // en dash
792 '/(\d+) ?x ?(\d+)/', // dimension sign
793 '/\b ?[([]TM[])]/i', // trademark
794 '/\b ?[([]R[])]/i', // registered
795 '/\b ?[([]C[])]/i'); // copyright
797 $glyph_replace = array('$1’$2', // single closing
798 '‘', // single opening
799 '$1”', // double closing
800 '“', // double opening
801 '$1…', // ellipsis
802 '<acronym title="$2">$1</acronym>', // 3+ uppercase acronym
803 '—', // em dash
804 ' – ', // en dash
805 '$1×$2', // dimension sign
806 '™', // trademark
807 '®', // registered
808 '©'); // copyright
811 /* if no html, do a simple search and replace... */
812 if (!preg_match("/<.*>/", $text)) {
813 $text = preg_replace($glyph_search, $glyph_replace, $text);
817 $text = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE
);
818 foreach($text as $line) {
819 $offtags = ('code|pre|kbd|notextile|txp:php');
821 /* matches are off if we're between <code>, <pre> etc. */
822 if (preg_match('/<(' . $offtags . ')>/i', $line)) $codepre = true
;
823 if (preg_match('/<\/(' . $offtags . ')>/i', $line)) $codepre = false
;
825 if (!preg_match("/<.*>/", $line) && $codepre == false
) {
826 $line = preg_replace($glyph_search, $glyph_replace, $line);
829 /* do htmlspecial if between <code> */
830 if ($codepre == true
) {
831 $line = htmlspecialchars($line, ENT_NOQUOTES
, "UTF-8");
832 $line = preg_replace('/<(\/?' . $offtags . ')>/', "<$1>", $line);
833 $line = str_replace("&#","&#",$line);
836 $glyph_out[] = $line;
838 return join('', $glyph_out);
842 // -------------------------------------------------------------
849 return (isset($vals[$in])) ?
$vals[$in] : '';
852 // -------------------------------------------------------------
860 return (isset($vals[$in])) ?
$vals[$in] : '';
863 // -------------------------------------------------------------
870 return (isset($vals[$in])) ?
$vals[$in] : '';
873 // -------------------------------------------------------------
874 function encode_high($text, $charset = "UTF-8")
876 return mb_encode_numericentity($text, $this->cmap(), $charset);
879 // -------------------------------------------------------------
880 function decode_high($text, $charset = "UTF-8")
882 return mb_decode_numericentity($text, $this->cmap(), $charset);
885 // -------------------------------------------------------------
890 0x0080, 0xffff, 0, $f);
894 // -------------------------------------------------------------
895 function textile_popup_help($name, $helpvar, $windowW, $windowH)
897 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 />';
902 // -------------------------------------------------------------
903 function txtgps($thing)
905 if (isset($_POST[$thing])) {
906 if (get_magic_quotes_gpc()) {
907 return stripslashes($_POST[$thing]);
910 return $_POST[$thing];
918 // -------------------------------------------------------------
921 foreach (func_get_args() as $a)
922 echo "\n<pre>",(is_array($a)) ?
print_r($a) : $a, "</pre>\n";
925 // -------------------------------------------------------------
926 function blockLite($text)
928 $find = array('bq', 'p');
930 $text = preg_replace("/(.+)\n(?![#*\s|])/",
933 $text = explode("\n", $text);
934 array_push($text, " ");
936 foreach($text as $line) {
938 foreach($find as $tag) {
939 $line = preg_replace_callback("/^($tag)($this->a$this->c)\.(?::(\S+))? (.*)$/",
940 array(&$this, "fBlock"), $line);
943 $line = preg_replace('/^(?!\t|<\/?pre|<\/?code|$| )(.*)/', "\t<p>$1</p>", $line);
946 return join("\n", $out);