PageRenderTime 53ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/www/wiki/inc/template.php

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