Html.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * HTML renderer
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * LICENSE: This source file is subject to version 3.0 of the PHP license
  9. * that is available through the world-wide-web at the following URI:
  10. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  11. * the PHP License and are unable to obtain it through the web, please
  12. * send a note to license@php.net so we can mail you a copy immediately.
  13. *
  14. * @category Text
  15. * @package Text_Highlighter
  16. * @author Andrey Demenev <demenev@gmail.com>
  17. * @copyright 2004-2006 Andrey Demenev
  18. * @license http://www.php.net/license/3_0.txt PHP License
  19. * @version CVS: $Id: Html.php,v 1.2 2007/06/29 06:56:34 ssttoo Exp $
  20. * @link http://pear.php.net/package/Text_Highlighter
  21. */
  22. /**
  23. * @ignore
  24. */
  25. require_once dirname(__FILE__).'/../Renderer.php';
  26. require_once dirname(__FILE__).'/../Renderer/Array.php';
  27. // BC trick : only define constants if Text/Highlighter.php
  28. // is not yet included
  29. if (!defined('HL_NUMBERS_LI')) {
  30. /**#@+
  31. * Constant for use with $options['numbers']
  32. */
  33. /**
  34. * use numbered list, deprecated, use HL_NUMBERS_OL instaed
  35. * @deprecated
  36. */
  37. define ('HL_NUMBERS_LI' , 1);
  38. /**
  39. * Use 2-column table with line numbers in left column and code in right column.
  40. */
  41. define ('HL_NUMBERS_TABLE' , 2);
  42. /**#@-*/
  43. }
  44. /**#@+
  45. * Constant for use with $options['numbers']
  46. */
  47. /**
  48. * Use numbered list
  49. */
  50. define ('HL_NUMBERS_OL', 1);
  51. /**
  52. * Use non-numbered list
  53. */
  54. define ('HL_NUMBERS_UL', 3);
  55. /**#@-*/
  56. /**
  57. * HTML renderer
  58. *
  59. * Elements of $options argument of constructor (each being optional):
  60. *
  61. * - 'numbers' - Line numbering style 0 or {@link HL_NUMBERS_TABLE}
  62. * or {@link HL_NUMBERS_UL} or {@link HL_NUMBERS_OL}
  63. * - 'numbers_start' - starting number for numbered lines
  64. * - 'tabsize' - Tab size
  65. * - 'style_map' - Mapping of keywords to formatting rules using inline styles
  66. * - 'class_map' - Mapping of keywords to formatting rules using class names
  67. * - 'doclinks' - array that has keys "url", "target" and "elements", used for
  68. * generating links to online documentation
  69. * - 'use_language' - class names will be prefixed with language, like "php-reserved" or "css-code"
  70. *
  71. * Example of setting documentation links:
  72. * $options['doclinks'] = array(
  73. * 'url' => 'http://php.net/%s',
  74. * 'target' => '_blank',
  75. * 'elements' => array('reserved', 'identifier')
  76. * );
  77. *
  78. * Example of setting class names map:
  79. * $options['class_map'] = array(
  80. * 'main' => 'my-main',
  81. * 'table' => 'my-table',
  82. * 'gutter' => 'my-gutter',
  83. * 'brackets' => 'my-brackets',
  84. * 'builtin' => 'my-builtin',
  85. * 'code' => 'my-code',
  86. * 'comment' => 'my-comment',
  87. * 'default' => 'my-default',
  88. * 'identifier' => 'my-identifier',
  89. * 'inlinedoc' => 'my-inlinedoc',
  90. * 'inlinetags' => 'my-inlinetags',
  91. * 'mlcomment' => 'my-mlcomment',
  92. * 'number' => 'my-number',
  93. * 'quotes' => 'my-quotes',
  94. * 'reserved' => 'my-reserved',
  95. * 'special' => 'my-special',
  96. * 'string' => 'my-string',
  97. * 'url' => 'my-url',
  98. * 'var' => 'my-var',
  99. * );
  100. *
  101. * Example of setting styles mapping:
  102. * $options['style_map'] = array(
  103. * 'main' => 'color: black',
  104. * 'table' => 'border: 1px solid black',
  105. * 'gutter' => 'background-color: yellow',
  106. * 'brackets' => 'color: blue',
  107. * 'builtin' => 'color: red',
  108. * 'code' => 'color: green',
  109. * 'comment' => 'color: orange',
  110. * // ....
  111. * );
  112. *
  113. *
  114. * @author Andrey Demenev <demenev@gmail.com>
  115. * @category Text
  116. * @package Text_Highlighter
  117. * @copyright 2004-2006 Andrey Demenev
  118. * @license http://www.php.net/license/3_0.txt PHP License
  119. * @version Release: 0.7.1
  120. * @link http://pear.php.net/package/Text_Highlighter
  121. */
  122. class Text_Highlighter_Renderer_Html extends Text_Highlighter_Renderer_Array
  123. {
  124. /**#@+
  125. * @access private
  126. */
  127. /**
  128. * Line numbering style
  129. *
  130. * @var integer
  131. */
  132. var $_numbers = 0;
  133. /**
  134. * For numberered lines - where to start
  135. *
  136. * @var integer
  137. */
  138. var $_numbers_start = 0;
  139. /**
  140. * Tab size
  141. *
  142. * @var integer
  143. */
  144. var $_tabsize = 4;
  145. /**
  146. * Highlighted code
  147. *
  148. * @var string
  149. */
  150. var $_output = '';
  151. /**
  152. * Mapping of keywords to formatting rules using inline styles
  153. *
  154. * @var array
  155. */
  156. var $_style_map = array();
  157. /**
  158. * Mapping of keywords to formatting rules using class names
  159. *
  160. * @var array
  161. */
  162. var $_class_map = array(
  163. 'main' => 'hl-main',
  164. 'table' => 'hl-table',
  165. 'gutter' => 'hl-gutter',
  166. 'brackets' => 'hl-brackets',
  167. 'builtin' => 'hl-builtin',
  168. 'code' => 'hl-code',
  169. 'comment' => 'hl-comment',
  170. 'default' => 'hl-default',
  171. 'identifier' => 'hl-identifier',
  172. 'inlinedoc' => 'hl-inlinedoc',
  173. 'inlinetags' => 'hl-inlinetags',
  174. 'mlcomment' => 'hl-mlcomment',
  175. 'number' => 'hl-number',
  176. 'quotes' => 'hl-quotes',
  177. 'reserved' => 'hl-reserved',
  178. 'special' => 'hl-special',
  179. 'string' => 'hl-string',
  180. 'url' => 'hl-url',
  181. 'var' => 'hl-var',
  182. );
  183. /**
  184. * Setup for links to online documentation
  185. *
  186. * This is an array with keys:
  187. * - url, ex. http://php.net/%s
  188. * - target, ex. _blank, default - no target
  189. * - elements, default is <code>array('reserved', 'identifier')</code>
  190. *
  191. * @var array
  192. */
  193. var $_doclinks = array();
  194. /**#@-*/
  195. /**
  196. * Resets renderer state
  197. *
  198. * @access protected
  199. *
  200. *
  201. * Descendents of Text_Highlighter call this method from the constructor,
  202. * passing $options they get as parameter.
  203. */
  204. function reset()
  205. {
  206. $this->_output = '';
  207. if (isset($this->_options['numbers'])) {
  208. $this->_numbers = (int)$this->_options['numbers'];
  209. if ($this->_numbers != HL_NUMBERS_LI
  210. && $this->_numbers != HL_NUMBERS_UL
  211. && $this->_numbers != HL_NUMBERS_OL
  212. && $this->_numbers != HL_NUMBERS_TABLE
  213. ) {
  214. $this->_numbers = 0;
  215. }
  216. }
  217. if (isset($this->_options['tabsize'])) {
  218. $this->_tabsize = $this->_options['tabsize'];
  219. }
  220. if (isset($this->_options['numbers_start'])) {
  221. $this->_numbers_start = intval($this->_options['numbers_start']);
  222. }
  223. if (isset($this->_options['doclinks']) &&
  224. is_array($this->_options['doclinks']) &&
  225. !empty($this->_options['doclinks']['url'])
  226. ) {
  227. $this->_doclinks = $this->_options['doclinks']; // keys: url, target, elements array
  228. if (empty($this->_options['doclinks']['elements'])) {
  229. $this->_doclinks['elements'] = array('reserved', 'identifier');
  230. }
  231. }
  232. if (isset($this->_options['style_map'])) {
  233. $this->_style_map = $this->_options['style_map'];
  234. }
  235. if (isset($this->_options['class_map'])) {
  236. $this->_class_map = array_merge($this->_class_map, $this->_options['class_map']);
  237. }
  238. $this->_htmlspecialchars = true;
  239. }
  240. /**
  241. * Given a CSS class name, returns the class name
  242. * with language name prepended, if necessary
  243. *
  244. * @access private
  245. *
  246. * @param string $class Token class
  247. */
  248. function _getFullClassName($class)
  249. {
  250. if (!empty($this->_options['use_language'])) {
  251. $the_class = $this->_language . '-' . $class;
  252. } else {
  253. $the_class = $class;
  254. }
  255. return $the_class;
  256. }
  257. /**
  258. * Signals that no more tokens are available
  259. *
  260. * @access public
  261. */
  262. function finalize()
  263. {
  264. // get parent's output
  265. parent::finalize();
  266. $output = parent::getOutput();
  267. if(empty($output))
  268. return;
  269. $html_output = '';
  270. $numbers_li = false;
  271. if (
  272. $this->_numbers == HL_NUMBERS_LI ||
  273. $this->_numbers == HL_NUMBERS_UL ||
  274. $this->_numbers == HL_NUMBERS_OL
  275. )
  276. {
  277. $numbers_li = true;
  278. }
  279. // loop through each class=>content pair
  280. foreach ($output AS $token) {
  281. if ($this->_enumerated) {
  282. $key = false;
  283. $the_class = $token[0];
  284. $content = $token[1];
  285. } else {
  286. $key = key($token);
  287. $the_class = $key;
  288. $content = $token[$key];
  289. }
  290. $span = $this->_getStyling($the_class);
  291. $decorated_output = $this->_decorate($content, $key);
  292. //print "<pre> token = ".var_export($token, true)." -- span = " . htmlentities($span). "-- deco = ".$decorated_output."</pre>\n";
  293. $html_output .= sprintf($span, $decorated_output);
  294. }
  295. // format lists
  296. if (!empty($this->_numbers) && $numbers_li == true) {
  297. //$html_output = "<pre>".$html_output."</pre>";
  298. // additional whitespace for browsers that do not display
  299. // empty list items correctly
  300. $this->_output = '<li><pre>&nbsp;' . str_replace("\n", "</pre></li>\n<li><pre>&nbsp;", $html_output) . '</pre></li>';
  301. $start = '';
  302. if ($this->_numbers == HL_NUMBERS_OL && intval($this->_numbers_start) > 0) {
  303. $start = ' start="' . $this->_numbers_start . '"';
  304. }
  305. $list_tag = 'ol';
  306. if ($this->_numbers == HL_NUMBERS_UL) {
  307. $list_tag = 'ul';
  308. }
  309. $this->_output = '<' . $list_tag . $start
  310. . ' ' . $this->_getStyling('main', false) . '>'
  311. . $this->_output . '</'. $list_tag .'>';
  312. // render a table
  313. } else if ($this->_numbers == HL_NUMBERS_TABLE) {
  314. $start_number = 0;
  315. if (intval($this->_numbers_start)) {
  316. $start_number = $this->_numbers_start - 1;
  317. }
  318. $numbers = '';
  319. $nlines = substr_count($html_output,"\n")+1;
  320. for ($i=1; $i <= $nlines; $i++) {
  321. $numbers .= ($start_number + $i) . "\n";
  322. }
  323. $this->_output = '<table ' . $this->_getStyling('table', false) . ' width="100%"><tr>' .
  324. '<td '. $this->_getStyling('gutter', false) .' align="right" valign="top">' .
  325. '<pre>' . $numbers . '</pre></td><td '. $this->_getStyling('main', false) .
  326. ' valign="top"><pre>' .
  327. $html_output . '</pre></td></tr></table>';
  328. }
  329. if (!$this->_numbers) {
  330. $this->_output = '<pre>' . $html_output . '</pre>';
  331. }
  332. $this->_output = '<div ' . $this->_getStyling('main', false) . '>' . $this->_output . '</div>';
  333. }
  334. /**
  335. * Provides additional formatting to a keyword
  336. *
  337. * @param string $content Keyword
  338. * @return string Keyword with additional formatting
  339. * @access public
  340. *
  341. */
  342. function _decorate($content, $key = false)
  343. {
  344. // links to online documentation
  345. if (!empty($this->_doclinks) &&
  346. !empty($this->_doclinks['url']) &&
  347. in_array($key, $this->_doclinks['elements'])
  348. ) {
  349. $link = '<a href="'. sprintf($this->_doclinks['url'], $content) . '"';
  350. if (!empty($this->_doclinks['target'])) {
  351. $link.= ' target="' . $this->_doclinks['target'] . '"';
  352. }
  353. $link .= '>';
  354. $link.= $content;
  355. $link.= '</a>';
  356. $content = $link;
  357. }
  358. return $content;
  359. }
  360. /**
  361. * Returns <code>class</code> and/or <code>style</code> attribute,
  362. * optionally enclosed in a <code>span</code> tag
  363. *
  364. * @param string $class Class name
  365. * @paran boolean $span_tag Whether or not to return styling attributes in a <code>&gt;span&lt;</code> tag
  366. * @return string <code>span</code> tag or just a <code>class</code> and/or <code>style</code> attributes
  367. * @access private
  368. */
  369. function _getStyling($class, $span_tag = true)
  370. {
  371. $attrib = '';
  372. if (!empty($this->_style_map) &&
  373. !empty($this->_style_map[$class])
  374. ) {
  375. $attrib = 'style="'. $this->_style_map[$class] .'"';
  376. }
  377. if (!empty($this->_class_map) &&
  378. !empty($this->_class_map[$class])
  379. ) {
  380. if ($attrib) {
  381. $attrib .= ' ';
  382. }
  383. $attrib .= 'class="'. $this->_getFullClassName($this->_class_map[$class]) .'"';
  384. }
  385. if ($span_tag) {
  386. $span = '<span ' . $attrib . '>%s</span>';
  387. return $span;
  388. } else {
  389. return $attrib;
  390. }
  391. }
  392. }
  393. /*
  394. * Local variables:
  395. * tab-width: 4
  396. * c-basic-offset: 4
  397. * c-hanging-comment-ender-p: nil
  398. * End:
  399. */
  400. ?>