Advertisement
that0n3guy

textile - drush make

Oct 10th, 2011
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 53.99 KB | None | 0 0
  1. From 3cd5a9e53fd4d6ab6a784547a7097a6b2e0c5e39 Mon Sep 17 00:00:00 2001
  2. From: that0n3guy <peter@quadputer>
  3. Date: Mon, 10 Oct 2011 10:28:02 -0500
  4. Subject: [PATCH] added textile class
  5.  
  6. ---
  7. include/classTextile.php | 1717 ++++++++++++++++++++++++++++++++++++++++++++++
  8. 1 files changed, 1717 insertions(+), 0 deletions(-)
  9. create mode 100644 include/classTextile.php
  10.  
  11. diff --git include/classTextile.php b/include/classTextile.php
  12. new file mode 100644
  13. index 0000000..e32e337
  14. --- /dev/null
  15. +++ include/classTextile.php
  16. @@ -0,0 +1,1717 @@
  17. +<?php
  18. +
  19. +/**
  20. + * Example: get XHTML from a given Textile-markup string ($string)
  21. + *
  22. + * $textile = new Textile;
  23. + * echo $textile->TextileThis($string);
  24. + *
  25. + */
  26. +
  27. +/*
  28. +$HeadURL: https://textpattern.googlecode.com/svn/releases/4.4.1/source/textpattern/lib/classTextile.php $
  29. +$LastChangedRevision: 3566 $
  30. +*/
  31. +
  32. +/*
  33. +
  34. +_____________
  35. +T E X T I L E
  36. +
  37. +A Humane Web Text Generator
  38. +
  39. +Version 2.2
  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. +Additions and fixes Copyright (c) 2006 Alex Shiels http://thresholdstate.com/
  48. +
  49. +_____________
  50. +L I C E N S E
  51. +
  52. +Redistribution and use in source and binary forms, with or without
  53. +modification, are permitted provided that the following conditions are met:
  54. +
  55. +* Redistributions of source code must retain the above copyright notice,
  56. + this list of conditions and the following disclaimer.
  57. +
  58. +* Redistributions in binary form must reproduce the above copyright notice,
  59. + this list of conditions and the following disclaimer in the documentation
  60. + and/or other materials provided with the distribution.
  61. +
  62. +* Neither the name Textile nor the names of its contributors may be used to
  63. + endorse or promote products derived from this software without specific
  64. + prior written permission.
  65. +
  66. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  67. +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  68. +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  69. +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  70. +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  71. +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  72. +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  73. +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  74. +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  75. +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  76. +POSSIBILITY OF SUCH DAMAGE.
  77. +
  78. +_________
  79. +U S A G E
  80. +
  81. +Block modifier syntax:
  82. +
  83. + Header: h(1-6).
  84. + Paragraphs beginning with 'hn. ' (where n is 1-6) are wrapped in header tags.
  85. + Example: h1. Header... -> <h1>Header...</h1>
  86. +
  87. + Paragraph: p. (also applied by default)
  88. + Example: p. Text -> <p>Text</p>
  89. +
  90. + Blockquote: bq.
  91. + Example: bq. Block quotation... -> <blockquote>Block quotation...</blockquote>
  92. +
  93. + Blockquote with citation: bq.:http://citation.url
  94. + Example: bq.:http://textism.com/ Text...
  95. + -> <blockquote cite="http://textism.com">Text...</blockquote>
  96. +
  97. + Footnote: fn(1-100).
  98. + Example: fn1. Footnote... -> <p id="fn1">Footnote...</p>
  99. +
  100. + Numeric list: #, ##
  101. + Consecutive paragraphs beginning with # are wrapped in ordered list tags.
  102. + Example: <ol><li>ordered list</li></ol>
  103. +
  104. + Bulleted list: *, **
  105. + Consecutive paragraphs beginning with * are wrapped in unordered list tags.
  106. + Example: <ul><li>unordered list</li></ul>
  107. +
  108. + Definition list:
  109. + Terms ;, ;;
  110. + Definitions :, ::
  111. + Consecutive paragraphs beginning with ; or : are wrapped in definition list tags.
  112. + Example: <dl><dt>term</dt><dd>definition</dd></dl>
  113. +
  114. +Phrase modifier syntax:
  115. +
  116. + _emphasis_ -> <em>emphasis</em>
  117. + __italic__ -> <i>italic</i>
  118. + *strong* -> <strong>strong</strong>
  119. + **bold** -> <b>bold</b>
  120. + ??citation?? -> <cite>citation</cite>
  121. + -deleted text- -> <del>deleted</del>
  122. + +inserted text+ -> <ins>inserted</ins>
  123. + ^superscript^ -> <sup>superscript</sup>
  124. + ~subscript~ -> <sub>subscript</sub>
  125. + @code@ -> <code>computer code</code>
  126. + %(bob)span% -> <span class="bob">span</span>
  127. +
  128. + ==notextile== -> leave text alone (do not format)
  129. +
  130. + "linktext":url -> <a href="url">linktext</a>
  131. + "linktext(title)":url -> <a href="url" title="title">linktext</a>
  132. + "$":url -> <a href="url">url</a>
  133. + "$(title)":url -> <a href="url" title="title">url</a>
  134. +
  135. + !imageurl! -> <img src="imageurl" />
  136. + !imageurl(alt text)! -> <img src="imageurl" alt="alt text" />
  137. + !imageurl!:linkurl -> <a href="linkurl"><img src="imageurl" /></a>
  138. +
  139. +ABC(Always Be Closing) -> <acronym title="Always Be Closing">ABC</acronym>
  140. +
  141. +
  142. +Linked Notes:
  143. +============
  144. +
  145. + Allows the generation of an automated list of notes with links.
  146. +
  147. + Linked notes are composed of three parts, a set of named _definitions_, a set of
  148. + _references_ to those definitions and one or more _placeholders_ indicating where
  149. + the consolidated list of notes is to be placed in your document.
  150. +
  151. + Definitions.
  152. + -----------
  153. +
  154. + Each note definition must occur in its own paragraph and should look like this...
  155. +
  156. + note#mynotelabel. Your definition text here.
  157. +
  158. + You are free to use whatever label you wish after the # as long as it is made up
  159. + of letters, numbers, colon(:) or dash(-).
  160. +
  161. + References.
  162. + ----------
  163. +
  164. + Each note reference is marked in your text like this[#mynotelabel] and
  165. + it will be replaced with a superscript reference that links into the list of
  166. + note definitions.
  167. +
  168. + List Placeholder(s).
  169. + -------------------
  170. +
  171. + The note list can go anywhere in your document. You have to indicate where
  172. + like this...
  173. +
  174. + notelist.
  175. +
  176. + notelist can take attributes (class#id) like this: notelist(class#id).
  177. +
  178. + By default, the note list will show each definition in the order that they
  179. + are referenced in the text by the _references_. It will show each definition with
  180. + a full list of backlinks to each reference. If you do not want this, you can choose
  181. + to override the backlinks like this...
  182. +
  183. + notelist(class#id)!. Produces a list with no backlinks.
  184. + notelist(class#id)^. Produces a list with only the first backlink.
  185. +
  186. + Should you wish to have a specific definition display backlinks differently to this
  187. + then you can override the backlink method by appending a link override to the
  188. + _definition_ you wish to customise.
  189. +
  190. + note#label. Uses the citelist's setting for backlinks.
  191. + note#label!. Causes that definition to have no backlinks.
  192. + note#label^. Causes that definition to have one backlink (to the first ref.)
  193. + note#label*. Causes that definition to have all backlinks.
  194. +
  195. + Any unreferenced notes will be left out of the list unless you explicitly state
  196. + you want them by adding a '+'. Like this...
  197. +
  198. + notelist(class#id)!+. Giving a list of all notes without any backlinks.
  199. +
  200. + You can mix and match the list backlink control and unreferenced links controls
  201. + but the backlink control (if any) must go first. Like so: notelist^+. , not
  202. + like this: notelist+^.
  203. +
  204. + Example...
  205. + Scientists say[#lavader] the moon is small.
  206. +
  207. + note#other. An unreferenced note.
  208. +
  209. + note#lavader(myliclass). "Proof":url of a small moon.
  210. +
  211. + notelist(myclass#myid)+.
  212. +
  213. + Would output (the actual IDs used would be randomised)...
  214. +
  215. + <p>Scientists say<sup><a href="#def_id_1" id="ref_id_1a">1</sup> the moon is small.</p>
  216. +
  217. + <ol class="myclass" id="myid">
  218. + <li class="myliclass"><a href="#ref_id_1a"><sup>a</sup></a><span id="def_id_1"> </span><a href="url">Proof</a> of a small moon.</li>
  219. + <li>An unreferenced note.</li>
  220. + </ol>
  221. +
  222. + The 'a b c' backlink characters can be altered too.
  223. + For example if you wanted the notes to have numeric backlinks starting from 1:
  224. +
  225. + notelist:1.
  226. +
  227. +Table syntax:
  228. +
  229. + Simple tables:
  230. +
  231. + |a|simple|table|row|
  232. + |And|Another|table|row|
  233. + |With an||empty|cell|
  234. +
  235. + |=. My table caption goes here
  236. + |_. A|_. table|_. header|_.row|
  237. + |A|simple|table|row|
  238. +
  239. + Tables with attributes:
  240. +
  241. + table{border:1px solid black}. My table summary here
  242. + {background:#ddd;color:red}. |{}| | | |
  243. +
  244. + To specify thead / tfoot / tbody groups, add one of these on its own line
  245. + above the row(s) you wish to wrap (you may specify attributes before the dot):
  246. +
  247. + |^. # thead
  248. + |-. # tbody
  249. + |~. # tfoot
  250. +
  251. + Column groups:
  252. +
  253. + |:\3. 100
  254. +
  255. + Becomes:
  256. + <colgroup span="3" width="100"></colgroup>
  257. +
  258. + You can omit either of the \N or width values. You may also
  259. + add cells after the colgroup definition to specify span/width/attributes:
  260. +
  261. + |:\5. 50 |(firstcol). |\2. 250||300|
  262. +
  263. + Becomes:
  264. + <colgroup span="5" width="50">
  265. + <col class="firstcol" />
  266. + <col span="2" width="250" />
  267. + <col />
  268. + <col width="300" />
  269. + </colgroup>
  270. +
  271. +Applying Attributes:
  272. +
  273. + Most anywhere Textile code is used, attributes such as arbitrary css style,
  274. + css classes, and ids can be applied. The syntax is fairly consistent.
  275. +
  276. + The following characters quickly alter the alignment of block elements:
  277. +
  278. + < -> left align ex. p<. left-aligned para
  279. + > -> right align h3>. right-aligned header 3
  280. + = -> centred h4=. centred header 4
  281. + <> -> justified p<>. justified paragraph
  282. +
  283. + These will change vertical alignment in table cells:
  284. +
  285. + ^ -> top ex. |^. top-aligned table cell|
  286. + - -> middle |-. middle aligned|
  287. + ~ -> bottom |~. bottom aligned cell|
  288. +
  289. + Plain (parentheses) inserted between block syntax and the closing dot-space
  290. + indicate classes and ids:
  291. +
  292. + p(hector). paragraph -> <p class="hector">paragraph</p>
  293. +
  294. + p(#fluid). paragraph -> <p id="fluid">paragraph</p>
  295. +
  296. + (classes and ids can be combined)
  297. + p(hector#fluid). paragraph -> <p class="hector" id="fluid">paragraph</p>
  298. +
  299. + Curly {brackets} insert arbitrary css style
  300. +
  301. + p{line-height:18px}. paragraph -> <p style="line-height:18px">paragraph</p>
  302. +
  303. + h3{color:red}. header 3 -> <h3 style="color:red">header 3</h3>
  304. +
  305. + Square [brackets] insert language attributes
  306. +
  307. + p[no]. paragraph -> <p lang="no">paragraph</p>
  308. +
  309. + %[fr]phrase% -> <span lang="fr">phrase</span>
  310. +
  311. + Usually Textile block element syntax requires a dot and space before the block
  312. + begins, but since lists don't, they can be styled just using braces
  313. +
  314. + #{color:blue} one -> <ol style="color:blue">
  315. + # big <li>one</li>
  316. + # list <li>big</li>
  317. + <li>list</li>
  318. + </ol>
  319. +
  320. + Using the span tag to style a phrase
  321. +
  322. + It goes like this, %{color:red}the fourth the fifth%
  323. + -> It goes like this, <span style="color:red">the fourth the fifth</span>
  324. +
  325. +*/
  326. +
  327. +// define these before including this file to override the standard glyphs
  328. +@define('txt_quote_single_open', '&#8216;');
  329. +@define('txt_quote_single_close', '&#8217;');
  330. +@define('txt_quote_double_open', '&#8220;');
  331. +@define('txt_quote_double_close', '&#8221;');
  332. +@define('txt_apostrophe', '&#8217;');
  333. +@define('txt_prime', '&#8242;');
  334. +@define('txt_prime_double', '&#8243;');
  335. +@define('txt_ellipsis', '&#8230;');
  336. +@define('txt_emdash', '&#8212;');
  337. +@define('txt_endash', '&#8211;');
  338. +@define('txt_dimension', '&#215;');
  339. +@define('txt_trademark', '&#8482;');
  340. +@define('txt_registered', '&#174;');
  341. +@define('txt_copyright', '&#169;');
  342. +@define('txt_half', '&#189;');
  343. +@define('txt_quarter', '&#188;');
  344. +@define('txt_threequarters', '&#190;');
  345. +@define('txt_degrees', '&#176;');
  346. +@define('txt_plusminus', '&#177;');
  347. +@define('txt_has_unicode', @preg_match('/\pL/u', 'a')); // Detect if Unicode is compiled into PCRE
  348. +
  349. +class Textile
  350. +{
  351. + var $hlgn;
  352. + var $vlgn;
  353. + var $clas;
  354. + var $lnge;
  355. + var $styl;
  356. + var $cspn;
  357. + var $rspn;
  358. + var $a;
  359. + var $s;
  360. + var $c;
  361. + var $pnct;
  362. + var $rel;
  363. + var $fn;
  364. +
  365. + var $shelf = array();
  366. + var $restricted = false;
  367. + var $noimage = false;
  368. + var $lite = false;
  369. + var $url_schemes = array();
  370. + var $glyph = array();
  371. + var $hu = '';
  372. + var $max_span_depth = 5;
  373. +
  374. + var $ver = '2.2.0';
  375. + var $rev = '$Rev: 3566 $';
  376. +
  377. + var $doc_root;
  378. +
  379. +// -------------------------------------------------------------
  380. + function Textile()
  381. + {
  382. + $this->hlgn = "(?:\<(?!>)|(?<!<)\>|\<\>|\=|[()]+(?! ))";
  383. + $this->vlgn = "[\-^~]";
  384. + $this->clas = "(?:\([^)\n]+\))"; # Don't allow classes/ids/languages/styles to span across newlines
  385. + $this->lnge = "(?:\[[^]\n]+\])";
  386. + $this->styl = "(?:\{[^}\n]+\})";
  387. + $this->cspn = "(?:\\\\\d+)";
  388. + $this->rspn = "(?:\/\d+)";
  389. + $this->a = "(?:{$this->hlgn}|{$this->vlgn})*";
  390. + $this->s = "(?:{$this->cspn}|{$this->rspn})*";
  391. + $this->c = "(?:{$this->clas}|{$this->styl}|{$this->lnge}|{$this->hlgn})*";
  392. + $this->lc = "(?:{$this->clas}|{$this->styl}|{$this->lnge})*";
  393. +
  394. + $this->pnct = '[\!"#\$%&\'()\*\+,\-\./:;<=>\?@\[\\\]\^_`{\|}\~]';
  395. + $this->urlch = '[\w"$\-_.+!*\'(),";\/?:@=&%#{}|\\^~\[\]`]';
  396. + $pnc = '[[:punct:]]';
  397. +
  398. + $this->url_schemes = array('http','https','ftp','mailto');
  399. +
  400. + $this->btag = array('bq', 'bc', 'notextile', 'pre', 'h[1-6]', 'fn\d+', 'p', '###' );
  401. +
  402. + if (txt_has_unicode) {
  403. + $this->regex_snippets = array(
  404. + 'acr' => '\p{Lu}\p{Nd}',
  405. + 'abr' => '\p{Lu}',
  406. + 'nab' => '\p{Ll}',
  407. + 'wrd' => '(?:\p{L}|\p{M}|\p{N}|\p{Pc})',
  408. + 'mod' => 'u', # Make sure to mark the unicode patterns as such, Some servers seem to need this.
  409. + );
  410. + } else {
  411. + $this->regex_snippets = array(
  412. + 'acr' => 'A-Z0-9',
  413. + 'abr' => 'A-Z',
  414. + 'nab' => 'a-z',
  415. + 'wrd' => '\w',
  416. + 'mod' => '',
  417. + );
  418. + }
  419. + extract( $this->regex_snippets );
  420. +
  421. + $this->glyph_search = array(
  422. + '/('.$wrd.')\'('.$wrd.')/'.$mod, // I'm an apostrophe
  423. + '/(\s)\'(\d+'.$wrd.'?)\b(?![.]?['.$wrd.']*?\')/'.$mod, // back in '88/the '90s but not in his '90s', '1', '1.' '10m' or '5.png'
  424. + '/(\S)\'(?=\s|'.$pnc.'|<|$)/', // single closing
  425. + '/\'/', // single opening
  426. + '/(\S)\"(?=\s|'.$pnc.'|<|$)/', // double closing
  427. + '/"/', // double opening
  428. + '/\b(['.$abr.']['.$acr.']{2,})\b(?:[(]([^)]*)[)])/'.$mod, // 3+ uppercase acronym
  429. + '/(?<=\s|^|[>(;-])(['.$abr.']{3,})(['.$nab.']*)(?=\s|'.$pnc.'|<|$)(?=[^">]*?(<|$))/'.$mod, // 3+ uppercase
  430. + '/([^.]?)\.{3}/', // ellipsis
  431. + '/(\s?)--(\s?)/', // em dash
  432. + '/\s-(?:\s|$)/', // en dash
  433. + '/(\d+)( ?)x( ?)(?=\d+)/', // dimension sign
  434. + '/(\b ?|\s|^)[([]TM[])]/i', // trademark
  435. + '/(\b ?|\s|^)[([]R[])]/i', // registered
  436. + '/(\b ?|\s|^)[([]C[])]/i', // copyright
  437. + '/[([]1\/4[])]/', // 1/4
  438. + '/[([]1\/2[])]/', // 1/2
  439. + '/[([]3\/4[])]/', // 3/4
  440. + '/[([]o[])]/', // degrees -- that's a small 'oh'
  441. + '/[([]\+\/-[])]/', // plus minus
  442. + );
  443. +
  444. + $this->glyph_replace = array(
  445. + '$1'.txt_apostrophe.'$2', // I'm an apostrophe
  446. + '$1'.txt_apostrophe.'$2', // back in '88
  447. + '$1'.txt_quote_single_close, // single closing
  448. + txt_quote_single_open, // single opening
  449. + '$1'.txt_quote_double_close, // double closing
  450. + txt_quote_double_open, // double opening
  451. + '<acronym title="$2">$1</acronym>', // 3+ uppercase acronym
  452. + '<span class="caps">glyph:$1</span>$2', // 3+ uppercase
  453. + '$1'.txt_ellipsis, // ellipsis
  454. + '$1'.txt_emdash.'$2', // em dash
  455. + ' '.txt_endash.' ', // en dash
  456. + '$1$2'.txt_dimension.'$3', // dimension sign
  457. + '$1'.txt_trademark, // trademark
  458. + '$1'.txt_registered, // registered
  459. + '$1'.txt_copyright, // copyright
  460. + txt_quarter, // 1/4
  461. + txt_half, // 1/2
  462. + txt_threequarters, // 3/4
  463. + txt_degrees, // degrees
  464. + txt_plusminus, // plus minus
  465. + );
  466. +
  467. + if (defined('hu'))
  468. + $this->hu = hu;
  469. +
  470. + if (defined('DIRECTORY_SEPARATOR'))
  471. + $this->ds = constant('DIRECTORY_SEPARATOR');
  472. + else
  473. + $this->ds = '/';
  474. +
  475. + $this->doc_root = @$_SERVER['DOCUMENT_ROOT'];
  476. + if (!$this->doc_root)
  477. + $this->doc_root = @$_SERVER['PATH_TRANSLATED']; // IIS
  478. +
  479. + $this->doc_root = rtrim($this->doc_root, $this->ds).$this->ds;
  480. + }
  481. +
  482. +// -------------------------------------------------------------
  483. +
  484. + function TextileThis($text, $lite = '', $encode = '', $noimage = '', $strict = '', $rel = '')
  485. + {
  486. + $this->span_depth = 0;
  487. + $this->tag_index = 1;
  488. + $this->notes = $this->unreferencedNotes = $this->notelist_cache = array();
  489. + $this->note_index = 1;
  490. + $this->rel = ($rel) ? ' rel="'.$rel.'"' : '';
  491. +
  492. + $this->lite = $lite;
  493. + $this->noimage = $noimage;
  494. +
  495. + if ($encode)
  496. + {
  497. + $text = $this->incomingEntities($text);
  498. + $text = str_replace("x%x%", "&amp;", $text);
  499. + return $text;
  500. + } else {
  501. + if(!$strict) {
  502. + $text = $this->cleanWhiteSpace($text);
  503. + }
  504. +
  505. + if(!$lite) {
  506. + $text = $this->block($text);
  507. + $text = $this->placeNoteLists($text);
  508. + }
  509. +
  510. + $text = $this->retrieve($text);
  511. + $text = $this->replaceGlyphs($text);
  512. + $text = $this->retrieveTags($text);
  513. + $text = $this->retrieveURLs($text);
  514. + $this->span_depth = 0;
  515. +
  516. + // just to be tidy
  517. + $text = str_replace("<br />", "<br />\n", $text);
  518. +
  519. + return $text;
  520. + }
  521. + }
  522. +
  523. +// -------------------------------------------------------------
  524. +
  525. + function TextileRestricted($text, $lite = 1, $noimage = 1, $rel = 'nofollow')
  526. + {
  527. + $this->restricted = true;
  528. + $this->lite = $lite;
  529. + $this->noimage = $noimage;
  530. +
  531. + $this->span_depth = 0;
  532. + $this->tag_index = 1;
  533. + $this->notes = $this->unreferencedNotes = $this->notelist_cache = array();
  534. + $this->note_index = 1;
  535. +
  536. + $this->rel = ($rel) ? ' rel="'.$rel.'"' : '';
  537. +
  538. + // escape any raw html
  539. + $text = $this->encode_html($text, 0);
  540. +
  541. + $text = $this->cleanWhiteSpace($text);
  542. +
  543. + if($lite) {
  544. + $text = $this->blockLite($text);
  545. + } else {
  546. + $text = $this->block($text);
  547. + $text = $this->placeNoteLists($text);
  548. + }
  549. +
  550. + $text = $this->retrieve($text);
  551. + $text = $this->replaceGlyphs($text);
  552. + $text = $this->retrieveTags($text);
  553. + $text = $this->retrieveURLs($text);
  554. + $this->span_depth = 0;
  555. +
  556. + // just to be tidy
  557. + $text = str_replace("<br />", "<br />\n", $text);
  558. +
  559. + return $text;
  560. + }
  561. +
  562. +// -------------------------------------------------------------
  563. + function pba($in, $element = "", $include_id = 1) // "parse block attributes"
  564. + {
  565. + $style = '';
  566. + $class = '';
  567. + $lang = '';
  568. + $colspan = '';
  569. + $rowspan = '';
  570. + $span = '';
  571. + $width = '';
  572. + $id = '';
  573. + $atts = '';
  574. +
  575. + if (!empty($in)) {
  576. + $matched = $in;
  577. + if ($element == 'td') {
  578. + if (preg_match("/\\\\(\d+)/", $matched, $csp)) $colspan = $csp[1];
  579. + if (preg_match("/\/(\d+)/", $matched, $rsp)) $rowspan = $rsp[1];
  580. + }
  581. +
  582. + if ($element == 'td' or $element == 'tr') {
  583. + if (preg_match("/($this->vlgn)/", $matched, $vert))
  584. + $style[] = "vertical-align:" . $this->vAlign($vert[1]);
  585. + }
  586. +
  587. + if (preg_match("/\{([^}]*)\}/", $matched, $sty)) {
  588. + $style[] = rtrim($sty[1], ';');
  589. + $matched = str_replace($sty[0], '', $matched);
  590. + }
  591. +
  592. + if (preg_match("/\[([^]]+)\]/U", $matched, $lng)) {
  593. + $lang = $lng[1];
  594. + $matched = str_replace($lng[0], '', $matched);
  595. + }
  596. +
  597. + if (preg_match("/\(([^()]+)\)/U", $matched, $cls)) {
  598. + $class = $cls[1];
  599. + $matched = str_replace($cls[0], '', $matched);
  600. + }
  601. +
  602. + if (preg_match("/([(]+)/", $matched, $pl)) {
  603. + $style[] = "padding-left:" . strlen($pl[1]) . "em";
  604. + $matched = str_replace($pl[0], '', $matched);
  605. + }
  606. +
  607. + if (preg_match("/([)]+)/", $matched, $pr)) {
  608. + $style[] = "padding-right:" . strlen($pr[1]) . "em";
  609. + $matched = str_replace($pr[0], '', $matched);
  610. + }
  611. +
  612. + if (preg_match("/($this->hlgn)/", $matched, $horiz))
  613. + $style[] = "text-align:" . $this->hAlign($horiz[1]);
  614. +
  615. + if (preg_match("/^(.*)#(.*)$/", $class, $ids)) {
  616. + $id = $ids[2];
  617. + $class = $ids[1];
  618. + }
  619. +
  620. + if ($element == 'col') {
  621. + if (preg_match("/(?:\\\\(\d+))?\s*(\d+)?/", $matched, $csp)) {
  622. + $span = isset($csp[1]) ? $csp[1] : '';
  623. + $width = isset($csp[2]) ? $csp[2] : '';
  624. + }
  625. + }
  626. +
  627. + if ($this->restricted)
  628. + return ($lang) ? ' lang="' . $lang . '"':'';
  629. +
  630. + $o = '';
  631. + if( $style ) {
  632. + foreach($style as $s) {
  633. + $parts = explode(';', $s);
  634. + foreach( $parts as $p ) {
  635. + $p = trim($p, '; ');
  636. + if( !empty( $p ) )
  637. + $o .= $p.'; ';
  638. + }
  639. + }
  640. + $style = trim( strtr($o, array("\n"=>'',';;'=>';')) );
  641. + }
  642. +
  643. + return join('',array(
  644. + ($style) ? ' style="' . $style .'"':'',
  645. + ($class) ? ' class="' . $class .'"':'',
  646. + ($lang) ? ' lang="' . $lang .'"':'',
  647. + ($id and $include_id) ? ' id="' . $id .'"':'',
  648. + ($colspan) ? ' colspan="' . $colspan .'"':'',
  649. + ($rowspan) ? ' rowspan="' . $rowspan .'"':'',
  650. + ($span) ? ' span="' . $span .'"':'',
  651. + ($width) ? ' width="' . $width .'"':'',
  652. + ));
  653. + }
  654. + return '';
  655. + }
  656. +
  657. +// -------------------------------------------------------------
  658. + function hasRawText($text)
  659. + {
  660. + // checks whether the text has text not already enclosed by a block tag
  661. + $r = trim(preg_replace('@<(p|blockquote|div|form|table|ul|ol|dl|pre|h\d)[^>]*?>.*</\1>@s', '', trim($text)));
  662. + $r = trim(preg_replace('@<(hr|br)[^>]*?/>@', '', $r));
  663. + return '' != $r;
  664. + }
  665. +
  666. +// -------------------------------------------------------------
  667. + function table($text)
  668. + {
  669. + $text = $text . "\n\n";
  670. + return preg_replace_callback("/^(?:table(_?{$this->s}{$this->a}{$this->c})\.(.*)?\n)?^({$this->a}{$this->c}\.? ?\|.*\|)[\s]*\n\n/smU",
  671. + array(&$this, "fTable"), $text);
  672. + }
  673. +
  674. +// -------------------------------------------------------------
  675. + function fTable($matches)
  676. + {
  677. + $tatts = $this->pba($matches[1], 'table');
  678. +
  679. + $sum = trim($matches[2]) ? ' summary="'.htmlspecialchars(trim($matches[2])).'"' : '';
  680. + $cap = '';
  681. + $colgrp = $last_rgrp = '';
  682. + foreach(preg_split("/\|\s*?$/m", $matches[3], -1, PREG_SPLIT_NO_EMPTY) as $row) {
  683. + // Caption
  684. + if (preg_match("/^\|\=($this->s$this->a$this->c)\. ([^\|\n]*)(.*)/s", ltrim($row), $cmtch)) {
  685. + $capts = $this->pba($cmtch[1]);
  686. + $cap = "\t<caption".$capts.">".trim($cmtch[2])."</caption>\n";
  687. + $row = $cmtch[3];
  688. + }
  689. +
  690. + // Colgroup
  691. + if (preg_match("/^\|:($this->s$this->a$this->c\. .*)/m", ltrim($row), $gmtch)) {
  692. + $idx=0;
  693. + foreach (explode('|', str_replace('.', '', $gmtch[1])) as $col) {
  694. + $gatts = $this->pba(trim($col), 'col');
  695. + $colgrp .= "\t<col".(($idx==0) ? "group".$gatts.">" : $gatts." />")."\n";
  696. + $idx++;
  697. + }
  698. + $colgrp .= "\t</colgroup>\n";
  699. + continue;
  700. + }
  701. +
  702. + preg_match("/(:?^\|($this->vlgn)($this->s$this->a$this->c)\.\s*$\n)?^(.*)/sm", ltrim($row), $grpmatch);
  703. +
  704. + // Row group
  705. + $rgrp = isset($grpmatch[2]) ? (($grpmatch[2] == '^') ? 'head' : ( ($grpmatch[2] == '~') ? 'foot' : (($grpmatch[2] == '-') ? 'body' : '' ) ) ) : '';
  706. + $rgrpatts = isset($grpmatch[3]) ? $this->pba($grpmatch[3]) : '';
  707. + $row = $grpmatch[4];
  708. +
  709. + if (preg_match("/^($this->a$this->c\. )(.*)/m", ltrim($row), $rmtch)) {
  710. + $ratts = $this->pba($rmtch[1], 'tr');
  711. + $row = $rmtch[2];
  712. + } else $ratts = '';
  713. +
  714. + $cells = array();
  715. + $cellctr = 0;
  716. + foreach(explode("|", $row) as $cell) {
  717. + $ctyp = "d";
  718. + if (preg_match("/^_/", $cell)) $ctyp = "h";
  719. + if (preg_match("/^(_?$this->s$this->a$this->c\. )(.*)/", $cell, $cmtch)) {
  720. + $catts = $this->pba($cmtch[1], 'td');
  721. + $cell = $cmtch[2];
  722. + } else $catts = '';
  723. +
  724. + $cell = $this->graf($cell);
  725. +
  726. + if ($cellctr>0) // Ignore first 'cell': it precedes the opening pipe
  727. + $cells[] = $this->doTagBr("t$ctyp", "\t\t\t<t$ctyp$catts>$cell</t$ctyp>");
  728. +
  729. + $cellctr++;
  730. + }
  731. + $grp = (($rgrp && $last_rgrp) ? "\t</t".$last_rgrp.">\n" : '') . (($rgrp) ? "\t<t".$rgrp.$rgrpatts.">\n" : '');
  732. + $last_rgrp = ($rgrp) ? $rgrp : $last_rgrp;
  733. + $rows[] = $grp."\t\t<tr$ratts>\n" . join("\n", $cells) . ($cells ? "\n" : "") . "\t\t</tr>";
  734. + unset($cells, $catts);
  735. + }
  736. +
  737. + return "\t<table{$tatts}{$sum}>\n" .$cap. $colgrp. join("\n", $rows) . "\n".(($last_rgrp) ? "\t</t".$last_rgrp.">\n" : '')."\t</table>\n\n";
  738. + }
  739. +
  740. +// -------------------------------------------------------------
  741. + function lists($text)
  742. + {
  743. + return preg_replace_callback("/^([#*;:]+$this->lc[ .].*)$(?![^#*;:])/smU", array(&$this, "fList"), $text);
  744. + }
  745. +
  746. +// -------------------------------------------------------------
  747. + function fList($m)
  748. + {
  749. + $text = preg_split('/\n(?=[*#;:])/m', $m[0]);
  750. + $pt = '';
  751. + foreach($text as $nr => $line) {
  752. + $nextline = isset($text[$nr+1]) ? $text[$nr+1] : false;
  753. + if (preg_match("/^([#*;:]+)($this->lc)[ .](.*)$/s", $line, $m)) {
  754. + list(, $tl, $atts, $content) = $m;
  755. + $content = trim($content);
  756. + $nl = '';
  757. + $ltype = $this->lT($tl);
  758. + $litem = (strpos($tl, ';') !== false) ? 'dt' : ((strpos($tl, ':') !== false) ? 'dd' : 'li');
  759. + $showitem = (strlen($content) > 0);
  760. +
  761. + if (preg_match("/^([#*;:]+)($this->lc)[ .].*/", $nextline, $nm))
  762. + $nl = $nm[1];
  763. +
  764. + if ((strpos($pt, ';') !== false) && (strpos($tl, ':') !== false)) {
  765. + $lists[$tl] = 2; // We're already in a <dl> so flag not to start another
  766. + }
  767. +
  768. + $atts = $this->pba($atts);
  769. + if (!isset($lists[$tl])) {
  770. + $lists[$tl] = 1;
  771. + $line = "\t<" . $ltype . "l$atts>" . (($showitem) ? "\n\t\t<$litem>" . $content : '');
  772. + } else {
  773. + $line = ($showitem) ? "\t\t<$litem$atts>" . $content : '';
  774. + }
  775. +
  776. + if((strlen($nl) <= strlen($tl))) $line .= (($showitem) ? "</$litem>" : '');
  777. + foreach(array_reverse($lists) as $k => $v) {
  778. + if(strlen($k) > strlen($nl)) {
  779. + $line .= ($v==2) ? '' : "\n\t</" . $this->lT($k) . "l>";
  780. + if((strlen($k) > 1) && ($v != 2))
  781. + $line .= "</".$litem.">";
  782. + unset($lists[$k]);
  783. + }
  784. + }
  785. + $pt = $tl; // Remember the current Textile tag
  786. + }
  787. + else {
  788. + $line .= "\n";
  789. + }
  790. + $out[] = $line;
  791. + }
  792. + return $this->doTagBr($litem, join("\n", $out));
  793. + }
  794. +
  795. +// -------------------------------------------------------------
  796. + function lT($in)
  797. + {
  798. + return preg_match("/^#+/", $in) ? 'o' : ((preg_match("/^\*+/", $in)) ? 'u' : 'd');
  799. + }
  800. +
  801. +// -------------------------------------------------------------
  802. + function doTagBr($tag, $in)
  803. + {
  804. + return preg_replace_callback('@<('.preg_quote($tag).')([^>]*?)>(.*)(</\1>)@s', array(&$this, 'fBr'), $in);
  805. + }
  806. +
  807. +// -------------------------------------------------------------
  808. + function doPBr($in)
  809. + {
  810. + return preg_replace_callback('@<(p)([^>]*?)>(.*)(</\1>)@s', array(&$this, 'fPBr'), $in);
  811. + }
  812. +
  813. +// -------------------------------------------------------------
  814. + function fPBr($m)
  815. + {
  816. + # Less restrictive version of fBr() ... used only in paragraphs where the next
  817. + # row may start with a smiley or perhaps something like '#8 bolt...' or '*** stars...'
  818. + $content = preg_replace("@(.+)(?<!<br>|<br />)\n(?![\s|])@", '$1<br />', $m[3]);
  819. + return '<'.$m[1].$m[2].'>'.$content.$m[4];
  820. + }
  821. +
  822. +// -------------------------------------------------------------
  823. + function fBr($m)
  824. + {
  825. + $content = preg_replace("@(.+)(?<!<br>|<br />)\n(?![#*;:\s|])@", '$1<br />', $m[3]);
  826. + return '<'.$m[1].$m[2].'>'.$content.$m[4];
  827. + }
  828. +
  829. +// -------------------------------------------------------------
  830. + function block($text)
  831. + {
  832. + $find = $this->btag;
  833. + $tre = join('|', $find);
  834. +
  835. + $text = explode("\n\n", $text);
  836. +
  837. + $tag = 'p';
  838. + $atts = $cite = $graf = $ext = '';
  839. + $eat = false;
  840. +
  841. + $out = array();
  842. +
  843. + foreach($text as $line) {
  844. + $anon = 0;
  845. + if (preg_match("/^($tre)($this->a$this->c)\.(\.?)(?::(\S+))? (.*)$/s", $line, $m)) {
  846. + // last block was extended, so close it
  847. + if ($ext)
  848. + $out[count($out)-1] .= $c1;
  849. + // new block
  850. + list(,$tag,$atts,$ext,$cite,$graf) = $m;
  851. + list($o1, $o2, $content, $c2, $c1, $eat) = $this->fBlock(array(0,$tag,$atts,$ext,$cite,$graf));
  852. +
  853. + // leave off c1 if this block is extended, we'll close it at the start of the next block
  854. + if ($ext)
  855. + $line = $o1.$o2.$content.$c2;
  856. + else
  857. + $line = $o1.$o2.$content.$c2.$c1;
  858. + }
  859. + else {
  860. + // anonymous block
  861. + $anon = 1;
  862. + if ($ext or !preg_match('/^ /', $line)) {
  863. + list($o1, $o2, $content, $c2, $c1, $eat) = $this->fBlock(array(0,$tag,$atts,$ext,$cite,$line));
  864. + // skip $o1/$c1 because this is part of a continuing extended block
  865. + if ($tag == 'p' and !$this->hasRawText($content)) {
  866. + $line = $content;
  867. + }
  868. + else {
  869. + $line = $o2.$content.$c2;
  870. + }
  871. + }
  872. + else {
  873. + $line = $this->graf($line);
  874. + }
  875. + }
  876. +
  877. + $line = $this->doPBr($line);
  878. + $line = preg_replace('/<br>/', '<br />', $line);
  879. +
  880. + if ($ext and $anon)
  881. + $out[count($out)-1] .= "\n".$line;
  882. + elseif(!$eat)
  883. + $out[] = $line;
  884. +
  885. + if (!$ext) {
  886. + $tag = 'p';
  887. + $atts = '';
  888. + $cite = '';
  889. + $graf = '';
  890. + $eat = false;
  891. + }
  892. + }
  893. + if ($ext) $out[count($out)-1] .= $c1;
  894. + return join("\n\n", $out);
  895. + }
  896. +
  897. +// -------------------------------------------------------------
  898. + function fBlock($m)
  899. + {
  900. + extract($this->regex_snippets);
  901. + list(, $tag, $att, $ext, $cite, $content) = $m;
  902. + $atts = $this->pba($att);
  903. +
  904. + $o1 = $o2 = $c2 = $c1 = '';
  905. + $eat = false;
  906. +
  907. + if( $tag === 'p' ) {
  908. + # Is this an anonymous block with a note definition?
  909. + $notedef = preg_replace_callback("/
  910. + ^note\# # start of note def marker
  911. + ([$wrd:-]+) # !label
  912. + ([*!^]?) # !link
  913. + ({$this->c}) # !att
  914. + \.[\s]+ # end of def marker
  915. + (.*)$ # !content
  916. + /x$mod", array(&$this, "fParseNoteDefs"), $content);
  917. + if( empty($notedef) ) # It will be empty if the regex matched and ate it.
  918. + return array($o1, $o2, $notedef, $c2, $c1, true);
  919. + }
  920. +
  921. + if (preg_match("/fn(\d+)/", $tag, $fns)) {
  922. + $tag = 'p';
  923. + $fnid = empty($this->fn[$fns[1]]) ? $fns[1] : $this->fn[$fns[1]];
  924. +
  925. + # If there is an author-specified ID goes on the wrapper & the auto-id gets pushed to the <sup>
  926. + $supp_id = '';
  927. + if (strpos($atts, ' id=') === false)
  928. + $atts .= ' id="fn' . $fnid . '"';
  929. + else
  930. + $supp_id = ' id="fn' . $fnid . '"';
  931. +
  932. + if (strpos($atts, 'class=') === false)
  933. + $atts .= ' class="footnote"';
  934. +
  935. + $backlink = (strpos($att, '^') === false) ? $fns[1] : '<a href="#fnrev' . $fnid . '">'.$fns[1].'</a>';
  936. + $sup = "<sup$supp_id>$backlink</sup>";
  937. +
  938. + $content = $sup . ' ' . $content;
  939. + }
  940. +
  941. + if ($tag == "bq") {
  942. + $cite = $this->shelveURL($cite);
  943. + $cite = ($cite != '') ? ' cite="' . $cite . '"' : '';
  944. + $o1 = "\t<blockquote$cite$atts>\n";
  945. + $o2 = "\t\t<p".$this->pba($att, '', 0).">";
  946. + $c2 = "</p>";
  947. + $c1 = "\n\t</blockquote>";
  948. + }
  949. + elseif ($tag == 'bc') {
  950. + $o1 = "<pre$atts>";
  951. + $o2 = "<code".$this->pba($att, '', 0).">";
  952. + $c2 = "</code>";
  953. + $c1 = "</pre>";
  954. + $content = $this->shelve($this->r_encode_html(rtrim($content, "\n")."\n"));
  955. + }
  956. + elseif ($tag == 'notextile') {
  957. + $content = $this->shelve($content);
  958. + $o1 = $o2 = '';
  959. + $c1 = $c2 = '';
  960. + }
  961. + elseif ($tag == 'pre') {
  962. + $content = $this->shelve($this->r_encode_html(rtrim($content, "\n")."\n"));
  963. + $o1 = "<pre$atts>";
  964. + $o2 = $c2 = '';
  965. + $c1 = "</pre>";
  966. + }
  967. + elseif ($tag == '###') {
  968. + $eat = true;
  969. + }
  970. + else {
  971. + $o2 = "\t<$tag$atts>";
  972. + $c2 = "</$tag>";
  973. + }
  974. +
  975. + $content = (!$eat) ? $this->graf($content) : '';
  976. +
  977. + return array($o1, $o2, $content, $c2, $c1, $eat);
  978. + }
  979. +
  980. +// -------------------------------------------------------------
  981. + function graf($text)
  982. + {
  983. + // handle normal paragraph text
  984. + if (!$this->lite) {
  985. + $text = $this->noTextile($text);
  986. + $text = $this->code($text);
  987. + }
  988. +
  989. + $text = $this->getRefs($text);
  990. + $text = $this->links($text);
  991. + if (!$this->noimage)
  992. + $text = $this->image($text);
  993. +
  994. + if (!$this->lite) {
  995. + $text = $this->table($text);
  996. + $text = $this->lists($text);
  997. + }
  998. +
  999. + $text = $this->span($text);
  1000. + $text = $this->footnoteRef($text);
  1001. + $text = $this->noteRef($text);
  1002. + $text = $this->glyphs($text);
  1003. + return rtrim($text, "\n");
  1004. + }
  1005. +
  1006. +// -------------------------------------------------------------
  1007. + function span($text)
  1008. + {
  1009. + $qtags = array('\*\*','\*','\?\?','-','__','_','%','\+','~','\^');
  1010. + $pnct = ".,\"'?!;:";
  1011. + $this->span_depth++;
  1012. +
  1013. + if( $this->span_depth <= $this->max_span_depth )
  1014. + {
  1015. + foreach($qtags as $f)
  1016. + {
  1017. + $text = preg_replace_callback("/
  1018. + (^|(?<=[\s>$pnct\(])|[{[]) # pre
  1019. + ($f)(?!$f) # tag
  1020. + ({$this->c}) # atts
  1021. + (?::(\S+))? # cite
  1022. + ([^\s$f]+|\S.*?[^\s$f\n]) # content
  1023. + ([$pnct]*) # end
  1024. + $f
  1025. + ($|[\]}]|(?=[[:punct:]]{1,2}|\s|\))) # tail
  1026. + /x", array(&$this, "fSpan"), $text);
  1027. + }
  1028. + }
  1029. + $this->span_depth--;
  1030. + return $text;
  1031. + }
  1032. +
  1033. +// -------------------------------------------------------------
  1034. + function fSpan($m)
  1035. + {
  1036. + $qtags = array(
  1037. + '*' => 'strong',
  1038. + '**' => 'b',
  1039. + '??' => 'cite',
  1040. + '_' => 'em',
  1041. + '__' => 'i',
  1042. + '-' => 'del',
  1043. + '%' => 'span',
  1044. + '+' => 'ins',
  1045. + '~' => 'sub',
  1046. + '^' => 'sup',
  1047. + );
  1048. +
  1049. + list(, $pre, $tag, $atts, $cite, $content, $end, $tail) = $m;
  1050. +
  1051. + $tag = $qtags[$tag];
  1052. + $atts = $this->pba($atts);
  1053. + $atts .= ($cite != '') ? 'cite="' . $cite . '"' : '';
  1054. +
  1055. + $content = $this->span($content);
  1056. +
  1057. + $opentag = '<'.$tag.$atts.'>';
  1058. + $closetag = '</'.$tag.'>';
  1059. + $tags = $this->storeTags($opentag, $closetag);
  1060. + $out = "{$tags['open']}{$content}{$end}{$tags['close']}";
  1061. +
  1062. + if (($pre and !$tail) or ($tail and !$pre))
  1063. + $out = $pre.$out.$tail;
  1064. +
  1065. + return $out;
  1066. + }
  1067. +
  1068. +// -------------------------------------------------------------
  1069. + function storeTags($opentag,$closetag='')
  1070. + {
  1071. + $key = ($this->tag_index++);
  1072. +
  1073. + $key = str_pad( (string)$key, 10, '0', STR_PAD_LEFT ); # $key must be of fixed length to allow proper matching in retrieveTags
  1074. + $this->tagCache[$key] = array('open'=>$opentag, 'close'=>$closetag);
  1075. + $tags = array(
  1076. + 'open' => "textileopentag{$key} ",
  1077. + 'close' => " textileclosetag{$key}",
  1078. + );
  1079. + return $tags;
  1080. + }
  1081. +
  1082. +// -------------------------------------------------------------
  1083. + function retrieveTags($text)
  1084. + {
  1085. + $text = preg_replace_callback('/textileopentag([\d]{10}) /' , array(&$this, 'fRetrieveOpenTags'), $text);
  1086. + $text = preg_replace_callback('/ textileclosetag([\d]{10})/', array(&$this, 'fRetrieveCloseTags'), $text);
  1087. + return $text;
  1088. + }
  1089. +
  1090. +// -------------------------------------------------------------
  1091. + function fRetrieveOpenTags($m)
  1092. + {
  1093. + list(, $key ) = $m;
  1094. + return $this->tagCache[$key]['open'];
  1095. + }
  1096. +
  1097. +// -------------------------------------------------------------
  1098. + function fRetrieveCloseTags($m)
  1099. + {
  1100. + list(, $key ) = $m;
  1101. + return $this->tagCache[$key]['close'];
  1102. + }
  1103. +
  1104. +// -------------------------------------------------------------
  1105. + function placeNoteLists($text)
  1106. + {
  1107. + extract($this->regex_snippets);
  1108. +
  1109. + # Sequence all referenced definitions...
  1110. + if( !empty($this->notes) ) {
  1111. + $o = array();
  1112. + foreach( $this->notes as $label=>$info ) {
  1113. + $i = @$info['seq'];
  1114. + if( !empty($i) ) {
  1115. + $info['seq'] = $label;
  1116. + $o[$i] = $info;
  1117. + } else {
  1118. + $this->unreferencedNotes[] = $info; # unreferenced definitions go here for possible future use.
  1119. + }
  1120. + }
  1121. + if( !empty($o) ) ksort($o);
  1122. + $this->notes = $o;
  1123. + }
  1124. +
  1125. + # Replace list markers...
  1126. + $text = preg_replace_callback("@<p>notelist({$this->c})(?:\:($wrd))?([\^!]?)(\+?)\.[\s]*</p>@U$mod", array(&$this, "fNoteLists"), $text );
  1127. +
  1128. + return $text;
  1129. + }
  1130. +
  1131. +// -------------------------------------------------------------
  1132. + function fParseNoteDefs($m)
  1133. + {
  1134. + list(, $label, $link, $att, $content) = $m;
  1135. +
  1136. + # Assign an id if the note reference parse hasn't found the label yet.
  1137. + $id = @$this->notes[$label]['id'];
  1138. + if( !$id )
  1139. + $this->notes[$label]['id'] = uniqid(rand());
  1140. +
  1141. + if( empty($this->notes[$label]['def']) ) # Ignores subsequent defs using the same label
  1142. + {
  1143. + $this->notes[$label]['def'] = array(
  1144. + 'atts' => $this->pba($att),
  1145. + 'content' => $this->graf($content),
  1146. + 'link' => $link,
  1147. + );
  1148. + }
  1149. + return '';
  1150. + }
  1151. +
  1152. +// -------------------------------------------------------------
  1153. + function noteRef($text)
  1154. + {
  1155. + $text = preg_replace_callback("/
  1156. + \[ # start
  1157. + ({$this->c}) # !atts
  1158. + \#
  1159. + ([^\]!]+?) # !label
  1160. + ([!]?) # !nolink
  1161. + \]
  1162. + /Ux", array(&$this, "fParseNoteRefs"), $text);
  1163. + return $text;
  1164. + }
  1165. +
  1166. +// -------------------------------------------------------------
  1167. + function fParseNoteRefs($m)
  1168. + {
  1169. + # By the time this function is called, all the defs will have been processed
  1170. + # into the notes array. So now we can resolve the link numbers in the order
  1171. + # we process the refs...
  1172. +
  1173. + list(, $atts, $label, $nolink) = $m;
  1174. + $atts = $this->pba($atts);
  1175. + $nolink = ($nolink === '!');
  1176. +
  1177. + # Assign a sequence number to this reference if there isn't one already...
  1178. + $num = @$this->notes[$label]['seq'];
  1179. + if( !$num )
  1180. + $num = $this->notes[$label]['seq'] = ($this->note_index++);
  1181. +
  1182. + # Make our anchor point & stash it for possible use in backlinks when the
  1183. + # note list is generated later...
  1184. + $this->notes[$label]['refids'][] = $refid = uniqid(rand());
  1185. +
  1186. + # If we are referencing a note that hasn't had the definition parsed yet, then assign it an ID...
  1187. + $id = @$this->notes[$label]['id'];
  1188. + if( !$id )
  1189. + $id = $this->notes[$label]['id'] = uniqid(rand());
  1190. +
  1191. + # Build the link (if any)...
  1192. + $_ = '<span id="noteref'.$refid.'">'.$num.'</span>';
  1193. + if( !$nolink )
  1194. + $_ = '<a href="#note'.$id.'">'.$_.'</a>';
  1195. +
  1196. + # Build the reference...
  1197. + $_ = '<sup'.$atts.'>'.$_.'</sup>';
  1198. +
  1199. + return $_;
  1200. + }
  1201. +
  1202. +// -------------------------------------------------------------
  1203. + function fNoteLists($m)
  1204. + {
  1205. + list(, $att, $start_char, $g_links, $extras) = $m;
  1206. + if( !$start_char ) $start_char = 'a';
  1207. + $index = $g_links.$extras.$start_char;
  1208. +
  1209. + if( empty($this->notelist_cache[$index]) ) { # If not in cache, build the entry...
  1210. + $o = array();
  1211. +
  1212. + if( !empty($this->notes)) {
  1213. + foreach($this->notes as $seq=>$info) {
  1214. + $links = $this->makeBackrefLink($info, $g_links, $start_char );
  1215. + if( !empty($info['def'])) {
  1216. + $id = $info['id'];
  1217. + extract($info['def']);
  1218. + $o[] = "\t".'<li'.$atts.'>'.$links.'<span id="note'.$id.'"> </span>'.$content.'</li>';
  1219. + } else {
  1220. + $o[] = "\t".'<li'.$atts.'>'.$links.' Undefined Note [#'.$info['seq'].'].</li>';
  1221. + }
  1222. + }
  1223. + }
  1224. + if( '+' == $extras && !empty($this->unreferencedNotes) ) {
  1225. + foreach($this->unreferencedNotes as $seq=>$info) {
  1226. + if( !empty($info['def'])) {
  1227. + extract($info['def']);
  1228. + $o[] = "\t".'<li'.$atts.'>'.$content.'</li>';
  1229. + }
  1230. + }
  1231. + }
  1232. +
  1233. + $this->notelist_cache[$index] = join("\n",$o);
  1234. + }
  1235. +
  1236. + $_ = ($this->notelist_cache[$index]) ? $this->notelist_cache[$index] : '';
  1237. +
  1238. + if( !empty($_) ) {
  1239. + $list_atts = $this->pba($att);
  1240. + $_ = "<ol$list_atts>\n$_\n</ol>";
  1241. + }
  1242. +
  1243. + return $_;
  1244. + }
  1245. +
  1246. +// -------------------------------------------------------------
  1247. + function makeBackrefLink( &$info, $g_links, $i )
  1248. + {
  1249. + $atts = $content = $id = $link = '';
  1250. + @extract( $info['def'] );
  1251. + $backlink_type = ($link) ? $link : $g_links;
  1252. +
  1253. + $i_ = strtr( $this->encode_high($i) , array('&'=>'', ';'=>'', '#'=>''));
  1254. + $decode = (strlen($i) !== strlen($i_));
  1255. +
  1256. + if( $backlink_type === '!' )
  1257. + return '';
  1258. + elseif( $backlink_type === '^' )
  1259. + return '<a href="#noteref'.$info['refids'][0].'"><sup>'.$i.'</sup></a>';
  1260. + else {
  1261. + $_ = array();
  1262. + foreach( $info['refids'] as $id ) {
  1263. + $_[] = '<a href="#noteref'.$id.'"><sup>'. ( ($decode) ? $this->decode_high('&#'.$i_.';') : $i_ ) .'</sup></a>';
  1264. + $i_++;
  1265. + }
  1266. + $_ = join( ' ', $_ );
  1267. + return $_;
  1268. + }
  1269. +
  1270. + return '';
  1271. + }
  1272. +
  1273. +// -------------------------------------------------------------
  1274. + function links($text)
  1275. + {
  1276. + return preg_replace_callback('/
  1277. + (^|(?<=[\s>.\(])|[{[]) # $pre
  1278. + " # start
  1279. + (' . $this->c . ') # $atts
  1280. + ([^"]+?) # $text
  1281. + (?:\(([^)]+?)\)(?="))? # $title
  1282. + ":
  1283. + ('.$this->urlch.'+?) # $url
  1284. + (\/)? # $slash
  1285. + ([^\w\/;]*?) # $post
  1286. + ([\]}]|(?=\s|$|\)))
  1287. + /x', array(&$this, "fLink"), $text);
  1288. + }
  1289. +
  1290. +// -------------------------------------------------------------
  1291. + function fLink($m)
  1292. + {
  1293. + list(, $pre, $atts, $text, $title, $url, $slash, $post, $tail) = $m;
  1294. +
  1295. + if( '$' === $text ) $text = $url;
  1296. +
  1297. + $atts = $this->pba($atts);
  1298. + $atts .= ($title != '') ? ' title="' . $this->encode_html($title) . '"' : '';
  1299. +
  1300. + if (!$this->noimage)
  1301. + $text = $this->image($text);
  1302. +
  1303. + $text = $this->span($text);
  1304. + $text = $this->glyphs($text);
  1305. + $url = $this->shelveURL($url.$slash);
  1306. +
  1307. + $opentag = '<a href="' . $url . '"' . $atts . $this->rel . '>';
  1308. + $closetag = '</a>';
  1309. + $tags = $this->storeTags($opentag, $closetag);
  1310. + $out = $tags['open'].trim($text).$tags['close'];
  1311. +
  1312. + if (($pre and !$tail) or ($tail and !$pre))
  1313. + {
  1314. + $out = $pre.$out.$post.$tail;
  1315. + $post = '';
  1316. + }
  1317. +
  1318. + return $this->shelve($out).$post;
  1319. + }
  1320. +
  1321. +// -------------------------------------------------------------
  1322. + function getRefs($text)
  1323. + {
  1324. + return preg_replace_callback("/^\[(.+)\]((?:http:\/\/|\/)\S+)(?=\s|$)/Um",
  1325. + array(&$this, "refs"), $text);
  1326. + }
  1327. +
  1328. +// -------------------------------------------------------------
  1329. + function refs($m)
  1330. + {
  1331. + list(, $flag, $url) = $m;
  1332. + $this->urlrefs[$flag] = $url;
  1333. + return '';
  1334. + }
  1335. +
  1336. +// -------------------------------------------------------------
  1337. + function shelveURL($text)
  1338. + {
  1339. + if (!$text) return '';
  1340. + $ref = md5($text);
  1341. + $this->urlshelf[$ref] = $text;
  1342. + return 'urlref:'.$ref;
  1343. + }
  1344. +
  1345. +// -------------------------------------------------------------
  1346. + function retrieveURLs($text)
  1347. + {
  1348. + return preg_replace_callback('/urlref:(\w{32})/',
  1349. + array(&$this, "retrieveURL"), $text);
  1350. + }
  1351. +
  1352. +// -------------------------------------------------------------
  1353. + function retrieveURL($m)
  1354. + {
  1355. + $ref = $m[1];
  1356. + if (!isset($this->urlshelf[$ref]))
  1357. + return $ref;
  1358. + $url = $this->urlshelf[$ref];
  1359. + if (isset($this->urlrefs[$url]))
  1360. + $url = $this->urlrefs[$url];
  1361. + return $this->r_encode_html($this->relURL($url));
  1362. + }
  1363. +
  1364. +// -------------------------------------------------------------
  1365. + function relURL($url)
  1366. + {
  1367. + $parts = @parse_url(urldecode($url));
  1368. + if ((empty($parts['scheme']) or @$parts['scheme'] == 'http') and
  1369. + empty($parts['host']) and
  1370. + preg_match('/^\w/', @$parts['path']))
  1371. + $url = $this->hu.$url;
  1372. + if ($this->restricted and !empty($parts['scheme']) and
  1373. + !in_array($parts['scheme'], $this->url_schemes))
  1374. + return '#';
  1375. + return $url;
  1376. + }
  1377. +
  1378. +// -------------------------------------------------------------
  1379. + function isRelURL($url)
  1380. + {
  1381. + $parts = @parse_url($url);
  1382. + return (empty($parts['scheme']) and empty($parts['host']));
  1383. + }
  1384. +
  1385. +// -------------------------------------------------------------
  1386. + function image($text)
  1387. + {
  1388. + return preg_replace_callback("/
  1389. + (?:[[{])? # pre
  1390. + \! # opening !
  1391. + (\<|\=|\>)? # optional alignment atts
  1392. + ($this->c) # optional style,class atts
  1393. + (?:\. )? # optional dot-space
  1394. + ([^\s(!]+) # presume this is the src
  1395. + \s? # optional space
  1396. + (?:\(([^\)]+)\))? # optional title
  1397. + \! # closing
  1398. + (?::(\S+))? # optional href
  1399. + (?:[\]}]|(?=\s|$|\))) # lookahead: space or end of string
  1400. + /x", array(&$this, "fImage"), $text);
  1401. + }
  1402. +
  1403. +// -------------------------------------------------------------
  1404. + function fImage($m)
  1405. + {
  1406. + list(, $algn, $atts, $url) = $m;
  1407. + $url = htmlspecialchars($url);
  1408. + $atts = $this->pba($atts);
  1409. + $atts .= ($algn != '') ? ' align="' . $this->iAlign($algn) . '"' : '';
  1410. + if (isset($m[4])) {
  1411. + $m[4] = htmlspecialchars($m[4]);
  1412. + $atts .= ' title="' . $m[4] . '" alt="' . $m[4] . '"';
  1413. + } else {
  1414. + $atts .= ' alt=""';
  1415. + }
  1416. +
  1417. + $size = false;
  1418. + if ($this->isRelUrl($url))
  1419. + $size = @getimagesize(realpath($this->doc_root.ltrim($url, $this->ds)));
  1420. + if ($size) $atts .= " $size[3]";
  1421. +
  1422. + $href = (isset($m[5])) ? $this->shelveURL($m[5]) : '';
  1423. + $url = $this->shelveURL($url);
  1424. +
  1425. + $out = array(
  1426. + ($href) ? '<a href="' . $href . '">' : '',
  1427. + '<img src="' . $url . '"' . $atts . ' />',
  1428. + ($href) ? '</a>' : ''
  1429. + );
  1430. +
  1431. + return $this->shelve(join('',$out));
  1432. + }
  1433. +
  1434. +// -------------------------------------------------------------
  1435. + function code($text)
  1436. + {
  1437. + $text = $this->doSpecial($text, '<code>', '</code>', 'fCode');
  1438. + $text = $this->doSpecial($text, '@', '@', 'fCode');
  1439. + $text = $this->doSpecial($text, '<pre>', '</pre>', 'fPre');
  1440. + return $text;
  1441. + }
  1442. +
  1443. +// -------------------------------------------------------------
  1444. + function fCode($m)
  1445. + {
  1446. + @list(, $before, $text, $after) = $m;
  1447. + return $before.$this->shelve('<code>'.$this->r_encode_html($text).'</code>').$after;
  1448. + }
  1449. +
  1450. +// -------------------------------------------------------------
  1451. + function fPre($m)
  1452. + {
  1453. + @list(, $before, $text, $after) = $m;
  1454. + return $before.'<pre>'.$this->shelve($this->r_encode_html($text)).'</pre>'.$after;
  1455. + }
  1456. +
  1457. +// -------------------------------------------------------------
  1458. + function shelve($val)
  1459. + {
  1460. + $i = uniqid(rand());
  1461. + $this->shelf[$i] = $val;
  1462. + return $i;
  1463. + }
  1464. +
  1465. +// -------------------------------------------------------------
  1466. + function retrieve($text)
  1467. + {
  1468. + if (is_array($this->shelf))
  1469. + do {
  1470. + $old = $text;
  1471. + $text = strtr($text, $this->shelf);
  1472. + } while ($text != $old);
  1473. +
  1474. + return $text;
  1475. + }
  1476. +
  1477. +// -------------------------------------------------------------
  1478. +// NOTE: deprecated
  1479. + function incomingEntities($text)
  1480. + {
  1481. + return preg_replace("/&(?![#a-z0-9]+;)/i", "x%x%", $text);
  1482. + }
  1483. +
  1484. +// -------------------------------------------------------------
  1485. +// NOTE: deprecated
  1486. + function encodeEntities($text)
  1487. + {
  1488. + return (function_exists('mb_encode_numericentity'))
  1489. + ? $this->encode_high($text)
  1490. + : htmlentities($text, ENT_NOQUOTES, "utf-8");
  1491. + }
  1492. +
  1493. +// -------------------------------------------------------------
  1494. +// NOTE: deprecated
  1495. + function fixEntities($text)
  1496. + {
  1497. + /* de-entify any remaining angle brackets or ampersands */
  1498. + return str_replace(array("&gt;", "&lt;", "&amp;"),
  1499. + array(">", "<", "&"), $text);
  1500. + }
  1501. +
  1502. +// -------------------------------------------------------------
  1503. + function cleanWhiteSpace($text)
  1504. + {
  1505. + $out = preg_replace("/^\xEF\xBB\xBF|\x1A/", '', $text); # Byte order mark (if present)
  1506. + $out = preg_replace("/\r\n?/", "\n", $out); # DOS and MAC line endings to *NIX style endings
  1507. + $out = preg_replace("/^[ \t]*\n/m", "\n", $out); # lines containing only whitespace
  1508. + $out = preg_replace("/\n{3,}/", "\n\n", $out); # 3 or more line ends
  1509. + $out = preg_replace("/^\n*/", "", $out); # leading blank lines
  1510. + return $out;
  1511. + }
  1512. +
  1513. +// -------------------------------------------------------------
  1514. + function doSpecial($text, $start, $end, $method='fSpecial')
  1515. + {
  1516. + return preg_replace_callback('/(^|\s|[[({>])'.preg_quote($start, '/').'(.*?)'.preg_quote($end, '/').'(\s|$|[\])}])?/ms',
  1517. + array(&$this, $method), $text);
  1518. + }
  1519. +
  1520. +// -------------------------------------------------------------
  1521. + function fSpecial($m)
  1522. + {
  1523. + // A special block like notextile or code
  1524. + @list(, $before, $text, $after) = $m;
  1525. + return $before.$this->shelve($this->encode_html($text)).$after;
  1526. + }
  1527. +
  1528. +// -------------------------------------------------------------
  1529. + function noTextile($text)
  1530. + {
  1531. + $text = $this->doSpecial($text, '<notextile>', '</notextile>', 'fTextile');
  1532. + return $this->doSpecial($text, '==', '==', 'fTextile');
  1533. +
  1534. + }
  1535. +
  1536. +// -------------------------------------------------------------
  1537. + function fTextile($m)
  1538. + {
  1539. + @list(, $before, $notextile, $after) = $m;
  1540. + #$notextile = str_replace(array_keys($modifiers), array_values($modifiers), $notextile);
  1541. + return $before.$this->shelve($notextile).$after;
  1542. + }
  1543. +
  1544. +// -------------------------------------------------------------
  1545. + function footnoteRef($text)
  1546. + {
  1547. + return preg_replace('/(?<=\S)\[([0-9]+)([\!]?)\](\s)?/Ue',
  1548. + '$this->footnoteID(\'\1\',\'\2\',\'\3\')', $text);
  1549. + }
  1550. +
  1551. +// -------------------------------------------------------------
  1552. + function footnoteID($id, $nolink, $t)
  1553. + {
  1554. + $backref = '';
  1555. + if (empty($this->fn[$id])) {
  1556. + $this->fn[$id] = $a = uniqid(rand());
  1557. + $backref = 'id="fnrev'.$a.'" ';
  1558. + }
  1559. +
  1560. + $fnid = $this->fn[$id];
  1561. +
  1562. + $footref = ( '!' == $nolink ) ? $id : '<a href="#fn'.$fnid.'">'.$id.'</a>';
  1563. + $footref = '<sup '.$backref.'class="footnote">'.$footref.'</sup>';
  1564. +
  1565. + return $footref;
  1566. + }
  1567. +
  1568. +// -------------------------------------------------------------
  1569. + function glyphs($text)
  1570. + {
  1571. + // fix: hackish -- adds a space if final char of text is a double quote.
  1572. + $text = preg_replace('/"\z/', "\" ", $text);
  1573. +
  1574. + $text = preg_split("@(<[\w/!?].*>)@Us", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
  1575. + $i = 0;
  1576. + foreach($text as $line) {
  1577. + // text tag text tag text ...
  1578. + if (++$i % 2) {
  1579. + // raw < > & chars are already entity encoded in restricted mode
  1580. + if (!$this->restricted) {
  1581. + $line = $this->encode_raw_amp($line);
  1582. + $line = $this->encode_lt_gt($line);
  1583. + }
  1584. + $line = preg_replace($this->glyph_search, $this->glyph_replace, $line);
  1585. + }
  1586. + $glyph_out[] = $line;
  1587. + }
  1588. + return join('', $glyph_out);
  1589. + }
  1590. +
  1591. +// -------------------------------------------------------------
  1592. + function replaceGlyphs($text)
  1593. + {
  1594. + return preg_replace('/glyph:([^<]+)/','$1',$text);
  1595. + }
  1596. +
  1597. +// -------------------------------------------------------------
  1598. + function iAlign($in)
  1599. + {
  1600. + $vals = array(
  1601. + '<' => 'left',
  1602. + '=' => 'center',
  1603. + '>' => 'right');
  1604. + return (isset($vals[$in])) ? $vals[$in] : '';
  1605. + }
  1606. +
  1607. +// -------------------------------------------------------------
  1608. + function hAlign($in)
  1609. + {
  1610. + $vals = array(
  1611. + '<' => 'left',
  1612. + '=' => 'center',
  1613. + '>' => 'right',
  1614. + '<>' => 'justify');
  1615. + return (isset($vals[$in])) ? $vals[$in] : '';
  1616. + }
  1617. +
  1618. +// -------------------------------------------------------------
  1619. + function vAlign($in)
  1620. + {
  1621. + $vals = array(
  1622. + '^' => 'top',
  1623. + '-' => 'middle',
  1624. + '~' => 'bottom');
  1625. + return (isset($vals[$in])) ? $vals[$in] : '';
  1626. + }
  1627. +
  1628. +// -------------------------------------------------------------
  1629. +// NOTE: used in notelists
  1630. + function encode_high($text, $charset = "UTF-8")
  1631. + {
  1632. + return mb_encode_numericentity($text, $this->cmap(), $charset);
  1633. + }
  1634. +
  1635. +// -------------------------------------------------------------
  1636. +// NOTE: used in notelists
  1637. + function decode_high($text, $charset = "UTF-8")
  1638. + {
  1639. + return mb_decode_numericentity($text, $this->cmap(), $charset);
  1640. + }
  1641. +
  1642. +// -------------------------------------------------------------
  1643. +// NOTE: deprecated
  1644. + function cmap()
  1645. + {
  1646. + $f = 0xffff;
  1647. + $cmap = array(
  1648. + 0x0080, 0xffff, 0, $f);
  1649. + return $cmap;
  1650. + }
  1651. +
  1652. +// -------------------------------------------------------------
  1653. + function encode_raw_amp($text)
  1654. + {
  1655. + return preg_replace('/&(?!#?[a-z0-9]+;)/i', '&amp;', $text);
  1656. + }
  1657. +
  1658. +// -------------------------------------------------------------
  1659. + function encode_lt_gt($text)
  1660. + {
  1661. + return strtr($text, array('<' => '&lt;', '>' => '&gt;'));
  1662. + }
  1663. +
  1664. +// -------------------------------------------------------------
  1665. + function encode_html($str, $quotes=1)
  1666. + {
  1667. + $a = array(
  1668. + '&' => '&amp;',
  1669. + '<' => '&lt;',
  1670. + '>' => '&gt;',
  1671. + );
  1672. + if ($quotes) $a = $a + array(
  1673. + "'" => '&#39;', // numeric, as in htmlspecialchars
  1674. + '"' => '&quot;',
  1675. + );
  1676. +
  1677. + return strtr($str, $a);
  1678. + }
  1679. +
  1680. +// -------------------------------------------------------------
  1681. + function r_encode_html($str, $quotes=1)
  1682. + {
  1683. + // in restricted mode, input has already been escaped
  1684. + if ($this->restricted)
  1685. + return $str;
  1686. + return $this->encode_html($str, $quotes);
  1687. + }
  1688. +
  1689. +// -------------------------------------------------------------
  1690. + function textile_popup_help($name, $helpvar, $windowW, $windowH)
  1691. + {
  1692. + 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 />';
  1693. +
  1694. + return $out;
  1695. + }
  1696. +
  1697. +// -------------------------------------------------------------
  1698. +// NOTE: deprecated
  1699. + function txtgps($thing)
  1700. + {
  1701. + if (isset($_POST[$thing])) {
  1702. + if (get_magic_quotes_gpc()) {
  1703. + return stripslashes($_POST[$thing]);
  1704. + }
  1705. + else {
  1706. + return $_POST[$thing];
  1707. + }
  1708. + }
  1709. + else {
  1710. + return '';
  1711. + }
  1712. + }
  1713. +
  1714. +// -------------------------------------------------------------
  1715. +// NOTE: deprecated
  1716. + function dump()
  1717. + {
  1718. + static $bool = array( 0=>'false', 1=>'true' );
  1719. + foreach (func_get_args() as $a)
  1720. + echo "\n<pre>",(is_array($a)) ? print_r($a) : ((is_bool($a)) ? $bool[(int)$a] : $a), "</pre>\n";
  1721. + return $this;
  1722. + }
  1723. +
  1724. +// -------------------------------------------------------------
  1725. +
  1726. + function blockLite($text)
  1727. + {
  1728. + $this->btag = array('bq', 'p');
  1729. + return $this->block($text."\n\n");
  1730. + }
  1731. +
  1732. +
  1733. +} // end class
  1734. --
  1735. 1.7.0.4
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement