1<?php
2/**
3 * DokuWiki Plugin publish (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Jarrod Lowe <dokuwiki@rrod.net>
7 * @author  Andreas Gohr <gohr@cosmocode.de>
8 */
9
10
11// must be run within DokuWiki
12if(!defined('DOKU_INC')) die();
13
14
15class syntax_plugin_publish extends DokuWiki_Syntax_Plugin {
16
17    /**
18     * @var helper_plugin_publish
19     */
20    private $hlp;
21
22    function __construct(){
23        $this->hlp = plugin_load('helper','publish');
24    }
25
26    function pattern() {
27        return '\[APPROVALS.*?\]';
28    }
29
30    function getType() {
31        return 'substition';
32    }
33
34    function getSort() {
35        return 20;
36    }
37
38    function PType() {
39        return 'block';
40    }
41
42    function connectTo($mode) {
43        $this->Lexer->addSpecialPattern($this->pattern(),$mode,'plugin_publish');
44    }
45
46    function handle($match, $state, $pos, Doku_Handler $handler){
47        $namespace = substr($match, 11, -1);
48        return array($match, $state, $pos, $namespace);
49    }
50
51    function render($mode, Doku_Renderer $renderer, $data) {
52        global $conf;
53
54        if($mode != 'xhtml') {
55            return false;
56        }
57
58        list($match, $state, $pos, $namespace) = $data;
59
60        $namespace = cleanID(getNS($namespace . ":*"));
61
62        $pages = $this->hlp->getPagesFromNamespace($namespace);
63
64        if(count($pages) == 0) {
65            $renderer->doc .= '<p class="apr_none">' . $this->getLang('apr_p_none') . '</p>';
66            return true;
67        }
68
69        usort($pages, array($this,'_pagesorter'));
70
71        // Output Table
72        $renderer->doc .= '<table class="apr_table"><tr class="apr_head">';
73        $renderer->doc .= '<th class="apr_page">' . $this->getLang('apr_p_hdr_page') . '</th>';
74        $renderer->doc .= '<th class="apr_prev">' . $this->getLang('apr_p_hdr_previous') . '</th>';
75        $renderer->doc .= '<th class="apr_upd">' . $this->getLang('apr_p_hdr_updated') . '</th>';
76        $renderer->doc .= '</tr>';
77
78
79        $working_ns = null;
80        foreach($pages as $page) {
81            // $page: 0 -> pagename, 1 -> approval metadata, 2 -> last changed date
82            $this_ns = getNS($page[0]);
83
84            if($this_ns != $working_ns) {
85                $name_ns = $this_ns;
86                if($this_ns == '') { $name_ns = 'root'; }
87                $renderer->doc .= '<tr class="apr_ns"><td colspan="3"><a href="';
88                $renderer->doc .= wl($this_ns . ':' . $this->getConf('start'));
89                $renderer->doc .= '">';
90                $renderer->doc .= $name_ns;
91                $renderer->doc .= '</a> ';
92                $renderer->doc .= '<button class="publish__approveNS" type="button" ns="' . $name_ns .'">' . $this->getLang('approveNS') . '</button>';
93                $renderer->doc .= '</td></tr>';
94                $working_ns = $this_ns;
95            }
96
97            $updated = '<a href="' . wl($page[0]) . '">' . dformat($page[2]) . '</a>';
98            if($page[1] == null || count($page[1]) == 0) {
99                // Has never been approved
100                $approved = '';
101            }else{
102                $keys = array_keys($page[1]);
103                sort($keys);
104                $last = $keys[count($keys)-1];
105                $approved = sprintf($this->getLang('apr_p_approved'),
106                    $page[1][$last][1],
107                    wl($page[0], 'rev=' . $last),
108                    dformat($last));
109                if($last == $page[2]) { $updated = 'Unchanged'; } //shouldn't be possible:
110                //the search_helper should have
111                //excluded this
112            }
113
114            $renderer->doc .= '<tr class="apr_table';
115            if($approved == '') { $renderer->doc .= ' apr_never'; }
116            $renderer->doc .= '"><td class="apr_page"><a href="';
117            $renderer->doc .= wl($page[0]);
118            $renderer->doc .= '">';
119            $renderer->doc .= $page[0];
120            $renderer->doc .= '</a></td><td class="apr_prev">';
121            $renderer->doc .= $approved;
122            $renderer->doc .= '</td><td class="apr_upd">';
123            $renderer->doc .= $updated;
124            $renderer->doc .= '</td></tr>';
125
126            //$renderer->doc .= '<tr><td colspan="3">' . print_r($page, true) . '</td></tr>';
127        }
128        $renderer->doc .= '</table>';
129        return true;
130    }
131
132
133
134    /**
135     * Custom sort callback
136     */
137    function _pagesorter($a, $b){
138        $ac = explode(':',$a[0]);
139        $bc = explode(':',$b[0]);
140        $an = count($ac);
141        $bn = count($bc);
142
143        // Same number of elements, can just string sort
144        if($an == $bn) { return strcmp($a[0], $b[0]); }
145
146        // For each level:
147        // If this is not the last element in either list:
148        //   same -> continue
149        //   otherwise strcmp
150        // If this is the last element in either list, it wins
151        $n = 0;
152        while(true) {
153            if($n + 1 == $an) { return -1; }
154            if($n + 1 == $bn) { return 1; }
155            $s = strcmp($ac[$n], $bc[$n]);
156            if($s != 0) { return $s; }
157            $n += 1;
158        }
159    }
160
161}
162
163