1<?php
2
3/**
4 * Plugin TableWidth
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Mykola Ostrovskyy <dwpforge@gmail.com>
8 */
9
10class action_plugin_tablewidth extends DokuWiki_Action_Plugin {
11
12    /**
13     * Register callbacks
14     */
15    public function register(Doku_Event_Handler $controller) {
16        $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'replaceComments');
17    }
18
19    /**
20     * Replace table-width comments by HTML
21     */
22    public function replaceComments(&$event, $param) {
23        if ($event->data[0] == 'xhtml') {
24            $pattern = '/(<!-- table-width [^\n]+? -->\n)([^\n]*<table.*?>)(\s*<t)/';
25            $flags = PREG_SET_ORDER | PREG_OFFSET_CAPTURE;
26
27            if (preg_match_all($pattern, $event->data[1], $match, $flags) > 0) {
28                $start = 0;
29                $html = '';
30
31                foreach ($match as $data) {
32                    $html .= substr($event->data[1], $start, $data[0][1] - $start);
33                    $html .= $this->processTable($data);
34                    $start = $data[0][1] + strlen($data[0][0]);
35                }
36
37                $event->data[1] = $html . substr($event->data[1], $start);
38            }
39        }
40    }
41
42    /**
43     * Convert table-width comments and table mark-up into final HTML
44     */
45    private function processTable($data) {
46        preg_match('/<!-- table-width ([^\n]+?) -->/', $data[1][0], $match);
47
48        $width = preg_split('/\s+/', $match[1]);
49        $tableAlign = preg_match('/[<>]+/', $width[0]) == 1 ? array_shift($width) : '-';
50        $tableWidth = array_shift($width);
51
52        if ($tableWidth != '-' || $tableAlign != '-') {
53            $table = $this->styleTable($data[2][0], $tableWidth, $tableAlign);
54        }
55        else {
56            $table = $data[2][0];
57        }
58
59        return $table . $this->renderColumns($width) . $data[3][0];
60    }
61
62    /**
63     * Add width and align styles to the table
64     */
65    private function styleTable($html, $width, $align) {
66        preg_match('/^([^\n]*<table)(.*?)(>)$/', $html, $match);
67
68        $entry = $match[1];
69        $attributes = $match[2];
70        $exit = $match[3];
71
72        $widthStyle = $this->getTableWidthStyle($width);
73        $alignStyle = $this->getTableAlignStyle($align);
74        $tableStyle = implode(' ', array_filter([$widthStyle, $alignStyle]));
75
76        if (preg_match('/(.*?style\s*=\s*(["\']).*?)(\2.*)/', $attributes, $match) == 1) {
77            $attributes = $match[1] . '; ' . $tableStyle . $match[3];
78        }
79        else {
80            $attributes .= ' style="' . $tableStyle . '"';
81        }
82
83        return $entry . $attributes . $exit;
84    }
85
86    /**
87     * Return table width style
88     */
89    private function getTableWidthStyle($width) {
90        if ($width != '-') {
91            return 'min-width: 0; width: ' . $width . ';';
92        }
93
94        return '';
95    }
96
97    /**
98     * Return table align style
99     */
100    private function getTableAlignStyle($align) {
101        switch ($align) {
102            case '><':
103                return 'margin-left: auto; margin-right: auto;';
104            case '>':
105                return 'margin-left: auto; margin-right: 0;';
106            case '<':
107                return 'margin-left: 0; margin-right: auto;';
108        }
109
110        return '';
111    }
112
113    /**
114     * Render column tags
115     */
116    private function renderColumns($width) {
117        $html = DOKU_LF;
118
119        foreach ($width as $w) {
120            if ($w != '-') {
121                $html .= '<col style="width: ' . $w . '" />';
122            }
123            else {
124                $html .= '<col />';
125            }
126        }
127
128        return $html;
129    }
130}
131