1<?php
2/**
3 * Helper Component for the Wrap Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Anika Henke <anika@selfthinker.org>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_wrap extends DokuWiki_Plugin {
13    static protected $boxes = array ('wrap_box', 'wrap_danger', 'wrap_warning', 'wrap_caution', 'wrap_notice', 'wrap_safety',
14                                     'wrap_info', 'wrap_important', 'wrap_alert', 'wrap_tip', 'wrap_help', 'wrap_todo',
15                                     'wrap_download', 'wrap_hi', 'wrap_spoiler');
16    static protected $paragraphs = array ('wrap_leftalign', 'wrap_rightalign', 'wrap_centeralign', 'wrap_justify');
17    static protected $column_count = 0;
18    static $box_left_pos = 0;
19    static $box_right_pos = 0;
20    static $box_first = true;
21    static $table_entr = 0;
22
23    /**
24     * get attributes (pull apart the string between '<wrap' and '>')
25     *  and identify classes, width, lang and dir
26     *
27     * @author Anika Henke <anika@selfthinker.org>
28     * @author Christopher Smith <chris@jalakai.co.uk>
29     *   (parts taken from http://www.dokuwiki.org/plugin:box)
30     */
31    function getAttributes($data, $useNoPrefix=true) {
32
33        $attr = array();
34        $tokens = preg_split('/\s+/', $data, 9);
35
36        // anonymous function to convert inclusive comma separated items to regex pattern
37        $pattern = function ($csv) {
38            return '/^(?:'. str_replace(['?','*',' ',','],
39                                        ['.','.*','','|'], $csv) .')$/';
40        };
41
42        // noPrefix: comma separated class names that should be excluded from
43        //   being prefixed with "wrap_",
44        //   each item may contain wildcard (*, ?)
45        $noPrefix = ($this->getConf('noPrefix') && $useNoPrefix) ? $pattern($this->getConf('noPrefix')) : '';
46
47        // restrictedClasses : comma separated class names that should be checked
48        //   based on restriction type (whitelist or blacklist),
49        //   each item may contain wildcard (*, ?)
50        $restrictedClasses = ($this->getConf('restrictedClasses')) ?
51                            $pattern($this->getConf('restrictedClasses')) : '';
52        $restrictionType = $this->getConf('restrictionType');
53
54        foreach ($tokens as $token) {
55
56            //get width
57            if (preg_match('/^\d*\.?\d+(%|px|em|rem|ex|ch|vw|vh|pt|pc|cm|mm|in)$/', $token)) {
58                $attr['width'] = $token;
59                continue;
60            }
61
62            //get lang
63            if (preg_match('/\:([a-z\-]+)/', $token)) {
64                $attr['lang'] = trim($token,':');
65                continue;
66            }
67
68            //get id
69            if (preg_match('/#([A-Za-z0-9_-]+)/', $token)) {
70                $attr['id'] = trim($token,'#');
71                continue;
72            }
73
74            //get classes
75            //restrict token (class names) characters to prevent any malicious data
76            if (preg_match('/[^A-Za-z0-9_-]/',$token)) continue;
77            if ($restrictedClasses) {
78                $classIsInList = preg_match($restrictedClasses, $token);
79                // either allow only certain classes or disallow certain classes
80                if ($restrictionType xor $classIsInList) continue;
81            }
82            // prefix adjustment of class name
83            $prefix = (preg_match($noPrefix, $token)) ? '' : 'wrap_';
84            $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').$prefix.$token;
85        }
86        if ($this->getConf('darkTpl')) {
87            $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').'wrap__dark';
88        }
89        if ($this->getConf('emulatedHeadings')) {
90            $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').'wrap__emuhead';
91        }
92
93        //get dir
94        if($attr['lang']) {
95            $lang2dirFile = dirname(__FILE__).'/conf/lang2dir.conf';
96            if (@file_exists($lang2dirFile)) {
97                $lang2dir = confToHash($lang2dirFile);
98                $attr['dir'] = strtr($attr['lang'],$lang2dir);
99            }
100        }
101
102        return $attr;
103    }
104
105    /**
106     * build attributes (write out classes, width, lang and dir)
107     */
108    function buildAttributes($data, $addClass='', $mode='xhtml') {
109
110        $attr = $this->getAttributes($data);
111        $out = '';
112
113        if ($mode=='xhtml') {
114            if($attr['class']) $out .= ' class="'.hsc($attr['class']).' '.$addClass.'"';
115            // if used in other plugins, they might want to add their own class(es)
116            elseif($addClass)  $out .= ' class="'.$addClass.'"';
117            if($attr['id'])    $out .= ' id="'.hsc($attr['id']).'"';
118            // width on spans normally doesn't make much sense, but in the case of floating elements it could be used
119            if($attr['width']) {
120                if (strpos($attr['width'],'%') !== false) {
121                    $out .= ' style="width: '.hsc($attr['width']).';"';
122                } else {
123                    // anything but % should be 100% when the screen gets smaller
124                    $out .= ' style="width: '.hsc($attr['width']).'; max-width: 100%;"';
125                }
126            }
127            // only write lang if it's a language in lang2dir.conf
128            if($attr['dir'])   $out .= ' lang="'.$attr['lang'].'" xml:lang="'.$attr['lang'].'" dir="'.$attr['dir'].'"';
129        }
130
131        return $out;
132    }
133
134    /**
135     * render ODT element, Open
136     * (get Attributes, select ODT element that fits, render it, return element name)
137     */
138    function renderODTElementOpen($renderer, $HTMLelement, $data) {
139        $attr = $this->getAttributes($data, false);
140        $attr_string = $this->buildAttributes($data);
141        $classes = explode (' ', $attr['class']);
142
143        // Get language
144        $language = $attr['lang'];
145
146        $is_indent    = in_array ('wrap_indent', $classes);
147        $is_outdent   = in_array ('wrap_outdent', $classes);
148        $is_column    = in_array ('wrap_column', $classes);
149        $is_group     = in_array ('wrap_group', $classes);
150        $is_pagebreak = in_array ('wrap_pagebreak', $classes);
151
152        // Check for multicolumns
153        $columns = 0;
154        preg_match ('/wrap_col\d/', $attr ['class'], $matches);
155        if ( empty ($matches [0]) === false ) {
156            $columns = $matches [0] [strlen($matches [0])-1];
157        }
158
159        // Check for boxes
160        $is_box = false;
161        foreach (self::$boxes as $box) {
162            if ( strpos ($attr ['class'], $box) !== false ) {
163                $is_box = true;
164                break;
165            }
166        }
167
168        // Check for paragraphs
169        $is_paragraph = false;
170        if ( empty($language) === false ) {
171            $is_paragraph = true;
172        } else {
173            foreach (self::$paragraphs as $paragraph) {
174                if ( strpos ($attr ['class'], $paragraph) !== false ) {
175                    $is_paragraph = true;
176                    break;
177                }
178            }
179        }
180
181        $style = NULL;
182        if ( empty($attr['width']) === false ) {
183            $style = 'width: '.$attr['width'].';';
184        }
185        $attr ['class'] = 'dokuwiki '.$attr ['class'];
186
187        // Call corresponding functions for current wrap class
188        if ( $HTMLelement == 'span' ) {
189            if ( $is_indent === false && $is_outdent === false ) {
190                $this->renderODTOpenSpan ($renderer, $attr ['class'], $style, $language, $attr_string);
191                return 'span';
192            } else {
193                $this->renderODTOpenParagraph ($renderer, $attr ['class'], $style, $attr ['dir'], $language, $is_indent, $is_outdent, true, $attr_string);
194                return 'paragraph';
195            }
196        } else if ( $HTMLelement == 'div' ) {
197            if ( $is_box === true ) {
198                $wrap = $this->loadHelper('wrap');
199                $fullattr = $wrap->buildAttributes($data, 'plugin_wrap');
200
201                if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) {
202                    $this->renderODTOpenBox ($renderer, $attr ['class'], $style, $fullattr);
203                } else {
204                    $this->renderODTOpenTable ($renderer, $attr, $style,  $attr_string);
205                }
206                return 'box';
207            } else if ( $columns > 0 ) {
208                $this->renderODTOpenColumns ($renderer, $attr ['class'], $style);
209                return 'multicolumn';
210            } else if ( $is_paragraph === true || $is_indent === true || $is_outdent === true ) {
211                $this->renderODTOpenParagraph ($renderer, $attr ['class'], $style, $attr ['dir'], $language, $is_indent, $is_outdent, false, $attr_string);
212                return 'paragraph';
213            } else if ( $is_pagebreak === true ) {
214                $renderer->pagebreak ();
215                // Pagebreak hasn't got a closing stack so we return/push 'other' on the stack
216                return 'other';
217            } else if ( $is_column === true ) {
218                $this->renderODTOpenColumn ($renderer, $attr ['class'], $style, $attr_string);
219                return 'column';
220            } else if ( $is_group === true ) {
221                $this->renderODTOpenGroup ($renderer, $attr ['class'], $style);
222                return 'group';
223            } else if (strpos ($attr ['class'], 'wrap_clear') !== false ) {
224                $renderer->linebreak();
225                $renderer->p_close();
226                $renderer->p_open();
227
228                self::$box_left_pos = 0;
229                self::$box_right_pos = 0;
230                self::$box_first = true;
231            }
232        }
233        return 'other';
234    }
235
236    /**
237     * render ODT element, Close
238     */
239    function renderODTElementClose($renderer, $element) {
240        switch ($element) {
241            case 'box':
242                if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) {
243                    $this->renderODTCloseBox ($renderer);
244                } else {
245                    $this->renderODTCloseTable ($renderer);
246                }
247            break;
248            case 'multicolumn':
249                $this->renderODTCloseColumns($renderer);
250            break;
251            case 'paragraph':
252                $this->renderODTCloseParagraph($renderer);
253            break;
254            case 'column':
255                $this->renderODTCloseColumn($renderer);
256            break;
257            case 'group':
258                $this->renderODTCloseGroup($renderer);
259            break;
260            case 'span':
261                $this->renderODTCloseSpan($renderer);
262            break;
263            // No default by intention.
264        }
265    }
266
267    function renderODTOpenBox ($renderer, $class, $style, $fullattr) {
268        $properties = array ();
269
270        if ( method_exists ($renderer, 'getODTProperties') === false ) {
271            // Function is not supported by installed ODT plugin version, return.
272            return;
273        }
274
275        // Get CSS properties for ODT export.
276        $renderer->getODTProperties ($properties, 'div', $class, $style);
277
278        if ( empty($properties ['background-image']) === false ) {
279            $properties ['background-image'] =
280                $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC);
281        }
282
283        if ( empty($properties ['float']) === true ) {
284            // If the float property is not set, set it to 'left' becuase the ODT plugin
285            // would default to 'center' which is diffeent to the XHTML behaviour.
286            if ( strpos ($class, 'wrap_center') === false ) {
287                $properties ['float'] = 'left';
288            } else {
289                $properties ['float'] = 'center';
290            }
291        }
292
293        // The display property has differing usage in CSS. So we better overwrite it.
294        $properties ['display'] = 'always';
295        if ( stripos ($class, 'wrap_noprint') !== false ) {
296            $properties ['display'] = 'screen';
297        }
298        if ( stripos ($class, 'wrap_onlyprint') !== false ) {
299            $properties ['display'] = 'printer';
300        }
301
302        $renderer->_odtDivOpenAsFrameUseProperties ($properties);
303    }
304
305    function renderODTCloseBox ($renderer) {
306        if ( method_exists ($renderer, '_odtDivCloseAsFrame') === false ) {
307            // Function is not supported by installed ODT plugin version, return.
308            return;
309        }
310        $renderer->_odtDivCloseAsFrame ();
311    }
312
313    function renderODTOpenColumns ($renderer, $class, $style) {
314        $properties = array ();
315
316        if ( method_exists ($renderer, 'getODTProperties') === false ) {
317            // Function is not supported by installed ODT plugin version, return.
318            return;
319        }
320
321        // Get CSS properties for ODT export.
322        $renderer->getODTProperties ($properties, 'div', $class, $style);
323
324        $renderer->_odtOpenMultiColumnFrame($properties);
325    }
326
327    function renderODTCloseColumns ($renderer) {
328        if ( method_exists ($renderer, '_odtCloseMultiColumnFrame') === false ) {
329            // Function is not supported by installed ODT plugin version, return.
330            return;
331        }
332        $renderer->_odtCloseMultiColumnFrame();
333    }
334
335    function renderODTOpenParagraph ($renderer, $class, $style, $dir, $language, $is_indent, $is_outdent, $indent_first, $attr=NULL) {
336        $properties = array ();
337
338        if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) {
339            // Get CSS properties for ODT export.
340            // Set parameter $inherit=false to prevent changiung the font-size and family!
341            $renderer->getODTPropertiesNew ($properties, 'p', $attr, NULL, false);
342        } else if ( method_exists ($renderer, 'getODTProperties') === true ) {
343            // Get CSS properties for ODT export (deprecated version).
344            $renderer->getODTProperties ($properties, 'p', $class, $style);
345
346            if ( empty($properties ['background-image']) === false ) {
347                $properties ['background-image'] =
348                    $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC);
349            }
350        } else {
351            // To old ODT plugin version.
352            return;
353        }
354
355        if ( empty($properties ['text-align']) )
356        {
357            if ($dir == 'ltr') {
358                $properties ['text-align'] = 'left';
359                $properties ['writing-mode'] = 'lr';
360            }
361            if ($dir == 'rtl') {
362                $properties ['text-align'] = 'right';
363                $properties ['writing-mode'] = 'rl';
364            }
365        }
366
367        $name = '';
368        if ( empty($language) === false ) {
369            $properties ['lang'] = $language;
370            $name .= 'Language: '.$language;
371        }
372
373        if ( $indent_first === true ) {
374            // Eventually indent or outdent first line only...
375            if ( $is_indent === true ) {
376                // FIXME: Has to be adjusted if test direction will be supported.
377                // See all.css
378                $properties ['text-indent'] = $properties ['padding-left'];
379                $properties ['padding-left'] = 0;
380                $name .= 'Indent first';
381            }
382            if ( $is_outdent === true ) {
383                // FIXME: Has to be adjusted if text (RTL, LTR) direction will be supported.
384                // See all.css
385                $properties ['text-indent'] = $properties ['margin-left'];
386                $properties ['margin-left'] = 0;
387                $name .= 'Outdent first';
388            }
389        } else {
390            // Eventually indent or outdent the whole paragraph...
391            if ( $is_indent === true ) {
392                // FIXME: Has to be adjusted if test direction will be supported.
393                // See all.css
394                $properties ['margin-left'] = $properties ['padding-left'];
395                $properties ['padding-left'] = 0;
396                $name .= 'Indent';
397            }
398            if ( $is_outdent === true ) {
399                // Nothing to change: keep left margin property.
400                // FIXME: Has to be adjusted if text (RTL, LTR) direction will be supported.
401                // See all.css
402                $name .= 'Outdent';
403            }
404        }
405
406        $renderer->p_close();
407        if ( method_exists ($renderer, 'createParagraphStyle') === false ) {
408            // Older ODT plugin version.
409            $renderer->_odtParagraphOpenUseProperties($properties);
410        } else {
411            // Newer version create our own common styles.
412
413            // Create parent style to group the others beneath it
414            if (!$renderer->styleExists('Plugin_Wrap_Paragraphs')) {
415                $parent_properties = array();
416                $parent_properties ['style-parent'] = NULL;
417                $parent_properties ['style-class'] = 'Plugin Wrap Paragraphs';
418                $parent_properties ['style-name'] = 'Plugin_Wrap_Paragraphs';
419                $parent_properties ['style-display-name'] = 'Plugin Wrap';
420                $renderer->createParagraphStyle($parent_properties);
421            }
422
423            $name .= $this->getODTCommonStyleName($class);
424            $style_name = 'Plugin_Wrap_Paragraph_'.$name;
425            if (!$renderer->styleExists($style_name)) {
426                $properties ['style-parent'] = 'Plugin_Wrap_Paragraphs';
427                $properties ['style-class'] = NULL;
428                $properties ['style-name'] = $style_name;
429                $properties ['style-display-name'] = $name;
430                $renderer->createParagraphStyle($properties);
431            }
432
433            $renderer->p_open($style_name);
434        }
435    }
436
437    function renderODTCloseParagraph ($renderer) {
438        if ( method_exists ($renderer, 'p_close') === false ) {
439            // Function is not supported by installed ODT plugin version, return.
440            return;
441        }
442        $renderer->p_close();
443    }
444
445    function renderODTOpenColumn ($renderer, $class, $style, $attr) {
446        $properties = array ();
447
448        if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) {
449            // Get CSS properties for ODT export.
450            $renderer->getODTPropertiesNew ($properties, 'div', $attr);
451        } else if ( method_exists ($renderer, 'getODTProperties') === true ) {
452            // Get CSS properties for ODT export (deprecated version).
453            $renderer->getODTProperties ($properties, NULL, $class, $style);
454        } else {
455            // To old ODT plugin version.
456            return;
457        }
458
459        // Frames/Textboxes still have some issues with formatting (at least in LibreOffice)
460        // So as a workaround we implement columns as a table.
461        // This is why we now use the margin of the div as the padding for the ODT table.
462        $properties ['padding-left'] = $properties ['margin-left'];
463        $properties ['padding-right'] = $properties ['margin-right'];
464        $properties ['padding-top'] = $properties ['margin-top'];
465        $properties ['padding-bottom'] = $properties ['margin-bottom'];
466        $properties ['margin-left'] = NULL;
467        $properties ['margin-right'] = NULL;
468        $properties ['margin-top'] = NULL;
469        $properties ['margin-bottom'] = NULL;
470
471        // Percentage values are not supported for the padding. Convert to absolute values.
472        $length = strlen ($properties ['padding-left']);
473        if ( $length > 0 && $properties ['padding-left'] [$length-1] == '%' ) {
474            $properties ['padding-left'] = trim ($properties ['padding-left'], '%');
475            $properties ['padding-left'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-left']).'cm';
476        }
477        $length = strlen ($properties ['padding-right']);
478        if ( $length > 0 && $properties ['padding-right'] [$length-1] == '%' ) {
479            $properties ['padding-right'] = trim ($properties ['padding-right'], '%');
480            $properties ['padding-right'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-right']).'cm';
481        }
482        $length = strlen ($properties ['padding-top']);
483        if ( $length > 0 && $properties ['padding-top'] [$length-1] == '%' ) {
484            $properties ['padding-top'] = trim ($properties ['padding-top'], '%');
485            $properties ['padding-top'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-top']).'cm';
486        }
487        $length = strlen ($properties ['padding-bottom']);
488        if ( $length > 0 && $properties ['padding-bottom'] [$length-1] == '%' ) {
489            $properties ['padding-bottom'] = trim ($properties ['padding-bottom'], '%');
490            $properties ['padding-bottom'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-bottom']).'cm';
491        }
492
493        $this->column_count++;
494        if ( $this->column_count == 1 ) {
495            // If this is the first column opened since the group was opened
496            // then we have to open the table and a (single) row first.
497            $properties ['width'] = '100%';
498            $renderer->_odtTableOpenUseProperties($properties);
499            $renderer->_odtTableRowOpenUseProperties($properties);
500        }
501
502        // We did not specify any max column value when we opened the table.
503        // So we have to tell the renderer to add a column just now.
504        unset($properties ['width']);
505        $renderer->_odtTableAddColumnUseProperties($properties);
506
507        // Open the cell.
508        $renderer->_odtTableCellOpenUseProperties($properties);
509    }
510
511    function renderODTCloseColumn ($renderer) {
512        if ( method_exists ($renderer, '_odtTableAddColumnUseProperties') === false ) {
513            // Function is not supported by installed ODT plugin version, return.
514            return;
515        }
516
517        $renderer->tablecell_close();
518    }
519
520    function renderODTOpenGroup ($renderer, $class, $style) {
521        // Nothing to do for now.
522    }
523
524    function renderODTCloseGroup ($renderer) {
525        // If a table has been opened in the group we close it now.
526        if ( $this->column_count > 0 ) {
527            // At last we need to close the row and the table!
528            $renderer->tablerow_close();
529            //$renderer->table_close();
530            $renderer->_odtTableClose();
531        }
532        $this->column_count = 0;
533    }
534
535    function renderODTOpenSpan ($renderer, $class, $style, $language, $attr) {
536        $properties = array ();
537
538        if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) {
539            // Get CSS properties for ODT export.
540            // Set parameter $inherit=false to prevent changiung the font-size and family!
541            $renderer->getODTPropertiesNew ($properties, 'span', $attr, NULL, false);
542        } else if ( method_exists ($renderer, 'getODTProperties') === true ) {
543            // Get CSS properties for ODT export (deprecated version).
544            $renderer->getODTProperties ($properties, 'span', $class, $style);
545
546            if ( empty($properties ['background-image']) === false ) {
547                $properties ['background-image'] =
548                    $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC);
549            }
550        } else {
551            // To old ODT plugin version.
552            return;
553        }
554
555        $name = '';
556        if ( empty($language) === false ) {
557            $properties ['lang'] = $language;
558            $name .= 'Language: '.$language;
559        }
560
561        if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) {
562            // Older ODT plugin version.
563            $renderer->_odtSpanOpenUseProperties($properties);
564        } else {
565            // Newer version create our own common styles.
566            $properties ['font-size'] = NULL;
567
568            // Create parent style to group the others beneath it
569            if (!$renderer->styleExists('Plugin_Wrap_Spans')) {
570                $parent_properties = array();
571                $parent_properties ['style-parent'] = NULL;
572                $parent_properties ['style-class'] = 'Plugin Wrap Spans';
573                $parent_properties ['style-name'] = 'Plugin_Wrap_Spans';
574                $parent_properties ['style-display-name'] = 'Plugin Wrap';
575                $renderer->createTextStyle($parent_properties);
576            }
577
578            $name .= $this->getODTCommonStyleName($class);
579            $style_name = 'Plugin_Wrap_Span_'.$name;
580            if (!$renderer->styleExists($style_name)) {
581                $properties ['style-parent'] = 'Plugin_Wrap_Spans';
582                $properties ['style-class'] = NULL;
583                $properties ['style-name'] = $style_name;
584                $properties ['style-display-name'] = $name;
585                $renderer->createTextStyle($properties);
586            }
587
588            if (!empty($properties ['background-image'])) {
589                if (method_exists ($renderer, '_odtAddImageUseProperties') === true) {
590                    $size = NULL;
591                    if (!empty($properties ['font-size'])) {
592                        $size = $properties ['font-size'];
593                        $size = $renderer->addToValue($size, '2pt');
594                    }
595                    $properties ['width'] = $size;
596                    $properties ['height'] = $size;
597                    $properties ['title'] = NULL;
598                    $renderer->_odtAddImageUseProperties ($properties ['background-image'],$properties);
599                } else {
600                    $renderer->_odtAddImage ($properties ['background-image'],NULL,NULL,NULL,NULL,NULL);
601                }
602            }
603            $renderer->_odtSpanOpen($style_name);
604        }
605    }
606
607    function renderODTCloseSpan ($renderer) {
608        if ( method_exists ($renderer, '_odtSpanClose') === false ) {
609            // Function is not supported by installed ODT plugin version, return.
610            return;
611        }
612        $renderer->_odtSpanClose();
613    }
614
615    function renderODTOpenTable ($renderer, $attr, $style, $attr_string) {
616        self::$table_entr += 1;
617
618        $class = $attr ['class'];
619        $css_properties = array ();
620
621        if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) {
622            // Function is not supported by installed ODT plugin version, return.
623            return;
624        }
625
626        // Get CSS properties for ODT export.
627        $renderer->getODTPropertiesNew ($css_properties, 'div', $attr_string, NULL, true);
628
629        if ( empty($css_properties ['float']) === true ) {
630            // If the float property is not set, set it to 'left' becuase the ODT plugin
631            // would default to 'center' which is diffeent to the XHTML behaviour.
632            //$css_properties ['float'] = 'left';
633            if (strpos ($class, 'wrap_left') !== false ) {
634                $css_properties ['float'] = 'left';
635            } else if (strpos ($class, 'wrap_center') !== false ) {
636                $css_properties ['float'] = 'center';
637            } else if (strpos ($class, 'wrap_right') !== false) {
638                $css_properties ['float'] = 'right';
639            }
640        }
641
642        // The display property has differing usage in CSS. So we better overwrite it.
643        $css_properties ['display'] = 'always';
644        if ( stripos ($class, 'wrap_noprint') !== false ) {
645            $css_properties ['display'] = 'screen';
646        }
647        if ( stripos ($class, 'wrap_onlyprint') !== false ) {
648            $css_properties ['display'] = 'printer';
649        }
650
651        $background_color = $css_properties ['background-color'];
652        $image = $css_properties ['background-image'];
653        $margin_top = $css_properties ['margin-top'];
654        $margin_right = $css_properties ['margin-right'];
655        $margin_bottom = $css_properties ['margin-bottom'];
656        $margin_left = $css_properties ['margin-left'];
657        $width = $attr ['width'];
658
659        // Open 2x1 table if image is present
660        // otherwise only a 1x1 table
661        $properties = array();
662        $properties ['width'] = '100%';
663        $properties ['align'] = 'center';
664        $properties ['margin-top'] = $margin_top;
665        $properties ['margin-right'] = $margin_right;
666        $properties ['margin-bottom'] = $margin_bottom;
667        $properties ['margin-left'] = $margin_left;
668
669        $frame_props = array();
670        if (!empty($css_properties ['border'])) {
671            $frame_props ['border'] = $css_properties ['border'];
672        } else {
673            $frame_props ['border'] = 'none';
674        }
675        $frame_props ['min-height'] = '1cm';
676        $frame_props ['width'] = $attr ['width'];
677        $frame_props ['float'] = $css_properties ['float'];
678        if ( self::$table_entr > 1 ) {
679            $frame_props ['anchor-type'] = 'as-char';
680        } else {
681            $frame_props ['anchor-type'] = 'paragraph';
682        }
683        $frame_props ['textarea-horizontal-align'] = 'left';
684        $frame_props ['run-through'] = 'foreground';
685        $frame_props ['vertical-pos'] = 'from-top';
686        $frame_props ['vertical-rel'] = 'paragraph';
687        $frame_props ['horizontal-pos'] = 'from-left';
688        $frame_props ['horizontal-rel'] = 'paragraph';
689        $frame_props ['wrap'] = 'parallel';
690        $frame_props ['number-wrapped-paragraphs'] = 'no-limit';
691        if (!empty($frame_props ['float']) &&
692            $frame_props ['float'] != 'center') {
693            $frame_props ['margin-top'] = '0cm';
694            $frame_props ['margin-right'] = '0cm';
695            $frame_props ['margin-bottom'] = '0cm';
696            $frame_props ['margin-left'] = '0cm';
697            $frame_props ['padding-top'] = '0cm';
698            $frame_props ['padding-bottom'] = '0cm';
699        } else {
700            // No wrapping on not floating divs
701            $frame_props ['wrap'] = 'none';
702        }
703
704        switch ($frame_props ['float']) {
705            case 'left':
706                if ( self::$table_entr == 1 ) {
707                    $frame_props ['y'] = '0cm';
708                    $frame_props ['x'] = self::$box_left_pos.'cm';
709                    self::$box_left_pos += trim($frame_props ['width'], 'cm');
710                }
711                $frame_props ['padding-left'] = '0cm';
712            break;
713            case 'right':
714                $frame_props ['horizontal-rel'] = 'paragraph';
715                $frame_props ['horizontal-pos'] = 'right';
716                $frame_props ['padding-right'] = '0cm';
717            break;
718            case 'center':
719                $frame_props ['horizontal-pos'] = 'center';
720            break;
721            default:
722                $frame_props ['padding-left'] = '0cm';
723            break;
724        }
725        $renderer->_odtOpenTextBoxUseProperties($frame_props);
726
727        $renderer->_odtTableOpenUseProperties($properties);
728
729        if (!empty($image)) {
730            $properties = array();
731            $properties ['width'] = '2cm';
732            $renderer->_odtTableAddColumnUseProperties($properties);
733        }
734
735        $properties = array();
736        $renderer->_odtTableAddColumnUseProperties($properties);
737
738        $renderer->tablerow_open();
739
740        if (!empty($image)) {
741            $properties = array();
742            $properties ['vertical-align'] = 'middle';
743            $properties ['text-align'] = 'center';
744            $properties ['padding'] = '0.1cm';
745            $properties ['background-color'] = $background_color;
746
747            $renderer->_odtTableCellOpenUseProperties($properties);
748            $renderer->_odtAddImage($image);
749            $renderer->tablecell_close();
750        }
751
752        $properties = array();
753        $properties ['vertical-align'] = 'middle';
754        $properties ['padding'] = '0.3cm';
755        $properties ['background-color'] = $background_color;
756        $properties ['border'] = 'none';
757        $renderer->_odtTableCellOpenUseProperties($properties);
758    }
759
760    function renderODTCloseTable ($renderer) {
761        $renderer->tablecell_close();
762        $renderer->tablerow_close();
763        $renderer->_odtTableClose();
764        $renderer->_odtCloseTextBox ();
765
766        self::$table_entr -= 1;
767    }
768
769    protected function getODTCommonStyleName ($class_string) {
770        static $map = array (
771            'wrap_box' => 'Box', 'wrap_danger' => 'Danger', 'wrap_warning' => 'Warning',
772            'wrap_caution' => 'Caution', 'wrap_notice' => 'Notice', 'wrap_safety' => 'Safety',
773            'wrap_info' => 'Info', 'wrap_important' => 'Important', 'wrap_alert' => 'Alert',
774            'wrap_tip' => 'Tip', 'wrap_help' => 'Help', 'wrap_todo' => 'To do',
775            'wrap_download' => 'Download', 'wrap_hi' => 'Highlighted', 'wrap_spoiler' => 'Spoiler',
776            'wrap_leftalign' => 'Left aligned', 'wrap_rightalign' => 'Right aligned',
777            'wrap_centeralign' => 'Centered', 'wrap_justify' => 'Justify', 'wrap_em' => 'Emphasised',
778            'wrap_lo' => 'Less significant');
779        $classes = explode(' ', $class_string);
780        $name = '';
781        foreach ($classes as $class) {
782            if (array_key_exists($class, $map)) {
783                $name .= $map [$class];
784            }
785        }
786        return ($name);
787    }
788}
789