3 * DokuWiki template functions
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
9 if(!defined('DOKU_INC')) die('meh.');
12 * Returns the path to the given template, uses
13 * default one if the custom version doesn't exist.
15 * @author Andreas Gohr <andi@splitbrain.org>
17 function template($tpl){
20 if(@is_readable
(DOKU_INC
.'lib/tpl/'.$conf['template'].'/'.$tpl))
21 return DOKU_INC
.'lib/tpl/'.$conf['template'].'/'.$tpl;
23 return DOKU_INC
.'lib/tpl/default/'.$tpl;
29 * This function is used for printing all the usual content
30 * (defined by the global $ACT var) by calling the appropriate
31 * outputfunction(s) from html.php
33 * Everything that doesn't use the main template file isn't
34 * handled by this function. ACL stuff is not done here either.
36 * @author Andreas Gohr <andi@splitbrain.org>
38 function tpl_content($prependTOC=true) {
41 $INFO['prependTOC'] = $prependTOC;
44 trigger_event('TPL_ACT_RENDER',$ACT,'tpl_content_core');
45 $html_output = ob_get_clean();
46 trigger_event('TPL_CONTENT_DISPLAY',$html_output,'ptln');
48 return !empty($html_output);
51 function tpl_content_core(){
77 html_edit($TEXT,'wordblock');
83 $first = isset($_REQUEST['first']) ?
intval($_REQUEST['first']) : 0;
84 html_revisions($first);
90 if (is_array($_REQUEST['first'])) {
91 $_REQUEST['first'] = array_keys($_REQUEST['first']);
92 $_REQUEST['first'] = $_REQUEST['first'][0];
94 $first = is_numeric($_REQUEST['first']) ?
intval($_REQUEST['first']) : 0;
98 html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly?
104 html_conflict(con($PRE,$TEXT,$SUF),$SUM);
105 html_diff(con($PRE,$TEXT,$SUF),false);
121 print p_locale_xhtml('denied');
124 html_updateprofile();
133 $evt = new Doku_Event('TPL_ACT_UNKNOWN',$ACT);
134 if ($evt->advise_before())
135 msg("Failed to handle command: ".hsc($ACT),-1);
136 $evt->advise_after();
144 * Places the TOC where the function is called
146 * If you use this you most probably want to call tpl_content with
149 * @author Andreas Gohr <andi@splitbrain.org>
151 function tpl_toc($return=false){
161 // if a TOC was prepared in global scope, always use it
163 }elseif(($ACT == 'show' ||
substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){
164 // get TOC from metadata, render if neccessary
165 $meta = p_get_metadata($ID, false, true);
166 if(isset($meta['internal']['toc'])){
167 $tocok = $meta['internal']['toc'];
171 $toc = $meta['description']['tableofcontents'];
172 if(!$tocok ||
!is_array($toc) ||
!$conf['tocminheads'] ||
count($toc) < $conf['tocminheads']){
175 }elseif($ACT == 'admin'){
176 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin
178 if (!empty($_REQUEST['page'])) {
179 $pluginlist = plugin_list('admin');
180 if (in_array($_REQUEST['page'], $pluginlist)) {
181 // attempt to load the plugin
182 $plugin =& plugin_load('admin',$_REQUEST['page']);
185 if ( ($plugin !== null) &&
186 (!$plugin->forAdminOnly() ||
$INFO['isadmin']) ){
187 $toc = $plugin->getTOC();
188 $TOC = $toc; // avoid later rebuild
192 trigger_event('TPL_TOC_RENDER', $toc, null, false);
193 $html = html_TOC($toc);
194 if($return) return $html;
199 * Handle the admin page contents
201 * @author Andreas Gohr <andi@splitbrain.org>
203 function tpl_admin(){
208 if (!empty($_REQUEST['page'])) {
209 $pluginlist = plugin_list('admin');
211 if (in_array($_REQUEST['page'], $pluginlist)) {
213 // attempt to load the plugin
214 $plugin =& plugin_load('admin',$_REQUEST['page']);
218 if ($plugin !== null){
219 if($plugin->forAdminOnly() && !$INFO['isadmin']){
220 msg('For admins only',-1);
223 if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
224 if($INFO['prependTOC']) tpl_toc();
234 * Print the correct HTML meta headers
236 * This has to go into the head section of your template.
238 * @triggers TPL_METAHEADER_OUTPUT
239 * @param boolean $alt Should feeds and alternative format links be added?
240 * @author Andreas Gohr <andi@splitbrain.org>
242 function tpl_metaheaders($alt=true){
253 // prepare the head array
256 // prepare seed for js and css
258 $depends = getConfigFiles('main');
259 foreach($depends as $f) {
260 $time = @filemtime
($f);
261 if($time > $tseed) $tseed = $time;
265 $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki '.getVersion() );
266 $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml',
267 'href'=>DOKU_BASE
.'lib/exe/opensearch.php', 'title'=>$conf['title'] );
268 $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE
);
269 if(actionOK('index')){
270 $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'),
271 'title'=>$lang['btn_index'] );
275 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
276 'title'=>'Recent Changes', 'href'=>DOKU_BASE
.'feed.php');
277 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
278 'title'=>'Current Namespace',
279 'href'=>DOKU_BASE
.'feed.php?mode=list&ns='.$INFO['namespace']);
280 if(($ACT == 'show' ||
$ACT == 'search') && $INFO['writable']){
281 $head['link'][] = array( 'rel'=>'edit',
282 'title'=>$lang['btn_edit'],
283 'href'=> wl($ID,'do=edit',false,'&'));
286 if($ACT == 'search'){
287 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
288 'title'=>'Search Result',
289 'href'=>DOKU_BASE
.'feed.php?mode=search&q='.$QUERY);
292 if(actionOK('export_xhtml')){
293 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML',
294 'href'=>exportlink($ID, 'xhtml', '', false, '&'));
297 if(actionOK('export_raw')){
298 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup',
299 'href'=>exportlink($ID, 'raw', '', false, '&'));
303 // setup robot tags apropriate for different modes
304 if( ($ACT=='show' ||
$ACT=='export_xhtml') && !$REV){
307 if((time() - $INFO['lastmod']) >= $conf['indexdelay']){
308 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
310 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
312 $head['link'][] = array( 'rel'=>'canonical', 'href'=>wl($ID,'',true,'&') );
314 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow');
316 }elseif(defined('DOKU_MEDIADETAIL')){
317 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
319 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
323 if($ACT == 'show' ||
$ACT=='export_xhtml'){
324 // date of modification
326 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV));
328 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod']));
331 // keywords (explicit or implicit)
332 if(!empty($INFO['meta']['subject'])){
333 $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject']));
335 $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID));
340 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'screen', 'type'=>'text/css',
341 'href'=>DOKU_BASE
.'lib/exe/css.php?t='.$conf['template'].'&tseed='.$tseed);
342 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'all', 'type'=>'text/css',
343 'href'=>DOKU_BASE
.'lib/exe/css.php?s=all&t='.$conf['template'].'&tseed='.$tseed);
344 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'print', 'type'=>'text/css',
345 'href'=>DOKU_BASE
.'lib/exe/css.php?s=print&t='.$conf['template'].'&tseed='.$tseed);
347 // make $INFO and other vars available to JavaScripts
348 require_once(DOKU_INC
.'inc/JSON.php');
350 $script = "var NS='".$INFO['namespace']."';";
351 if($conf['useacl'] && $_SERVER['REMOTE_USER']){
352 require_once(DOKU_INC
.'inc/toolbar.php');
353 $script .= "var SIG='".toolbar_signature()."';";
355 $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
356 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8',
359 // load external javascript
360 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'',
361 'src'=>DOKU_BASE
.'lib/exe/js.php'.'?tseed='.$tseed);
363 // trigger event here
364 trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true);
369 * prints the array build by tpl_metaheaders
371 * $data is an array of different header tags. Each tag can have multiple
372 * instances. Attributes are given as key value pairs. Values will be HTML
373 * encoded automatically so they should be provided as is in the $data array.
375 * For tags having a body attribute specify the the body data in the special
376 * attribute '_data'. This field will NOT BE ESCAPED automatically.
378 * @author Andreas Gohr <andi@splitbrain.org>
380 function _tpl_metaheaders_action($data){
381 foreach($data as $tag => $inst){
382 foreach($inst as $attr){
383 echo '<',$tag,' ',buildAttributes($attr);
384 if(isset($attr['_data']) ||
$tag == 'script'){
385 if($tag == 'script' && $attr['_data'])
386 $attr['_data'] = "<!--//--><![CDATA[//><!--\n".
390 echo '>',$attr['_data'],'</',$tag,'>';
402 * Just builds a link.
404 * @author Andreas Gohr <andi@splitbrain.org>
406 function tpl_link($url,$name,$more='',$return=false){
407 $out = '<a href="'.$url.'" ';
408 if ($more) $out .= ' '.$more;
409 $out .= ">$name</a>";
410 if ($return) return $out;
416 * Prints a link to a WikiPage
418 * Wrapper around html_wikilink
420 * @author Andreas Gohr <andi@splitbrain.org>
422 function tpl_pagelink($id,$name=null){
423 print html_wikilink($id,$name);
428 * get the parent page
430 * Tries to find out which page is parent.
431 * returns false if none is available
433 * @author Andreas Gohr <andi@splitbrain.org>
435 function tpl_getparent($id){
437 $parent = getNS($id).':';
438 resolve_pageid('',$parent,$exists);
440 $pos = strrpos (getNS($id),':');
441 $parent = substr($parent,0,$pos).':';
442 resolve_pageid('',$parent,$exists);
443 if($parent == $id) return false;
449 * Print one of the buttons
451 * Available Buttons are
453 * edit - edit/create/show/draft button
454 * history - old revisions
455 * recent - recent changes
456 * login - login/logout button - if ACL enabled
457 * profile - user profile button (if logged in)
459 * admin - admin page - if enough rights
460 * top - a back to top button
461 * back - a back to parent button - if available
462 * backlink - links to the list of backlinks
463 * subscription- subscribe/unsubscribe button
465 * @author Andreas Gohr <andi@splitbrain.org>
466 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
468 function tpl_button($type,$return=false){
477 // check disabled actions and fix the badly named ones
479 if($type == 'history') $ctype='revisions';
480 if(!actionOK($ctype)) return false;
485 // most complicated type - we need to decide on current action
486 if($ACT == 'show' ||
$ACT == 'search'){
487 if($INFO['writable']){
488 if(!empty($INFO['draft'])){
489 $out .= html_btn('draft',$ID,'e',array('do' => 'draft'),'post');
492 $out .= html_btn('edit',$ID,'e',array('do' => 'edit','rev' => $REV),'post');
494 $out .= html_btn('create',$ID,'e',array('do' => 'edit','rev' => $REV),'post');
498 if(!actionOK('source')) return false; //pseudo action
499 $out .= html_btn('source',$ID,'v',array('do' => 'edit','rev' => $REV),'post');
502 $out .= html_btn('show',$ID,'v',array('do' => 'show'));
506 if(actionOK('revisions'))
507 $out .= html_btn('revs',$ID,'o',array('do' => 'revisions'));
510 if(actionOK('recent'))
511 $out .= html_btn('recent',$ID,'r',array('do' => 'recent'));
514 if(actionOK('index'))
515 $out .= html_btn('index',$ID,'x',array('do' => 'index'));
518 if ($parent = tpl_getparent($ID)) {
519 $out .= html_btn('back',$parent,'b',array('do' => 'show'));
523 $out .= html_topbtn();
526 if($conf['useacl'] && $auth){
527 if(isset($_SERVER['REMOTE_USER'])){
528 $out .= html_btn('logout',$ID,'',array('do' => 'logout', 'sectok' => getSecurityToken()));
530 $out .= html_btn('login',$ID,'',array('do' => 'login', 'sectok' => getSecurityToken()));
535 if($INFO['ismanager']){
536 $out .= html_btn('admin',$ID,'',array('do' => 'admin'));
540 if($INFO['ismanager'] && $REV && $INFO['writable'] && actionOK('revert')){
541 $out .= html_btn('revert',$ID,'',array('do' => 'revert', 'rev' => $REV, 'sectok' => getSecurityToken()));
545 if ($conf['useacl'] && $auth && $ACT == 'show' &&
546 $conf['subscribers'] && isset($_SERVER['REMOTE_USER']) &&
547 actionOK('subscribe')) {
548 $out .= html_btn('subscribe',$ID,'',array('do' => 'subscribe',));
552 if(actionOK('backlink'))
553 $out .= html_btn('backlink',$ID,'',array('do' => 'backlink'));
556 if($conf['useacl'] && isset($_SERVER['REMOTE_USER']) && $auth &&
557 $auth->canDo('Profile') && ($ACT!='profile')){
558 $out .= html_btn('profile',$ID,'',array('do' => 'profile'));
562 $out .= '[unknown button type]';
565 if ($return) return $out;
567 return $out ?
true : false;
571 * Like the action buttons but links
573 * Available links are
575 * edit - edit/create/show link
576 * history - old revisions
577 * recent - recent changes
578 * login - login/logout link - if ACL enabled
579 * profile - user profile link (if logged in)
581 * admin - admin page - if enough rights
582 * top - a back to top link
583 * back - a back to parent link - if available
584 * backlink - links to the list of backlinks
585 * subscribe/subscription - subscribe/unsubscribe link
587 * @author Andreas Gohr <andi@splitbrain.org>
588 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
591 function tpl_actionlink($type,$pre='',$suf='',$inner='',$return=false){
600 // check disabled actions and fix the badly named ones
602 if($type == 'history') $ctype='revisions';
603 if(!actionOK($ctype)) return false;
608 // most complicated type - we need to decide on current action
609 if($ACT == 'show' ||
$ACT == 'search'){
610 if($INFO['writable']){
611 if(!empty($INFO['draft'])) {
612 $out .= tpl_link(wl($ID,'do=draft'),
613 $pre.(($inner)?
$inner:$lang['btn_draft']).$suf,
614 'class="action edit" accesskey="e" rel="nofollow"',1);
617 $out .= tpl_link(wl($ID,'do=edit&rev='.$REV),
618 $pre.(($inner)?
$inner:$lang['btn_edit']).$suf,
619 'class="action edit" accesskey="e" rel="nofollow"',1);
621 $out .= tpl_link(wl($ID,'do=edit&rev='.$REV),
622 $pre.(($inner)?
$inner:$lang['btn_create']).$suf,
623 'class="action create" accesskey="e" rel="nofollow"',1);
627 if(actionOK('source')) //pseudo action
628 $out .= tpl_link(wl($ID,'do=edit&rev='.$REV),
629 $pre.(($inner)?
$inner:$lang['btn_source']).$suf,
630 'class="action source" accesskey="v" rel="nofollow"',1);
633 $out .= tpl_link(wl($ID,'do=show'),
634 $pre.(($inner)?
$inner:$lang['btn_show']).$suf,
635 'class="action show" accesskey="v" rel="nofollow"',1);
639 if(actionOK('revisions'))
640 $out .= tpl_link(wl($ID,'do=revisions'),
641 $pre.(($inner)?
$inner:$lang['btn_revs']).$suf,
642 'class="action revisions" accesskey="o" rel="nofollow"',1);
645 if(actionOK('recent'))
646 $out .= tpl_link(wl($ID,'do=recent'),
647 $pre.(($inner)?
$inner:$lang['btn_recent']).$suf,
648 'class="action recent" accesskey="r" rel="nofollow"',1);
651 if(actionOK('index'))
652 $out .= tpl_link(wl($ID,'do=index'),
653 $pre.(($inner)?
$inner:$lang['btn_index']).$suf,
654 'class="action index" accesskey="x" rel="nofollow"',1);
657 $out .= '<a href="#dokuwiki__top" class="action top" accesskey="x">'.
658 $pre.(($inner)?
$inner:$lang['btn_top']).$suf.'</a>';
661 if ($parent = tpl_getparent($ID)) {
662 $out .= tpl_link(wl($parent,'do=show'),
663 $pre.(($inner)?
$inner:$lang['btn_back']).$suf,
664 'class="action back" accesskey="b" rel="nofollow"',1);
668 if($conf['useacl'] && $auth){
669 if($_SERVER['REMOTE_USER']){
670 $out .= tpl_link(wl($ID,'do=logout&sectok='.getSecurityToken()),
671 $pre.(($inner)?
$inner:$lang['btn_logout']).$suf,
672 'class="action logout" rel="nofollow"',1);
674 $out .= tpl_link(wl($ID,'do=login&sectok='.getSecurityToken()),
675 $pre.(($inner)?
$inner:$lang['btn_login']).$suf,
676 'class="action login" rel="nofollow"',1);
681 if($INFO['ismanager']){
682 $out .= tpl_link(wl($ID,'do=admin'),
683 $pre.(($inner)?
$inner:$lang['btn_admin']).$suf,
684 'class="action admin" rel="nofollow"',1);
688 if($INFO['ismanager'] && $REV && $INFO['writable'] && actionOK('revert')){
689 $out .= tpl_link(wl($ID,array('do' => 'revert', 'rev' => $REV, 'sectok' => getSecurityToken())),
690 $pre.(($inner)?
$inner:$lang['btn_revert']).$suf,
691 'class="action revert" rel="nofollow"',1);
696 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers']) {
697 if($_SERVER['REMOTE_USER']){
698 if(actionOK('subscribe'))
699 $out .= tpl_link(wl($ID,'do=subscribe'),
700 $pre.(($inner)?
$inner:$lang['btn_subscribe']).$suf,
701 'class="action subscribe" rel="nofollow"',1);
706 if(actionOK('backlink'))
707 $out .= tpl_link(wl($ID,'do=backlink'),
708 $pre.(($inner)?
$inner:$lang['btn_backlink']).$suf,
709 'class="action backlink" rel="nofollow"',1);
712 if($conf['useacl'] && $auth && $_SERVER['REMOTE_USER'] &&
713 $auth->canDo('Profile') && ($ACT!='profile')){
714 $out .= tpl_link(wl($ID,'do=profile'),
715 $pre.(($inner)?
$inner:$lang['btn_profile']).$suf,
716 'class="action profile" rel="nofollow"',1);
720 $out .= '[unknown link type]';
723 if ($return) return $out;
725 return $out ?
true : false;
729 * Wrapper around tpl_button() and tpl_actionlink()
731 * @author Anika Henke <anika@selfthinker.org>
733 function tpl_action($type,$link=0,$wrapper=false,$return=false,$pre='',$suf='',$inner='') {
735 if ($link) $out .= tpl_actionlink($type,$pre,$suf,$inner,1);
736 else $out .= tpl_button($type,1);
737 if ($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
739 if ($return) return $out;
741 return $out ?
true : false;
745 * Print the search form
747 * If the first parameter is given a div with the ID 'qsearch_out' will
748 * be added which instructs the ajax pagequicksearch to kick in and place
749 * its output into this div. The second parameter controls the propritary
750 * attribute autocomplete. If set to false this attribute will be set with an
751 * value of "off" to instruct the browser to disable it's own built in
752 * autocompletion feature (MSIE and Firefox)
754 * @author Andreas Gohr <andi@splitbrain.org>
756 function tpl_searchform($ajax=true,$autocomplete=true){
761 // don't print the search form if search action has been disabled
762 if (!actionOk('search')) return false;
764 print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search"><div class="no">';
765 print '<input type="hidden" name="do" value="search" />';
766 print '<input type="text" ';
767 if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
768 if(!$autocomplete) print 'autocomplete="off" ';
769 print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
770 print '<input type="submit" value="'.$lang['btn_search'].'" class="button" title="'.$lang['btn_search'].'" />';
771 if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
772 print '</div></form>';
777 * Print the breadcrumbs trace
779 * @author Andreas Gohr <andi@splitbrain.org>
781 function tpl_breadcrumbs($sep='»'){
786 if(!$conf['breadcrumbs']) return false;
788 $crumbs = breadcrumbs(); //setup crumb trace
790 //reverse crumborder in right-to-left mode, add RLM character to fix heb/eng display mixups
791 if($lang['direction'] == 'rtl') {
792 $crumbs = array_reverse($crumbs,true);
793 $crumbs_sep = ' ‏<span class="bcsep">'.$sep.'</span>‏ ';
795 $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
798 //render crumbs, highlight the last one
799 print '<span class="bchead">'.$lang['breadcrumb'].':</span>';
800 $last = count($crumbs);
802 foreach ($crumbs as $id => $name){
805 if ($i == $last) print '<span class="curid">';
806 tpl_link(wl($id),hsc($name),'class="breadcrumbs" title="'.$id.'"');
807 if ($i == $last) print '</span>';
813 * Hierarchical breadcrumbs
815 * This code was suggested as replacement for the usual breadcrumbs.
816 * It only makes sense with a deep site structure.
818 * @author Andreas Gohr <andi@splitbrain.org>
819 * @author Nigel McNie <oracle.shinoda@gmail.com>
820 * @author Sean Coates <sean@caedmon.net>
821 * @author <fredrik@averpil.com>
822 * @todo May behave strangely in RTL languages
824 function tpl_youarehere($sep=' » '){
830 if(!$conf['youarehere']) return false;
832 $parts = explode(':', $ID);
833 $count = count($parts);
835 if($GLOBALS['ACT'] == 'search')
837 $parts = array($conf['start']);
841 echo '<span class="bchead">'.$lang['youarehere'].': </span>';
843 // always print the startpage
844 $title = useHeading('navigation') ?
p_get_first_heading($conf['start']) : $conf['start'];
845 if(!$title) $title = $conf['start'];
846 tpl_link(wl($conf['start']),hsc($title),'title="'.$conf['start'].'"');
848 // print intermediate namespace links
850 for($i=0; $i<$count - 1; $i++
){
851 $part .= $parts[$i].':';
853 resolve_pageid('',$page,$exists);
854 if ($page == $conf['start']) continue; // Skip startpage
859 $title = useHeading('navigation') ?
p_get_first_heading($page) : $parts[$i];
860 tpl_link(wl($page),hsc($title),'title="'.$page.'"');
862 tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"');
866 // print current page, skipping start page, skipping for namespace index
867 if(isset($page) && $page==$part.$parts[$i]) return;
868 $page = $part.$parts[$i];
869 if($page == $conf['start']) return;
871 if(page_exists($page)){
872 $title = useHeading('navigation') ?
p_get_first_heading($page) : $parts[$i];
873 tpl_link(wl($page),hsc($title),'title="'.$page.'"');
875 tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"');
881 * Print info if the user is logged in
882 * and show full name in that case
884 * Could be enhanced with a profile link in future?
886 * @author Andreas Gohr <andi@splitbrain.org>
888 function tpl_userinfo(){
891 if(isset($_SERVER['REMOTE_USER'])){
892 print $lang['loggedinas'].': '.$INFO['userinfo']['name'].' ('.$_SERVER['REMOTE_USER'].')';
899 * Print some info about the current page
901 * @author Andreas Gohr <andi@splitbrain.org>
903 function tpl_pageinfo($ret=false){
909 // return if we are not allowed to view the page
910 if (!auth_quickaclcheck($ID)) { return false; }
912 // prepare date and path
913 $fn = $INFO['filepath'];
914 if(!$conf['fullpath']){
916 $fn = str_replace(fullpath($conf['olddir']).'/','',$fn);
918 $fn = str_replace(fullpath($conf['datadir']).'/','',$fn);
921 $fn = utf8_decodeFN($fn);
922 $date = dformat($INFO['lastmod']);
928 $out .= ' · ';
929 $out .= $lang['lastmod'];
933 $out .= ' '.$lang['by'].' ';
934 $out .= editorinfo($INFO['editor']);
936 $out .= ' ('.$lang['external_edit'].')';
939 $out .= ' · ';
940 $out .= $lang['lockedby'];
942 $out .= editorinfo($INFO['locked']);
955 * Prints or returns the name of the given page (current one if none given).
957 * If useheading is enabled this will use the first headline else
958 * the given ID is used.
960 * @author Andreas Gohr <andi@splitbrain.org>
962 function tpl_pagetitle($id=null, $ret=false){
970 if (useHeading('navigation')) {
971 $title = p_get_first_heading($id);
972 if ($title) $name = $title;
984 * Returns the requested EXIF/IPTC tag from the current image
986 * If $tags is an array all given tags are tried until a
987 * value is found. If no value is found $alt is returned.
989 * Which texts are known is defined in the functions _exifTagNames
990 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
991 * to the names of the latter one)
993 * Only allowed in: detail.php
995 * @author Andreas Gohr <andi@splitbrain.org>
997 function tpl_img_getTag($tags,$alt='',$src=null){
1001 if(is_null($src)) $src = $SRC;
1003 static $meta = null;
1004 if(is_null($meta)) $meta = new JpegMeta($src);
1005 if($meta === false) return $alt;
1006 $info = $meta->getField($tags);
1007 if($info == false) return $alt;
1012 * Prints the image with a link to the full sized version
1014 * Only allowed in: detail.php
1016 function tpl_img($maxwidth=0,$maxheight=0){
1018 $w = tpl_img_getTag('File.Width');
1019 $h = tpl_img_getTag('File.Height');
1021 //resize to given max values
1024 if($maxwidth && $w >= $maxwidth){
1025 $ratio = $maxwidth/$w;
1026 }elseif($maxheight && $h > $maxheight){
1027 $ratio = $maxheight/$h;
1030 if($maxheight && $h >= $maxheight){
1031 $ratio = $maxheight/$h;
1032 }elseif($maxwidth && $w > $maxwidth){
1033 $ratio = $maxwidth/$w;
1037 $w = floor($ratio*$w);
1038 $h = floor($ratio*$h);
1042 $url=ml($IMG,array('cache'=>$_REQUEST['cache']));
1043 $src=ml($IMG,array('cache'=>$_REQUEST['cache'],'w'=>$w,'h'=>$h));
1045 //prepare attributes
1046 $alt=tpl_img_getTag('Simple.Title');
1048 if($w) $p['width'] = $w;
1049 if($h) $p['height'] = $h;
1050 $p['class'] = 'img_detail';
1057 $p = buildAttributes($p);
1059 print '<a href="'.$url.'">';
1060 print '<img src="'.$src.'" '.$p.'/>';
1066 * This function inserts a 1x1 pixel gif which in reality
1067 * is the indexer function.
1069 * Should be called somewhere at the very end of the main.php
1072 function tpl_indexerWebBug(){
1075 if(!$INFO['exists']) return false;
1077 if(isHiddenPage($ID)) return false; //no need to index hidden pages
1080 $p['src'] = DOKU_BASE
.'lib/exe/indexer.php?id='.rawurlencode($ID).
1085 $att = buildAttributes($p);
1086 print "<img $att />";
1090 // configuration methods
1094 * use this function to access template configuration variables
1096 function tpl_getConf($id){
1098 global $tpl_configloaded;
1100 $tpl = $conf['template'];
1102 if (!$tpl_configloaded){
1103 $tconf = tpl_loadConfig();
1104 if ($tconf !== false){
1105 foreach ($tconf as $key => $value){
1106 if (isset($conf['tpl'][$tpl][$key])) continue;
1107 $conf['tpl'][$tpl][$key] = $value;
1109 $tpl_configloaded = true;
1113 return $conf['tpl'][$tpl][$id];
1118 * reads all template configuration variables
1119 * this function is automatically called by tpl_getConf()
1121 function tpl_loadConfig(){
1123 $file = DOKU_TPLINC
.'/conf/default.php';
1126 if (!@file_exists
($file)) return false;
1128 // load default config file
1135 * prints the "main content" in the mediamanger popup
1137 * Depending on the user's actions this may be a list of
1138 * files in a namespace, the meta editing dialog or
1139 * a message of referencing pages
1141 * Only allowed in mediamanager.php
1143 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1144 * @param bool $fromajax - set true when calling this function via ajax
1145 * @author Andreas Gohr <andi@splitbrain.org>
1147 function tpl_mediaContent($fromajax=false){
1154 if(is_array($_REQUEST['do'])){
1155 $do = array_shift(array_keys($_REQUEST['do']));
1157 $do = $_REQUEST['do'];
1159 if(in_array($do,array('save','cancel'))) $do = '';
1162 if($_REQUEST['edit']){
1164 }elseif(is_array($INUSE)){
1171 // output the content pane, wrapped in an event.
1172 if(!$fromajax) ptln('<div id="media__content">');
1173 $data = array( 'do' => $do);
1174 $evt = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1175 if ($evt->advise_before()) {
1177 if($do == 'metaform'){
1178 media_metaform($IMG,$AUTH);
1179 }elseif($do == 'filesinuse'){
1180 media_filesinuse($INUSE,$IMG);
1181 }elseif($do == 'filelist'){
1182 media_filelist($NS,$AUTH,$JUMPTO);
1183 }elseif($do == 'searchlist'){
1184 media_searchlist($_REQUEST['q'],$NS,$AUTH);
1186 msg('Unknown action '.hsc($do),-1);
1189 $evt->advise_after();
1191 if(!$fromajax) ptln('</div>');
1196 * prints the namespace tree in the mediamanger popup
1198 * Only allowed in mediamanager.php
1200 * @author Andreas Gohr <andi@splitbrain.org>
1202 function tpl_mediaTree(){
1205 ptln('<div id="media__tree">');
1212 * Print a dropdown menu with all DokuWiki actions
1214 * Note: this will not use any pretty URLs
1216 * @author Andreas Gohr <andi@splitbrain.org>
1218 function tpl_actiondropdown($empty='',$button='>'){
1227 echo '<form method="post" accept-charset="utf-8">'; #FIXME action
1228 echo '<input type="hidden" name="id" value="'.$ID.'" />';
1229 if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
1230 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
1232 echo '<select name="do" id="action__selector" class="edit">';
1233 echo '<option value="">'.$empty.'</option>';
1235 echo '<optgroup label=" — ">';
1236 // 'edit' - most complicated type, we need to decide on current action
1237 if($ACT == 'show' ||
$ACT == 'search'){
1238 if($INFO['writable']){
1239 if(!empty($INFO['draft'])) {
1240 echo '<option value="edit">'.$lang['btn_draft'].'</option>';
1242 if($INFO['exists']){
1243 echo '<option value="edit">'.$lang['btn_edit'].'</option>';
1245 echo '<option value="edit">'.$lang['btn_create'].'</option>';
1248 }else if(actionOK('source')) { //pseudo action
1249 echo '<option value="edit">'.$lang['btn_source'].'</option>';
1252 echo '<option value="show">'.$lang['btn_show'].'</option>';
1255 echo '<option value="revisions">'.$lang['btn_revs'].'</option>';
1256 if($INFO['ismanager'] && $REV && $INFO['writable'] && actionOK('revert')){
1257 echo '<option value="revert">'.$lang['btn_revert'].'</option>';
1259 echo '<option value="backlink">'.$lang['btn_backlink'].'</option>';
1262 echo '<optgroup label=" — ">';
1263 echo '<option value="recent">'.$lang['btn_recent'].'</option>';
1264 echo '<option value="index">'.$lang['btn_index'].'</option>';
1267 echo '<optgroup label=" — ">';
1268 if($conf['useacl'] && $auth){
1269 if($_SERVER['REMOTE_USER']){
1270 echo '<option value="logout">'.$lang['btn_logout'].'</option>';
1272 echo '<option value="login">'.$lang['btn_login'].'</option>';
1276 if($conf['useacl'] && $auth && $_SERVER['REMOTE_USER'] &&
1277 $auth->canDo('Profile') && ($ACT!='profile')){
1278 echo '<option value="profile">'.$lang['btn_profile'].'</option>';
1281 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers']){
1282 if($_SERVER['REMOTE_USER']){
1283 echo '<option value="subscribe">'.$lang['btn_subscribe'].'</option>';
1287 if($INFO['ismanager']){
1288 echo '<option value="admin">'.$lang['btn_admin'].'</option>';
1293 echo '<input type="submit" value="'.$button.'" id="action__selectorbtn" />';
1298 * Print a informational line about the used license
1300 * @author Andreas Gohr <andi@splitbrain.org>
1301 * @param string $img - print image? (|button|badge)
1302 * @param bool $return - when true don't print, but return HTML
1304 function tpl_license($img='badge',$imgonly=false,$return=false){
1308 if(!$conf['license']) return '';
1309 if(!is_array($license[$conf['license']])) return '';
1310 $lic = $license[$conf['license']];
1312 $out = '<div class="license">';
1314 $src = license_img($img);
1316 $out .= '<a href="'.$lic['url'].'" rel="license"';
1317 if($conf['target']['external']) $out .= ' target="'.$conf['target']['external'].'"';
1318 $out .= '><img src="'.DOKU_BASE
.$src.'" class="medialeft lic'.$img.'" alt="'.$lic['name'].'" /></a> ';
1322 $out .= $lang['license'];
1323 $out .= '<a href="'.$lic['url'].'" rel="license" class="urlextern"';
1324 if(isset($conf['target']['external'])) $out .= ' target="'.$conf['target']['external'].'"';
1325 $out .= '>'.$lic['name'].'</a>';
1329 if($return) return $out;
1335 * Includes the rendered XHTML of a given page
1337 * This function is useful to populate sidebars or similar features in a
1340 function tpl_include_page($pageid,$print=true){
1343 $html = p_wiki_xhtml($pageid,'',false);
1346 if(!$print) return $html;
1351 * Display the subscribe form
1353 * @author Adrian Lang <lang@cosmocode.de>
1355 function tpl_subscribe() {
1360 echo p_locale_xhtml('subscr_form');
1361 echo '<h2>' . $lang['subscr_m_current_header'] . '</h2>';
1362 echo '<div class="level2">';
1363 if ($INFO['subscribed'] === false) {
1364 echo '<p>' . $lang['subscr_m_not_subscribed'] . '</p>';
1367 foreach($INFO['subscribed'] as $sub) {
1368 echo '<li><div class="li">';
1369 if ($sub['target'] !== $ID) {
1370 echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1372 echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1374 $sstl = $lang['subscr_style_'.$sub['style']];
1375 if(!$sstl) $sstl = hsc($sub['style']);
1376 echo ' ('.$sstl.') ';
1378 echo '<a href="'.wl($ID,array('do'=>'subscribe','sub_target'=>$sub['target'],'sub_style'=>$sub['style'],'sub_action'=>'unsubscribe')).'" class="unsubscribe">'.$lang['subscr_m_unsubscribe'].'</a>';
1386 // Add new subscription form
1387 echo '<h2>' . $lang['subscr_m_new_header'] . '</h2>';
1388 echo '<div class="level2">';
1389 $ns = getNS($ID).':';
1391 $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1392 $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1395 'every' => $lang['subscr_style_every'],
1396 'digest' => $lang['subscr_style_digest'],
1397 'list' => $lang['subscr_style_list'],
1400 $form = new Doku_Form(array('id' => 'subscribe__form'));
1401 $form->startFieldset($lang['subscr_m_subscribe']);
1402 $form->addRadioSet('sub_target', $targets);
1403 $form->startFieldset($lang['subscr_m_receive']);
1404 $form->addRadioSet('sub_style', $styles);
1405 $form->addHidden('sub_action', 'subscribe');
1406 $form->addHidden('do', 'subscribe');
1407 $form->addHidden('id', $ID);
1408 $form->endFieldset();
1409 $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1410 html_form('SUBSCRIBE', $form);
1414 //Setup VIM: ex: et ts=4 enc=utf-8 :