@@ -69,6 +69,8 @@ class renderer_plugin_odt_page extends Doku_Renderer {
6969 protected $ page = null ;
7070 /** @var Array of used page styles. Will stay empty if only A4-portrait is used */
7171 protected $ page_styles = array ();
72+ /** @var Array of paragraph style names that prevent an empty paragraph from being deleted */
73+ protected $ preventDeletetionStyles = array ();
7274 /** @var refIDCount */
7375 protected $ refIDCount = 0 ;
7476
@@ -341,17 +343,84 @@ public function setPageFormat ($format, $orientation, $margin_top=2, $margin_rig
341343 $ style_name = $ this ->factory ->createParagraphStyle ($ style_content , $ properties );
342344 $ this ->autostyles [$ style_name ] = $ style_content ;
343345
346+ // Save paragraph style name in 'Do not delete array'!
347+ $ this ->preventDeletetionStyles [] = $ style_name ;
348+
344349 // Open paragraph with new style format
345350 $ this ->p_close ();
346351 $ this ->p_open ($ style_name );
347352 }
348353
354+ /**
355+ * This function deletes the useless elements. Right now, these are empty paragraphs
356+ * or paragraphs that only include whitespace.
357+ *
358+ * IMPORTANT:
359+ * Paragraphs can be used for pagebreaks/changing page format.
360+ * Such paragraphs may not be deleted!
361+ */
362+ protected function deleteUselessElements () {
363+ $ length_open = strlen ('<text:p> ' );
364+ $ length_close = strlen ('</text:p> ' );
365+ $ max = strlen ($ this ->doc );
366+ $ pos = 0 ;
367+
368+ while ($ pos < $ max ) {
369+ $ start_open = strpos ($ this ->doc , '<text:p ' , $ pos );
370+ if ( $ start_open === false ) {
371+ break ;
372+ }
373+ $ start_close = strpos ($ this ->doc , '> ' , $ start_open + $ length_open );
374+ if ( $ start_close === false ) {
375+ break ;
376+ }
377+ $ end = strpos ($ this ->doc , '</text:p> ' , $ start_close + 1 );
378+ if ( $ end === false ) {
379+ break ;
380+ }
381+
382+ $ deleted = false ;
383+ $ length = $ end - $ start_open + $ length_close ;
384+ $ content = substr ($ this ->doc , $ start_close + 1 , $ end - ($ start_close + 1 ));
385+
386+ if ( empty ($ content ) || ctype_space ($ content ) ) {
387+ // Paragraph is empty or consists of whitespace only. Check style name.
388+ $ style_start = strpos ($ this ->doc , '" ' , $ start_open );
389+ if ( $ style_start === false ) {
390+ // No '"' found??? Ignore this paragraph.
391+ break ;
392+ }
393+ $ style_end = strpos ($ this ->doc , '" ' , $ style_start +1 );
394+ if ( $ style_end === false ) {
395+ // No '"' found??? Ignore this paragraph.
396+ break ;
397+ }
398+ $ style_name = substr ($ this ->doc , $ style_start +1 , $ style_end - ($ style_start +1 ));
399+
400+ // Only delete empty paragraph if not listed in 'Do not delete' array!
401+ if ( !in_array ($ style_name , $ this ->preventDeletetionStyles ) )
402+ {
403+ $ this ->doc = substr_replace ($ this ->doc , '' , $ start_open , $ length );
404+
405+ $ deleted = true ;
406+ $ max -= $ length ;
407+ $ pos = $ start_open ;
408+ }
409+ }
410+
411+ if ( $ deleted == false ) {
412+ $ pos = $ start_open + $ length ;
413+ }
414+ }
415+ }
416+
349417 /**
350418 * Completes the ODT file
351419 */
352420 public function finalize_ODTfile () {
353- // Delete paragraphs which only contain whitespace
354- $ this ->doc = preg_replace ('#<text:p[^>]*>\s*</text:p># ' , '' , $ this ->doc );
421+ // Delete paragraphs which only contain whitespace (but keep pagebreaks!)
422+ $ this ->deleteUselessElements ();
423+
355424 // Build the document
356425 $ this ->docHandler ->build ($ this ->doc ,
357426 $ this ->_odtAutoStyles (),
@@ -826,6 +895,9 @@ function linebreak() {
826895 protected function createPagebreakStyle () {
827896 if ( empty ($ this ->autostyles ['pagebreak ' ]) ) {
828897 $ this ->autostyles ['pagebreak ' ] = '<style:style style:name="pagebreak" style:family="paragraph"><style:paragraph-properties fo:break-before="page"/></style:style> ' ;
898+
899+ // Save paragraph style name in 'Do not delete array'!
900+ $ this ->preventDeletetionStyles [] = 'pagebreak ' ;
829901 }
830902 }
831903
0 commit comments