1<?php 2/** 3 * HTML output functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8use dokuwiki\Ui\MediaRevisions; 9use dokuwiki\Form\Form; 10use dokuwiki\Action\Denied; 11use dokuwiki\Action\Locked; 12use dokuwiki\ChangeLog\PageChangeLog; 13use dokuwiki\Extension\AuthPlugin; 14use dokuwiki\Extension\Event; 15use dokuwiki\Ui\Backlinks; 16use dokuwiki\Ui\Editor; 17use dokuwiki\Ui\Index; 18use dokuwiki\Ui\Login; 19use dokuwiki\Ui\PageConflict; 20use dokuwiki\Ui\PageDiff; 21use dokuwiki\Ui\PageDraft; 22use dokuwiki\Ui\PageRevisions; 23use dokuwiki\Ui\PageView; 24use dokuwiki\Ui\Recent; 25use dokuwiki\Ui\UserProfile; 26use dokuwiki\Ui\UserRegister; 27use dokuwiki\Ui\UserResendPwd; 28use dokuwiki\Utf8\Clean; 29 30if (!defined('SEC_EDIT_PATTERN')) { 31 define('SEC_EDIT_PATTERN', '#<!-- EDIT({.*?}) -->#'); 32} 33 34 35/** 36 * Convenience function to quickly build a wikilink 37 * 38 * @author Andreas Gohr <andi@splitbrain.org> 39 * @param string $id id of the target page 40 * @param string $name the name of the link, i.e. the text that is displayed 41 * @param string|array $search search string(s) that shall be highlighted in the target page 42 * @return string the HTML code of the link 43 */ 44function html_wikilink($id, $name = null, $search = '') 45{ 46 /** @var Doku_Renderer_xhtml $xhtml_renderer */ 47 static $xhtml_renderer = null; 48 if (is_null($xhtml_renderer)) { 49 $xhtml_renderer = p_get_renderer('xhtml'); 50 } 51 52 return $xhtml_renderer->internallink($id, $name, $search, true, 'navigation'); 53} 54 55/** 56 * The loginform 57 * 58 * @author Andreas Gohr <andi@splitbrain.org> 59 * 60 * @param bool $svg Whether to show svg icons in the register and resendpwd links or not 61 * @deprecated 2020-07-18 62 */ 63function html_login($svg = false) 64{ 65 dbg_deprecated(Login::class .'::show()'); 66 (new Login($svg))->show(); 67} 68 69 70/** 71 * Denied page content 72 * 73 * @deprecated 2020-07-18 not called anymore, see inc/Action/Denied::tplContent() 74 */ 75function html_denied() 76{ 77 dbg_deprecated(Denied::class .'::showBanner()'); 78 (new Denied())->showBanner(); 79} 80 81/** 82 * inserts section edit buttons if wanted or removes the markers 83 * 84 * @author Andreas Gohr <andi@splitbrain.org> 85 * 86 * @param string $text 87 * @param bool $show show section edit buttons? 88 * @return string 89 */ 90function html_secedit($text, $show = true) 91{ 92 global $INFO; 93 94 if ((isset($INFO) && !$INFO['writable']) || !$show || (isset($INFO) && $INFO['rev'])) { 95 return preg_replace(SEC_EDIT_PATTERN, '', $text); 96 } 97 98 return preg_replace_callback(SEC_EDIT_PATTERN, 99 'html_secedit_button', $text); 100} 101 102/** 103 * prepares section edit button data for event triggering 104 * used as a callback in html_secedit 105 * 106 * @author Andreas Gohr <andi@splitbrain.org> 107 * 108 * @param array $matches matches with regexp 109 * @return string 110 * @triggers HTML_SECEDIT_BUTTON 111 */ 112function html_secedit_button($matches) 113{ 114 $json = htmlspecialchars_decode($matches[1], ENT_QUOTES); 115 $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); 116 if ($data === null) { 117 return ''; 118 } 119 $data['target'] = strtolower($data['target']); 120 $data['hid'] = strtolower($data['hid'] ?? ''); 121 122 return Event::createAndTrigger( 123 'HTML_SECEDIT_BUTTON', 124 $data, 125 'html_secedit_get_button' 126 ); 127} 128 129/** 130 * prints a section editing button 131 * used as default action form HTML_SECEDIT_BUTTON 132 * 133 * @author Adrian Lang <lang@cosmocode.de> 134 * 135 * @param array $data name, section id and target 136 * @return string html 137 */ 138function html_secedit_get_button($data) 139{ 140 global $ID; 141 global $INFO; 142 143 if (!isset($data['name']) || $data['name'] === '') return ''; 144 145 $name = $data['name']; 146 unset($data['name']); 147 148 $secid = $data['secid']; 149 unset($data['secid']); 150 151 $params = array_merge( 152 ['do' => 'edit', 'rev' => $INFO['lastmod'], 'summary' => '['.$name.'] '], 153 $data 154 ); 155 156 $html = '<div class="secedit editbutton_'.$data['target'] .' editbutton_'.$secid .'">'; 157 $html.= html_btn('secedit', $ID, '', $params, 'post', $name); 158 $html.= '</div>'; 159 return $html; 160} 161 162/** 163 * Just the back to top button (in its own form) 164 * 165 * @author Andreas Gohr <andi@splitbrain.org> 166 * 167 * @return string html 168 */ 169function html_topbtn() 170{ 171 global $lang; 172 173 return '<a class="nolink" href="#dokuwiki__top">' 174 .'<button class="button" onclick="window.scrollTo(0, 0)" title="'. $lang['btn_top'] .'">' 175 . $lang['btn_top'] 176 .'</button></a>'; 177} 178 179/** 180 * Displays a button (using its own form) 181 * If tooltip exists, the access key tooltip is replaced. 182 * 183 * @author Andreas Gohr <andi@splitbrain.org> 184 * 185 * @param string $name 186 * @param string $id 187 * @param string $akey access key 188 * @param string[] $params key-value pairs added as hidden inputs 189 * @param string $method 190 * @param string $tooltip 191 * @param bool|string $label label text, false: lookup btn_$name in localization 192 * @param string $svg (optional) svg code, inserted into the button 193 * @return string 194 */ 195function html_btn($name, $id, $akey, $params, $method = 'get', $tooltip = '', $label = false, $svg = null) 196{ 197 global $conf; 198 global $lang; 199 200 if (!$label) 201 $label = $lang['btn_'.$name]; 202 203 //filter id (without urlencoding) 204 $id = idfilter($id, false); 205 206 //make nice URLs even for buttons 207 if ($conf['userewrite'] == 2) { 208 $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id; 209 } elseif ($conf['userewrite']) { 210 $script = DOKU_BASE.$id; 211 } else { 212 $script = DOKU_BASE.DOKU_SCRIPT; 213 $params['id'] = $id; 214 } 215 216 $html = '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">'; 217 218 if (is_array($params)) { 219 foreach ($params as $key => $val) { 220 $html .= '<input type="hidden" name="'.$key.'" value="'.hsc($val).'" />'; 221 } 222 } 223 224 $tip = empty($tooltip) ? hsc($label) : hsc($tooltip); 225 226 $html .= '<button type="submit" '; 227 if ($akey) { 228 $tip .= ' ['.strtoupper($akey).']'; 229 $html .= 'accesskey="'.$akey.'" '; 230 } 231 $html .= 'title="'.$tip.'">'; 232 if ($svg) { 233 $html .= '<span>'. hsc($label) .'</span>'. inlineSVG($svg); 234 } else { 235 $html .= hsc($label); 236 } 237 $html .= '</button>'; 238 $html .= '</div></form>'; 239 240 return $html; 241} 242/** 243 * show a revision warning 244 * 245 * @author Szymon Olewniczak <dokuwiki@imz.re> 246 * @deprecated 2020-07-18 247 */ 248function html_showrev() 249{ 250 dbg_deprecated(PageView::class .'::showrev()'); 251} 252 253/** 254 * Show a wiki page 255 * 256 * @author Andreas Gohr <andi@splitbrain.org> 257 * 258 * @param null|string $txt wiki text or null for showing $ID 259 * @deprecated 2020-07-18 260 */ 261function html_show($txt = null) 262{ 263 dbg_deprecated(PageView::class .'::show()'); 264 (new PageView($txt))->show(); 265} 266 267/** 268 * ask the user about how to handle an exisiting draft 269 * 270 * @author Andreas Gohr <andi@splitbrain.org> 271 * @deprecated 2020-07-18 272 */ 273function html_draft() 274{ 275 dbg_deprecated(PageDraft::class .'::show()'); 276 (new PageDraft)->show(); 277} 278 279/** 280 * Highlights searchqueries in HTML code 281 * 282 * @author Andreas Gohr <andi@splitbrain.org> 283 * @author Harry Fuecks <hfuecks@gmail.com> 284 * 285 * @param string $html 286 * @param array|string $phrases 287 * @return string html 288 */ 289function html_hilight($html, $phrases) 290{ 291 $phrases = (array) $phrases; 292 $phrases = array_map('preg_quote_cb', $phrases); 293 $phrases = array_map('ft_snippet_re_preprocess', $phrases); 294 $phrases = array_filter($phrases); 295 296 $regex = implode('|', $phrases); 297 298 if ($regex === '') return $html; 299 if (!Clean::isUtf8($regex)) return $html; 300 301 return @preg_replace_callback("/((<[^>]*)|$regex)/ui", function ($match) { 302 $hlight = unslash($match[0]); 303 if (!isset($match[2])) { 304 $hlight = '<span class="search_hit">'.$hlight.'</span>'; 305 } 306 return $hlight; 307 }, $html); 308} 309 310/** 311 * Display error on locked pages 312 * 313 * @author Andreas Gohr <andi@splitbrain.org> 314 * @deprecated 2020-07-18 not called anymore, see inc/Action/Locked::tplContent() 315 */ 316function html_locked() 317{ 318 dbg_deprecated(Locked::class .'::showBanner()'); 319 (new Locked())->showBanner(); 320} 321 322/** 323 * list old revisions 324 * 325 * @author Andreas Gohr <andi@splitbrain.org> 326 * @author Ben Coburn <btcoburn@silicodon.net> 327 * @author Kate Arzamastseva <pshns@ukr.net> 328 * 329 * @param int $first skip the first n changelog lines 330 * @param string $media_id id of media, or empty for current page 331 * @deprecated 2020-07-18 332 */ 333function html_revisions($first = -1, $media_id = '') 334{ 335 dbg_deprecated(PageRevisions::class .'::show()'); 336 if ($media_id) { 337 (new MediaRevisions($media_id))->show($first); 338 } else { 339 global $INFO; 340 (new PageRevisions($INFO['id']))->show($first); 341 } 342} 343 344/** 345 * display recent changes 346 * 347 * @author Andreas Gohr <andi@splitbrain.org> 348 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 349 * @author Ben Coburn <btcoburn@silicodon.net> 350 * @author Kate Arzamastseva <pshns@ukr.net> 351 * 352 * @param int $first 353 * @param string $show_changes 354 * @deprecated 2020-07-18 355 */ 356function html_recent($first = 0, $show_changes = 'both') 357{ 358 dbg_deprecated(Recent::class .'::show()'); 359 (new Recent($first, $show_changes))->show(); 360} 361 362/** 363 * Display page index 364 * 365 * @author Andreas Gohr <andi@splitbrain.org> 366 * 367 * @param string $ns 368 * @deprecated 2020-07-18 369 */ 370function html_index($ns) 371{ 372 dbg_deprecated(Index::class .'::show()'); 373 (new Index($ns))->show(); 374} 375 376/** 377 * Index tree item formatter for html_buildlist() 378 * 379 * User function for html_buildlist() 380 * 381 * @author Andreas Gohr <andi@splitbrain.org> 382 * 383 * @param array $item 384 * @return string 385 * @deprecated 2020-07-18 386 */ 387function html_list_index($item) 388{ 389 dbg_deprecated(Index::class .'::formatListItem()'); 390 return (new Index)->formatListItem($item); 391} 392 393/** 394 * Index list item formatter for html_buildlist() 395 * 396 * This user function is used in html_buildlist to build the 397 * <li> tags for namespaces when displaying the page index 398 * it gives different classes to opened or closed "folders" 399 * 400 * @author Andreas Gohr <andi@splitbrain.org> 401 * 402 * @param array $item 403 * @return string html 404 * @deprecated 2020-07-18 405 */ 406function html_li_index($item) 407{ 408 dbg_deprecated(Index::class .'::tagListItem()'); 409 return (new Index)->tagListItem($item); 410} 411 412/** 413 * Default list item formatter for html_buildlist() 414 * 415 * @author Andreas Gohr <andi@splitbrain.org> 416 * 417 * @param array $item 418 * @return string html 419 * @deprecated 2020-07-18 420 */ 421function html_li_default($item) 422{ 423 return '<li class="level'.$item['level'].'">'; 424} 425 426/** 427 * Build an unordered list 428 * 429 * Build an unordered list from the given $data array 430 * Each item in the array has to have a 'level' property 431 * the item itself gets printed by the given $func user 432 * function. The second and optional function is used to 433 * print the <li> tag. Both user function need to accept 434 * a single item. 435 * 436 * Both user functions can be given as array to point to 437 * a member of an object. 438 * 439 * @author Andreas Gohr <andi@splitbrain.org> 440 * 441 * @param array $data array with item arrays 442 * @param string $class class of ul wrapper 443 * @param callable $func callback to print an list item 444 * @param callable $lifunc (optional) callback to the opening li tag 445 * @param bool $forcewrapper (optional) Trigger building a wrapper ul if the first level is 446 * 0 (we have a root object) or 1 (just the root content) 447 * @return string html of an unordered list 448 */ 449function html_buildlist($data, $class, $func, $lifunc = null, $forcewrapper = false) 450{ 451 if ($data === []) { 452 return ''; 453 } 454 455 $firstElement = reset($data); 456 $start_level = $firstElement['level']; 457 $level = $start_level; 458 $html = ''; 459 $open = 0; 460 461 // set callback function to build the <li> tag, formerly defined as html_li_default() 462 if (!is_callable($lifunc)) { 463 $lifunc = static fn($item) => '<li class="level'.$item['level'].'">'; 464 } 465 466 foreach ($data as $item) { 467 if ($item['level'] > $level) { 468 //open new list 469 for ($i = 0; $i < ($item['level'] - $level); $i++) { 470 if ($i) $html .= '<li class="clear">'; 471 $html .= "\n".'<ul class="'.$class.'">'."\n"; 472 $open++; 473 } 474 $level = $item['level']; 475 476 } elseif ($item['level'] < $level) { 477 //close last item 478 $html .= '</li>'."\n"; 479 while ($level > $item['level'] && $open > 0 ) { 480 //close higher lists 481 $html .= '</ul>'."\n".'</li>'."\n"; 482 $level--; 483 $open--; 484 } 485 } elseif ($html !== '') { 486 //close previous item 487 $html .= '</li>'."\n"; 488 } 489 490 //print item 491 $html .= call_user_func($lifunc, $item); 492 $html .= '<div class="li">'; 493 494 $html .= call_user_func($func, $item); 495 $html .= '</div>'; 496 } 497 498 //close remaining items and lists 499 $html .= '</li>'."\n"; 500 while ($open-- > 0) { 501 $html .= '</ul></li>'."\n"; 502 } 503 504 if ($forcewrapper || $start_level < 2) { 505 // Trigger building a wrapper ul if the first level is 506 // 0 (we have a root object) or 1 (just the root content) 507 $html = "\n".'<ul class="'.$class.'">'."\n".$html.'</ul>'."\n"; 508 } 509 510 return $html; 511} 512 513/** 514 * display backlinks 515 * 516 * @author Andreas Gohr <andi@splitbrain.org> 517 * @author Michael Klier <chi@chimeric.de> 518 * @deprecated 2020-07-18 519 */ 520function html_backlinks() 521{ 522 dbg_deprecated(Backlinks::class .'::show()'); 523 (new Backlinks)->show(); 524} 525 526/** 527 * Get header of diff HTML 528 * 529 * @param string $l_rev Left revisions 530 * @param string $r_rev Right revision 531 * @param string $id Page id, if null $ID is used 532 * @param bool $media If it is for media files 533 * @param bool $inline Return the header on a single line 534 * @return string[] HTML snippets for diff header 535 * @deprecated 2020-07-18 536 */ 537function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) 538{ 539 dbg_deprecated('see '. PageDiff::class .'::buildDiffHead()'); 540 return ['', '', '', '']; 541} 542 543/** 544 * Show diff 545 * between current page version and provided $text 546 * or between the revisions provided via GET or POST 547 * 548 * @author Andreas Gohr <andi@splitbrain.org> 549 * @param string $text when non-empty: compare with this text with most current version 550 * @param bool $intro display the intro text 551 * @param string $type type of the diff (inline or sidebyside) 552 * @deprecated 2020-07-18 553 */ 554function html_diff($text = '', $intro = true, $type = null) 555{ 556 dbg_deprecated(PageDiff::class .'::show()'); 557 global $INFO; 558 (new PageDiff($INFO['id']))->compareWith($text)->preference([ 559 'showIntro' => $intro, 560 'difftype' => $type, 561 ])->show(); 562} 563 564/** 565 * Create html for revision navigation 566 * 567 * @param PageChangeLog $pagelog changelog object of current page 568 * @param string $type inline vs sidebyside 569 * @param int $l_rev left revision timestamp 570 * @param int $r_rev right revision timestamp 571 * @return string[] html of left and right navigation elements 572 * @deprecated 2020-07-18 573 */ 574function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) 575{ 576 dbg_deprecated('see '. PageDiff::class .'::buildRevisionsNavigation()'); 577 return ['', '']; 578} 579 580/** 581 * Create html link to a diff defined by two revisions 582 * 583 * @param string $difftype display type 584 * @param string $linktype 585 * @param int $lrev oldest revision 586 * @param int $rrev newest revision or null for diff with current revision 587 * @return string html of link to a diff 588 * @deprecated 2020-07-18 589 */ 590function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) 591{ 592 dbg_deprecated('see '. PageDiff::class .'::diffViewlink()'); 593 return ''; 594} 595 596/** 597 * Insert soft breaks in diff html 598 * 599 * @param string $diffhtml 600 * @return string 601 * @deprecated 2020-07-18 602 */ 603function html_insert_softbreaks($diffhtml) 604{ 605 dbg_deprecated(PageDiff::class .'::insertSoftbreaks()'); 606 return (new PageDiff)->insertSoftbreaks($diffhtml); 607} 608 609/** 610 * show warning on conflict detection 611 * 612 * @author Andreas Gohr <andi@splitbrain.org> 613 * 614 * @param string $text 615 * @param string $summary 616 * @deprecated 2020-07-18 617 */ 618function html_conflict($text, $summary) 619{ 620 dbg_deprecated(PageConflict::class .'::show()'); 621 (new PageConflict($text, $summary))->show(); 622} 623 624/** 625 * Prints the global message array 626 * 627 * @author Andreas Gohr <andi@splitbrain.org> 628 */ 629function html_msgarea() 630{ 631 global $MSG, $MSG_shown; 632 /** @var array $MSG */ 633 // store if the global $MSG has already been shown and thus HTML output has been started 634 $MSG_shown = true; 635 636 if (!isset($MSG)) return; 637 638 $shown = []; 639 foreach ($MSG as $msg) { 640 $hash = md5($msg['msg']); 641 if (isset($shown[$hash])) continue; // skip double messages 642 if (info_msg_allowed($msg)) { 643 print '<div class="'.$msg['lvl'].'">'; 644 print $msg['msg']; 645 print '</div>'; 646 } 647 $shown[$hash] = 1; 648 } 649 650 unset($GLOBALS['MSG']); 651} 652 653/** 654 * Prints the registration form 655 * 656 * @author Andreas Gohr <andi@splitbrain.org> 657 * @deprecated 2020-07-18 658 */ 659function html_register() 660{ 661 dbg_deprecated(UserRegister::class .'::show()'); 662 (new UserRegister)->show(); 663} 664 665/** 666 * Print the update profile form 667 * 668 * @author Christopher Smith <chris@jalakai.co.uk> 669 * @author Andreas Gohr <andi@splitbrain.org> 670 * @deprecated 2020-07-18 671 */ 672function html_updateprofile() 673{ 674 dbg_deprecated(UserProfile::class .'::show()'); 675 (new UserProfile)->show(); 676} 677 678/** 679 * Preprocess edit form data 680 * 681 * @author Andreas Gohr <andi@splitbrain.org> 682 * 683 * @deprecated 2020-07-18 684 */ 685function html_edit() 686{ 687 dbg_deprecated(Editor::class .'::show()'); 688 (new Editor)->show(); 689} 690 691/** 692 * Display the default edit form 693 * 694 * Is the default action for HTML_EDIT_FORMSELECTION. 695 * 696 * @param array $param 697 * @deprecated 2020-07-18 698 */ 699function html_edit_form($param) 700{ 701 dbg_deprecated(Editor::class .'::addTextarea()'); 702 (new Editor)->addTextarea($param); 703} 704 705/** 706 * prints some debug info 707 * 708 * @author Andreas Gohr <andi@splitbrain.org> 709 */ 710function html_debug() 711{ 712 global $conf; 713 global $lang; 714 /** @var AuthPlugin $auth */ 715 global $auth; 716 global $INFO; 717 718 //remove sensitive data 719 $cnf = $conf; 720 debug_guard($cnf); 721 $nfo = $INFO; 722 debug_guard($nfo); 723 $ses = $_SESSION; 724 debug_guard($ses); 725 726 print '<html><body>'; 727 728 print '<p>When reporting bugs please send all the following '; 729 print 'output as a mail to andi@splitbrain.org '; 730 print 'The best way to do this is to save this page in your browser</p>'; 731 732 print '<b>$INFO:</b><pre>'; 733 print_r($nfo); 734 print '</pre>'; 735 736 print '<b>$_SERVER:</b><pre>'; 737 print_r($_SERVER); 738 print '</pre>'; 739 740 print '<b>$conf:</b><pre>'; 741 print_r($cnf); 742 print '</pre>'; 743 744 print '<b>DOKU_BASE:</b><pre>'; 745 print DOKU_BASE; 746 print '</pre>'; 747 748 print '<b>abs DOKU_BASE:</b><pre>'; 749 print DOKU_URL; 750 print '</pre>'; 751 752 print '<b>rel DOKU_BASE:</b><pre>'; 753 print dirname($_SERVER['PHP_SELF']).'/'; 754 print '</pre>'; 755 756 print '<b>PHP Version:</b><pre>'; 757 print phpversion(); 758 print '</pre>'; 759 760 print '<b>locale:</b><pre>'; 761 print setlocale(LC_ALL, 0); 762 print '</pre>'; 763 764 print '<b>encoding:</b><pre>'; 765 print $lang['encoding']; 766 print '</pre>'; 767 768 if ($auth) { 769 print '<b>Auth backend capabilities:</b><pre>'; 770 foreach ($auth->getCapabilities() as $cando) { 771 print ' '.str_pad($cando, 16) .' => '. (int)$auth->canDo($cando) . DOKU_LF; 772 } 773 print '</pre>'; 774 } 775 776 print '<b>$_SESSION:</b><pre>'; 777 print_r($ses); 778 print '</pre>'; 779 780 print '<b>Environment:</b><pre>'; 781 print_r($_ENV); 782 print '</pre>'; 783 784 print '<b>PHP settings:</b><pre>'; 785 $inis = ini_get_all(); 786 print_r($inis); 787 print '</pre>'; 788 789 if (function_exists('apache_get_version')) { 790 $apache = []; 791 $apache['version'] = apache_get_version(); 792 793 if (function_exists('apache_get_modules')) { 794 $apache['modules'] = apache_get_modules(); 795 } 796 print '<b>Apache</b><pre>'; 797 print_r($apache); 798 print '</pre>'; 799 } 800 801 print '</body></html>'; 802} 803 804/** 805 * Form to request a new password for an existing account 806 * 807 * @author Benoit Chesneau <benoit@bchesneau.info> 808 * @author Andreas Gohr <gohr@cosmocode.de> 809 * @deprecated 2020-07-18 810 */ 811function html_resendpwd() 812{ 813 dbg_deprecated(UserResendPwd::class .'::show()'); 814 (new UserResendPwd)->show(); 815} 816 817/** 818 * Return the TOC rendered to XHTML 819 * 820 * @author Andreas Gohr <andi@splitbrain.org> 821 * 822 * @param array $toc 823 * @return string html 824 */ 825function html_TOC($toc) 826{ 827 if ($toc === []) return ''; 828 global $lang; 829 $out = '<!-- TOC START -->'.DOKU_LF; 830 $out .= '<div id="dw__toc" class="dw__toc">'.DOKU_LF; 831 $out .= '<h3 class="toggle">'; 832 $out .= $lang['toc']; 833 $out .= '</h3>'.DOKU_LF; 834 $out .= '<div>'.DOKU_LF; 835 $out .= html_buildlist($toc, 'toc', 'html_list_toc', null, true); 836 $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF; 837 $out .= '<!-- TOC END -->'.DOKU_LF; 838 return $out; 839} 840 841/** 842 * Callback for html_buildlist 843 * 844 * @param array $item 845 * @return string html 846 */ 847function html_list_toc($item) 848{ 849 if (isset($item['hid'])){ 850 $link = '#'.$item['hid']; 851 } else { 852 $link = $item['link']; 853 } 854 855 return '<a href="'.$link.'">'.hsc($item['title']).'</a>'; 856} 857 858/** 859 * Helper function to build TOC items 860 * 861 * Returns an array ready to be added to a TOC array 862 * 863 * @param string $link - where to link (if $hash set to '#' it's a local anchor) 864 * @param string $text - what to display in the TOC 865 * @param int $level - nesting level 866 * @param string $hash - is prepended to the given $link, set blank if you want full links 867 * @return array the toc item 868 */ 869function html_mktocitem($link, $text, $level, $hash = '#') 870{ 871 return [ 872 'link' => $hash.$link, 873 'title' => $text, 874 'type' => 'ul', 875 'level' => $level 876 ]; 877} 878 879/** 880 * Output a Doku_Form object. 881 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT 882 * 883 * @author Tom N Harris <tnharris@whoopdedo.org> 884 * 885 * @param string $name The name of the form 886 * @param Doku_Form $form The form 887 * @return void 888 * @deprecated 2020-07-18 889 */ 890function html_form($name, $form) 891{ 892 dbg_deprecated('use dokuwiki\Form\Form instead of Doku_Form'); 893 // Safety check in case the caller forgets. 894 $form->endFieldset(); 895 Event::createAndTrigger('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false); 896} 897 898/** 899 * Form print function. 900 * Just calls printForm() on the form object. 901 * 902 * @param Doku_Form $form The form 903 * @return void 904 * @deprecated 2020-07-18 905 */ 906function html_form_output($form) 907{ 908 dbg_deprecated('use ' . Form::class . '::toHTML()'); 909 $form->printForm(); 910} 911 912/** 913 * Embed a flash object in HTML 914 * 915 * This will create the needed HTML to embed a flash movie in a cross browser 916 * compatble way using valid XHTML 917 * 918 * The parameters $params, $flashvars and $atts need to be associative arrays. 919 * No escaping needs to be done for them. The alternative content *has* to be 920 * escaped because it is used as is. If no alternative content is given 921 * $lang['noflash'] is used. 922 * 923 * @author Andreas Gohr <andi@splitbrain.org> 924 * @link http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml 925 * 926 * @param string $swf - the SWF movie to embed 927 * @param int $width - width of the flash movie in pixels 928 * @param int $height - height of the flash movie in pixels 929 * @param array $params - additional parameters (<param>) 930 * @param array $flashvars - parameters to be passed in the flashvar parameter 931 * @param array $atts - additional attributes for the <object> tag 932 * @param string $alt - alternative content (is NOT automatically escaped!) 933 * @return string - the XHTML markup 934 */ 935function html_flashobject($swf, $width, $height, $params = null, $flashvars = null, $atts = null, $alt = '') 936{ 937 global $lang; 938 939 $out = ''; 940 941 // prepare the object attributes 942 if(is_null($atts)) $atts = []; 943 $atts['width'] = (int) $width; 944 $atts['height'] = (int) $height; 945 if(!$atts['width']) $atts['width'] = 425; 946 if(!$atts['height']) $atts['height'] = 350; 947 948 // add object attributes for standard compliant browsers 949 $std = $atts; 950 $std['type'] = 'application/x-shockwave-flash'; 951 $std['data'] = $swf; 952 953 // add object attributes for IE 954 $ie = $atts; 955 $ie['classid'] = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; 956 957 // open object (with conditional comments) 958 $out .= '<!--[if !IE]> -->'.NL; 959 $out .= '<object '.buildAttributes($std).'>'.NL; 960 $out .= '<!-- <![endif]-->'.NL; 961 $out .= '<!--[if IE]>'.NL; 962 $out .= '<object '.buildAttributes($ie).'>'.NL; 963 $out .= ' <param name="movie" value="'.hsc($swf).'" />'.NL; 964 $out .= '<!--><!-- -->'.NL; 965 966 // print params 967 if(is_array($params)) foreach($params as $key => $val){ 968 $out .= ' <param name="'.hsc($key).'" value="'.hsc($val).'" />'.NL; 969 } 970 971 // add flashvars 972 if(is_array($flashvars)){ 973 $out .= ' <param name="FlashVars" value="'.buildURLparams($flashvars).'" />'.NL; 974 } 975 976 // alternative content 977 if($alt){ 978 $out .= $alt.NL; 979 }else{ 980 $out .= $lang['noflash'].NL; 981 } 982 983 // finish 984 $out .= '</object>'.NL; 985 $out .= '<!-- <![endif]-->'.NL; 986 987 return $out; 988} 989 990/** 991 * Prints HTML code for the given tab structure 992 * 993 * @param array $tabs tab structure 994 * @param string $current_tab the current tab id 995 * @return void 996 */ 997function html_tabs($tabs, $current_tab = null) 998{ 999 echo '<ul class="tabs">'.NL; 1000 1001 foreach ($tabs as $id => $tab) { 1002 html_tab($tab['href'], $tab['caption'], $id === $current_tab); 1003 } 1004 1005 echo '</ul>'.NL; 1006} 1007 1008/** 1009 * Prints a single tab 1010 * 1011 * @author Kate Arzamastseva <pshns@ukr.net> 1012 * @author Adrian Lang <mail@adrianlang.de> 1013 * 1014 * @param string $href - tab href 1015 * @param string $caption - tab caption 1016 * @param boolean $selected - is tab selected 1017 * @return void 1018 */ 1019 1020function html_tab($href, $caption, $selected = false) 1021{ 1022 $tab = '<li>'; 1023 if ($selected) { 1024 $tab .= '<strong>'; 1025 } else { 1026 $tab .= '<a href="' . hsc($href) . '">'; 1027 } 1028 $tab .= hsc($caption) 1029 . '</' . ($selected ? 'strong' : 'a') . '>' 1030 . '</li>'.NL; 1031 echo $tab; 1032} 1033 1034/** 1035 * Display size change 1036 * 1037 * @param int $sizechange - size of change in Bytes 1038 * @param Doku_Form $form - (optional) form to add elements to 1039 * @return void|string 1040 */ 1041function html_sizechange($sizechange, $form = null) 1042{ 1043 if (isset($sizechange)) { 1044 $class = 'sizechange'; 1045 $value = filesize_h(abs($sizechange)); 1046 if ($sizechange > 0) { 1047 $class .= ' positive'; 1048 $value = '+' . $value; 1049 } elseif ($sizechange < 0) { 1050 $class .= ' negative'; 1051 $value = '-' . $value; 1052 } else { 1053 $value = '±' . $value; 1054 } 1055 if (!isset($form)) { 1056 return '<span class="'.$class.'">'.$value.'</span>'; 1057 } else { // Doku_Form 1058 $form->addElement(form_makeOpenTag('span', ['class' => $class])); 1059 $form->addElement($value); 1060 $form->addElement(form_makeCloseTag('span')); 1061 } 1062 } 1063} 1064