xref: /plugin/struct/syntax/output.php (revision 0ceefd5c55d49dcf9a9f59c8e57e60eaeea1c187)
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                $schemadata = AccessTable::byTableName($table, $ID, $REV);
124            } catch(StructException $ignored) {
125                continue; // no such schema at this revision
126            }
127            $schemadata->optionSkipEmpty(true);
128            $data = $schemadata->getData();
129            if(!count($data)) continue;
130            $hasdata = true;
131
132            $R->table_open();
133
134            $R->tablethead_open();
135            $R->tablerow_open();
136            $R->tableheader_open(2);
137            $R->cdata($schemadata->getSchema()->getTranslatedLabel());
138            $R->tableheader_close();
139            $R->tablerow_close();
140            $R->tablethead_close();
141
142            $R->tabletbody_open();
143            foreach($data as $field) {
144                $R->tablerow_open();
145                $R->tableheader_open();
146                $R->cdata($field->getColumn()->getTranslatedLabel());
147                $R->tableheader_close();
148                $R->tablecell_open();
149                if($mode == 'xhtml') {
150                    $R->doc = substr($R->doc, 0, -1) . ' data-struct="'.hsc($field->getColumn()->getFullQualifiedLabel()).'">';
151                }
152                $field->render($R, $mode);
153                $R->tablecell_close();
154                $R->tablerow_close();
155            }
156            $R->tabletbody_close();
157            $R->table_close();
158        }
159
160        if($mode == 'xhtml') $R->doc .= self::XHTML_CLOSE;
161
162        // if no data has been output, remove empty wrapper again
163        if($mode == 'xhtml' && !$hasdata) {
164            $R->doc = substr($R->doc, 0, -1 * strlen(self::XHTML_OPEN . self::XHTML_CLOSE));
165        }
166
167        return true;
168    }
169}
170
171// vim:ts=4:sw=4:et:
172