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(){
80 $first = isset($_REQUEST['first']) ? intval($_REQUEST['first']) : 0;
81 html_revisions($first);
87 if (is_array($_REQUEST['first'])) {
88 $_REQUEST['first'] = array_keys($_REQUEST['first']);
89 $_REQUEST['first'] = $_REQUEST['first'][0];
91 $first = is_numeric($_REQUEST['first']) ? intval($_REQUEST['first']) : 0;
92 $show_changes = $_REQUEST['show_changes'];
93 html_recent($first, $show_changes);
96 html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly?
102 html_conflict(con($PRE,$TEXT,$SUF),$SUM);
103 html_diff(con($PRE,$TEXT,$SUF),false);
115 print p_locale_xhtml('denied');
118 html_updateprofile();
130 $evt = new Doku_Event('TPL_ACT_UNKNOWN',$ACT);
131 if ($evt->advise_before())
132 msg("Failed to handle command: ".hsc($ACT),-1);
133 $evt->advise_after();
141 * Places the TOC where the function is called
143 * If you use this you most probably want to call tpl_content with
146 * @author Andreas Gohr <andi@splitbrain.org>
148 function tpl_toc($return=false){
158 // if a TOC was prepared in global scope, always use it
160 }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){
161 // get TOC from metadata, render if neccessary
162 $meta = p_get_metadata($ID, false, METADATA_RENDER_USING_CACHE);
163 if(isset($meta['internal']['toc'])){
164 $tocok = $meta['internal']['toc'];
168 $toc = $meta['description']['tableofcontents'];
169 if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']){
172 }elseif($ACT == 'admin'){
173 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin
175 if (!empty($_REQUEST['page'])) {
176 $pluginlist = plugin_list('admin');
177 if (in_array($_REQUEST['page'], $pluginlist)) {
178 // attempt to load the plugin
179 $plugin =& plugin_load('admin',$_REQUEST['page']);
182 if ( ($plugin !== null) &&
183 (!$plugin->forAdminOnly() || $INFO['isadmin']) ){
184 $toc = $plugin->getTOC();
185 $TOC = $toc; // avoid later rebuild
189 trigger_event('TPL_TOC_RENDER', $toc, null, false);
190 $html = html_TOC($toc);
191 if($return) return $html;
196 * Handle the admin page contents
198 * @author Andreas Gohr <andi@splitbrain.org>
200 function tpl_admin(){
205 if (!empty($_REQUEST['page'])) {
206 $pluginlist = plugin_list('admin');
208 if (in_array($_REQUEST['page'], $pluginlist)) {
210 // attempt to load the plugin
211 $plugin =& plugin_load('admin',$_REQUEST['page']);
215 if ($plugin !== null){
216 if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
217 if($INFO['prependTOC']) tpl_toc();
226 * Print the correct HTML meta headers
228 * This has to go into the head section of your template.
230 * @triggers TPL_METAHEADER_OUTPUT
231 * @param boolean $alt Should feeds and alternative format links be added?
232 * @author Andreas Gohr <andi@splitbrain.org>
234 function tpl_metaheaders($alt=true){
245 // prepare the head array
248 // prepare seed for js and css
250 $depends = getConfigFiles('main');
251 foreach($depends as $f) {
252 $time = @filemtime($f);
253 if($time > $tseed) $tseed = $time;
257 $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki');
258 $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml',
259 'href'=>DOKU_BASE.'lib/exe/opensearch.php', 'title'=>$conf['title'] );
260 $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE );
261 if(actionOK('index')){
262 $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'),
263 'title'=>$lang['btn_index'] );
267 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
268 'title'=>'Recent Changes', 'href'=>DOKU_BASE.'feed.php');
269 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
270 'title'=>'Current Namespace',
271 'href'=>DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']);
272 if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']){
273 $head['link'][] = array( 'rel'=>'edit',
274 'title'=>$lang['btn_edit'],
275 'href'=> wl($ID,'do=edit',false,'&'));
278 if($ACT == 'search'){
279 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
280 'title'=>'Search Result',
281 'href'=>DOKU_BASE.'feed.php?mode=search&q='.$QUERY);
284 if(actionOK('export_xhtml')){
285 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML',
286 'href'=>exportlink($ID, 'xhtml', '', false, '&'));
289 if(actionOK('export_raw')){
290 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup',
291 'href'=>exportlink($ID, 'raw', '', false, '&'));
295 // setup robot tags apropriate for different modes
296 if( ($ACT=='show' || $ACT=='export_xhtml') && !$REV){
299 if((time() - $INFO['lastmod']) >= $conf['indexdelay']){
300 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
302 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
304 $head['link'][] = array( 'rel'=>'canonical', 'href'=>wl($ID,'',true,'&') );
306 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow');
308 }elseif(defined('DOKU_MEDIADETAIL')){
309 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
311 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
315 if($ACT == 'show' || $ACT=='export_xhtml'){
316 // date of modification
318 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV));
320 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod']));
323 // keywords (explicit or implicit)
324 if(!empty($INFO['meta']['subject'])){
325 $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject']));
327 $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID));
332 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'screen', 'type'=>'text/css',
333 'href'=>DOKU_BASE.'lib/exe/css.php?t='.$conf['template'].'&tseed='.$tseed);
334 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'all', 'type'=>'text/css',
335 'href'=>DOKU_BASE.'lib/exe/css.php?s=all&t='.$conf['template'].'&tseed='.$tseed);
336 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'print', 'type'=>'text/css',
337 'href'=>DOKU_BASE.'lib/exe/css.php?s=print&t='.$conf['template'].'&tseed='.$tseed);
339 // make $INFO and other vars available to JavaScripts
341 $script = "var NS='".$INFO['namespace']."';";
342 if($conf['useacl'] && $_SERVER['REMOTE_USER']){
343 $script .= "var SIG='".toolbar_signature()."';";
345 $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
346 $head['script'][] = array( 'type'=>'text/javascript', '_data'=> $script);
348 // load external javascript
349 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'',
350 'src'=>DOKU_BASE.'lib/exe/js.php'.'?tseed='.$tseed);
352 // trigger event here
353 trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true);
358 * prints the array build by tpl_metaheaders
360 * $data is an array of different header tags. Each tag can have multiple
361 * instances. Attributes are given as key value pairs. Values will be HTML
362 * encoded automatically so they should be provided as is in the $data array.
364 * For tags having a body attribute specify the the body data in the special
365 * attribute '_data'. This field will NOT BE ESCAPED automatically.
367 * @author Andreas Gohr <andi@splitbrain.org>
369 function _tpl_metaheaders_action($data){
370 foreach($data as $tag => $inst){
371 foreach($inst as $attr){
372 echo '<',$tag,' ',buildAttributes($attr);
373 if(isset($attr['_data']) || $tag == 'script'){
374 if($tag == 'script' && $attr['_data'])
375 $attr['_data'] = "<!--//--><![CDATA[//><!--\n".
379 echo '>',$attr['_data'],'</',$tag,'>';
391 * Just builds a link.
393 * @author Andreas Gohr <andi@splitbrain.org>
395 function tpl_link($url,$name,$more='',$return=false){
396 $out = '<a href="'.$url.'" ';
397 if ($more) $out .= ' '.$more;
398 $out .= ">$name</a>";
399 if ($return) return $out;
405 * Prints a link to a WikiPage
407 * Wrapper around html_wikilink
409 * @author Andreas Gohr <andi@splitbrain.org>
411 function tpl_pagelink($id,$name=null){
412 print html_wikilink($id,$name);
417 * get the parent page
419 * Tries to find out which page is parent.
420 * returns false if none is available
422 * @author Andreas Gohr <andi@splitbrain.org>
424 function tpl_getparent($id){
426 $parent = getNS($id).':';
427 resolve_pageid('',$parent,$exists);
429 $pos = strrpos (getNS($id),':');
430 $parent = substr($parent,0,$pos).':';
431 resolve_pageid('',$parent,$exists);
432 if($parent == $id) return false;
438 * Print one of the buttons
440 * @author Adrian Lang <mail@adrianlang.de>
441 * @see tpl_get_action
443 function tpl_button($type,$return=false){
444 $data = tpl_get_action($type);
445 if ($data === false) {
447 } elseif (!is_array($data)) {
448 $out = sprintf($data, 'button');
451 if ($id === '#dokuwiki__top') {
452 $out = html_topbtn();
454 $out = html_btn($type, $id, $accesskey, $params, $method);
457 if ($return) return $out;
463 * Like the action buttons but links
465 * @author Adrian Lang <mail@adrianlang.de>
466 * @see tpl_get_action
468 function tpl_actionlink($type,$pre='',$suf='',$inner='',$return=false){
470 $data = tpl_get_action($type);
471 if ($data === false) {
473 } elseif (!is_array($data)) {
474 $out = sprintf($data, 'link');
477 if (strpos($id, '#') === 0) {
480 $linktarget = wl($id, $params);
482 $caption = $lang['btn_' . $type];
483 $akey = $addTitle = '';
485 $akey = 'accesskey="'.$accesskey.'" ';
486 $addTitle = ' ['.strtoupper($accesskey).']';
488 $out = tpl_link($linktarget, $pre.(($inner)?$inner:$caption).$suf,
489 'class="action ' . $type . '" ' .
490 $akey . 'rel="nofollow" ' .
491 'title="' . hsc($caption).$addTitle . '"', 1);
493 if ($return) return $out;
499 * Check the actions and get data for buttons and links
501 * Available actions are
503 * edit - edit/create/show/draft
504 * history - old revisions
505 * recent - recent changes
506 * login - login/logout - if ACL enabled
507 * profile - user profile (if logged in)
509 * admin - admin page - if enough rights
511 * back - back to parent - if available
512 * backlink - links to the list of backlinks
513 * subscribe/subscription- subscribe/unsubscribe
515 * @author Andreas Gohr <andi@splitbrain.org>
516 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
517 * @author Adrian Lang <mail@adrianlang.de>
519 function tpl_get_action($type) {
527 // check disabled actions and fix the badly named ones
528 if($type == 'history') $type='revisions';
529 if(!actionOK($type)) return false;
534 $params = array('do' => $type);
537 // most complicated type - we need to decide on current action
538 if($ACT == 'show' || $ACT == 'search'){
540 if($INFO['writable']){
542 if(!empty($INFO['draft'])) {
544 $params['do'] = 'draft';
546 $params['rev'] = $REV;
547 if(!$INFO['exists']){
552 if(!actionOK('source')) return false; //pseudo action
553 $params['rev'] = $REV;
576 $id = '#dokuwiki__top';
579 $parent = tpl_getparent($ID);
588 $params['sectok'] = getSecurityToken();
589 if(isset($_SERVER['REMOTE_USER'])){
590 if (!actionOK('logout')) {
593 $params['do'] = 'logout';
598 if($_SERVER['REMOTE_USER']){
603 if($_SERVER['REMOTE_USER']){
608 if(!$INFO['ismanager']){
613 if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
616 $params['rev'] = $REV;
617 $params['sectok'] = getSecurityToken();
621 $params['do'] = 'subscribe';
623 if(!$_SERVER['REMOTE_USER']){
630 if(!isset($_SERVER['REMOTE_USER'])){
637 return '[unknown %s type]';
640 return compact('accesskey', 'type', 'id', 'method', 'params');
644 * Wrapper around tpl_button() and tpl_actionlink()
646 * @author Anika Henke <anika@selfthinker.org>
648 function tpl_action($type,$link=0,$wrapper=false,$return=false,$pre='',$suf='',$inner='') {
650 if ($link) $out .= tpl_actionlink($type,$pre,$suf,$inner,1);
651 else $out .= tpl_button($type,1);
652 if ($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
654 if ($return) return $out;
656 return $out ? true : false;
660 * Print the search form
662 * If the first parameter is given a div with the ID 'qsearch_out' will
663 * be added which instructs the ajax pagequicksearch to kick in and place
664 * its output into this div. The second parameter controls the propritary
665 * attribute autocomplete. If set to false this attribute will be set with an
666 * value of "off" to instruct the browser to disable it's own built in
667 * autocompletion feature (MSIE and Firefox)
669 * @author Andreas Gohr <andi@splitbrain.org>
671 function tpl_searchform($ajax=true,$autocomplete=true){
676 // don't print the search form if search action has been disabled
677 if (!actionOk('search')) return false;
679 print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get"><div class="no">';
680 print '<input type="hidden" name="do" value="search" />';
681 print '<input type="text" ';
682 if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
683 if(!$autocomplete) print 'autocomplete="off" ';
684 print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
685 print '<input type="submit" value="'.$lang['btn_search'].'" class="button" title="'.$lang['btn_search'].'" />';
686 if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
687 print '</div></form>';
692 * Print the breadcrumbs trace
694 * @author Andreas Gohr <andi@splitbrain.org>
696 function tpl_breadcrumbs($sep='•'){
701 if(!$conf['breadcrumbs']) return false;
703 $crumbs = breadcrumbs(); //setup crumb trace
705 //reverse crumborder in right-to-left mode, add RLM character to fix heb/eng display mixups
706 if($lang['direction'] == 'rtl') {
707 $crumbs = array_reverse($crumbs,true);
708 $crumbs_sep = ' ‏<span class="bcsep">'.$sep.'</span>‏ ';
710 $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
713 //render crumbs, highlight the last one
714 print '<span class="bchead">'.$lang['breadcrumb'].':</span>';
715 $last = count($crumbs);
717 foreach ($crumbs as $id => $name){
720 if ($i == $last) print '<span class="curid">';
721 tpl_link(wl($id),hsc($name),'class="breadcrumbs" title="'.$id.'"');
722 if ($i == $last) print '</span>';
728 * Hierarchical breadcrumbs
730 * This code was suggested as replacement for the usual breadcrumbs.
731 * It only makes sense with a deep site structure.
733 * @author Andreas Gohr <andi@splitbrain.org>
734 * @author Nigel McNie <oracle.shinoda@gmail.com>
735 * @author Sean Coates <sean@caedmon.net>
736 * @author <fredrik@averpil.com>
737 * @todo May behave strangely in RTL languages
739 function tpl_youarehere($sep=' » '){
745 if(!$conf['youarehere']) return false;
747 $parts = explode(':', $ID);
748 $count = count($parts);
750 echo '<span class="bchead">'.$lang['youarehere'].': </span>';
752 // always print the startpage
753 tpl_pagelink(':'.$conf['start']);
755 // print intermediate namespace links
757 for($i=0; $i<$count - 1; $i++){
758 $part .= $parts[$i].':';
760 if ($page == $conf['start']) continue; // Skip startpage
767 // print current page, skipping start page, skipping for namespace index
768 resolve_pageid('',$page,$exists);
769 if(isset($page) && $page==$part.$parts[$i]) return;
770 $page = $part.$parts[$i];
771 if($page == $conf['start']) return;
778 * Print info if the user is logged in
779 * and show full name in that case
781 * Could be enhanced with a profile link in future?
783 * @author Andreas Gohr <andi@splitbrain.org>
785 function tpl_userinfo(){
788 if(isset($_SERVER['REMOTE_USER'])){
789 print $lang['loggedinas'].': '.hsc($INFO['userinfo']['name']).' ('.hsc($_SERVER['REMOTE_USER']).')';
796 * Print some info about the current page
798 * @author Andreas Gohr <andi@splitbrain.org>
800 function tpl_pageinfo($ret=false){
806 // return if we are not allowed to view the page
807 if (!auth_quickaclcheck($ID)) { return false; }
809 // prepare date and path
810 $fn = $INFO['filepath'];
811 if(!$conf['fullpath']){
813 $fn = str_replace(fullpath($conf['olddir']).'/','',$fn);
815 $fn = str_replace(fullpath($conf['datadir']).'/','',$fn);
818 $fn = utf8_decodeFN($fn);
819 $date = dformat($INFO['lastmod']);
825 $out .= ' · ';
826 $out .= $lang['lastmod'];
830 $out .= ' '.$lang['by'].' ';
831 $out .= editorinfo($INFO['editor']);
833 $out .= ' ('.$lang['external_edit'].')';
836 $out .= ' · ';
837 $out .= $lang['lockedby'];
839 $out .= editorinfo($INFO['locked']);
852 * Prints or returns the name of the given page (current one if none given).
854 * If useheading is enabled this will use the first headline else
855 * the given ID is used.
857 * @author Andreas Gohr <andi@splitbrain.org>
859 function tpl_pagetitle($id=null, $ret=false){
867 if (useHeading('navigation')) {
868 $title = p_get_first_heading($id);
869 if ($title) $name = $title;
881 * Returns the requested EXIF/IPTC tag from the current image
883 * If $tags is an array all given tags are tried until a
884 * value is found. If no value is found $alt is returned.
886 * Which texts are known is defined in the functions _exifTagNames
887 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
888 * to the names of the latter one)
890 * Only allowed in: detail.php
892 * @author Andreas Gohr <andi@splitbrain.org>
894 function tpl_img_getTag($tags,$alt='',$src=null){
898 if(is_null($src)) $src = $SRC;
901 if(is_null($meta)) $meta = new JpegMeta($src);
902 if($meta === false) return $alt;
903 $info = $meta->getField($tags);
904 if($info == false) return $alt;
909 * Prints the image with a link to the full sized version
911 * Only allowed in: detail.php
913 * @param $maxwidth int - maximal width of the image
914 * @param $maxheight int - maximal height of the image
915 * @param $link bool - link to the orginal size?
916 * @param $params array - additional image attributes
918 function tpl_img($maxwidth=0,$maxheight=0,$link=true,$params=null){
920 $w = tpl_img_getTag('File.Width');
921 $h = tpl_img_getTag('File.Height');
923 //resize to given max values
926 if($maxwidth && $w >= $maxwidth){
927 $ratio = $maxwidth/$w;
928 }elseif($maxheight && $h > $maxheight){
929 $ratio = $maxheight/$h;
932 if($maxheight && $h >= $maxheight){
933 $ratio = $maxheight/$h;
934 }elseif($maxwidth && $w > $maxwidth){
935 $ratio = $maxwidth/$w;
939 $w = floor($ratio*$w);
940 $h = floor($ratio*$h);
944 $url=ml($IMG,array('cache'=>$_REQUEST['cache']),true,'&');
945 $src=ml($IMG,array('cache'=>$_REQUEST['cache'],'w'=>$w,'h'=>$h),true,'&');
948 $alt=tpl_img_getTag('Simple.Title');
949 if(is_null($params)){
954 if($w) $p['width'] = $w;
955 if($h) $p['height'] = $h;
956 $p['class'] = 'img_detail';
965 $data = array('url'=>($link?$url:null), 'params'=>$p);
966 return trigger_event('TPL_IMG_DISPLAY',$data,'_tpl_img_action',true);
970 * Default action for TPL_IMG_DISPLAY
972 function _tpl_img_action($data, $param=NULL) {
974 $p = buildAttributes($data['params']);
976 if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">';
977 print '<img '.$p.'/>';
978 if($data['url']) print '</a>';
983 * This function inserts a small gif which in reality is the indexer function.
985 * Should be called somewhere at the very end of the main.php
988 function tpl_indexerWebBug(){
991 if(!$INFO['exists']) return false;
994 $p['src'] = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
996 $p['width'] = 2; //no more 1x1 px image because we live in times of ad blockers...
999 $att = buildAttributes($p);
1000 print "<img $att />";
1004 // configuration methods
1008 * use this function to access template configuration variables
1010 function tpl_getConf($id){
1012 static $tpl_configloaded = false;
1014 $tpl = $conf['template'];
1016 if (!$tpl_configloaded){
1017 $tconf = tpl_loadConfig();
1018 if ($tconf !== false){
1019 foreach ($tconf as $key => $value){
1020 if (isset($conf['tpl'][$tpl][$key])) continue;
1021 $conf['tpl'][$tpl][$key] = $value;
1023 $tpl_configloaded = true;
1027 return $conf['tpl'][$tpl][$id];
1032 * reads all template configuration variables
1033 * this function is automatically called by tpl_getConf()
1035 function tpl_loadConfig(){
1037 $file = DOKU_TPLINC.'/conf/default.php';
1040 if (!@file_exists($file)) return false;
1042 // load default config file
1052 * use this function to access template language variables
1054 function tpl_getLang($id){
1055 static $lang = array();
1057 if (count($lang) === 0){
1058 $path = DOKU_TPLINC.'lang/';
1062 global $conf; // definitely don't invoke "global $lang"
1063 // don't include once
1064 @include($path.'en/lang.php');
1065 if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
1072 * prints the "main content" in the mediamanger popup
1074 * Depending on the user's actions this may be a list of
1075 * files in a namespace, the meta editing dialog or
1076 * a message of referencing pages
1078 * Only allowed in mediamanager.php
1080 * @triggers MEDIAMANAGER_CONTENT_OUTPUT
1081 * @param bool $fromajax - set true when calling this function via ajax
1082 * @author Andreas Gohr <andi@splitbrain.org>
1084 function tpl_mediaContent($fromajax=false){
1091 if(is_array($_REQUEST['do'])){
1092 $do = array_shift(array_keys($_REQUEST['do']));
1094 $do = $_REQUEST['do'];
1096 if(in_array($do,array('save','cancel'))) $do = '';
1099 if($_REQUEST['edit']){
1101 }elseif(is_array($INUSE)){
1108 // output the content pane, wrapped in an event.
1109 if(!$fromajax) ptln('<div id="media__content">');
1110 $data = array( 'do' => $do);
1111 $evt = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
1112 if ($evt->advise_before()) {
1114 if($do == 'filesinuse'){
1115 media_filesinuse($INUSE,$IMG);
1116 }elseif($do == 'filelist'){
1117 media_filelist($NS,$AUTH,$JUMPTO);
1118 }elseif($do == 'searchlist'){
1119 media_searchlist($_REQUEST['q'],$NS,$AUTH);
1121 msg('Unknown action '.hsc($do),-1);
1124 $evt->advise_after();
1126 if(!$fromajax) ptln('</div>');
1131 * Prints the central column in full-screen media manager
1132 * Depending on the opened tab this may be a list of
1133 * files in a namespace, upload form or search form
1135 * @author Kate Arzamastseva <pshns@ukr.net>
1137 function tpl_mediaFileList(){
1143 $opened_tab = $_REQUEST['tab_files'];
1144 if (!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files';
1145 if ($_REQUEST['mediado'] == 'update') $opened_tab = 'upload';
1147 echo '<h2 class="a11y">' . $lang['mediaselect'] . '</h2>'.NL;
1149 media_tabs_files($opened_tab);
1151 echo '<div class="panelHeader">'.NL;
1153 $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']';
1154 printf($lang['media_' . $opened_tab], '<strong>'.hsc($tabTitle).'</strong>');
1156 if ($opened_tab === 'search' || $opened_tab === 'files') {
1157 media_tab_files_options();
1161 echo '<div class="panelContent">'.NL;
1162 if ($opened_tab == 'files') {
1163 media_tab_files($NS,$AUTH,$JUMPTO);
1164 } elseif ($opened_tab == 'upload') {
1165 media_tab_upload($NS,$AUTH,$JUMPTO);
1166 } elseif ($opened_tab == 'search') {
1167 media_tab_search($NS,$AUTH);
1173 * Prints the third column in full-screen media manager
1174 * Depending on the opened tab this may be details of the
1175 * selected file, the meta editing dialog or
1176 * list of file revisions
1178 * @author Kate Arzamastseva <pshns@ukr.net>
1180 function tpl_mediaFileDetails($image, $rev){
1181 global $AUTH, $NS, $conf, $DEL, $lang;
1183 $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']);
1184 if (!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return '';
1185 if ($rev && !file_exists(mediaFN($image, $rev))) $rev = false;
1186 if (isset($NS) && getNS($image) != $NS) return '';
1187 $do = $_REQUEST['mediado'];
1189 $opened_tab = $_REQUEST['tab_details'];
1191 $tab_array = array('view');
1192 list($ext, $mime) = mimetype($image);
1193 if ($mime == 'image/jpeg') {
1194 $tab_array[] = 'edit';
1196 if ($conf['mediarevisions']) {
1197 $tab_array[] = 'history';
1200 if (!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view';
1201 if ($_REQUEST['edit']) $opened_tab = 'edit';
1202 if ($do == 'restore') $opened_tab = 'view';
1204 media_tabs_details($image, $opened_tab);
1206 echo '<div class="panelHeader"><h3>';
1207 list($ext,$mime,$dl) = mimetype($image,false);
1208 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
1209 $class = 'select mediafile mf_'.$class;
1210 $tabTitle = '<strong class="'.$class.'">'.$image.'</strong>';
1211 if ($opened_tab === 'view' && $rev) {
1212 printf($lang['media_viewold'], $tabTitle, dformat($rev));
1214 printf($lang['media_' . $opened_tab], $tabTitle);
1217 echo '</h3></div>'.NL;
1219 echo '<div class="panelContent">'.NL;
1221 if ($opened_tab == 'view') {
1222 media_tab_view($image, $NS, $AUTH, $rev);
1224 } elseif ($opened_tab == 'edit' && !$removed) {
1225 media_tab_edit($image, $NS, $AUTH);
1227 } elseif ($opened_tab == 'history' && $conf['mediarevisions']) {
1228 media_tab_history($image,$NS,$AUTH);
1235 * prints the namespace tree in the mediamanger popup
1237 * Only allowed in mediamanager.php
1239 * @author Andreas Gohr <andi@splitbrain.org>
1241 function tpl_mediaTree(){
1243 ptln('<div id="media__tree">');
1250 * Print a dropdown menu with all DokuWiki actions
1252 * Note: this will not use any pretty URLs
1254 * @author Andreas Gohr <andi@splitbrain.org>
1256 function tpl_actiondropdown($empty='',$button='>'){
1265 echo '<form action="' . DOKU_SCRIPT . '" method="post" accept-charset="utf-8">';
1266 echo '<input type="hidden" name="id" value="'.$ID.'" />';
1267 if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
1268 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
1270 echo '<select name="do" class="edit quickselect">';
1271 echo '<option value="">'.$empty.'</option>';
1273 echo '<optgroup label=" — ">';
1274 $act = tpl_get_action('edit');
1275 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1277 $act = tpl_get_action('revisions');
1278 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1280 $act = tpl_get_action('revert');
1281 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1283 $act = tpl_get_action('backlink');
1284 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1287 echo '<optgroup label=" — ">';
1288 $act = tpl_get_action('recent');
1289 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1291 $act = tpl_get_action('index');
1292 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1295 echo '<optgroup label=" — ">';
1296 $act = tpl_get_action('login');
1297 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1299 $act = tpl_get_action('profile');
1300 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1302 $act = tpl_get_action('subscribe');
1303 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1305 $act = tpl_get_action('admin');
1306 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
1310 echo '<input type="submit" value="'.$button.'" />';
1315 * Print a informational line about the used license
1317 * @author Andreas Gohr <andi@splitbrain.org>
1318 * @param string $img - print image? (|button|badge)
1319 * @param bool $return - when true don't print, but return HTML
1321 function tpl_license($img='badge',$imgonly=false,$return=false){
1325 if(!$conf['license']) return '';
1326 if(!is_array($license[$conf['license']])) return '';
1327 $lic = $license[$conf['license']];
1329 $out = '<div class="license">';
1331 $src = license_img($img);
1333 $out .= '<a href="'.$lic['url'].'" rel="license"';
1334 if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1335 $out .= '><img src="'.DOKU_BASE.$src.'" class="medialeft lic'.$img.'" alt="'.$lic['name'].'" /></a> ';
1339 $out .= $lang['license'];
1340 $out .= ' <a href="'.$lic['url'].'" rel="license" class="urlextern"';
1341 if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
1342 $out .= '>'.$lic['name'].'</a>';
1346 if($return) return $out;
1352 * Includes the rendered XHTML of a given page
1354 * This function is useful to populate sidebars or similar features in a
1357 function tpl_include_page($pageid,$print=true){
1362 $html = p_wiki_xhtml($pageid,'',false);
1366 if(!$print) return $html;
1371 * Display the subscribe form
1373 * @author Adrian Lang <lang@cosmocode.de>
1375 function tpl_subscribe() {
1380 $stime_days = $conf['subscribe_time']/60/60/24;
1382 echo p_locale_xhtml('subscr_form');
1383 echo '<h2>' . $lang['subscr_m_current_header'] . '</h2>';
1384 echo '<div class="level2">';
1385 if ($INFO['subscribed'] === false) {
1386 echo '<p>' . $lang['subscr_m_not_subscribed'] . '</p>';
1389 foreach($INFO['subscribed'] as $sub) {
1390 echo '<li><div class="li">';
1391 if ($sub['target'] !== $ID) {
1392 echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
1394 echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
1396 $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
1397 if(!$sstl) $sstl = hsc($sub['style']);
1398 echo ' ('.$sstl.') ';
1400 echo '<a href="' . wl($ID,
1401 array('do'=>'subscribe',
1402 'sub_target'=>$sub['target'],
1403 'sub_style'=>$sub['style'],
1404 'sub_action'=>'unsubscribe',
1405 'sectok' => getSecurityToken())) .
1406 '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'] .
1413 // Add new subscription form
1414 echo '<h2>' . $lang['subscr_m_new_header'] . '</h2>';
1415 echo '<div class="level2">';
1416 $ns = getNS($ID).':';
1418 $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
1419 $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
1422 'every' => $lang['subscr_style_every'],
1423 'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
1424 'list' => sprintf($lang['subscr_style_list'], $stime_days),
1427 $form = new Doku_Form(array('id' => 'subscribe__form'));
1428 $form->startFieldset($lang['subscr_m_subscribe']);
1429 $form->addRadioSet('sub_target', $targets);
1430 $form->startFieldset($lang['subscr_m_receive']);
1431 $form->addRadioSet('sub_style', $styles);
1432 $form->addHidden('sub_action', 'subscribe');
1433 $form->addHidden('do', 'subscribe');
1434 $form->addHidden('id', $ID);
1435 $form->endFieldset();
1436 $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
1437 html_form('SUBSCRIBE', $form);
1442 * Tries to send already created content right to the browser
1444 * Wraps around ob_flush() and flush()
1446 * @author Andreas Gohr <andi@splitbrain.org>
1448 function tpl_flush(){
1455 * Returns icon from data/media root directory if it exists, otherwise
1456 * the one in the template's image directory.
1458 * @param bool $abs - if to use absolute URL
1459 * @param string $fileName - file name of icon
1460 * @author Anika Henke <anika@selfthinker.org>
1462 function tpl_getFavicon($abs=false, $fileName='favicon.ico') {
1463 if (file_exists(mediaFN($fileName))) {
1464 return ml($fileName, '', true, '', $abs);
1468 return DOKU_URL.substr(DOKU_TPL.'images/'.$fileName, strlen(DOKU_REL));
1470 return DOKU_TPL.'images/'.$fileName;
1474 * Returns <link> tag for various icon types (favicon|mobile|generic)
1476 * @param array $types - list of icon types to display (favicon|mobile|generic)
1477 * @author Anika Henke <anika@selfthinker.org>
1479 function tpl_favicon($types=array('favicon')) {
1483 foreach ($types as $type) {
1486 $return .= '<link rel="shortcut icon" href="'.tpl_getFavicon().'" />'.NL;
1489 $return .= '<link rel="apple-touch-icon" href="'.tpl_getFavicon(false, 'apple-touch-icon.png').'" />'.NL;
1492 // ideal world solution, which doesn't work in any browser yet
1493 $return .= '<link rel="icon" href="'.tpl_getFavicon(false, 'icon.svg').'" type="image/svg+xml" />'.NL;
1502 * Prints full-screen media manager
1504 * @author Kate Arzamastseva <pshns@ukr.net>
1506 function tpl_media() {
1507 global $DEL, $NS, $IMG, $AUTH, $JUMPTO, $REV, $lang, $fullscreen, $conf;
1509 require_once DOKU_INC.'lib/exe/mediamanager.php';
1511 if ($_REQUEST['image']) $image = cleanID($_REQUEST['image']);
1512 if (isset($IMG)) $image = $IMG;
1513 if (isset($JUMPTO)) $image = $JUMPTO;
1514 if (isset($REV) && !$JUMPTO) $rev = $REV;
1516 echo '<div id="mediamanager__page">'.NL;
1517 echo '<h1>'.$lang['btn_media'].'</h1>'.NL;
1520 echo '<div class="panel namespaces">'.NL;
1521 echo '<h2>'.$lang['namespaces'].'</h2>'.NL;
1522 echo '<div class="panelHeader">';
1523 echo $lang['media_namespaces'];
1526 echo '<div class="panelContent" id="media__tree">'.NL;
1531 echo '<div class="panel filelist">'.NL;
1532 tpl_mediaFileList();
1535 echo '<div class="panel file">'.NL;
1536 echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL;
1537 tpl_mediaFileDetails($image, $rev);
1543 //Setup VIM: ex: et ts=4 :