PageRenderTime 56ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/wiki/inc/template.php

https://github.com/godber/PHXdata-Website
PHP | 1363 lines | 918 code | 133 blank | 312 comment | 213 complexity | 4f9a995f39872cd712948da20190544d MD5 | raw file
  1. <?php
  2. /**
  3. * DokuWiki template functions
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Andreas Gohr <andi@splitbrain.org>
  7. */
  8. if(!defined('DOKU_INC')) die('meh.');
  9. /**
  10. * Returns the path to the given template, uses
  11. * default one if the custom version doesn't exist.
  12. *
  13. * @author Andreas Gohr <andi@splitbrain.org>
  14. */
  15. function template($tpl){
  16. global $conf;
  17. if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl))
  18. return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl;
  19. return DOKU_INC.'lib/tpl/default/'.$tpl;
  20. }
  21. /**
  22. * Print the content
  23. *
  24. * This function is used for printing all the usual content
  25. * (defined by the global $ACT var) by calling the appropriate
  26. * outputfunction(s) from html.php
  27. *
  28. * Everything that doesn't use the main template file isn't
  29. * handled by this function. ACL stuff is not done here either.
  30. *
  31. * @author Andreas Gohr <andi@splitbrain.org>
  32. */
  33. function tpl_content($prependTOC=true) {
  34. global $ACT;
  35. global $INFO;
  36. $INFO['prependTOC'] = $prependTOC;
  37. ob_start();
  38. trigger_event('TPL_ACT_RENDER',$ACT,'tpl_content_core');
  39. $html_output = ob_get_clean();
  40. trigger_event('TPL_CONTENT_DISPLAY',$html_output,'ptln');
  41. return !empty($html_output);
  42. }
  43. function tpl_content_core(){
  44. global $ACT;
  45. global $TEXT;
  46. global $PRE;
  47. global $SUF;
  48. global $SUM;
  49. global $IDX;
  50. switch($ACT){
  51. case 'show':
  52. html_show();
  53. break;
  54. case 'locked':
  55. html_locked();
  56. case 'edit':
  57. case 'recover':
  58. html_edit();
  59. break;
  60. case 'preview':
  61. html_edit();
  62. html_show($TEXT);
  63. break;
  64. case 'draft':
  65. html_draft();
  66. break;
  67. case 'search':
  68. html_search();
  69. break;
  70. case 'revisions':
  71. $first = isset($_REQUEST['first']) ? intval($_REQUEST['first']) : 0;
  72. html_revisions($first);
  73. break;
  74. case 'diff':
  75. html_diff();
  76. break;
  77. case 'recent':
  78. if (is_array($_REQUEST['first'])) {
  79. $_REQUEST['first'] = array_keys($_REQUEST['first']);
  80. $_REQUEST['first'] = $_REQUEST['first'][0];
  81. }
  82. $first = is_numeric($_REQUEST['first']) ? intval($_REQUEST['first']) : 0;
  83. html_recent($first);
  84. break;
  85. case 'index':
  86. html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly?
  87. break;
  88. case 'backlink':
  89. html_backlinks();
  90. break;
  91. case 'conflict':
  92. html_conflict(con($PRE,$TEXT,$SUF),$SUM);
  93. html_diff(con($PRE,$TEXT,$SUF),false);
  94. break;
  95. case 'login':
  96. html_login();
  97. break;
  98. case 'register':
  99. html_register();
  100. break;
  101. case 'resendpwd':
  102. html_resendpwd();
  103. break;
  104. case 'denied':
  105. print p_locale_xhtml('denied');
  106. break;
  107. case 'profile' :
  108. html_updateprofile();
  109. break;
  110. case 'admin':
  111. tpl_admin();
  112. break;
  113. case 'subscribe':
  114. tpl_subscribe();
  115. break;
  116. default:
  117. $evt = new Doku_Event('TPL_ACT_UNKNOWN',$ACT);
  118. if ($evt->advise_before())
  119. msg("Failed to handle command: ".hsc($ACT),-1);
  120. $evt->advise_after();
  121. unset($evt);
  122. return false;
  123. }
  124. return true;
  125. }
  126. /**
  127. * Places the TOC where the function is called
  128. *
  129. * If you use this you most probably want to call tpl_content with
  130. * a false argument
  131. *
  132. * @author Andreas Gohr <andi@splitbrain.org>
  133. */
  134. function tpl_toc($return=false){
  135. global $TOC;
  136. global $ACT;
  137. global $ID;
  138. global $REV;
  139. global $INFO;
  140. global $conf;
  141. $toc = array();
  142. if(is_array($TOC)){
  143. // if a TOC was prepared in global scope, always use it
  144. $toc = $TOC;
  145. }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){
  146. // get TOC from metadata, render if neccessary
  147. $meta = p_get_metadata($ID, false, true);
  148. if(isset($meta['internal']['toc'])){
  149. $tocok = $meta['internal']['toc'];
  150. }else{
  151. $tocok = true;
  152. }
  153. $toc = $meta['description']['tableofcontents'];
  154. if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']){
  155. $toc = array();
  156. }
  157. }elseif($ACT == 'admin'){
  158. // try to load admin plugin TOC FIXME: duplicates code from tpl_admin
  159. $plugin = null;
  160. if (!empty($_REQUEST['page'])) {
  161. $pluginlist = plugin_list('admin');
  162. if (in_array($_REQUEST['page'], $pluginlist)) {
  163. // attempt to load the plugin
  164. $plugin =& plugin_load('admin',$_REQUEST['page']);
  165. }
  166. }
  167. if ( ($plugin !== null) &&
  168. (!$plugin->forAdminOnly() || $INFO['isadmin']) ){
  169. $toc = $plugin->getTOC();
  170. $TOC = $toc; // avoid later rebuild
  171. }
  172. }
  173. trigger_event('TPL_TOC_RENDER', $toc, null, false);
  174. $html = html_TOC($toc);
  175. if($return) return $html;
  176. echo $html;
  177. }
  178. /**
  179. * Handle the admin page contents
  180. *
  181. * @author Andreas Gohr <andi@splitbrain.org>
  182. */
  183. function tpl_admin(){
  184. global $INFO;
  185. global $TOC;
  186. $plugin = null;
  187. if (!empty($_REQUEST['page'])) {
  188. $pluginlist = plugin_list('admin');
  189. if (in_array($_REQUEST['page'], $pluginlist)) {
  190. // attempt to load the plugin
  191. $plugin =& plugin_load('admin',$_REQUEST['page']);
  192. }
  193. }
  194. if ($plugin !== null){
  195. if($plugin->forAdminOnly() && !$INFO['isadmin']){
  196. msg('For admins only',-1);
  197. html_admin();
  198. }else{
  199. if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet
  200. if($INFO['prependTOC']) tpl_toc();
  201. $plugin->html();
  202. }
  203. }else{
  204. html_admin();
  205. }
  206. return true;
  207. }
  208. /**
  209. * Print the correct HTML meta headers
  210. *
  211. * This has to go into the head section of your template.
  212. *
  213. * @triggers TPL_METAHEADER_OUTPUT
  214. * @param boolean $alt Should feeds and alternative format links be added?
  215. * @author Andreas Gohr <andi@splitbrain.org>
  216. */
  217. function tpl_metaheaders($alt=true){
  218. global $ID;
  219. global $REV;
  220. global $INFO;
  221. global $JSINFO;
  222. global $ACT;
  223. global $QUERY;
  224. global $lang;
  225. global $conf;
  226. $it=2;
  227. // prepare the head array
  228. $head = array();
  229. // prepare seed for js and css
  230. $tseed = 0;
  231. $depends = getConfigFiles('main');
  232. foreach($depends as $f) {
  233. $time = @filemtime($f);
  234. if($time > $tseed) $tseed = $time;
  235. }
  236. // the usual stuff
  237. $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki');
  238. $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml',
  239. 'href'=>DOKU_BASE.'lib/exe/opensearch.php', 'title'=>$conf['title'] );
  240. $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE );
  241. if(actionOK('index')){
  242. $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'),
  243. 'title'=>$lang['btn_index'] );
  244. }
  245. if($alt){
  246. $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
  247. 'title'=>'Recent Changes', 'href'=>DOKU_BASE.'feed.php');
  248. $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
  249. 'title'=>'Current Namespace',
  250. 'href'=>DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']);
  251. if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']){
  252. $head['link'][] = array( 'rel'=>'edit',
  253. 'title'=>$lang['btn_edit'],
  254. 'href'=> wl($ID,'do=edit',false,'&'));
  255. }
  256. if($ACT == 'search'){
  257. $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml',
  258. 'title'=>'Search Result',
  259. 'href'=>DOKU_BASE.'feed.php?mode=search&q='.$QUERY);
  260. }
  261. if(actionOK('export_xhtml')){
  262. $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML',
  263. 'href'=>exportlink($ID, 'xhtml', '', false, '&'));
  264. }
  265. if(actionOK('export_raw')){
  266. $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup',
  267. 'href'=>exportlink($ID, 'raw', '', false, '&'));
  268. }
  269. }
  270. // setup robot tags apropriate for different modes
  271. if( ($ACT=='show' || $ACT=='export_xhtml') && !$REV){
  272. if($INFO['exists']){
  273. //delay indexing:
  274. if((time() - $INFO['lastmod']) >= $conf['indexdelay']){
  275. $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
  276. }else{
  277. $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
  278. }
  279. $head['link'][] = array( 'rel'=>'canonical', 'href'=>wl($ID,'',true,'&') );
  280. }else{
  281. $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow');
  282. }
  283. }elseif(defined('DOKU_MEDIADETAIL')){
  284. $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow');
  285. }else{
  286. $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow');
  287. }
  288. // set metadata
  289. if($ACT == 'show' || $ACT=='export_xhtml'){
  290. // date of modification
  291. if($REV){
  292. $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV));
  293. }else{
  294. $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod']));
  295. }
  296. // keywords (explicit or implicit)
  297. if(!empty($INFO['meta']['subject'])){
  298. $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject']));
  299. }else{
  300. $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID));
  301. }
  302. }
  303. // load stylesheets
  304. $head['link'][] = array('rel'=>'stylesheet', 'media'=>'screen', 'type'=>'text/css',
  305. 'href'=>DOKU_BASE.'lib/exe/css.php?t='.$conf['template'].'&tseed='.$tseed);
  306. $head['link'][] = array('rel'=>'stylesheet', 'media'=>'all', 'type'=>'text/css',
  307. 'href'=>DOKU_BASE.'lib/exe/css.php?s=all&t='.$conf['template'].'&tseed='.$tseed);
  308. $head['link'][] = array('rel'=>'stylesheet', 'media'=>'print', 'type'=>'text/css',
  309. 'href'=>DOKU_BASE.'lib/exe/css.php?s=print&t='.$conf['template'].'&tseed='.$tseed);
  310. // make $INFO and other vars available to JavaScripts
  311. $json = new JSON();
  312. $script = "var NS='".$INFO['namespace']."';";
  313. if($conf['useacl'] && $_SERVER['REMOTE_USER']){
  314. $script .= "var SIG='".toolbar_signature()."';";
  315. }
  316. $script .= 'var JSINFO = '.$json->encode($JSINFO).';';
  317. $head['script'][] = array( 'type'=>'text/javascript', '_data'=> $script);
  318. // load external javascript
  319. $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'',
  320. 'src'=>DOKU_BASE.'lib/exe/js.php'.'?tseed='.$tseed);
  321. // trigger event here
  322. trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true);
  323. return true;
  324. }
  325. /**
  326. * prints the array build by tpl_metaheaders
  327. *
  328. * $data is an array of different header tags. Each tag can have multiple
  329. * instances. Attributes are given as key value pairs. Values will be HTML
  330. * encoded automatically so they should be provided as is in the $data array.
  331. *
  332. * For tags having a body attribute specify the the body data in the special
  333. * attribute '_data'. This field will NOT BE ESCAPED automatically.
  334. *
  335. * @author Andreas Gohr <andi@splitbrain.org>
  336. */
  337. function _tpl_metaheaders_action($data){
  338. foreach($data as $tag => $inst){
  339. foreach($inst as $attr){
  340. echo '<',$tag,' ',buildAttributes($attr);
  341. if(isset($attr['_data']) || $tag == 'script'){
  342. if($tag == 'script' && $attr['_data'])
  343. $attr['_data'] = "<!--//--><![CDATA[//><!--\n".
  344. $attr['_data'].
  345. "\n//--><!]]>";
  346. echo '>',$attr['_data'],'</',$tag,'>';
  347. }else{
  348. echo '/>';
  349. }
  350. echo "\n";
  351. }
  352. }
  353. }
  354. /**
  355. * Print a link
  356. *
  357. * Just builds a link.
  358. *
  359. * @author Andreas Gohr <andi@splitbrain.org>
  360. */
  361. function tpl_link($url,$name,$more='',$return=false){
  362. $out = '<a href="'.$url.'" ';
  363. if ($more) $out .= ' '.$more;
  364. $out .= ">$name</a>";
  365. if ($return) return $out;
  366. print $out;
  367. return true;
  368. }
  369. /**
  370. * Prints a link to a WikiPage
  371. *
  372. * Wrapper around html_wikilink
  373. *
  374. * @author Andreas Gohr <andi@splitbrain.org>
  375. */
  376. function tpl_pagelink($id,$name=null){
  377. print html_wikilink($id,$name);
  378. return true;
  379. }
  380. /**
  381. * get the parent page
  382. *
  383. * Tries to find out which page is parent.
  384. * returns false if none is available
  385. *
  386. * @author Andreas Gohr <andi@splitbrain.org>
  387. */
  388. function tpl_getparent($id){
  389. global $conf;
  390. $parent = getNS($id).':';
  391. resolve_pageid('',$parent,$exists);
  392. if($parent == $id) {
  393. $pos = strrpos (getNS($id),':');
  394. $parent = substr($parent,0,$pos).':';
  395. resolve_pageid('',$parent,$exists);
  396. if($parent == $id) return false;
  397. }
  398. return $parent;
  399. }
  400. /**
  401. * Print one of the buttons
  402. *
  403. * @author Adrian Lang <mail@adrianlang.de>
  404. * @see tpl_get_action
  405. */
  406. function tpl_button($type,$return=false){
  407. $data = tpl_get_action($type);
  408. if ($data === false) {
  409. return false;
  410. } elseif (!is_array($data)) {
  411. $out = sprintf($data, 'button');
  412. } else {
  413. extract($data);
  414. if ($id === '#dokuwiki__top') {
  415. $out = html_topbtn();
  416. } else {
  417. $out = html_btn($type, $id, $accesskey, $params, $method);
  418. }
  419. }
  420. if ($return) return $out;
  421. echo $out;
  422. return true;
  423. }
  424. /**
  425. * Like the action buttons but links
  426. *
  427. * @author Adrian Lang <mail@adrianlang.de>
  428. * @see tpl_get_action
  429. */
  430. function tpl_actionlink($type,$pre='',$suf='',$inner='',$return=false){
  431. global $lang;
  432. $data = tpl_get_action($type);
  433. if ($data === false) {
  434. return false;
  435. } elseif (!is_array($data)) {
  436. $out = sprintf($data, 'link');
  437. } else {
  438. extract($data);
  439. if (strpos($id, '#') === 0) {
  440. $linktarget = $id;
  441. } else {
  442. $linktarget = wl($id, $params);
  443. }
  444. $caption = $lang['btn_' . $type];
  445. $out = tpl_link($linktarget, $pre.(($inner)?$inner:$caption).$suf,
  446. 'class="action ' . $type . '" ' .
  447. 'accesskey="' . $accesskey . '" rel="nofollow" ' .
  448. 'title="' . hsc($caption) . '"', 1);
  449. }
  450. if ($return) return $out;
  451. echo $out;
  452. return true;
  453. }
  454. /**
  455. * Check the actions and get data for buttons and links
  456. *
  457. * Available actions are
  458. *
  459. * edit - edit/create/show/draft
  460. * history - old revisions
  461. * recent - recent changes
  462. * login - login/logout - if ACL enabled
  463. * profile - user profile (if logged in)
  464. * index - The index
  465. * admin - admin page - if enough rights
  466. * top - back to top
  467. * back - back to parent - if available
  468. * backlink - links to the list of backlinks
  469. * subscribe/subscription- subscribe/unsubscribe
  470. *
  471. * @author Andreas Gohr <andi@splitbrain.org>
  472. * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
  473. * @author Adrian Lang <mail@adrianlang.de>
  474. */
  475. function tpl_get_action($type) {
  476. global $ID;
  477. global $INFO;
  478. global $REV;
  479. global $ACT;
  480. global $conf;
  481. global $auth;
  482. // check disabled actions and fix the badly named ones
  483. if($type == 'history') $type='revisions';
  484. if(!actionOK($type)) return false;
  485. $accesskey = null;
  486. $id = $ID;
  487. $method = 'get';
  488. $params = array('do' => $type);
  489. switch($type){
  490. case 'edit':
  491. // most complicated type - we need to decide on current action
  492. if($ACT == 'show' || $ACT == 'search'){
  493. $method = 'post';
  494. if($INFO['writable']){
  495. $accesskey = 'e';
  496. if(!empty($INFO['draft'])) {
  497. $type = 'draft';
  498. $params['do'] = 'draft';
  499. } else {
  500. $params['rev'] = $REV;
  501. if(!$INFO['exists']){
  502. $type = 'create';
  503. }
  504. }
  505. }else{
  506. if(!actionOK('source')) return false; //pseudo action
  507. $params['rev'] = $REV;
  508. $type = 'source';
  509. $accesskey = 'v';
  510. }
  511. }else{
  512. $params = '';
  513. $type = 'show';
  514. $accesskey = 'v';
  515. }
  516. break;
  517. case 'revisions':
  518. $type = 'revs';
  519. $accesskey = 'o';
  520. break;
  521. case 'recent':
  522. $accesskey = 'r';
  523. break;
  524. case 'index':
  525. $accesskey = 'x';
  526. break;
  527. case 'top':
  528. $accesskey = 'x';
  529. $params = '';
  530. $id = '#dokuwiki__top';
  531. break;
  532. case 'back':
  533. $parent = tpl_getparent($ID);
  534. if (!$parent) {
  535. return false;
  536. }
  537. $id = $parent;
  538. $params = '';
  539. $accesskey = 'b';
  540. break;
  541. case 'login':
  542. if(!$conf['useacl'] || !$auth){
  543. return false;
  544. }
  545. $params['sectok'] = getSecurityToken();
  546. if(isset($_SERVER['REMOTE_USER'])){
  547. if (!$auth->canDo('logout')) {
  548. return false;
  549. }
  550. $params['do'] = 'logout';
  551. $type = 'logout';
  552. }
  553. break;
  554. case 'admin':
  555. if(!$INFO['ismanager']){
  556. return false;
  557. }
  558. break;
  559. case 'revert':
  560. if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) {
  561. return false;
  562. }
  563. $params['rev'] = $REV;
  564. $params['sectok'] = getSecurityToken();
  565. break;
  566. case 'subscription':
  567. $type = 'subscribe';
  568. $params['do'] = 'subscribe';
  569. case 'subscribe':
  570. if(!$conf['useacl'] || !$auth || $ACT !== 'show' || !$conf['subscribers'] || !$_SERVER['REMOTE_USER']){
  571. return false;
  572. }
  573. break;
  574. case 'backlink':
  575. break;
  576. case 'profile':
  577. if(!$conf['useacl'] || !$auth || !isset($_SERVER['REMOTE_USER']) ||
  578. !$auth->canDo('Profile') || ($ACT=='profile')){
  579. return false;
  580. }
  581. break;
  582. case 'subscribens':
  583. // Superseeded by subscribe/subscription
  584. return '';
  585. break;
  586. default:
  587. return '[unknown %s type]';
  588. break;
  589. }
  590. return compact('accesskey', 'type', 'id', 'method', 'params');
  591. }
  592. /**
  593. * Wrapper around tpl_button() and tpl_actionlink()
  594. *
  595. * @author Anika Henke <anika@selfthinker.org>
  596. */
  597. function tpl_action($type,$link=0,$wrapper=false,$return=false,$pre='',$suf='',$inner='') {
  598. $out = '';
  599. if ($link) $out .= tpl_actionlink($type,$pre,$suf,$inner,1);
  600. else $out .= tpl_button($type,1);
  601. if ($out && $wrapper) $out = "<$wrapper>$out</$wrapper>";
  602. if ($return) return $out;
  603. print $out;
  604. return $out ? true : false;
  605. }
  606. /**
  607. * Print the search form
  608. *
  609. * If the first parameter is given a div with the ID 'qsearch_out' will
  610. * be added which instructs the ajax pagequicksearch to kick in and place
  611. * its output into this div. The second parameter controls the propritary
  612. * attribute autocomplete. If set to false this attribute will be set with an
  613. * value of "off" to instruct the browser to disable it's own built in
  614. * autocompletion feature (MSIE and Firefox)
  615. *
  616. * @author Andreas Gohr <andi@splitbrain.org>
  617. */
  618. function tpl_searchform($ajax=true,$autocomplete=true){
  619. global $lang;
  620. global $ACT;
  621. global $QUERY;
  622. // don't print the search form if search action has been disabled
  623. if (!actionOk('search')) return false;
  624. print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get"><div class="no">';
  625. print '<input type="hidden" name="do" value="search" />';
  626. print '<input type="text" ';
  627. if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" ';
  628. if(!$autocomplete) print 'autocomplete="off" ';
  629. print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />';
  630. print '<input type="submit" value="'.$lang['btn_search'].'" class="button" title="'.$lang['btn_search'].'" />';
  631. if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>';
  632. print '</div></form>';
  633. return true;
  634. }
  635. /**
  636. * Print the breadcrumbs trace
  637. *
  638. * @author Andreas Gohr <andi@splitbrain.org>
  639. */
  640. function tpl_breadcrumbs($sep='&raquo;'){
  641. global $lang;
  642. global $conf;
  643. //check if enabled
  644. if(!$conf['breadcrumbs']) return false;
  645. $crumbs = breadcrumbs(); //setup crumb trace
  646. //reverse crumborder in right-to-left mode, add RLM character to fix heb/eng display mixups
  647. if($lang['direction'] == 'rtl') {
  648. $crumbs = array_reverse($crumbs,true);
  649. $crumbs_sep = ' &#8207;<span class="bcsep">'.$sep.'</span>&#8207; ';
  650. } else {
  651. $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> ';
  652. }
  653. //render crumbs, highlight the last one
  654. print '<span class="bchead">'.$lang['breadcrumb'].':</span>';
  655. $last = count($crumbs);
  656. $i = 0;
  657. foreach ($crumbs as $id => $name){
  658. $i++;
  659. echo $crumbs_sep;
  660. if ($i == $last) print '<span class="curid">';
  661. tpl_link(wl($id),hsc($name),'class="breadcrumbs" title="'.$id.'"');
  662. if ($i == $last) print '</span>';
  663. }
  664. return true;
  665. }
  666. /**
  667. * Hierarchical breadcrumbs
  668. *
  669. * This code was suggested as replacement for the usual breadcrumbs.
  670. * It only makes sense with a deep site structure.
  671. *
  672. * @author Andreas Gohr <andi@splitbrain.org>
  673. * @author Nigel McNie <oracle.shinoda@gmail.com>
  674. * @author Sean Coates <sean@caedmon.net>
  675. * @author <fredrik@averpil.com>
  676. * @todo May behave strangely in RTL languages
  677. */
  678. function tpl_youarehere($sep=' &raquo; '){
  679. global $conf;
  680. global $ID;
  681. global $lang;
  682. // check if enabled
  683. if(!$conf['youarehere']) return false;
  684. $parts = explode(':', $ID);
  685. $count = count($parts);
  686. if($GLOBALS['ACT'] == 'search')
  687. {
  688. $parts = array($conf['start']);
  689. $count = 1;
  690. }
  691. echo '<span class="bchead">'.$lang['youarehere'].': </span>';
  692. // always print the startpage
  693. $title = useHeading('navigation') ? p_get_first_heading($conf['start']) : $conf['start'];
  694. if(!$title) $title = $conf['start'];
  695. tpl_link(wl($conf['start']),hsc($title),'title="'.$conf['start'].'"');
  696. // print intermediate namespace links
  697. $part = '';
  698. for($i=0; $i<$count - 1; $i++){
  699. $part .= $parts[$i].':';
  700. $page = $part;
  701. resolve_pageid('',$page,$exists);
  702. if ($page == $conf['start']) continue; // Skip startpage
  703. // output
  704. echo $sep;
  705. if($exists){
  706. $title = useHeading('navigation') ? p_get_first_heading($page) : $parts[$i];
  707. tpl_link(wl($page),hsc($title),'title="'.$page.'"');
  708. }else{
  709. tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"');
  710. }
  711. }
  712. // print current page, skipping start page, skipping for namespace index
  713. if(isset($page) && $page==$part.$parts[$i]) return;
  714. $page = $part.$parts[$i];
  715. if($page == $conf['start']) return;
  716. echo $sep;
  717. if(page_exists($page)){
  718. $title = useHeading('navigation') ? p_get_first_heading($page) : $parts[$i];
  719. tpl_link(wl($page),hsc($title),'title="'.$page.'"');
  720. }else{
  721. tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"');
  722. }
  723. return true;
  724. }
  725. /**
  726. * Print info if the user is logged in
  727. * and show full name in that case
  728. *
  729. * Could be enhanced with a profile link in future?
  730. *
  731. * @author Andreas Gohr <andi@splitbrain.org>
  732. */
  733. function tpl_userinfo(){
  734. global $lang;
  735. global $INFO;
  736. if(isset($_SERVER['REMOTE_USER'])){
  737. print $lang['loggedinas'].': '.hsc($INFO['userinfo']['name']).' ('.hsc($_SERVER['REMOTE_USER']).')';
  738. return true;
  739. }
  740. return false;
  741. }
  742. /**
  743. * Print some info about the current page
  744. *
  745. * @author Andreas Gohr <andi@splitbrain.org>
  746. */
  747. function tpl_pageinfo($ret=false){
  748. global $conf;
  749. global $lang;
  750. global $INFO;
  751. global $ID;
  752. // return if we are not allowed to view the page
  753. if (!auth_quickaclcheck($ID)) { return false; }
  754. // prepare date and path
  755. $fn = $INFO['filepath'];
  756. if(!$conf['fullpath']){
  757. if($INFO['rev']){
  758. $fn = str_replace(fullpath($conf['olddir']).'/','',$fn);
  759. }else{
  760. $fn = str_replace(fullpath($conf['datadir']).'/','',$fn);
  761. }
  762. }
  763. $fn = utf8_decodeFN($fn);
  764. $date = dformat($INFO['lastmod']);
  765. // print it
  766. if($INFO['exists']){
  767. $out = '';
  768. $out .= $fn;
  769. $out .= ' &middot; ';
  770. $out .= $lang['lastmod'];
  771. $out .= ': ';
  772. $out .= $date;
  773. if($INFO['editor']){
  774. $out .= ' '.$lang['by'].' ';
  775. $out .= editorinfo($INFO['editor']);
  776. }else{
  777. $out .= ' ('.$lang['external_edit'].')';
  778. }
  779. if($INFO['locked']){
  780. $out .= ' &middot; ';
  781. $out .= $lang['lockedby'];
  782. $out .= ': ';
  783. $out .= editorinfo($INFO['locked']);
  784. }
  785. if($ret){
  786. return $out;
  787. }else{
  788. echo $out;
  789. return true;
  790. }
  791. }
  792. return false;
  793. }
  794. /**
  795. * Prints or returns the name of the given page (current one if none given).
  796. *
  797. * If useheading is enabled this will use the first headline else
  798. * the given ID is used.
  799. *
  800. * @author Andreas Gohr <andi@splitbrain.org>
  801. */
  802. function tpl_pagetitle($id=null, $ret=false){
  803. global $conf;
  804. if(is_null($id)){
  805. global $ID;
  806. $id = $ID;
  807. }
  808. $name = $id;
  809. if (useHeading('navigation')) {
  810. $title = p_get_first_heading($id);
  811. if ($title) $name = $title;
  812. }
  813. if ($ret) {
  814. return hsc($name);
  815. } else {
  816. print hsc($name);
  817. return true;
  818. }
  819. }
  820. /**
  821. * Returns the requested EXIF/IPTC tag from the current image
  822. *
  823. * If $tags is an array all given tags are tried until a
  824. * value is found. If no value is found $alt is returned.
  825. *
  826. * Which texts are known is defined in the functions _exifTagNames
  827. * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC
  828. * to the names of the latter one)
  829. *
  830. * Only allowed in: detail.php
  831. *
  832. * @author Andreas Gohr <andi@splitbrain.org>
  833. */
  834. function tpl_img_getTag($tags,$alt='',$src=null){
  835. // Init Exif Reader
  836. global $SRC;
  837. if(is_null($src)) $src = $SRC;
  838. static $meta = null;
  839. if(is_null($meta)) $meta = new JpegMeta($src);
  840. if($meta === false) return $alt;
  841. $info = $meta->getField($tags);
  842. if($info == false) return $alt;
  843. return $info;
  844. }
  845. /**
  846. * Prints the image with a link to the full sized version
  847. *
  848. * Only allowed in: detail.php
  849. *
  850. * @param $maxwidth int - maximal width of the image
  851. * @param $maxheight int - maximal height of the image
  852. * @param $link bool - link to the orginal size?
  853. * @param $params array - additional image attributes
  854. */
  855. function tpl_img($maxwidth=0,$maxheight=0,$link=true,$params=null){
  856. global $IMG;
  857. $w = tpl_img_getTag('File.Width');
  858. $h = tpl_img_getTag('File.Height');
  859. //resize to given max values
  860. $ratio = 1;
  861. if($w >= $h){
  862. if($maxwidth && $w >= $maxwidth){
  863. $ratio = $maxwidth/$w;
  864. }elseif($maxheight && $h > $maxheight){
  865. $ratio = $maxheight/$h;
  866. }
  867. }else{
  868. if($maxheight && $h >= $maxheight){
  869. $ratio = $maxheight/$h;
  870. }elseif($maxwidth && $w > $maxwidth){
  871. $ratio = $maxwidth/$w;
  872. }
  873. }
  874. if($ratio){
  875. $w = floor($ratio*$w);
  876. $h = floor($ratio*$h);
  877. }
  878. //prepare URLs
  879. $url=ml($IMG,array('cache'=>$_REQUEST['cache']),true,'&');
  880. $src=ml($IMG,array('cache'=>$_REQUEST['cache'],'w'=>$w,'h'=>$h),true,'&');
  881. //prepare attributes
  882. $alt=tpl_img_getTag('Simple.Title');
  883. if(is_null($params)){
  884. $p = array();
  885. }else{
  886. $p = $params;
  887. }
  888. if($w) $p['width'] = $w;
  889. if($h) $p['height'] = $h;
  890. $p['class'] = 'img_detail';
  891. if($alt){
  892. $p['alt'] = $alt;
  893. $p['title'] = $alt;
  894. }else{
  895. $p['alt'] = '';
  896. }
  897. $p['src'] = $src;
  898. $data = array('url'=>($link?$url:null), 'params'=>$p);
  899. return trigger_event('TPL_IMG_DISPLAY',$data,'_tpl_img_action',true);
  900. }
  901. /**
  902. * Default action for TPL_IMG_DISPLAY
  903. */
  904. function _tpl_img_action($data, $param=NULL) {
  905. $p = buildAttributes($data['params']);
  906. if($data['url']) print '<a href="'.hsc($data['url']).'">';
  907. print '<img '.$p.'/>';
  908. if($data['url']) print '</a>';
  909. return true;
  910. }
  911. /**
  912. * This function inserts a 1x1 pixel gif which in reality
  913. * is the indexer function.
  914. *
  915. * Should be called somewhere at the very end of the main.php
  916. * template
  917. */
  918. function tpl_indexerWebBug(){
  919. global $ID;
  920. global $INFO;
  921. if(!$INFO['exists']) return false;
  922. if(isHiddenPage($ID)) return false; //no need to index hidden pages
  923. $p = array();
  924. $p['src'] = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID).
  925. '&'.time();
  926. $p['width'] = 1;
  927. $p['height'] = 1;
  928. $p['alt'] = '';
  929. $att = buildAttributes($p);
  930. print "<img $att />";
  931. return true;
  932. }
  933. // configuration methods
  934. /**
  935. * tpl_getConf($id)
  936. *
  937. * use this function to access template configuration variables
  938. */
  939. function tpl_getConf($id){
  940. global $conf;
  941. static $tpl_configloaded = false;
  942. $tpl = $conf['template'];
  943. if (!$tpl_configloaded){
  944. $tconf = tpl_loadConfig();
  945. if ($tconf !== false){
  946. foreach ($tconf as $key => $value){
  947. if (isset($conf['tpl'][$tpl][$key])) continue;
  948. $conf['tpl'][$tpl][$key] = $value;
  949. }
  950. $tpl_configloaded = true;
  951. }
  952. }
  953. return $conf['tpl'][$tpl][$id];
  954. }
  955. /**
  956. * tpl_loadConfig()
  957. * reads all template configuration variables
  958. * this function is automatically called by tpl_getConf()
  959. */
  960. function tpl_loadConfig(){
  961. $file = DOKU_TPLINC.'/conf/default.php';
  962. $conf = array();
  963. if (!@file_exists($file)) return false;
  964. // load default config file
  965. include($file);
  966. return $conf;
  967. }
  968. // language methods
  969. /**
  970. * tpl_getLang($id)
  971. *
  972. * use this function to access template language variables
  973. */
  974. function tpl_getLang($id){
  975. static $lang = array();
  976. if (count($lang) === 0){
  977. $path = DOKU_TPLINC.'lang/';
  978. $lang = array();
  979. global $conf; // definitely don't invoke "global $lang"
  980. // don't include once
  981. @include($path.'en/lang.php');
  982. if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
  983. }
  984. return $lang[$id];
  985. }
  986. /**
  987. * prints the "main content" in the mediamanger popup
  988. *
  989. * Depending on the user's actions this may be a list of
  990. * files in a namespace, the meta editing dialog or
  991. * a message of referencing pages
  992. *
  993. * Only allowed in mediamanager.php
  994. *
  995. * @triggers MEDIAMANAGER_CONTENT_OUTPUT
  996. * @param bool $fromajax - set true when calling this function via ajax
  997. * @author Andreas Gohr <andi@splitbrain.org>
  998. */
  999. function tpl_mediaContent($fromajax=false){
  1000. global $IMG;
  1001. global $AUTH;
  1002. global $INUSE;
  1003. global $NS;
  1004. global $JUMPTO;
  1005. if(is_array($_REQUEST['do'])){
  1006. $do = array_shift(array_keys($_REQUEST['do']));
  1007. }else{
  1008. $do = $_REQUEST['do'];
  1009. }
  1010. if(in_array($do,array('save','cancel'))) $do = '';
  1011. if(!$do){
  1012. if($_REQUEST['edit']){
  1013. $do = 'metaform';
  1014. }elseif(is_array($INUSE)){
  1015. $do = 'filesinuse';
  1016. }else{
  1017. $do = 'filelist';
  1018. }
  1019. }
  1020. // output the content pane, wrapped in an event.
  1021. if(!$fromajax) ptln('<div id="media__content">');
  1022. $data = array( 'do' => $do);
  1023. $evt = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data);
  1024. if ($evt->advise_before()) {
  1025. $do = $data['do'];
  1026. if($do == 'metaform'){
  1027. media_metaform($IMG,$AUTH);
  1028. }elseif($do == 'filesinuse'){
  1029. media_filesinuse($INUSE,$IMG);
  1030. }elseif($do == 'filelist'){
  1031. media_filelist($NS,$AUTH,$JUMPTO);
  1032. }elseif($do == 'searchlist'){
  1033. media_searchlist($_REQUEST['q'],$NS,$AUTH);
  1034. }else{
  1035. msg('Unknown action '.hsc($do),-1);
  1036. }
  1037. }
  1038. $evt->advise_after();
  1039. unset($evt);
  1040. if(!$fromajax) ptln('</div>');
  1041. }
  1042. /**
  1043. * prints the namespace tree in the mediamanger popup
  1044. *
  1045. * Only allowed in mediamanager.php
  1046. *
  1047. * @author Andreas Gohr <andi@splitbrain.org>
  1048. */
  1049. function tpl_mediaTree(){
  1050. global $NS;
  1051. ptln('<div id="media__tree">');
  1052. media_nstree($NS);
  1053. ptln('</div>');
  1054. }
  1055. /**
  1056. * Print a dropdown menu with all DokuWiki actions
  1057. *
  1058. * Note: this will not use any pretty URLs
  1059. *
  1060. * @author Andreas Gohr <andi@splitbrain.org>
  1061. */
  1062. function tpl_actiondropdown($empty='',$button='&gt;'){
  1063. global $ID;
  1064. global $INFO;
  1065. global $REV;
  1066. global $ACT;
  1067. global $conf;
  1068. global $lang;
  1069. global $auth;
  1070. echo '<form action="' . DOKU_SCRIPT . '" method="post" accept-charset="utf-8">';
  1071. echo '<input type="hidden" name="id" value="'.$ID.'" />';
  1072. if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />';
  1073. echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
  1074. echo '<select name="do" id="action__selector" class="edit">';
  1075. echo '<option value="">'.$empty.'</option>';
  1076. echo '<optgroup label=" &mdash; ">';
  1077. $act = tpl_get_action('edit');
  1078. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1079. $act = tpl_get_action('revisions');
  1080. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1081. $act = tpl_get_action('revert');
  1082. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1083. $act = tpl_get_action('backlink');
  1084. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1085. echo '</optgroup>';
  1086. echo '<optgroup label=" &mdash; ">';
  1087. $act = tpl_get_action('recent');
  1088. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1089. $act = tpl_get_action('index');
  1090. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1091. echo '</optgroup>';
  1092. echo '<optgroup label=" &mdash; ">';
  1093. $act = tpl_get_action('login');
  1094. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1095. $act = tpl_get_action('profile');
  1096. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1097. $act = tpl_get_action('subscribe');
  1098. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1099. $act = tpl_get_action('admin');
  1100. if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>';
  1101. echo '</optgroup>';
  1102. echo '</select>';
  1103. echo '<input type="submit" value="'.$button.'" id="action__selectorbtn" />';
  1104. echo '</form>';
  1105. }
  1106. /**
  1107. * Print a informational line about the used license
  1108. *
  1109. * @author Andreas Gohr <andi@splitbrain.org>
  1110. * @param string $img - print image? (|button|badge)
  1111. * @param bool $return - when true don't print, but return HTML
  1112. */
  1113. function tpl_license($img='badge',$imgonly=false,$return=false){
  1114. global $license;
  1115. global $conf;
  1116. global $lang;
  1117. if(!$conf['license']) return '';
  1118. if(!is_array($license[$conf['license']])) return '';
  1119. $lic = $license[$conf['license']];
  1120. $out = '<div class="license">';
  1121. if($img){
  1122. $src = license_img($img);
  1123. if($src){
  1124. $out .= '<a href="'.$lic['url'].'" rel="license"';
  1125. if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
  1126. $out .= '><img src="'.DOKU_BASE.$src.'" class="medialeft lic'.$img.'" alt="'.$lic['name'].'" /></a> ';
  1127. }
  1128. }
  1129. if(!$imgonly) {
  1130. $out .= $lang['license'];
  1131. $out .= '<a href="'.$lic['url'].'" rel="license" class="urlextern"';
  1132. if($conf['target']['extern']) $out .= ' target="'.$conf['target']['extern'].'"';
  1133. $out .= '>'.$lic['name'].'</a>';
  1134. }
  1135. $out .= '</div>';
  1136. if($return) return $out;
  1137. echo $out;
  1138. }
  1139. /**
  1140. * Includes the rendered XHTML of a given page
  1141. *
  1142. * This function is useful to populate sidebars or similar features in a
  1143. * template
  1144. */
  1145. function tpl_include_page($pageid,$print=true){
  1146. global $ID;
  1147. $oldid = $ID;
  1148. $html = p_wiki_xhtml($pageid,'',false);
  1149. $ID = $oldid;
  1150. if(!$print) return $html;
  1151. echo $html;
  1152. }
  1153. /**
  1154. * Display the subscribe form
  1155. *
  1156. * @author Adrian Lang <lang@cosmocode.de>
  1157. */
  1158. function tpl_subscribe() {
  1159. global $INFO;
  1160. global $ID;
  1161. global $lang;
  1162. global $conf;
  1163. $stime_days = $conf['subscribe_time']/60/60/24;
  1164. echo p_locale_xhtml('subscr_form');
  1165. echo '<h2>' . $lang['subscr_m_current_header'] . '</h2>';
  1166. echo '<div class="level2">';
  1167. if ($INFO['subscribed'] === false) {
  1168. echo '<p>' . $lang['subscr_m_not_subscribed'] . '</p>';
  1169. } else {
  1170. echo '<ul>';
  1171. foreach($INFO['subscribed'] as $sub) {
  1172. echo '<li><div class="li">';
  1173. if ($sub['target'] !== $ID) {
  1174. echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>';
  1175. } else {
  1176. echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>';
  1177. }
  1178. $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days);
  1179. if(!$sstl) $sstl = hsc($sub['style']);
  1180. echo ' ('.$sstl.') ';
  1181. echo '<a href="' . wl($ID,
  1182. array('do'=>'subscribe',
  1183. 'sub_target'=>$sub['target'],
  1184. 'sub_style'=>$sub['style'],
  1185. 'sub_action'=>'unsubscribe',
  1186. 'sectok' => getSecurityToken())) .
  1187. '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'] .
  1188. '</a></div></li>';
  1189. }
  1190. echo '</ul>';
  1191. }
  1192. echo '</div>';
  1193. // Add new subscription form
  1194. echo '<h2>' . $lang['subscr_m_new_header'] . '</h2>';
  1195. echo '<div class="level2">';
  1196. $ns = getNS($ID).':';
  1197. $targets = array(
  1198. $ID => '<code class="page">'.prettyprint_id($ID).'</code>',
  1199. $ns => '<code class="ns">'.prettyprint_id($ns).'</code>',
  1200. );
  1201. $styles = array(
  1202. 'every' => $lang['subscr_style_every'],
  1203. 'digest' => sprintf($lang['subscr_style_digest'], $stime_days),
  1204. 'list' => sprintf($lang['subscr_style_list'], $stime_days),
  1205. );
  1206. $form = new Doku_Form(array('id' => 'subscribe__form'));
  1207. $form->startFieldset($lang['subscr_m_subscribe']);
  1208. $form->addRadioSet('sub_target', $targets);
  1209. $form->startFieldset($lang['subscr_m_receive']);
  1210. $form->addRadioSet('sub_style', $styles);
  1211. $form->addHidden('sub_action', 'subscribe');
  1212. $form->addHidden('do', 'subscribe');
  1213. $form->addHidden('id', $ID);
  1214. $form->endFieldset();
  1215. $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe']));
  1216. html_form('SUBSCRIBE', $form);
  1217. echo '</div>';
  1218. }
  1219. /**
  1220. * Tries to send already created content right to the browser
  1221. *
  1222. * Wraps around ob_flush() and flush()
  1223. *
  1224. * @author Andreas Gohr <andi@splitbrain.org>
  1225. */
  1226. function tpl_flush(){
  1227. ob_flush();
  1228. flush();
  1229. }
  1230. //Setup VIM: ex: et ts=4 enc=utf-8 :