1<?php
2/**
3 * Table Renderer for Table Editor
4 *
5 * This renderer will use the inverse renderer to create Wiki text for everything inside the table. The table
6 * it self is stored in two arrays which then can be outputted as JSON.
7 *
8 * @author     Andreas Gohr <gohr@cosmocode.de>
9 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 */
11
12// must be run within Dokuwiki
13if (!defined('DOKU_INC')) die();
14
15require_once DOKU_PLUGIN . "/edittable/renderer/inverse.php";
16
17class renderer_plugin_edittable_json extends renderer_plugin_edittable_inverse {
18    /** @var array holds the data cells */
19    private $tdata = array();
20    /** @var array holds the cell meta data */
21    private $tmeta = array();
22
23    /** @var array holds the meta data of the current cell */
24    private $tmetacell = array();
25
26    /** @var int current row */
27    private $current_row = -1;
28
29    /** @var int current column */
30    private $current_col = 0;
31
32    /**
33     * Returns the whole table data as two dimensional array
34     *
35     * @return array
36     */
37    public function getDataJSON() {
38        return json_encode($this->tdata);
39    }
40
41    /**
42     * Returns meta data for all cells in a two dimensional array of arrays
43     *
44     * @return array
45     */
46    public function getMetaJSON() {
47        return json_encode($this->tmeta);
48    }
49
50    // renderer functions below
51
52    function table_open($maxcols = null, $numrows = null, $pos = null) {
53        // FIXME: is this needed somewhere? $this->_counter['table_begin_pos'] = strlen($this->doc);
54    }
55
56    function table_close($pos = null) {
57    }
58
59    function tablerow_open() {
60        // move counters
61        $this->current_row++;
62        $this->current_col = 0;
63    }
64
65    function tablerow_close() {
66        // resort just for better debug readability
67        ksort($this->tdata[$this->current_row]);
68        ksort($this->tmeta[$this->current_row]);
69    }
70
71    function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
72        $this->_tablefield_open('th', $colspan, $align, $rowspan);
73    }
74
75    function tableheader_close() {
76        $this->_tablefield_close();
77    }
78
79    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
80        $this->_tablefield_open('td', $colspan, $align, $rowspan);
81    }
82
83    function tablecell_close() {
84        $this->_tablefield_close();
85    }
86
87    /**
88     * Used for a opening THs and TDs
89     *
90     * @param $tag
91     * @param $colspan
92     * @param $align
93     * @param $rowspan
94     */
95    private function _tablefield_open($tag, $colspan, $align, $rowspan) {
96        // skip cells that already exist - those are previous (span) cells!
97        while(isset($this->tmeta[$this->current_row][$this->current_col])) {
98            $this->current_col++;
99        }
100
101        // remember these, we use them when closing
102        $this->tmetacell = array();
103        $this->tmetacell['tag'] = $tag;
104        $this->tmetacell['colspan'] = $colspan;
105        $this->tmetacell['rowspan'] = $rowspan;
106        $this->tmetacell['align'] = $align;
107
108        // empty $doc
109        $this->doc = '';
110    }
111
112    /**
113     * Used for closing THs and TDs
114     */
115    private function _tablefield_close() {
116        // these have been set to the correct cell already
117        $row = $this->current_row;
118        $col = $this->current_col;
119
120        $this->tdata[$row][$col] = trim(str_replace("\n", ' ', $this->doc)); // no newlines in table cells!
121        $this->tmeta[$row][$col] = $this->tmetacell; // as remembered in the open call
122
123        // now fill up missing span cells
124        {
125            $rowspan = $this->tmetacell['rowspan'];
126            $colspan = $this->tmetacell['colspan'];
127
128            for($c = 1; $c < $colspan; $c++) {
129                // hide colspanned cell in same row
130                $this->tmeta[$row][$col + $c]['hide'] = true;
131                $this->tmeta[$row][$col + $c]['rowspan'] = 1;
132                $this->tmeta[$row][$col + $c]['colspan'] = 1;
133                $this->tdata[$row][$col + $c] = '';
134
135                // hide colspanned rows below if rowspan is in effect as well
136                for($r = 1; $r < $rowspan; $r++) {
137                    $this->tmeta[$row + $r][$col + $c]['hide'] = true;
138                    $this->tmeta[$row + $r][$col + $c]['rowspan'] = 1;
139                    $this->tmeta[$row + $r][$col + $c]['colspan'] = 1;
140                    $this->tdata[$row + $r][$col + $c] = '';
141                }
142            }
143
144            // hide rowspanned columns
145            for($r = 1; $r < $rowspan; $r++) {
146                $this->tmeta[$row + $r][$col]['hide'] = true;
147                $this->tmeta[$row + $r][$col]['rowspan'] = 1;
148                $this->tmeta[$row + $r][$col]['colspan'] = 1;
149                $this->tdata[$row + $r][$col] = ':::';
150            }
151        }
152    }
153}
154