PageRenderTime 65ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/plugins/dir/syntax.php

https://bitbucket.org/lifthrasiir/dokuwiki-custom
PHP | 1410 lines | 983 code | 203 blank | 224 comment | 197 complexity | 62209c3de2fd9b559f280be6862f927d MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * Dir Plugin: Shows pages in one or namespaces in a table or list
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Jacobus Geluk <Jacobus.Geluk@gmail.com>
  7. * @based_on "pageindex" plugin by Kite <Kite@puzzlers.org>
  8. * @based_on "externallink" plugin by Otto Vainio <plugins@valjakko.net>
  9. * @based_on "pagelist" plugin by Esther Brunner <wikidesign@gmail.com>
  10. *
  11. * Contributions by:
  12. *
  13. * - Jean-Philippe Prade
  14. * - Gunther Hartmann
  15. * - Sebastian Menge
  16. */
  17. if (! defined ('DOKU_INC')) {
  18. define ('DOKU_INC', realpath (dirname (__FILE__) . '/../../') . '/') ;
  19. }
  20. if (! defined ('DOKU_PLUGIN')) {
  21. define ('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/') ;
  22. }
  23. require_once (DOKU_PLUGIN . 'syntax.php') ;
  24. require_once (DOKU_INC . 'inc/search.php') ;
  25. define ("DIR_PLUGIN_PATTERN", "DIR") ;
  26. /**
  27. * The main DIR plugin class...
  28. */
  29. class syntax_plugin_dir extends DokuWiki_Syntax_Plugin {
  30. var $debug = false ;
  31. var $plugins = Array () ;
  32. var $opts = Array () ;
  33. var $cols = Array () ;
  34. var $hdrs = Array () ;
  35. var $pages = Array () ;
  36. var $includeTags = Array () ;
  37. var $excludeTags = Array () ;
  38. var $hasTags = false ;
  39. var $style = "default" ;
  40. var $rdr = NULL ;
  41. var $rdrMode = NULL ;
  42. var $start = "start" ;
  43. var $dformat = NULL ;
  44. var $sortKeys = Array () ;
  45. var $nbrOfSortKeys = 0 ;
  46. var $useDefaultTitle = true ;
  47. var $modeIsXHTML = false ;
  48. var $modeIsLatex = false ;
  49. var $processedLatex = false ;
  50. var $rowNumber = 0 ;
  51. /**
  52. * Constructor
  53. */
  54. function syntax_plugin_dir () {
  55. global $conf ;
  56. //
  57. // In the config you can set allowdebug, but you can also
  58. // specify the debug attribute in the ~~DIR~~ line...
  59. //
  60. if ($conf ["allowdebug"] == 1)
  61. $this->debug = true ;
  62. $this->start = $conf ["start"] ;
  63. $this->dformat = $conf ["dformat"] ;
  64. $this->style = $this->getConf ("style") ;
  65. }
  66. /**
  67. * return some info
  68. */
  69. function getInfo () {
  70. return array (
  71. 'author' => 'Jacobus Geluk',
  72. 'email' => 'Jacobus.Geluk@gmail.com',
  73. 'date' => '2008-06-28',
  74. 'name' => 'Dir Plugin',
  75. 'desc' => 'Shows pages in one or namespaces in a table or list',
  76. 'url' => 'http://wiki.splitbrain.org/plugin:dir',
  77. ) ;
  78. }
  79. /**
  80. * What kind of syntax are we?
  81. */
  82. function getType () {
  83. return "substition" ;
  84. }
  85. /**
  86. * Just before build in links
  87. */
  88. function getSort () {
  89. return 299 ;
  90. }
  91. /**
  92. * What about paragraphs?
  93. */
  94. function getPType () {
  95. return "block" ;
  96. }
  97. /**
  98. * Register the ~~DIR~~ verb...
  99. * Supported signatures:
  100. *
  101. * 1. ~~DIR~~
  102. * 2. ~~DIR:...~~
  103. * 3. ~~DIR?...~~
  104. */
  105. function connectTo ($mode) {
  106. $this->Lexer->addSpecialPattern (
  107. '~~' . DIR_PLUGIN_PATTERN . '~~', $mode, 'plugin_dir'
  108. ) ;
  109. $this->Lexer->addSpecialPattern (
  110. '~~' . DIR_PLUGIN_PATTERN . '[:?][^~]*~~', $mode, 'plugin_dir'
  111. ) ;
  112. }
  113. /**
  114. * Handle the match
  115. */
  116. function handle ($match, $state, $pos, &$handler) {
  117. return preg_replace (
  118. "%~~" . DIR_PLUGIN_PATTERN . ":(=(.*))?~~%", "\\2",
  119. $match
  120. ) ;
  121. }
  122. /**
  123. * Initialize the current object for each rendering pass
  124. */
  125. function _initRender ($mode, &$renderer) {
  126. $rc = FALSE ;
  127. $this->rowNumber = 0 ;
  128. $this->opts = Array () ;
  129. $this->cols = Array () ;
  130. $this->hdrs = Array () ;
  131. $this->pages = Array () ;
  132. $this->hasTags = false ;
  133. $this->excludeTags = Array () ;
  134. $this->includeTags = Array () ;
  135. $this->rdr =& $renderer ;
  136. $this->rdrMode = $mode ;
  137. switch ($mode) {
  138. case 'latex':
  139. $this->modeIsXHTML = false ;
  140. $this->modeIsLatex = true ;
  141. $rc = TRUE ;
  142. break ;
  143. case 'xhtml':
  144. $this->modeIsXHTML = true ;
  145. $this->modeIsLatex = false ;
  146. $rc = TRUE ;
  147. break ;
  148. default:
  149. $this->modeIsXHTML = false ;
  150. $this->modeIsLatex = false ;
  151. }
  152. return $rc ;
  153. }
  154. /**
  155. * Create output
  156. */
  157. function render ($mode, &$renderer, $data) {
  158. if (! $this->_initRender ($mode, $renderer))
  159. return false ;
  160. $rc = $this->_dir ($data) ;
  161. if ($this->modeIsLatex)
  162. $this->processedLatex = true ;
  163. $this->_showDebugMsg ("Leaving syntax_plugin_dir.render()") ;
  164. return $rc ;
  165. }
  166. /**
  167. * Put a debug message on screen...
  168. */
  169. function _showDebugMsg ($msg) {
  170. if (! $this->debug)
  171. return ;
  172. if (is_array ($msg)) {
  173. foreach ($msg as $index => $m) {
  174. $this->_showDebugMsg ("Array [$index]: " . $m) ;
  175. }
  176. return ;
  177. }
  178. $this->_putNewLine () ;
  179. switch ($this->rdrMode) {
  180. case 'xhtml':
  181. $this->_put (DOKU_LF . "<span style=\"color:red;\">~~") ;
  182. $this->_put (DIR_PLUGIN_PATTERN . "~~: " . $msg . "</span>") ;
  183. break ;
  184. case 'latex':
  185. $this->_put (DOKU_LF . "~~") ;
  186. $this->_put (DIR_PLUGIN_PATTERN . "~~: " . $msg) ;
  187. break ;
  188. }
  189. }
  190. /**
  191. * Load the specified plugin (like the tag or discussion plugin)
  192. */
  193. function _loadPlugin ($plugin) {
  194. if (plugin_isdisabled ($plugin))
  195. return false ;
  196. $plug = plugin_load ('helper', $plugin) ;
  197. if (! $plug) {
  198. $this->_showDebugMsg ("Plugin \"$plugin\" NOT loaded!") ;
  199. return false ;
  200. }
  201. $this->plugins [$plugin] = $plug ;
  202. $this->_showDebugMsg ("Plugin \"$plugin\" loaded!") ;
  203. return true ;
  204. }
  205. /**
  206. * Let another plugin generate the content...
  207. */
  208. function _pluginCell ($plugin, $id) {
  209. $plug = $this->plugins [$plugin] ;
  210. if (! $plug)
  211. return 'Plugin $plugin not loaded!' ;
  212. $html = $plug->td ($id) ;
  213. return $html ;
  214. }
  215. /**
  216. * Shows parsed options (in debug mode)
  217. */
  218. function _parseOptionsShow ($data, $dir, $ns) {
  219. if (! $this->debug)
  220. return ;
  221. $this->_put (DOKU_LF . "<xmp style=\"font-family: Courier; color: red;\">") ;
  222. $this->_put (DOKU_LF . " data = $data") ;
  223. $this->_put (DOKU_LF . " dir = $dir") ;
  224. $this->_put (DOKU_LF . " ns = $ns") ;
  225. foreach ($this->opts as $key => $opt) {
  226. if (is_array ($opt)) {
  227. foreach ($opt as $optkey => $optval) {
  228. $this->_put (DOKU_LF . " opts[$key][$optkey] = $optval") ;
  229. }
  230. } else if (is_bool ($opt)) {
  231. $this->_put (DOKU_LF . " opts[$key] = " . ($opt ? "true" : "false")) ;
  232. } else {
  233. $this->_put (DOKU_LF . " opts[$key] = $opt") ;
  234. }
  235. }
  236. $this->_put (DOKU_LF . DOKU_LF . "date: " . date ("D M j G:i:s T Y")) ;
  237. $this->_put (DOKU_LF . "</xmp>" . DOKU_LF) ;
  238. }
  239. /**
  240. * Get the namespace of the parent directory
  241. * (always prefixed and postfixed with a colon, root is ':')
  242. */
  243. function _getParentNS ($id) {
  244. $curNS = getNS ($id) ;
  245. if ($curNS == '')
  246. return ':' ;
  247. if (substr ($curNS, 0, 1) != ':') {
  248. $curNS = ':' . $curNS;
  249. }
  250. return ':' . $curNS . ':' ;
  251. }
  252. /**
  253. * Create a fully qualified namespace from the specified one.
  254. * The second parameter must be true when the given namespace
  255. * is never a page id. In that case, the returned namespace
  256. * always ends with a colon.
  257. */
  258. function _parseNS ($ns, $mustBeNSnoPage) {
  259. global $ID ;
  260. if (substr ($ns, 0, 2) == '.:') {
  261. $ns = ':' . getNS ($ID) . substr ($ns, 1) ;
  262. } elseif (substr ($ns, 0, 3) == '..:') {
  263. $ns = $this->_getParentNS ($ID) . substr ($ns, 3) ;
  264. } elseif ($ns == '..') {
  265. $ns = $this->_getParentNS ($ID) ;
  266. } elseif (substr ($ns, 0, 1) == ':') {
  267. } elseif ($ns == '.' || $ns == '*') {
  268. $ns = ':' . getNS ($ID) ;
  269. } else {
  270. $ns = ':' . getNS ($ID) . ':' . $ns ;
  271. }
  272. if ($mustBeNSnoPage && substr ($ns, -1) <> ':')
  273. $ns .= ':' ;
  274. return $ns ;
  275. }
  276. /**
  277. * Convert namespace to its path
  278. */
  279. function _ns2path ($ns) {
  280. global $conf ;
  281. if ($ns == ':' || $ns == '')
  282. return $conf ['datadir'] ;
  283. $ns = trim ($ns, ':') ;
  284. $path = $conf ['datadir'] . '/' . str_replace (':', '/', $ns) ;
  285. return $path ;
  286. }
  287. /**
  288. * Initialize the opts array...
  289. */
  290. function _initOpts ($flags) {
  291. $this->opts = array () ;
  292. $this->opts ["noheader"] = false ;
  293. $this->opts ["collapse"] = false ;
  294. $this->opts ["ego"] = false ;
  295. $flags = split ('\&', $flags) ;
  296. foreach ($flags as $index => $par) {
  297. $tmp = split ("=", $par) ;
  298. $key = $tmp [0] ;
  299. $val = $tmp [1] ;
  300. switch ($key) {
  301. case "skip":
  302. case "cols":
  303. case "hdrs":
  304. case "sort":
  305. case "tag":
  306. $val = split (';', trim ($val, ';')) ;
  307. break ;
  308. case "noheader":
  309. case "nohead":
  310. case "nohdr":
  311. $key = "noheader" ;
  312. $val = true ;
  313. break ;
  314. case "collapse":
  315. $key = "collapse" ;
  316. $val = true ;
  317. break ;
  318. case "ego":
  319. $key = "ego" ;
  320. $val = true ;
  321. break ;
  322. case "showheader":
  323. case "header":
  324. $key = "noheader" ;
  325. $val = false ;
  326. break ;
  327. case "nodefaulttitle":
  328. case "ndt":
  329. $key = "nodefaulttitle" ;
  330. $val = true ;
  331. $this->useDefaultTitle = false ;
  332. break ;
  333. case "widedesc":
  334. $val = true ;
  335. break ;
  336. case "table":
  337. $this->style = "table" ;
  338. break ;
  339. case "list":
  340. $this->style = "list" ;
  341. break ;
  342. case "debug":
  343. $this->debug = true ;
  344. }
  345. $this->opts [$key] = $val;
  346. }
  347. }
  348. /**
  349. * Check the supplied column names
  350. */
  351. function _parseColumnNames () {
  352. if (is_array ($this->opts ["cols"])) {
  353. $this->cols = $this->opts ["cols"] ;
  354. } else {
  355. $this->cols = Array ("page") ;
  356. }
  357. if (count ($this->cols) == 0) {
  358. $cols [] = "page" ;
  359. $cols [] = "desc" ;
  360. }
  361. $newCols = Array () ;
  362. foreach ($this->cols as $index => $col) {
  363. switch ($col) {
  364. case "page":
  365. case "desc":
  366. case "user":
  367. case "userid":
  368. case "mdate":
  369. case "cdate":
  370. case "rowno":
  371. break ;
  372. case "comments":
  373. $this->_loadPlugin ("discussion") ;
  374. break ;
  375. case "tags":
  376. $this->_loadPlugin ("tag") ;
  377. break ;
  378. case "date":
  379. $col = "mdate" ;
  380. break ;
  381. case "description":
  382. $col = "desc" ;
  383. break ;
  384. default:
  385. $this->_showDebugMsg ("Unrecognized column name: \"$col\"") ;
  386. $col = '' ;
  387. }
  388. if ($col != '') {
  389. $this->_showDebugMsg ("Recognized column name: $col") ;
  390. $newCols [] = $col ;
  391. }
  392. }
  393. $this->cols = $newCols ;
  394. if (count ($this->opts ["hdrs"]) != count ($this->cols)) {
  395. $this->_showDebugMsg (
  396. "The number of specified headers (" . count ($this->opts ["hdrs"]) .
  397. ") is not equal to the number of specified columns (" .
  398. count ($this->cols) . ")!"
  399. ) ;
  400. }
  401. }
  402. /**
  403. * Check the supplied tags
  404. */
  405. function _parseTags () {
  406. $this->hasTags = false ;
  407. if (is_array ($this->opts ["tag"])) {
  408. foreach ($this->opts ["tag"] as $tag) {
  409. if ($tag == NULL || $tag == '')
  410. continue ;
  411. $tag = mb_convert_case ($tag, MB_CASE_LOWER, "UTF-8") ;
  412. if (substr ($tag, 0, 1) == '!') {
  413. $this->excludeTags [] = substr ($tag, 1) ;
  414. } else {
  415. $this->includeTags [] = $tag ;
  416. }
  417. $this->hasTags = true ;
  418. }
  419. foreach ($this->excludeTags as $tag) {
  420. $this->_showDebugMsg ("Specified exclude tag: $tag") ;
  421. }
  422. foreach ($this->includeTags as $tag) {
  423. $this->_showDebugMsg ("Specified include tag: $tag") ;
  424. }
  425. }
  426. }
  427. /**
  428. * Check the supplied sort keys
  429. */
  430. function _parseSortKeys () {
  431. if (is_array ($this->opts ["sort"])) {
  432. $this->sortKeys = $this->opts ["sort"] ;
  433. }
  434. $sortKeys = Array () ;
  435. foreach ($this->sortKeys as $index => $sortKey) {
  436. $array = split ('-', strtolower ($sortKey)) ;
  437. if (count ($array) == 1) {
  438. $array = Array ($sortKey, "a") ;
  439. }
  440. switch ($array [1]) {
  441. case NULL:
  442. case "a":
  443. case "asc":
  444. case "ascending":
  445. $array [1] = false ;
  446. break ;
  447. case "d":
  448. case "desc":
  449. case "descending":
  450. $array [1] = true ;
  451. break ;
  452. default:
  453. $this->_showDebugMsg (
  454. "Unrecognized sort column name modifier: " .
  455. $array [1]
  456. ) ;
  457. $array [1] = false ;
  458. }
  459. switch ($array [0]) {
  460. case "page":
  461. case "desc":
  462. case "user":
  463. case "userid":
  464. case "mdate":
  465. case "cdate":
  466. case "rowno":
  467. break ;
  468. case "comments":
  469. $this->_loadPlugin ("discussion") ;
  470. break ;
  471. case "tags":
  472. $this->_loadPlugin ("tag") ;
  473. break ;
  474. case "date":
  475. $array [0] = "mdate" ;
  476. break ;
  477. case "description":
  478. $array [0] = "desc" ;
  479. break ;
  480. default:
  481. $this->_showDebugMsg (
  482. "Unrecognized sort column name: " . $array [0]
  483. ) ;
  484. $array [0] = NULL ;
  485. }
  486. if ($array [0]) {
  487. $this->_showDebugMsg (
  488. "Sort column " . $array [0] . " " .
  489. ($array [1] ? "descending" : "ascending")
  490. ) ;
  491. $sortKeys [] = $array ;
  492. }
  493. }
  494. $this->sortKeys = $sortKeys ;
  495. $this->nbrOfSortKeys = count ($this->sortKeys) ;
  496. }
  497. /**
  498. * Add a page to the collection of $pages. Check first if it should
  499. * not be skipped...
  500. */
  501. function _addFoundPage (&$data, $ns, $id, $type, $level) {
  502. global $ID ;
  503. $fqid = $ns . $id ; // Fully qualified id...
  504. //
  505. // If this file or directory should be skipped, do so
  506. //
  507. switch ($type) {
  508. case "f":
  509. if (($fqid == ':' . $ID) && ! $this->opts ["ego"]) // If we found ourself, skip it
  510. return false ;
  511. $pageName = noNS ($id) ;
  512. if ($pageName == $this->start)
  513. return false ;
  514. if ($this->opts['skipallfqid']) return false;
  515. foreach ($this->opts ["skipfqid"] as $index => $skipitem) {
  516. if ($skipitem) {
  517. if ($skipitem == $fqid) {
  518. //
  519. // Remove the skip rule, it has no use any more...
  520. //
  521. $this->opts ["skipfqid"] [$index] = NULL ;
  522. $this->_showDebugMsg ("Skipping $fqid due to skip rule $skipitem") ;
  523. return false ;
  524. }
  525. }
  526. }
  527. if ( $this->opts ["collapse"] ) {
  528. // With collapse, only show:
  529. // - pages within the same namespace as the current page
  530. if ( $this->_getParentNS($fqid) != $this->_getParentNS($ID) ) {
  531. return false ;
  532. }
  533. }
  534. $linkid = $fqid ;
  535. break ;
  536. case "d":
  537. $fqid .= ':' ;
  538. if ($this->opts['skipallns']) return false;
  539. foreach ($this->opts ["skipns"] as $skipitem) {
  540. if ($skipitem == $fqid) {
  541. $this->_showDebugMsg ("Skipping $fqid due to skip rule $skipitem") ;
  542. return false ;
  543. }
  544. }
  545. if ( $this->opts ["collapse"] ) {
  546. // With collapse, only show:
  547. // - sibling namespaces of the current namespace and it's ancestors
  548. $curPathSplit = split (":", trim (getNS($ID), ":")) ;
  549. $fqidPathSplit = split (":", trim (getNS($fqid), ":")) ;
  550. // Find the last parent namespace that matches
  551. // If there is only one more child namespace in the namespace under evaluation,
  552. // Then this is a sibling of one of the parent namespaces of the current page.
  553. // Siblings are ok, grandchild namespaces and below should be skipped (for collapse).
  554. $clevel = 0 ;
  555. if (count ($curPathSplit) > 0) {
  556. while (($clevel < count($fqidPathSplit) - 1) && ($clevel < count($curPathSplit))) {
  557. if ($curPathSplit[$clevel] == $fqidPathSplit[$clevel]) {
  558. $clevel++ ;
  559. } else {
  560. break ;
  561. }
  562. }
  563. }
  564. if (count($fqidPathSplit) > $clevel + 1) {
  565. return false;
  566. }
  567. }
  568. $linkid = $fqid . $this->start ;
  569. // Don't add startpages the user isn't authorized to read
  570. if (auth_quickaclcheck (substr($linkid,1)) < AUTH_READ)
  571. return false ;
  572. break ;
  573. }
  574. // $this->_showDebugMsg ("$level $type $ns$id:") ;
  575. $data [] = array (
  576. 'id' => $fqid,
  577. 'type' => $type,
  578. 'level' => $level,
  579. 'linkid' => $linkid,
  580. 'timestamp' => NULL
  581. ) ;
  582. return true ;
  583. }
  584. /**
  585. * Callback method for the search function in _parseOptions
  586. */
  587. function _searchDir (&$data, $base, $file, $type, $level, $opts) {
  588. global $ID ;
  589. $ns = $opts ["ns"] ;
  590. switch ($type) {
  591. case "d":
  592. return $this->_addFoundPage ($data, $ns, pathID ($file), $type, $level) ;
  593. case "f":
  594. if (! preg_match ('#\.txt$#', $file))
  595. return false ;
  596. //check ACL
  597. $id = pathID ($file) ;
  598. if (auth_quickaclcheck ($id) < AUTH_READ)
  599. return false ;
  600. $this->_addFoundPage ($data, $ns, $id, $type, $level) ;
  601. }
  602. return false ;
  603. }
  604. /**
  605. * Parse the options after the ~~DIR: string and
  606. * return true if the table can be generated...
  607. *
  608. * A namespace specifaction should start with a colon and the flags
  609. * should start with a question mark, like this:
  610. *
  611. * ~~DIR[[:<namespace>][?<flags>]]~~
  612. *
  613. * To not break pages created with an older version of this plugin, this
  614. * syntax is also supported:
  615. *
  616. * ~~DIR:<flags>~~
  617. *
  618. * This assumes that no other colon is put in <flags>
  619. */
  620. function _parseOptions ($data) {
  621. global $conf ;
  622. global $ID ;
  623. $ns = '.' ;
  624. $flags = trim ($data, '~') ;
  625. $flags = substr ($flags, strlen (DIR_PLUGIN_PATTERN)) ;
  626. $flags = trim ($flags) ;
  627. $this->_showDebugMsg ("specified arguments=" . $flags) ;
  628. if (
  629. substr ($flags, 0, 1) == ':' &&
  630. strpos (substr ($flags, 1), '?') === FALSE &&
  631. strpos (substr ($flags, 1), ':') === FALSE
  632. ) {
  633. //
  634. // This is the "old" syntax where flags do not start with a question mark
  635. //
  636. $this->_showDebugMsg ("parseOptions A") ;
  637. $flags = substr ($flags, 1) ;
  638. } else if (
  639. substr ($flags, 0, 1) == ':' &&
  640. strpos (substr ($flags, 1), '?') === FALSE
  641. ) {
  642. //
  643. // There is no questionmark so it's all namespace specification
  644. //
  645. $this->_showDebugMsg ("parseOptions B") ;
  646. $ns = substr ($flags, 1) ;
  647. $flags = '' ;
  648. } else if (substr ($flags, 0, 1) == '?') {
  649. $this->_showDebugMsg ("parseOptions C") ;
  650. $flags = substr ($flags, 1) ;
  651. } else if (strlen ($flags) == 0) {
  652. $this->_showDebugMsg ("parseOptions D") ;
  653. } else if (
  654. strpos (substr ($flags, 1), '?') !== FALSE
  655. ) {
  656. $this->_showDebugMsg ("parseOptions E") ;
  657. $tmp = split ('\?', $flags) ;
  658. if (count ($tmp) == 2) {
  659. $ns = substr ($tmp [0], 1) ;
  660. $flags = $tmp [1] ;
  661. } else {
  662. $this->_showDebugMsg ("ERROR: Multiple questionmarks are not supported") ;
  663. $flags = '' ;
  664. }
  665. } else {
  666. $this->_showDebugMsg ("parseOptions E") ;
  667. $ns = $flags ;
  668. $flags = '' ;
  669. }
  670. $this->_showDebugMsg ("specified namespace=$ns") ;
  671. $this->_showDebugMsg ("specified flags=$flags") ;
  672. $ns = $this->_parseNS ($ns, true) ;
  673. $path = $this->_ns2path ($ns) ;
  674. $this->_showDebugMsg ("path=$path") ;
  675. $this->_initOpts ($flags) ;
  676. $this->_parseColumnNames () ;
  677. $this->_parseSortKeys () ;
  678. $this->_parseTags () ;
  679. //
  680. // Check the column headers
  681. //
  682. $this->hdrs = $this->cols ;
  683. if (is_array ($this->opts ["hdrs"])) {
  684. foreach ($this->opts ["hdrs"] as $index => $hdr) {
  685. $this->hdrs [$index] = $hdr ;
  686. }
  687. }
  688. //
  689. // Check the skip items
  690. //
  691. $this->opts ["skipfqid"] = Array () ;
  692. $this->opts ["skipns"] = Array () ;
  693. $this->opts ["skipallfqid"] = false;
  694. $this->opts ["skipallns"] = false;
  695. if (is_array ($this->opts ["skip"])) {
  696. foreach ($this->opts ["skip"] as $skipitem) {
  697. if ($skipitem == '*:') {
  698. $this->opts['skipallns'] = true;
  699. } elseif ($skipitem == '*') {
  700. $this->opts['skipallfqid'] = true;
  701. } else {
  702. $item = $this->_parseNS ($skipitem, false) ;
  703. if (substr ($item, -1) == ":") {
  704. $this->opts ["skipns"] [] = $item ;
  705. } else {
  706. $this->opts ["skipfqid"] [] = $item ;
  707. }
  708. }
  709. }
  710. }
  711. $this->_parseOptionsShow ($data, $path, $ns) ;
  712. //
  713. // Search the directory $dir, only if the pages array
  714. // is empty, since we can pass here several times (xhtml, latex).
  715. //
  716. $this->_showDebugMsg ("Search directory $path") ;
  717. $this->_showDebugMsg ("for namespace $ns") ;
  718. if (count ($this->pages) == 0) {
  719. search (
  720. $this->pages, // results
  721. $path, // folder root
  722. array ($this, '_searchDir'), // handler
  723. array ('ns' => $ns) // namespace
  724. ) ;
  725. }
  726. $count = count ($this->pages) ;
  727. $this->_showDebugMsg ("Found " . $count . " pages!") ;
  728. if ($count == 0) {
  729. $this->_put (DOKU_LF . "\t<p>There are no documents to show.</p>" . DOKU_LF) ;
  730. return false ;
  731. }
  732. $this->_sortResult () ;
  733. return true ;
  734. }
  735. /**
  736. * Sort the found pages according to the settings
  737. */
  738. function _sortResult () {
  739. if ($this->nbrOfSortKeys == 0)
  740. return ;
  741. usort ($this->pages, array ($this, "_sortPage")) ;
  742. }
  743. /**
  744. * Compare function for usort
  745. */
  746. function _sortPage ($a, $b) {
  747. return $this->_sortPageByKey ($a, $b, 0) ;
  748. }
  749. function _sortPageByKey (&$a, &$b, $index) {
  750. if ($index >= $this->nbrOfSortKeys)
  751. return 0 ;
  752. $keyType = $this->sortKeys [$index] ;
  753. $sortKeyA = $this->_getSortKey ($a, $keyType [0]) ;
  754. $sortKeyB = $this->_getSortKey ($b, $keyType [0]) ;
  755. if ($sortKeyA == $sortKeyB)
  756. return $this->_sortPageByKey ($a, $b, $index + 1) ;
  757. if ($keyType [1]) {
  758. $tmp = $sortKeyA ;
  759. $sortKeyA = $sortKeyB ;
  760. $sortKeyB = $tmp ;
  761. }
  762. return ($sortKeyA < $sortKeyB) ? -1 : 1 ;
  763. }
  764. /**
  765. * Produces a sortable key
  766. */
  767. function _getSortKey (&$page, $keyType) {
  768. switch ($keyType) {
  769. case "page":
  770. return html_wikilink ($page ["id"]) ;
  771. case "desc":
  772. case "widedesc":
  773. return $this->_getMeta ($page, "description", "abstract") ;
  774. case "mdate":
  775. return $this->_getMeta ($page, "date", "modified") ;
  776. case "cdate":
  777. return $this->_getMeta ($page, "date", "created") ;
  778. case "user":
  779. $users = $this->_getMeta ($page, "contributor") ;
  780. if (is_array ($users)) {
  781. $index = 0 ;
  782. foreach ($users as $userid => $user) {
  783. if ($user && $user <> "") {
  784. return $user ;
  785. }
  786. }
  787. }
  788. return $users ;
  789. case "userid":
  790. $users = $this->_getMeta ($page, "contributor") ;
  791. if (is_array ($users)) {
  792. $index = 0 ;
  793. foreach ($users as $userid => $user) {
  794. if ($userid && $userid <> "") {
  795. return $userid ;
  796. }
  797. }
  798. }
  799. return $users ;
  800. case "comments":
  801. return $this->_pluginCell ("discussion", $page ["linkid"]) ;
  802. case "tags":
  803. return $this->_pluginCell ("tag", $page ["linkid"]) ;
  804. case "rowno":
  805. return '0' ;
  806. }
  807. return NULL ;
  808. }
  809. /**
  810. * Generate the content for the cell with the page link...
  811. */
  812. function _tableCellContentID (&$page) {
  813. $fqid = $page ["id"] ;
  814. $tmplvl = $page ["level"] - 1 ;
  815. $spacerWidth = $tmplvl * 20 ;
  816. $pageid = $fqid ;
  817. $name = NULL ;
  818. if ($page ["type"] == 'd')
  819. $pageid .= ':' . $this->start ;
  820. if (! $this->useDefaultTitle) {
  821. $name = split (':', $fqid) ;
  822. $name = ucfirst ($name [count ($name) - 1]) ;
  823. }
  824. switch ($this->rdrMode) {
  825. case 'latex':
  826. $this->rdr->internallink ($pageid, $name) ;
  827. break ;
  828. case 'xhtml':
  829. if ($spacerWidth > 0) {
  830. $this->_put ('<div style="margin-left: ' . $spacerWidth . 'px;">') ;
  831. }
  832. $this->_put (html_wikilink ($pageid, $name)) ;
  833. if ($spacerWidth > 0) {
  834. $this->_put ('</div>') ;
  835. }
  836. break ;
  837. }
  838. }
  839. /**
  840. * Get default value for an unset element
  841. */
  842. function _getMeta (&$page, $key1, $key2 = NULL) {
  843. if (! isset ($page ["meta"]))
  844. $page ["meta"] = p_get_metadata ($page ["linkid"], false, true) ;
  845. //
  846. // Use "created" instead of "modified" if null
  847. //
  848. if (
  849. $key1 == "date" &&
  850. $key2 == "modified" &&
  851. ! isset ($page ["meta"]["date"]["modified"])
  852. ) { $key2 = "created" ; } //
  853. // Return "creator" if "contributor" is null
  854. //
  855. if (
  856. $key1 == "contributor" &&
  857. ! isset ($page ["meta"]["contributor"])
  858. ) { $key1 = "creator" ; }
  859. if (is_string ($key2))
  860. return $page ["meta"] [$key1] [$key2] ;
  861. return $page ["meta"] [$key1] ;
  862. }
  863. /**
  864. * Generate the table cell content...
  865. */
  866. function _tableCellContent (&$page, $col) {
  867. switch ($col) {
  868. case "page":
  869. $this->_tableCellContentID ($page) ;
  870. break ;
  871. case "desc":
  872. case "widedesc":
  873. $this->_put ($this->_getMeta ($page, "description", "abstract")) ;
  874. break ;
  875. case "mdate":
  876. $this->_putDate ($this->_getMeta ($page, "date", "modified")) ;
  877. break ;
  878. case "cdate":
  879. $this->_putDate ($this->_getMeta ($page, "date", "created")) ;
  880. break ;
  881. case "user":
  882. $users = $this->_getMeta ($page, "contributor") ;
  883. if (is_array ($users)) {
  884. $index = 0 ;
  885. foreach ($users as $userid => $user) {
  886. if ($user && $user <> '') {
  887. if ($index++ > 0) {
  888. $this->_putNewLine () ;
  889. }
  890. $this->_put ($user) ;
  891. }
  892. }
  893. }
  894. break ;
  895. case "userid":
  896. $users = $this->_getMeta ($page, "contributor") ;
  897. if (is_array ($users)) {
  898. $index = 0 ;
  899. foreach ($users as $userid => $user) {
  900. if ($userid && $userid <> '') {
  901. if ($index++ > 0) {
  902. $this->_putNewLine () ;
  903. }
  904. $this->_put ($userid) ;
  905. }
  906. }
  907. }
  908. break ;
  909. case "comments":
  910. if (! $this->modeIsLatex)
  911. $this->_put ($this->_pluginCell ("discussion", $page ["linkid"])) ;
  912. break ;
  913. case "tags":
  914. if (! $this->modeIsLatex)
  915. $this->_put ($this->_pluginCell ("tag", $page ["linkid"])) ;
  916. break ;
  917. case "rowno":
  918. $this->_put ($this->rowNumber) ;
  919. break ;
  920. default:
  921. $this->_put ($col) ;
  922. }
  923. }
  924. /**
  925. * Rewrite of renderer->table_open () because of class
  926. */
  927. function _tableOpen () {
  928. if ($this->modeIsLatex) {
  929. $rdr = $this->rdr ;
  930. $rdr->_current_tab_cols = 0 ;
  931. if ($rdr->info ['usetablefigure'] == "on") {
  932. $this->_putCmdNl ("begin{figure}[h]") ;
  933. } else {
  934. $this->_putCmdNl ("vspace{0.8em}") ;
  935. }
  936. $rdr->putcmd ("begin{tabular}") ;
  937. $rdr->put ("{") ;
  938. foreach ($this->hdrs as $index => $hdr) {
  939. $rdr->put ("l") ;
  940. if ($index + 1 < sizeof ($this->hdrs))
  941. $rdr->put ('|') ;
  942. }
  943. $rdr->putnl ("}") ;
  944. return ;
  945. }
  946. switch ($this->style) {
  947. case "table":
  948. $class = "inline" ;
  949. break ;
  950. case "list":
  951. $class = "ul" ;
  952. break;
  953. default:
  954. $class = "pagelist" ;
  955. }
  956. $this->_showDebugMsg ("Style=" . $this->style . " table class=$class") ;
  957. $this->_put (DOKU_LF . '<table class="' . $class . '">' . DOKU_LF) ;
  958. }
  959. /**
  960. * Rewrite of renderer->table_close ()
  961. */
  962. function _tableClose () {
  963. if ($this->modeIsLatex) {
  964. $this->rdr->tabular_close () ;
  965. return ;
  966. }
  967. $this->rdr->table_close () ;
  968. }
  969. /**
  970. * Rewrite of renderer->tableheader_open () because of class
  971. */
  972. function _tableHeaderCellOpen ($class) {
  973. if ($this->modeIsLatex)
  974. return ;
  975. $this->_put (DOKU_LF . DOKU_TAB . DOKU_TAB . '<th class="' . $class . '">') ;
  976. }
  977. /**
  978. * Rewrite of renderer->tableheader_close ()
  979. */
  980. function _tableHeaderCellClose ($index) {
  981. if ($this->modeIsLatex) {
  982. if (($index + 1) == sizeof ($this->hdrs)) {
  983. $this->rdr->putnl ('\\\\') ;
  984. } else {
  985. $this->rdr->put ('&') ;
  986. }
  987. return ;
  988. }
  989. return $this->rdr->tableheader_close () ;
  990. }
  991. /**
  992. * Rewrite of renderer->tablecell_open () because of class
  993. */
  994. function _tableCellOpen ($colspan, $class) {
  995. if ($this->modeIsLatex)
  996. return ;
  997. $this->_put (DOKU_LF . DOKU_TAB . DOKU_TAB . '<td class="' . $class . '"') ;
  998. if ($colspan > 1)
  999. $this->_put (' colspan="' . $colspan . '"') ;
  1000. $this->_put (">") ;
  1001. }
  1002. /**
  1003. * Rewrite of renderer->tablecell_close () because of class
  1004. */
  1005. function _tableCellClose ($index) {
  1006. if ($this->modeIsLatex) {
  1007. if (($index + 1) == sizeof ($this->hdrs)) {
  1008. $this->rdr->putnl ('\\\\') ;
  1009. } else {
  1010. $this->rdr->put ('&') ;
  1011. }
  1012. return ;
  1013. }
  1014. return $this->rdr->tablecell_close () ;
  1015. }
  1016. /**
  1017. * Return the class name to be used for the <td> showing $col.
  1018. */
  1019. function _getCellClassForCol ($col) {
  1020. switch ($col) {
  1021. case "page":
  1022. return "dpage" ;
  1023. case "date":
  1024. case "user":
  1025. case "desc":
  1026. case "comments":
  1027. case "tags":
  1028. case "rowno":
  1029. return $col ;
  1030. case "mdate":
  1031. case "cdate":
  1032. return "date" ;
  1033. case "userid":
  1034. return "user" ;
  1035. case "":
  1036. return "" ;
  1037. }
  1038. $this->_showDebugMsg ("Unknown style class for col $col") ;
  1039. return "desc" ;
  1040. }
  1041. function _tableHeaderRowOpen () {
  1042. if ($this->modeIsLatex) {
  1043. $this->_putCmdNl ('hline') ;
  1044. return ;
  1045. }
  1046. $this->rdr->tablerow_open () ;
  1047. }
  1048. function _tableHeaderRowClose () {
  1049. if ($this->modeIsLatex) {
  1050. $this->_putCmdNl ('hline') ;
  1051. return ;
  1052. }
  1053. $this->rdr->tablerow_close () ;
  1054. }
  1055. function _tableRowOpen () {
  1056. if ($this->modeIsLatex)
  1057. return ;
  1058. $this->rdr->tablerow_open () ;
  1059. }
  1060. function _tableRowClose () {
  1061. if ($this->modeIsLatex)
  1062. return ;
  1063. $this->rdr->tablerow_close () ;
  1064. }
  1065. /**
  1066. * Return true if the tag plugin is not loaded,
  1067. * if the ~~DIR~~ line has no tag attribute or
  1068. * if the given page has one of the specified tags.
  1069. */
  1070. function _hasTag ($page) {
  1071. if (! $this->hasTags)
  1072. return true ;
  1073. $plug = $this->plugins ['tag'] ;
  1074. if (! $plug)
  1075. return true ;
  1076. //
  1077. // Get the tags of the current page
  1078. //
  1079. $tmp = $this->_getMeta ($page, "subject") ;
  1080. if (! is_array ($tmp))
  1081. return false ;
  1082. $tags = Array () ;
  1083. //
  1084. // Convert them to lowercase
  1085. //
  1086. foreach ($tmp as $tag) {
  1087. $tags [] = mb_convert_case ($tag, MB_CASE_LOWER, "UTF-8") ;
  1088. }
  1089. #
  1090. # If there is an intersection with the exclude tags then we can not show
  1091. # the current document
  1092. #
  1093. if (count ($this->excludeTags) > 0) {
  1094. if (count (array_intersect ($tags, $this->excludeTags)) > 0) {
  1095. $this->_showDebugMsg ('skip') ;
  1096. return false ;
  1097. }
  1098. }
  1099. #
  1100. # If the intersection with the include tags is not equal (in size) to the
  1101. # array of include tags, we must skip the current document.
  1102. #
  1103. if (count ($this->includeTags) > 0) {
  1104. $intersection = array_intersect ($tags, $this->includeTags) ;
  1105. if (count ($intersection) != count ($this->includeTags)) {
  1106. return false ;
  1107. }
  1108. }
  1109. return true ;
  1110. }
  1111. /**
  1112. * Generate the actual table content...
  1113. */
  1114. function _tableContent () {
  1115. $doWideDesc = $this->opts ["widedesc"] ;
  1116. if (! $this->opts ["noheader"]) {
  1117. $this->_tableHeaderRowOpen () ;
  1118. foreach ($this->hdrs as $index => $hdr) {
  1119. $this->_tableHeaderCellOpen (
  1120. $this->_getCellClassForCol ($this->cols [$index])
  1121. ) ;
  1122. $this->_put ($hdr) ;
  1123. $this->_tableHeaderCellClose ($index) ;
  1124. }
  1125. $this->_tableHeaderRowClose () ;
  1126. }
  1127. foreach ($this->pages as $page) {
  1128. if (! $this->_hasTag ($page))
  1129. continue ;
  1130. $this->rowNumber += 1 ;
  1131. $this->_tableRowOpen () ;
  1132. foreach ($this->cols as $index => $col) {
  1133. $this->_tableCellOpen (1, $this->_getCellClassForCol ($col)) ;
  1134. $this->_tableCellContent ($page, $col) ;
  1135. $this->_tableCellClose ($index) ;
  1136. }
  1137. $this->_tableRowClose () ;
  1138. if ($doWideDesc) {
  1139. $this->_tableRowOpen () ;
  1140. $this->_tableCellOpen (count ($this->cols), "desc") ;
  1141. $this->_tableCellContent ($page, "widedesc") ;
  1142. $this->_tableCellClose (0) ;
  1143. $this->_tableRowClose () ;
  1144. }
  1145. }
  1146. }
  1147. /**
  1148. * Write data to the output stream
  1149. */
  1150. function _put ($data) {
  1151. if ($data == NULL || $data == '')
  1152. return ;
  1153. switch ($this->rdrMode) {
  1154. case 'xhtml':
  1155. $this->rdr->doc .= $data ;
  1156. break ;
  1157. case 'latex':
  1158. $this->rdr->put ($data) ;
  1159. break ;
  1160. }
  1161. }
  1162. /**
  1163. * Write a date to the output stream
  1164. */
  1165. function _putDate ($date) {
  1166. $this->_put (strftime ($this->dformat, $date)) ;
  1167. }
  1168. function _putCmdNl ($cmd) {
  1169. $this->rdr->putcmdnl ($cmd) ;
  1170. }
  1171. function _putNewLine () {
  1172. if ($this->modeIsLatex) {
  1173. $this->_putCmdNl ('newline') ;
  1174. } else {
  1175. $this->_put ('<br />') ;
  1176. }
  1177. }
  1178. /**
  1179. * Do the real work
  1180. */
  1181. function _dir ($data) {
  1182. if (! $this->_parseOptions ($data))
  1183. return false ;
  1184. //
  1185. // If we already did the latex pass, skip the xhtml pass
  1186. //
  1187. if ($this->processedLatex && $this->rdrMode == 'xhtml') {
  1188. //return false ;
  1189. }
  1190. //
  1191. // Generate the actual table...
  1192. //
  1193. $this->_tableOpen () ;
  1194. $this->_tableContent () ;
  1195. $this->_tableClose () ;
  1196. return true ;
  1197. }
  1198. } // syntax_plugin_dir
  1199. //Setup VIM: ex: et ts=2 enc=utf-8 :