xref: /plugin/struct/syntax/output.php (revision 69f7ec8f84b3c07913242dc5ca1b67abd4a748fb)
1<?php
2/**
3 * DokuWiki Plugin struct (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
7 */
8
9// must be run within Dokuwiki
10use dokuwiki\plugin\struct\meta\AccessTable;
11use dokuwiki\plugin\struct\meta\Assignments;
12use dokuwiki\plugin\struct\meta\StructException;
13
14if(!defined('DOKU_INC')) die();
15
16class syntax_plugin_struct_output extends DokuWiki_Syntax_Plugin {
17
18    protected $hasBeenRendered = false;
19
20    const XHTML_OPEN = '<div id="plugin__struct_output">';
21    const XHTML_CLOSE = '</div>';
22
23    /**
24     * Class names of renderers which should NOT render struct data.
25     * All descendants are also blacklisted.
26     */
27    const BLACKLIST_RENDERER = array('Doku_Renderer_metadata');
28
29    /**
30     * Regexp to check on which actions the struct data may be rendered
31     */
32    const WHITELIST_ACTIONS = '/^(show|export_.*)$/';
33
34    /**
35     * @return string Syntax mode type
36     */
37    public function getType() {
38        return 'substition';
39    }
40
41    /**
42     * @return string Paragraph type
43     */
44    public function getPType() {
45        return 'block';
46    }
47
48    /**
49     * @return int Sort order - Low numbers go before high numbers
50     */
51    public function getSort() {
52        return 155;
53    }
54
55    /**
56     * Connect lookup pattern to lexer.
57     *
58     * We do not connect any pattern here, because the call to this plugin is not
59     * triggered from syntax but our action component
60     *
61     * @asee action_plugin_struct_output
62     * @param string $mode Parser mode
63     */
64    public function connectTo($mode) {
65
66    }
67
68    /**
69     * Handle matches of the struct syntax
70     *
71     * @param string $match The match of the syntax
72     * @param int $state The state of the handler
73     * @param int $pos The position in the document
74     * @param Doku_Handler $handler The handler
75     * @return array Data for the renderer
76     */
77    public function handle($match, $state, $pos, Doku_Handler $handler) {
78        // this is never called
79        return array();
80    }
81
82    /**
83     * Render schema data
84     *
85     * Currently completely renderer agnostic
86     *
87     * @param string $mode Renderer mode
88     * @param Doku_Renderer $R The renderer
89     * @param array $data The data from the handler() function
90     * @return bool If rendering was successful.
91     */
92    public function render($mode, Doku_Renderer $R, $data) {
93        global $ACT;
94        global $ID;
95        global $INFO;
96        global $REV;
97
98        foreach (self::BLACKLIST_RENDERER as $blacklisted) {
99            if ($R instanceof $blacklisted) {
100                return true;
101            }
102        }
103        if($ID != $INFO['id']) return true;
104        if(!$INFO['exists']) return true;
105        if($this->hasBeenRendered) return true;
106        if(!preg_match(self::WHITELIST_ACTIONS, act_clean($ACT))) return true;
107
108        // do not render the output twice on the same page, e.g. when another page has been included
109        $this->hasBeenRendered = true;
110        try {
111            $assignments = Assignments::getInstance();
112        } catch (StructException $e) {
113            return false;
114        }
115        $tables = $assignments->getPageAssignments($ID);
116        if(!$tables) return true;
117
118        if($mode == 'xhtml') $R->doc .= self::XHTML_OPEN;
119
120        $hasdata = false;
121        foreach($tables as $table) {
122            try {
123                // use the current revision if none is specified, otherwise we can't access page data
124                $ts = $REV ?: $INFO['currentrev'];
125                $schemadata = AccessTable::byTableName($table, $ID, $ts);
126            } catch(StructException $ignored) {
127                continue; // no such schema at this revision
128            }
129            $schemadata->optionSkipEmpty(true);
130            $data = $schemadata->getData();
131            if(!count($data)) continue;
132            $hasdata = true;
133
134            $R->table_open();
135
136            $R->tablethead_open();
137            $R->tablerow_open();
138            $R->tableheader_open(2);
139            $R->cdata($schemadata->getSchema()->getTranslatedLabel());
140            $R->tableheader_close();
141            $R->tablerow_close();
142            $R->tablethead_close();
143
144            $R->tabletbody_open();
145            foreach($data as $field) {
146                $R->tablerow_open();
147                $R->tableheader_open();
148                $R->cdata($field->getColumn()->getTranslatedLabel());
149                $R->tableheader_close();
150                $R->tablecell_open();
151                if($mode == 'xhtml') {
152                    $R->doc = substr($R->doc, 0, -1) . ' data-struct="'.hsc($field->getColumn()->getFullQualifiedLabel()).'">';
153                }
154                $field->render($R, $mode);
155                $R->tablecell_close();
156                $R->tablerow_close();
157            }
158            $R->tabletbody_close();
159            $R->table_close();
160        }
161
162        if($mode == 'xhtml') $R->doc .= self::XHTML_CLOSE;
163
164        // if no data has been output, remove empty wrapper again
165        if($mode == 'xhtml' && !$hasdata) {
166            $R->doc = substr($R->doc, 0, -1 * strlen(self::XHTML_OPEN . self::XHTML_CLOSE));
167        }
168
169        return true;
170    }
171}
172
173// vim:ts=4:sw=4:et:
174