PageRenderTime 51ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/wiki/lib/plugins/columns/syntax.php

https://github.com/houshuang/folders2web
PHP | 441 lines | 310 code | 52 blank | 79 comment | 76 complexity | 3dfc79b74509cccd66b46952b9ab353b MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * Plugin Columns: Syntax & rendering
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Mykola Ostrovskyy <spambox03@mail.ru>
  7. * Based on plugin by Michael Arlt <michael.arlt [at] sk-schwanstetten [dot] de>
  8. */
  9. /* Must be run within Dokuwiki */
  10. if(!defined('DOKU_INC')) die();
  11. if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
  12. require_once(DOKU_PLUGIN . 'syntax.php');
  13. require_once(DOKU_PLUGIN . 'columns/info.php');
  14. class syntax_plugin_columns extends DokuWiki_Syntax_Plugin {
  15. var $mode;
  16. var $lexerSyntax;
  17. var $syntax;
  18. /**
  19. * Constructor
  20. */
  21. function syntax_plugin_columns() {
  22. $this->mode = substr(get_class($this), 7);
  23. $columns = $this->_getColumnsTagName();
  24. $newColumn = $this->_getNewColumnTagName();
  25. if ($this->getConf('wrapnewcol') == 1) {
  26. $newColumnLexer = '<' . $newColumn . '(?:>|\s.*?>)';
  27. $newColumnHandler = '<' . $newColumn . '(.*?)>';
  28. }
  29. else {
  30. $newColumnLexer = $newColumn;
  31. $newColumnHandler = $newColumn;
  32. }
  33. $enterLexer = '<' . $columns . '(?:>|\s.*?>)';
  34. $enterHandler = '<' . $columns . '(.*?)>';
  35. $exit = '<\/' . $columns . '>';
  36. $this->lexerSyntax['enter'] = $enterLexer;
  37. $this->lexerSyntax['newcol'] = $newColumnLexer;
  38. $this->lexerSyntax['exit'] = $exit;
  39. $this->syntax[DOKU_LEXER_ENTER] = '/' . $enterHandler . '/';
  40. $this->syntax[DOKU_LEXER_MATCHED] = '/' . $newColumnHandler . '/';
  41. $this->syntax[DOKU_LEXER_EXIT] = '/' . $exit . '/';
  42. }
  43. /**
  44. * Return some info
  45. */
  46. function getInfo() {
  47. return columns_getInfo('syntax & rendering');
  48. }
  49. /**
  50. * What kind of syntax are we?
  51. */
  52. function getType() {
  53. return 'substition';
  54. }
  55. function getPType() {
  56. return 'block';
  57. }
  58. /**
  59. * Where to sort in?
  60. */
  61. function getSort() {
  62. return 65;
  63. }
  64. function connectTo($mode) {
  65. $this->Lexer->addSpecialPattern($this->lexerSyntax['enter'], $mode, $this->mode);
  66. $this->Lexer->addSpecialPattern($this->lexerSyntax['newcol'], $mode, $this->mode);
  67. $this->Lexer->addSpecialPattern($this->lexerSyntax['exit'], $mode, $this->mode);
  68. }
  69. /**
  70. * Handle the match
  71. */
  72. function handle($match, $state, $pos, &$handler) {
  73. foreach ($this->syntax as $state => $pattern) {
  74. if (preg_match($pattern, $match, $data) == 1) {
  75. break;
  76. }
  77. }
  78. switch ($state) {
  79. case DOKU_LEXER_ENTER:
  80. case DOKU_LEXER_MATCHED:
  81. return array($state, preg_split('/\s+/', $data[1], -1, PREG_SPLIT_NO_EMPTY));
  82. case DOKU_LEXER_EXIT:
  83. return array($state);
  84. }
  85. return false;
  86. }
  87. /**
  88. * Create output
  89. */
  90. function render($mode, &$renderer, $data) {
  91. if ($mode == 'xhtml') {
  92. switch ($data[0]) {
  93. case DOKU_LEXER_ENTER:
  94. $renderer->doc .= $this->_renderTable($data[1]) . DOKU_LF;
  95. $renderer->doc .= '<tr>' . $this->_renderTd($data[1]) . DOKU_LF;
  96. break;
  97. case DOKU_LEXER_MATCHED:
  98. $renderer->doc .= '</td>' . $this->_renderTd($data[1]) . DOKU_LF;
  99. break;
  100. case DOKU_LEXER_EXIT:
  101. $renderer->doc .= '</td></tr></table>' . DOKU_LF;
  102. break;
  103. }
  104. return true;
  105. }
  106. else if ($mode == 'odt') {
  107. switch ($data[0]) {
  108. case DOKU_LEXER_ENTER:
  109. $this->_addOdtTableStyle($renderer, $data[1]);
  110. $this->_addOdtColumnStyles($renderer, $data[1]);
  111. $this->_renderOdtTableEnter($renderer, $data[1]);
  112. $this->_renderOdtColumnEnter($renderer, $data[1]);
  113. break;
  114. case DOKU_LEXER_MATCHED:
  115. $this->_addOdtColumnStyles($renderer, $data[1]);
  116. $this->_renderOdtColumnExit($renderer);
  117. $this->_renderOdtColumnEnter($renderer, $data[1]);
  118. break;
  119. case DOKU_LEXER_EXIT:
  120. $this->_renderOdtColumnExit($renderer);
  121. $this->_renderOdtTableExit($renderer);
  122. break;
  123. }
  124. return true;
  125. }
  126. return false;
  127. }
  128. /**
  129. * Returns columns tag
  130. */
  131. function _getColumnsTagName() {
  132. $tag = $this->getConf('kwcolumns');
  133. if ($tag == '') {
  134. $tag = $this->getLang('kwcolumns');
  135. }
  136. return $tag;
  137. }
  138. /**
  139. * Returns new column tag
  140. */
  141. function _getNewColumnTagName() {
  142. $tag = $this->getConf('kwnewcol');
  143. if ($tag == '') {
  144. $tag = $this->getLang('kwnewcol');
  145. }
  146. return $tag;
  147. }
  148. /**
  149. *
  150. */
  151. function _renderTable($attribute) {
  152. $width = $this->_getAttribute($attribute, 'table-width');
  153. if ($width != '') {
  154. return '<table class="columns-plugin" style="width:' . $width . '">';
  155. }
  156. else {
  157. return '<table class="columns-plugin">';
  158. }
  159. }
  160. /**
  161. *
  162. */
  163. function _renderTd($attribute) {
  164. $class = $this->_getAttribute($attribute, 'class');
  165. $textAlign = $this->_getAttribute($attribute, 'text-align');
  166. if ($textAlign != '') {
  167. if ($class != '') {
  168. $class .= ' ';
  169. }
  170. $class .= $textAlign;
  171. }
  172. if ($class == '') {
  173. $html = '<td';
  174. }
  175. else {
  176. $html = '<td class="' . $class . '"';
  177. }
  178. $style = $this->_getStyle($attribute, 'column-width', 'width');
  179. $style .= $this->_getStyle($attribute, 'vertical-align');
  180. if ($style != '') {
  181. $html .= ' style="' . $style . '"';
  182. }
  183. return $html . '>';
  184. }
  185. /**
  186. *
  187. */
  188. function _getStyle($attribute, $attributeName, $styleName = '') {
  189. $result = $this->_getAttribute($attribute, $attributeName);
  190. if ($result != '') {
  191. if ($styleName == '') {
  192. $styleName = $attributeName;
  193. }
  194. $result = $styleName . ':' . $result . ';';
  195. }
  196. return $result;
  197. }
  198. /**
  199. *
  200. */
  201. function _getAttribute($attribute, $name) {
  202. $result = '';
  203. if (array_key_exists($name, $attribute)) {
  204. $result = $attribute[$name];
  205. }
  206. return $result;
  207. }
  208. /**
  209. *
  210. */
  211. function _renderOdtTableEnter(&$renderer, $attribute) {
  212. $columns = $this->_getAttribute($attribute, 'columns');
  213. $blockId = $this->_getAttribute($attribute, 'block-id');
  214. $styleName = $this->_getOdtTableStyleName($blockId);
  215. $renderer->doc .= '<table:table table:style-name="' . $styleName . '">';
  216. for ($c = 0; $c < $columns; $c++) {
  217. $styleName = $this->_getOdtTableStyleName($blockId, $c + 1);
  218. $renderer->doc .= '<table:table-column table:style-name="' . $styleName . '" />';
  219. }
  220. $renderer->doc .= '<table:table-row>';
  221. }
  222. /**
  223. *
  224. */
  225. function _renderOdtColumnEnter(&$renderer, $attribute) {
  226. $blockId = $this->_getAttribute($attribute, 'block-id');
  227. $columnId = $this->_getAttribute($attribute, 'column-id');
  228. $styleName = $this->_getOdtTableStyleName($blockId, $columnId, 1);
  229. $renderer->doc .= '<table:table-cell table:style-name="' . $styleName . '" office:value-type="string">';
  230. }
  231. /**
  232. *
  233. */
  234. function _renderOdtColumnExit(&$renderer) {
  235. $renderer->doc .= '</table:table-cell>';
  236. }
  237. /**
  238. *
  239. */
  240. function _renderOdtTableExit(&$renderer) {
  241. $renderer->doc .= '</table:table-row>';
  242. $renderer->doc .= '</table:table>';
  243. }
  244. /**
  245. *
  246. */
  247. function _addOdtTableStyle(&$renderer, $attribute) {
  248. $styleName = $this->_getOdtTableStyleName($this->_getAttribute($attribute, 'block-id'));
  249. $style = '<style:style style:name="' . $styleName . '" style:family="table">';
  250. $style .= '<style:table-properties';
  251. $width = $this->_getAttribute($attribute, 'table-width');
  252. if (($width != '') && ($width != '100%')) {
  253. $metrics = $this->_getOdtMetrics($renderer->autostyles);
  254. $style .= ' style:width="' . $this->_getOdtAbsoluteWidth($metrics, $width) . '"';
  255. }
  256. $align = ($width == '100%') ? 'margins' : 'left';
  257. $style .= ' table:align="' . $align . '"/>';
  258. $style .= '</style:style>';
  259. $renderer->autostyles[$styleName] = $style;
  260. }
  261. /**
  262. *
  263. */
  264. function _addOdtColumnStyles(&$renderer, $attribute) {
  265. $blockId = $this->_getAttribute($attribute, 'block-id');
  266. $columnId = $this->_getAttribute($attribute, 'column-id');
  267. $styleName = $this->_getOdtTableStyleName($blockId, $columnId);
  268. $style = '<style:style style:name="' . $styleName . '" style:family="table-column">';
  269. $style .= '<style:table-column-properties';
  270. $width = $this->_getAttribute($attribute, 'column-width');
  271. if ($width != '') {
  272. $metrics = $this->_getOdtMetrics($renderer->autostyles);
  273. $style .= ' style:column-width="' . $this->_getOdtAbsoluteWidth($metrics, $width) . '"';
  274. }
  275. $style .= '/>';
  276. $style .= '</style:style>';
  277. $renderer->autostyles[$styleName] = $style;
  278. $styleName = $this->_getOdtTableStyleName($blockId, $columnId, 1);
  279. $style = '<style:style style:name="' . $styleName . '" style:family="table-cell">';
  280. $style .= '<style:table-cell-properties';
  281. $style .= ' fo:border="none"';
  282. $style .= ' fo:padding-top="0cm"';
  283. $style .= ' fo:padding-bottom="0cm"';
  284. switch ($this->_getAttribute($attribute, 'class')) {
  285. case 'first':
  286. $style .= ' fo:padding-left="0cm"';
  287. $style .= ' fo:padding-right="0.4cm"';
  288. break;
  289. case 'last':
  290. $style .= ' fo:padding-left="0.4cm"';
  291. $style .= ' fo:padding-right="0cm"';
  292. break;
  293. }
  294. /* There seems to be no easy way to control horizontal alignment of text within
  295. the column as fo:text-align aplies to individual paragraphs. */
  296. //TODO: $this->_getAttribute($attribute, 'text-align');
  297. $align = $this->_getAttribute($attribute, 'vertical-align');
  298. if ($align != '') {
  299. $style .= ' style:vertical-align="' . $align . '"';
  300. }
  301. else {
  302. $style .= ' style:vertical-align="top"';
  303. }
  304. $style .= '/>';
  305. $style .= '</style:style>';
  306. $renderer->autostyles[$styleName] = $style;
  307. }
  308. /**
  309. *
  310. */
  311. function _getOdtMetrics($autoStyle) {
  312. $result = array();
  313. if (array_key_exists('pm1', $autoStyle)) {
  314. $style = $autoStyle['pm1'];
  315. if (preg_match('/fo:page-width="([\d\.]+)(.+?)"/', $style, $match) == 1) {
  316. $result['page-width'] = floatval($match[1]);
  317. $result['page-width-units'] = $match[2];
  318. $units = $match[2];
  319. if (preg_match('/fo:margin-left="([\d\.]+)(.+?)"/', $style, $match) == 1) {
  320. // TODO: Unit conversion
  321. if ($match[2] == $units) {
  322. $result['page-width'] -= floatval($match[1]);
  323. }
  324. }
  325. if (preg_match('/fo:margin-right="([\d\.]+)(.+?)"/', $style, $match) == 1) {
  326. if ($match[2] == $units) {
  327. $result['page-width'] -= floatval($match[1]);
  328. }
  329. }
  330. }
  331. }
  332. if (!array_key_exists('page-width', $result)) {
  333. $result['page-width'] = 17;
  334. $result['page-width-units'] = 'cm';
  335. }
  336. /* There seems to be no easy way to get default font size apart from loading styles.xml. */
  337. $styles = io_readFile(DOKU_PLUGIN . 'odt/styles.xml');
  338. if (preg_match('/<style:default-style style:family="paragraph">(.+?)<\/style:default-style>/s', $styles, $match) == 1) {
  339. if (preg_match('/<style:text-properties(.+?)>/', $match[1], $match) == 1) {
  340. if (preg_match('/fo:font-size="([\d\.]+)(.+?)"/', $match[1], $match) == 1) {
  341. $result['font-size'] = floatval($match[1]);
  342. $result['font-size-units'] = $match[2];
  343. }
  344. }
  345. }
  346. if (!array_key_exists('font-size', $result)) {
  347. $result['font-size'] = 12;
  348. $result['font-size-units'] = 'pt';
  349. }
  350. return $result;
  351. }
  352. /**
  353. *
  354. */
  355. function _getOdtTableStyleName($blockId, $columnId = 0, $cell = 0) {
  356. $result = 'ColumnsBlock' . $blockId;
  357. if ($columnId != 0) {
  358. if ($columnId <= 26) {
  359. $result .= '.' . chr(ord('A') + $columnId - 1);
  360. }
  361. else {
  362. /* To unlikey to handle it properly */
  363. $result .= '.a';
  364. }
  365. if ($cell != 0) {
  366. $result .= $cell;
  367. }
  368. }
  369. return $result;
  370. }
  371. /**
  372. * Convert relative units to absolute
  373. */
  374. function _getOdtAbsoluteWidth($metrics, $width) {
  375. if (preg_match('/([\d\.]+)(.+)/', $width, $match) == 1) {
  376. switch ($match[2]) {
  377. case '%':
  378. /* Won't work for nested column blocks */
  379. $width = ($match[1] / 100 * $metrics['page-width']) . $metrics['page-width-units'];
  380. break;
  381. case 'em':
  382. /* Rough estimate */
  383. $width = ($match[1] * 0.8 * $metrics['font-size']) . $metrics['font-size-units'];
  384. break;
  385. }
  386. }
  387. return $width;
  388. }
  389. }