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