1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2019 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Report; 21 22/** 23 * Class ReportHtmlTextbox 24 */ 25class ReportHtmlTextbox extends ReportBaseTextbox 26{ 27 /** 28 * Render the elements. 29 * 30 * @param ReportHtml $renderer 31 * 32 * @return void 33 */ 34 public function render($renderer) 35 { 36 // checkFootnote 37 $newelements = []; 38 $lastelement = []; 39 $footnote_element = []; 40 // Element counter 41 $cE = count($this->elements); 42 //-- collapse duplicate elements 43 for ($i = 0; $i < $cE; $i++) { 44 $element = $this->elements[$i]; 45 if ($element instanceof ReportBaseElement) { 46 if ($element instanceof ReportBaseText) { 47 if (!empty($footnote_element)) { 48 ksort($footnote_element); 49 foreach ($footnote_element as $links) { 50 $newelements[] = $links; 51 } 52 $footnote_element = []; 53 } 54 if (empty($lastelement)) { 55 $lastelement = $element; 56 } else { 57 // Checking if the Text has the same style 58 if ($element->getStyleName() === $lastelement->getStyleName()) { 59 $lastelement->addText(str_replace("\n", '<br>', $element->getValue())); 60 } elseif (!empty($lastelement)) { 61 $newelements[] = $lastelement; 62 $lastelement = $element; 63 } 64 } 65 } elseif ($element instanceof ReportHtmlFootnote) { 66 // Check if the Footnote has been set with it’s link number 67 $renderer->checkFootnote($element); 68 // Save first the last element if any 69 if (!empty($lastelement)) { 70 $newelements[] = $lastelement; 71 $lastelement = []; 72 } 73 // Save the Footnote with it’s link number as key for sorting later 74 $footnote_element[$element->num] = $element; 75 } elseif (trim($element->getValue()) !== '') { 76 // Do not keep empty footnotes 77 if (!empty($footnote_element)) { 78 ksort($footnote_element); 79 foreach ($footnote_element as $links) { 80 $newelements[] = $links; 81 } 82 $footnote_element = []; 83 } 84 if (!empty($lastelement)) { 85 $newelements[] = $lastelement; 86 $lastelement = []; 87 } 88 $newelements[] = $element; 89 } 90 } else { 91 if (!empty($lastelement)) { 92 $newelements[] = $lastelement; 93 $lastelement = []; 94 } 95 if (!empty($footnote_element)) { 96 ksort($footnote_element); 97 foreach ($footnote_element as $links) { 98 $newelements[] = $links; 99 } 100 $footnote_element = []; 101 } 102 $newelements[] = $element; 103 } 104 } 105 if (!empty($lastelement)) { 106 $newelements[] = $lastelement; 107 } 108 if (!empty($footnote_element)) { 109 ksort($footnote_element); 110 foreach ($footnote_element as $links) { 111 $newelements[] = $links; 112 } 113 } 114 $this->elements = $newelements; 115 unset($footnote_element, $lastelement, $newelements); 116 117 $cP = 0; // Class Padding 118 119 // Used with line breaks and cell height calculation within this box only 120 $renderer->largestFontHeight = 0; 121 122 // If current position (left) 123 if ($this->left === ReportBaseElement::CURRENT_POSITION) { 124 $cX = $renderer->getX(); 125 } else { 126 $cX = $this->left; 127 $renderer->setX($cX); 128 } 129 // If current position (top) 130 if ($this->top === ReportBaseElement::CURRENT_POSITION) { 131 $this->top = $renderer->getY(); 132 } else { 133 $renderer->setY($this->top); 134 } 135 136 // Check the width if set to page wide OR set by xml to larger then page width (margin) 137 if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) { 138 $this->width = $renderer->getRemainingWidth(); 139 } 140 // Setup the CellPadding 141 if ($this->padding) { 142 $cP = $renderer->cPadding; 143 } 144 145 // For padding, we have to use less wrap width 146 $cW = $this->width - ($cP * 2); 147 148 //-- calculate the text box height 149 // Number of lines, will be converted to height 150 $cHT = 0; 151 // Element height (exept text) 152 $eH = 0; 153 // Footnote height (in points) 154 $fH = 0; 155 $w = 0; 156 //-- $lw is an array 157 // 0 => last line width 158 // 1 => 1 if text was wrapped, 0 if text did not wrap 159 // 2 => number of LF 160 $lw = []; 161 // Element counter 162 $cE = count($this->elements); 163 for ($i = 0; $i < $cE; $i++) { 164 if (is_object($this->elements[$i])) { 165 $ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW); 166 if ($ew == $cW) { 167 $w = 0; 168 } 169 $lw = $this->elements[$i]->getWidth($renderer); 170 // Text is already gets the # LF 171 $cHT += $lw[2]; 172 if ($lw[1] == 1) { 173 $w = $lw[0]; 174 } elseif ($lw[1] == 2) { 175 $w = 0; 176 } else { 177 $w += $lw[0]; 178 } 179 if ($w > $cW) { 180 $w = $lw[0]; 181 } 182 // For anything else but text (images), get the height 183 $eH += $this->elements[$i]->getHeight($renderer); 184 } else { 185 $fH += abs($renderer->getFootnotesHeight($cW)); 186 } 187 } 188 189 // Add up what’s the final height 190 $cH = $this->height; 191 // If any element exist 192 if ($cE > 0) { 193 // Check if this is text or some other element, like images 194 if ($eH == 0) { 195 // Number of LF but at least one line 196 $cHT = ($cHT + 1) * $renderer->cellHeightRatio; 197 // Calculate the cell hight with the largest font size used 198 $cHT *= $renderer->largestFontHeight; 199 if ($cH < $cHT) { 200 $cH = $cHT; 201 } 202 } else { 203 // This is any other element 204 if ($cH < $eH) { 205 $cH = $eH; 206 } 207 // Add Footnote height to the rest of the height 208 $cH += $fH; 209 } 210 } 211 212 unset($lw, $cHT, $fH, $w); 213 214 // Finaly, check the last cells height 215 if ($cH < $renderer->lastCellHeight) { 216 $cH = $renderer->lastCellHeight; 217 } 218 // Update max Y incase of a pagebreak 219 // We don't want to over write any images or other stuff 220 $renderer->addMaxY($this->top + $cH); 221 222 // Start to print HTML 223 echo '<div style="position:absolute;top:', $this->top, 'pt;'; 224 // LTR (left) or RTL (right) 225 echo $renderer->alignRTL, ':', $cX, 'pt;'; 226 // Background color 227 if ($this->fill) { 228 if (!empty($this->bgcolor)) { 229 echo ' background-color:', $this->bgcolor, ';'; 230 } 231 } 232 // Print padding only when it’s set 233 if ($this->padding) { 234 // Use Cell around padding to support RTL also 235 echo 'padding:', $cP, 'pt;'; 236 } 237 // Border setup 238 if ($this->border) { 239 echo ' border:solid black 1pt;'; 240 echo 'width:', ($this->width - 1 - ($cP * 2)), 'pt;height:', $cH - 1, 'pt;'; 241 } else { 242 echo 'width:', ($this->width - ($cP * 2)), 'pt;height:', $cH, 'pt;'; 243 } 244 echo '">'; 245 246 // Do a little "margin" trick before print 247 // to get the correct current position => "." 248 $cXT = $renderer->getX(); 249 $cYT = $renderer->getY(); 250 $renderer->setXy(0, 0); 251 252 // Print the text elements 253 foreach ($this->elements as $element) { 254 if ($element instanceof ReportBaseElement) { 255 $element->render($renderer, $cX, false); 256 } elseif ($element === 'footnotetexts') { 257 $renderer->footnotes(); 258 } elseif ($element === 'addpage') { 259 $renderer->addPage(); 260 } 261 } 262 echo "</div>\n"; 263 264 // Reset "margins" 265 $renderer->setXy($cXT, $cYT); 266 // This will be mostly used to trick the multiple images last height 267 if ($this->reseth) { 268 $cH = 0; 269 } 270 // New line and some clean up 271 if (!$this->newline) { 272 $renderer->setXy($cX + $this->width, $this->top); 273 $renderer->lastCellHeight = $cH; 274 } else { 275 $renderer->setXy(0, $this->top + $cH + ($cP * 2)); 276 $renderer->lastCellHeight = 0; 277 } 278 } 279} 280