File modules/wikiparser/renderer/HtmlRenderer.class.php

Last commit: Sun Dec 5 20:33:24 2021 +0100	dankert	Cleanup: Removed unusable properties from class 'Value' and 'BaseObject'.
1 <?php 2 3 namespace wikiparser\renderer; 4 5 use cms\base\Configuration; 6 use cms\generator\PageContext; 7 use cms\model\File; 8 use cms\model\Image; 9 use cms\model\BaseObject; 10 use util\ClassUtils; 11 use util\exception\GeneratorException; 12 use wikiparser\model\DefinitionItemElement; 13 use DefinitionListEntryElement; 14 use DefinitionListItemElement; 15 use Exception; 16 use Geshi; 17 use wikiparser\model\LineBreakElement; 18 use wikiparser\model\LinkElement; 19 use cms\macros\MacroRunner; 20 use wikiparser\model\RawElement; 21 use util\Text; 22 use wikiparser\model\TextElement; 23 24 /** 25 * Dokument-Objekt.<br> 26 * Diese Objekt verk�rpert das Root-Objekt in einem DOM-Baum.<br> 27 * <br> 28 * Dieses Objekt kann Text parsen und seine Unterobjekte selbst erzeugen.<br> 29 * 30 * @author Jan Dankert, $Author$ 31 * @version $Revision$ 32 * @package openrat.text 33 */ 34 class HtmlRenderer 35 { 36 public $linkedObjectIds = array(); 37 public $encodeHtml = false; 38 39 /** 40 * Fu�noten. 41 * 42 * @var array 43 */ 44 public $footnotes = array(); 45 46 /** 47 * @var string 48 */ 49 public $renderedText; 50 51 /** 52 * @var \cms\model\Page 53 */ 54 public $page; 55 56 /** 57 * @var PageContext 58 */ 59 public $pageContext; 60 61 /** 62 * @var array 63 */ 64 public $children; 65 66 67 /** 68 * Rendert ein Dokument-Element. 69 * 70 * @param BaseObject $child Element 71 * @return String 72 */ 73 function renderElement($child) 74 { 75 $footnoteConfig = Configuration::subset('editor')->subset('footnote'); 76 $htmlConfig = Configuration::subset(['editor','html']); 77 78 $attr = array(); 79 $val = ''; 80 $praefix = ''; 81 $suffix = ''; 82 $empty = false; 83 84 if (count($child->children) > 0) { 85 $subChild1 = $child->children[0]; 86 87 if (!empty($subChild1->class)) 88 $attr['class'] = $subChild1->class; 89 90 if (!empty($subChild1->style)) 91 $attr['style'] = $subChild1->style; 92 93 if (!empty($subChild1->title)) 94 $attr['title'] = $subChild1->title; 95 } 96 97 switch (strtolower(ClassUtils::getSimpleClassName($child))) { 98 case 'tableofcontentelement': 99 $tag = 'p'; 100 foreach ($this->children as $h) { 101 if (strtolower(get_class($h)) == 'headlineelement') { 102 $child->children[] = new RawElement(str_repeat('&nbsp;&nbsp;', $h->level)); 103 $t = new TextElement($h->getText()); 104 $l = new LinkElement(); 105 $l->fragment = $h->getName(); 106 $l->children[] = $t; 107 $child->children[] = $l; 108 $child->children[] = new LineBreakElement(); 109 } 110 } 111 break; 112 113 case 'rawelement': 114 $tag = ''; 115 116 break; 117 118 case 'textelement': 119 $tag = ''; 120 // $tag = 'span'; 121 122 $val = $child->text; 123 if ($this->encodeHtml) 124 $val = Text::encodeHtml($val); 125 $val = Text::replaceHtmlChars($val); 126 break; 127 128 case 'footnoteelement': 129 $tag = 'a'; 130 $attr['href'] = '#footnote'; 131 132 $title = ''; 133 foreach ($child->children as $c) 134 $title .= $this->renderElement($c); 135 $attr['title'] = strip_tags($title); 136 137 $nr = 1; 138 foreach ($this->footnotes as $fn) 139 if (strtolower(get_class($fn)) == 'linebreakelement') 140 $nr++; 141 142 $val = $nr; 143 if ($footnoteConfig->is('bracket') ) 144 $val = '(' . $nr . ')'; 145 if ($footnoteConfig->is('sup')) 146 $val = '<sup><small>' . $nr . '</small></sup>'; 147 148 149 if ($nr == 1) { 150 $this->footnotes[] = new RawElement('&mdash;'); 151 $le = new LinkElement(); 152 $le->name = "footnote"; 153 $this->footnotes[] = $le; 154 $this->footnotes[] = new RawElement('&mdash;'); 155 } 156 $this->footnotes[] = new LineBreakElement(); 157 $this->footnotes[] = new RawElement($val); 158 $this->footnotes[] = new RawElement(' '); 159 foreach ($child->children as $c) 160 $this->footnotes[] = $c; 161 162 $child->children = array(); 163 164 break; 165 166 case 'codeelement': 167 168 if (empty($child->language)) 169 // Wenn keine Sprache verf�gbar, dann ein einfaches PRE-Element erzeugen. 170 $tag = 'pre'; 171 else { 172 // Wenn Sprache verf�gbar, dann den GESHI-Parser bem�hen. 173 $tag = ''; 174 $source = ''; 175 foreach ($child->children as $c) 176 if (strtolower(get_class($c)) == 'textelement') 177 $source .= $c->text . "\n"; 178 $child->children = array(); 179 require_once(__DIR__ . '/../../../geshi/geshi.php'); 180 $geshi = new Geshi($source, $child->language); 181 $val = $geshi->parse_code(); 182 } 183 break; 184 185 case 'quoteelement': 186 $tag = 'blockquote'; 187 break; 188 189 190 case 'paragraphelement': 191 $tag = 'p'; 192 break; 193 194 case 'speechelement': 195 if ($htmlConfig->has('tag_speech')) 196 $tag = $htmlConfig->get('tag_speech'); 197 else 198 $tag = 'cite'; 199 200 // Danke an: http://www.apostroph.de/tueddelchen.php 201 //TODO: Abh�ngigkeit von Spracheinstellung implementieren. 202 $language = 'de'; 203 switch ($language) { 204 case 'de': // deutsche Notation 205 $praefix = '&bdquo;'; 206 $suffix = '&ldquo;'; 207 break; 208 case 'fr': 209 $praefix = '&laquo;'; 210 $suffix = '&raquo;'; 211 break; 212 default: // englische Notation 213 $praefix = '&ldquo;'; 214 $suffix = '&rdquo;'; 215 } 216 217 if ($htmlConfig->is('override_speech')) { 218 $praefix = $htmlConfig->get('override_speech_open'); 219 $suffix = $htmlConfig->get('override_speech_close'); 220 } 221 break; 222 223 case 'macroelement': 224 225 $tag = ''; 226 227 $className = ucfirst($child->name); 228 229 $runner = new MacroRunner(); 230 try { 231 $val .= $runner->executeMacro($className, $child->attributes, $this->page,$this->pageContext); 232 } catch (Exception $e) { 233 throw new GeneratorException('Could not execute the macro '.$className,$e); 234 } 235 236 break; 237 238 case 'linebreakelement': 239 $tag = 'br'; 240 $empty = true; 241 break; 242 243 case 'linkelement': 244 $tag = 'a'; 245 if (!empty($child->name)) 246 $attr['name'] = $child->name; 247 else 248 $attr['href'] = htmlspecialchars($child->getUrl()); 249 250 if (BaseObject::available($child->objectId)) { 251 $file = new File($child->objectId); 252 $file->load(); 253 $attr['title'] = $file->getDefaultName()->description; 254 unset($file); 255 } 256 break; 257 258 case 'imageelement': 259 $empty = true; 260 $attr['alt'] = ''; 261 262 if (!BaseObject::available($child->objectId)) { 263 $tag = ''; 264 } elseif (empty($attr['title'])) { 265 $tag = 'img'; 266 $attr['src'] = $child->getUrl(); 267 $attr['border'] = '0'; 268 269 // Breite/H�he des Bildes bestimmen. 270 $image = new Image($child->objectId); 271 272 $image->load(); 273 $attr['alt' ] = $image->getDefaultName()->name; 274 $attr['title'] = $image->getDefaultName()->description; 275 276 $image->getImageSize(); 277 $attr['width'] = $image->width; 278 $attr['height'] = $image->height; 279 unset($image); 280 } else { 281 $tag = 'dl'; 282 283 if (empty($attr['class'])) 284 $attr['class'] = "image"; 285 286 $child->children = array(); 287 $dt = new DefinitionListItemElement(); 288 $dt->children[] = new TextElement('(image)'); 289 $dt->children[] = $child; 290 $child->children[] = $dt; 291 292 $dd = new DefinitionListEntryElement(); 293 $dd->children[] = new TextElement('(image)'); 294 $dd->children[] = new TextElement($attr['title']); 295 $child->children[] = $dd; 296 } 297 break; 298 299 case 'strongelement': 300 if ($htmlConfig->has('tag_strong')) 301 $tag = $htmlConfig->get('tag_strong'); 302 else 303 $tag = 'strong'; 304 break; 305 306 case 'emphaticelement': 307 if ($htmlConfig->has('tag_emphatic')) 308 $tag = $htmlConfig->get('tag_emphatic'); 309 else 310 $tag = 'em'; 311 break; 312 313 case 'insertedelement': 314 $tag = 'ins'; 315 break; 316 317 case 'removedelement': 318 $tag = 'del'; 319 break; 320 321 case 'headlineelement': 322 $tag = 'h' . $child->level; 323 324 $l = new LinkElement(); 325 $l->name = $child->getName(); 326 $child->children[] = $l; 327 328 break; 329 330 case 'tableelement': 331 $tag = 'table'; 332 break; 333 334 case 'tablelineelement': 335 $tag = 'tr'; 336 break; 337 338 case 'definitionlistelement': 339 $items = $child->children; 340 $newChildren = array(); 341 foreach ($items as $item) { 342 $def = new DefinitionItemElement(); 343 $def->key = $item->key; 344 $item->key = ''; 345 $newChildren[] = $def; 346 $newChildren[] = $item; 347 } 348 // Html::debug($newChildren,'Children-neu'); 349 $child->children = $newChildren; 350 $tag = 'dl'; 351 break; 352 353 case 'definitionitemelement': 354 if (!empty($child->key)) { 355 $tag = 'dt'; 356 $val = $child->key; 357 } else { 358 $tag = 'dd'; 359 } 360 break; 361 362 case 'tablecellelement': 363 if ($child->isHeading) 364 $tag = 'th'; else $tag = 'td'; 365 366 if ($child->rowSpan > 1) 367 $attr['rowspan'] = $child->rowSpan; 368 if ($child->colSpan > 1) 369 $attr['colspan'] = $child->colSpan; 370 break; 371 372 case 'listelement': 373 $tag = 'ul'; 374 break; 375 376 case 'teletypeelement': 377 if ($htmlConfig->has('tag_teletype')) 378 $tag = $htmlConfig->get('tag_teletype'); 379 else 380 $tag = 'code'; 381 break; 382 383 case 'numberedlistelement': 384 $tag = 'ol'; 385 break; 386 387 case 'listentryelement': 388 $tag = 'li'; 389 break; 390 391 default: 392 393 $tag = 'unknown-element'; 394 $attr['class'] = strtolower(get_class($child)); 395 break; 396 } 397 398 $val .= $praefix; 399 foreach ($child->children as $c) { 400 $val .= $this->renderElement($c); 401 } 402 403 $val .= $suffix; 404 return $this->renderHtmlElement($tag, $val, $empty, $attr); 405 406 } 407 408 409 /** 410 * Erzeugt ein HTML-Element. 411 * 412 * @param String $tag Name des Tags 413 * @param String $value Inhalt 414 * @param boolean $empty abk�rzen, wenn Inhalt leer ("<... />") 415 * @param array $attr Attribute als Array<String,String> 416 * @return String 417 */ 418 function renderHtmlElement($tag, $value, $empty, $attr = array()) 419 { 420 $htmlConfig = Configuration::subset(['editor','html']); 421 if ($tag == '') 422 return $value; 423 424 $val = '<' . $tag; 425 foreach ($attr as $attrName => $attrInhalt) { 426 $val .= ' ' . $attrName . '="' . $attrInhalt . '"'; 427 } 428 429 if ($value == '' && $empty) { 430 // Inhalt ist leer, also Kurzform verwenden. 431 // Die Kurzform ist abh�ngig vom Rendermode. 432 // SGML=<tag> 433 // XML=<tag /> 434 if ($htmlConfig->get('rendermode') == 'xml') { 435 $val .= ' />'; 436 return $val; 437 } else { 438 $val .= '>'; 439 return $val; 440 } 441 } 442 443 $val .= '>' . $value . '</' . $tag . '>'; 444 return $val; 445 } 446 447 448 /** 449 * Rendering des Dokumentes.<br> 450 * 451 * @return String 452 */ 453 function render() 454 { 455 $this->renderedText = ''; 456 $this->footnotes = array(); 457 458 foreach ($this->children as $child) 459 $this->renderedText .= $this->renderElement($child); 460 461 foreach ($this->footnotes as $child) 462 $this->renderedText .= $this->renderElement($child); 463 464 return $this->renderedText; 465 } 466 } 467 468 ?>
Download modules/wikiparser/renderer/HtmlRenderer.class.php
History Sun, 5 Dec 2021 20:33:24 +0100 dankert Cleanup: Removed unusable properties from class 'Value' and 'BaseObject'. Sun, 1 Nov 2020 03:08:55 +0100 Jan Dankert Replaced the calls to "Configuration::rawConfig()" with the OO style calls; Cleanup LoginAction. Sat, 26 Sep 2020 10:32:02 +0200 Jan Dankert Refactoring: No global $conf array any more. Mon, 21 Sep 2020 22:48:59 +0200 Jan Dankert Complexe refactoring: Moving all generation logic from the model (Value,Page,File) to generators classes. Sat, 29 Aug 2020 03:23:06 +0200 Jan Dankert Refactoring: Improved Exception-Handling; New: Generating pages using a page context which considers page aliases. Sun, 23 Feb 2020 04:49:34 +0100 Jan Dankert Refactoring with Namespaces for the cms modules, part 2. Sat, 22 Feb 2020 23:58:02 +0100 Jan Dankert Refactoring: Namespacing for module 'util'. Sat, 22 Feb 2020 22:45:05 +0100 Jan Dankert Refactoring: Enable Autoloading, Fix namespace structure. Sat, 16 Nov 2019 01:43:29 +0100 Jan Dankert New: MacroRunner for execution of macros. Fri, 15 Nov 2019 02:09:02 +0100 Jan Dankert Refactoring: No public attributes in Macro class; using YAML for macro parameters. Sun, 10 Nov 2019 22:07:48 +0100 Jan Dankert Refactoring: Macro classes should be able to do a simple 'echo'. Sun, 9 Dec 2018 23:32:58 +0100 Jan Dankert Fix: Geshi PHP7-fähig Tue, 22 May 2018 22:39:49 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'. Fri, 9 Feb 2018 00:48:31 +0100 Jan Dankert Die LanguageId und ModelId an alle Actions durchreichen. Diese sollen nicht mehr aus der Sitzung geladen werden, da nun in unterschiedlichen Tabs auch Objekte mit unterschiedlichen Model/Languages angezeigt werden können. Sat, 16 Dec 2017 23:58:50 +0100 Jan Dankert Fix: Makros in Texten wurden noch im alten Ordner gesucht. Sat, 16 Dec 2017 23:41:50 +0100 Jan Dankert Der Wikiparser als eigenes Modul (ehem. 'textclasses').