1<?php 2/** 3 * All output and handler function needed for the media management popup 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/'); 10if(!defined('NL')) define('NL',"\n"); 11 12require_once(DOKU_INC.'inc/html.php'); 13require_once(DOKU_INC.'inc/search.php'); 14require_once(DOKU_INC.'inc/JpegMeta.php'); 15 16/** 17 * Lists pages which currently use a media file selected for deletion 18 * 19 * References uses the same visual as search results and share 20 * their CSS tags except pagenames won't be links. 21 * 22 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 23 */ 24function media_filesinuse($data,$id){ 25 global $lang; 26 echo '<h1>'.$lang['reference'].' <code>'.hsc(noNS($id)).'</code></h1>'; 27 echo '<p>'.hsc($lang['ref_inuse']).'</p>'; 28 29 $hidden=0; //count of hits without read permission 30 foreach($data as $row){ 31 if(auth_quickaclcheck($row) >= AUTH_READ && isVisiblePage($row)){ 32 echo '<div class="search_result">'; 33 echo '<span class="mediaref_ref">'.hsc($row).'</span>'; 34 echo '</div>'; 35 }else 36 $hidden++; 37 } 38 if ($hidden){ 39 print '<div class="mediaref_hidden">'.$lang['ref_hidden'].'</div>'; 40 } 41} 42 43/** 44 * Handles the saving of image meta data 45 * 46 * @author Andreas Gohr <andi@splitbrain.org> 47 */ 48function media_metasave($id,$auth,$data){ 49 if($auth < AUTH_UPLOAD) return false; 50 if(!checkSecurityToken()) return false; 51 global $lang; 52 global $conf; 53 $src = mediaFN($id); 54 55 $meta = new JpegMeta($src); 56 $meta->_parseAll(); 57 58 foreach($data as $key => $val){ 59 $val=trim($val); 60 if(empty($val)){ 61 $meta->deleteField($key); 62 }else{ 63 $meta->setField($key,$val); 64 } 65 } 66 67 if($meta->save()){ 68 if($conf['fperm']) chmod($src, $conf['fperm']); 69 msg($lang['metasaveok'],1); 70 return $id; 71 }else{ 72 msg($lang['metasaveerr'],-1); 73 return false; 74 } 75} 76 77/** 78 * Display the form to edit image meta data 79 * 80 * @author Andreas Gohr <andi@splitbrain.org> 81 */ 82function media_metaform($id,$auth){ 83 if($auth < AUTH_UPLOAD) return false; 84 global $lang; 85 86 // load the field descriptions 87 static $fields = null; 88 if(is_null($fields)){ 89 include(DOKU_CONF.'mediameta.php'); 90 if(@file_exists(DOKU_CONF.'mediameta.local.php')){ 91 include(DOKU_CONF.'mediameta.local.php'); 92 } 93 } 94 95 $src = mediaFN($id); 96 97 // output 98 echo '<h1>'.hsc(noNS($id)).'</h1>'.NL; 99 echo '<form action="'.DOKU_BASE.'lib/exe/mediamanager.php" accept-charset="utf-8" method="post" class="meta">'.NL; 100 formSecurityToken(); 101 foreach($fields as $key => $field){ 102 // get current value 103 $tags = array($field[0]); 104 if(is_array($field[3])) $tags = array_merge($tags,$field[3]); 105 $value = tpl_img_getTag($tags,'',$src); 106 $value = cleanText($value); 107 108 // prepare attributes 109 $p = array(); 110 $p['class'] = 'edit'; 111 $p['id'] = 'meta__'.$key; 112 $p['name'] = 'meta['.$field[0].']'; 113 114 // put label 115 echo '<div class="metafield">'; 116 echo '<label for="meta__'.$key.'">'; 117 echo ($lang[$field[1]]) ? $lang[$field[1]] : $field[1]; 118 echo ':</label>'; 119 120 // put input field 121 if($field[2] == 'text'){ 122 $p['value'] = $value; 123 $p['type'] = 'text'; 124 $att = buildAttributes($p); 125 echo "<input $att/>".NL; 126 }else{ 127 $att = buildAttributes($p); 128 echo "<textarea $att rows=\"6\" cols=\"50\">".formText($value).'</textarea>'.NL; 129 } 130 echo '</div>'.NL; 131 } 132 echo '<div class="buttons">'.NL; 133 echo '<input type="hidden" name="img" value="'.hsc($id).'" />'.NL; 134 echo '<input name="do[save]" type="submit" value="'.$lang['btn_save']. 135 '" title="ALT+S" accesskey="s" class="button" />'.NL; 136 echo '<input name="do[cancel]" type="submit" value="'.$lang['btn_cancel']. 137 '" title="ALT+C" accesskey="c" class="button" />'.NL; 138 echo '</div>'.NL; 139 echo '</form>'.NL; 140} 141 142 143/** 144 * Handles media file deletions 145 * 146 * If configured, checks for media references before deletion 147 * 148 * @author Andreas Gohr <andi@splitbrain.org> 149 * @return mixed false on error, true on delete or array with refs 150 */ 151function media_delete($id,$auth){ 152 if($auth < AUTH_DELETE) return false; 153 if(!checkSecurityToken()) return false; 154 global $conf; 155 global $lang; 156 157 // check for references if needed 158 $mediareferences = array(); 159 if($conf['refcheck']){ 160 require_once(DOKU_INC.'inc/fulltext.php'); 161 $mediareferences = ft_mediause($id,$conf['refshow']); 162 } 163 164 if(!count($mediareferences)){ 165 $file = mediaFN($id); 166 if(@unlink($file)){ 167 msg(str_replace('%s',noNS($id),$lang['deletesucc']),1); 168 $del = io_sweepNS($id,'mediadir'); 169 if($del){ 170 // current namespace was removed. redirecting to root ns passing msg along 171 header('Location: '.DOKU_URL.'lib/exe/mediamanager.php?msg1='. 172 rawurlencode(str_replace('%s',noNS($id),$lang['deletesucc']))); 173 exit; 174 } 175 return true; 176 } 177 //something went wrong 178 msg(str_replace('%s',$file,$lang['deletefail']),-1); 179 return false; 180 }elseif(!$conf['refshow']){ 181 msg(str_replace('%s',noNS($id),$lang['mediainuse']),0); 182 return false; 183 } 184 185 return $mediareferences; 186} 187 188/** 189 * Handles media file uploads 190 * 191 * This generates an action event and delegates to _media_upload_action(). 192 * Action plugins are allowed to pre/postprocess the uploaded file. 193 * (The triggered event is preventable.) 194 * 195 * Event data: 196 * $data[0] fn_tmp: the temporary file name (read from $_FILES) 197 * $data[1] fn: the file name of the uploaded file 198 * $data[2] id: the future directory id of the uploaded file 199 * $data[3] imime: the mimetype of the uploaded file 200 * 201 * @triggers MEDIA_UPLOAD_FINISH 202 * @author Andreas Gohr <andi@splitbrain.org> 203 * @author Michael Klier <chi@chimeric.de> 204 * @return mixed false on error, id of the new file on success 205 */ 206function media_upload($ns,$auth){ 207 if($auth < AUTH_UPLOAD) return false; 208 if(!checkSecurityToken()) return false; 209 require_once(DOKU_INC.'inc/confutils.php'); 210 global $lang; 211 global $conf; 212 213 // get file and id 214 $id = $_POST['id']; 215 $file = $_FILES['upload']; 216 if(empty($id)) $id = $file['name']; 217 218 // check for data 219 if(!@filesize($file['tmp_name'])){ 220 msg('No data uploaded. Disk full?',-1); 221 return false; 222 } 223 224 // check extensions 225 list($fext,$fmime) = mimetype($file['name']); 226 list($iext,$imime) = mimetype($id); 227 if($fext && !$iext){ 228 // no extension specified in id - read original one 229 $id .= '.'.$fext; 230 $imime = $fmime; 231 }elseif($fext && $fext != $iext){ 232 // extension was changed, print warning 233 msg(sprintf($lang['mediaextchange'],$fext,$iext)); 234 } 235 236 // get filename 237 $id = cleanID($ns.':'.$id); 238 $fn = mediaFN($id); 239 240 // get filetype regexp 241 $types = array_keys(getMimeTypes()); 242 $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); 243 $regex = join('|',$types); 244 245 // because a temp file was created already 246 if(preg_match('/\.('.$regex.')$/i',$fn)){ 247 //check for overwrite 248 if(@file_exists($fn) && (!$_REQUEST['ow'] || $auth < AUTH_DELETE)){ 249 msg($lang['uploadexist'],0); 250 return false; 251 } 252 // check for valid content 253 $ok = media_contentcheck($file['tmp_name'],$imime); 254 if($ok == -1){ 255 msg(sprintf($lang['uploadbadcontent'],".$iext"),-1); 256 return false; 257 }elseif($ok == -2){ 258 msg($lang['uploadspam'],-1); 259 return false; 260 }elseif($ok == -3){ 261 msg($lang['uploadxss'],-1); 262 return false; 263 } 264 265 // prepare event data 266 $data[0] = $file['tmp_name']; 267 $data[1] = $fn; 268 $data[2] = $id; 269 $data[3] = $imime; 270 271 // trigger event 272 return trigger_event('MEDIA_UPLOAD_FINISH', $data, '_media_upload_action', true); 273 274 }else{ 275 msg($lang['uploadwrong'],-1); 276 } 277 return false; 278} 279 280/** 281 * Callback adapter for media_upload_finish() 282 * @author Michael Klier <chi@chimeric.de> 283 */ 284function _media_upload_action($data) { 285 // fixme do further sanity tests of given data? 286 if(is_array($data) && count($data)===4) { 287 return media_upload_finish($data[0], $data[1], $data[2], $data[3]); 288 } else { 289 return false; //callback error 290 } 291} 292 293/** 294 * Saves an uploaded media file 295 * 296 * @author Andreas Gohr <andi@splitbrain.org> 297 * @author Michael Klier <chi@chimeric.de> 298 */ 299function media_upload_finish($fn_tmp, $fn, $id, $imime) { 300 global $conf; 301 global $lang; 302 303 // prepare directory 304 io_createNamespace($id, 'media'); 305 306 if(move_uploaded_file($fn_tmp, $fn)) { 307 // Set the correct permission here. 308 // Always chmod media because they may be saved with different permissions than expected from the php umask. 309 // (Should normally chmod to $conf['fperm'] only if $conf['fperm'] is set.) 310 chmod($fn, $conf['fmode']); 311 msg($lang['uploadsucc'],1); 312 media_notify($id,$fn,$imime); 313 return $id; 314 }else{ 315 msg($lang['uploadfail'],-1); 316 } 317} 318 319/** 320 * This function checks if the uploaded content is really what the 321 * mimetype says it is. We also do spam checking for text types here. 322 * 323 * We need to do this stuff because we can not rely on the browser 324 * to do this check correctly. Yes, IE is broken as usual. 325 * 326 * @author Andreas Gohr <andi@splitbrain.org> 327 * @link http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting 328 * @fixme check all 26 magic IE filetypes here? 329 */ 330function media_contentcheck($file,$mime){ 331 global $conf; 332 if($conf['iexssprotect']){ 333 $fh = @fopen($file, 'rb'); 334 if($fh){ 335 $bytes = fread($fh, 256); 336 fclose($fh); 337 if(preg_match('/<(script|a|img|html|body|iframe)[\s>]/i',$bytes)){ 338 return -3; 339 } 340 } 341 } 342 if(substr($mime,0,6) == 'image/'){ 343 $info = @getimagesize($file); 344 if($mime == 'image/gif' && $info[2] != 1){ 345 return -1; 346 }elseif($mime == 'image/jpeg' && $info[2] != 2){ 347 return -1; 348 }elseif($mime == 'image/png' && $info[2] != 3){ 349 return -1; 350 } 351 # fixme maybe check other images types as well 352 }elseif(substr($mime,0,5) == 'text/'){ 353 global $TEXT; 354 $TEXT = io_readFile($file); 355 if(checkwordblock()){ 356 return -2; 357 } 358 } 359 return 0; 360} 361 362/** 363 * Send a notify mail on uploads 364 * 365 * @author Andreas Gohr <andi@splitbrain.org> 366 */ 367function media_notify($id,$file,$mime){ 368 global $lang; 369 global $conf; 370 if(empty($conf['notify'])) return; //notify enabled? 371 372 $text = rawLocale('uploadmail'); 373 $text = str_replace('@DATE@',strftime($conf['dformat']),$text); 374 $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); 375 $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text); 376 $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text); 377 $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); 378 $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); 379 $text = str_replace('@MIME@',$mime,$text); 380 $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text); 381 $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text); 382 383 $from = $conf['mailfrom']; 384 $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from); 385 $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from); 386 $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from); 387 388 $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id; 389 390 mail_send($conf['notify'],$subject,$text,$from); 391} 392 393/** 394 * List all files in a given Media namespace 395 */ 396function media_filelist($ns,$auth=null,$jump=''){ 397 global $conf; 398 global $lang; 399 $ns = cleanID($ns); 400 401 // check auth our self if not given (needed for ajax calls) 402 if(is_null($auth)) $auth = auth_quickaclcheck("$ns:*"); 403 404 echo '<h1 id="media__ns">:'.hsc($ns).'</h1>'.NL; 405 406 if($auth < AUTH_READ){ 407 // FIXME: print permission warning here instead? 408 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 409 return; 410 } 411 412 media_uploadform($ns, $auth); 413 414 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 415 $data = array(); 416 search($data,$conf['mediadir'],'search_media',array('showmsg'=>true),$dir); 417 418 if(!count($data)){ 419 echo '<div class="nothing">'.$lang['nothingfound'].'</div>'.NL; 420 return; 421 } 422 423 foreach($data as $item){ 424 media_printfile($item,$auth,$jump); 425 } 426} 427 428/** 429 * Print action links for a file depending on filetype 430 * and available permissions 431 * 432 * @todo contains inline javascript 433 */ 434function media_fileactions($item,$auth){ 435 global $lang; 436 437 // view button 438 $link = ml($item['id'],'',true); 439 echo ' <a href="'.$link.'" target="_blank"><img src="'.DOKU_BASE.'lib/images/magnifier.png" '. 440 'alt="'.$lang['mediaview'].'" title="'.$lang['mediaview'].'" class="btn" /></a>'; 441 442 443 // no further actions if not writable 444 if(!$item['writable']) return; 445 446 // delete button 447 if($auth >= AUTH_DELETE){ 448 $ask = addslashes($lang['del_confirm']).'\\n'; 449 $ask .= addslashes($item['id']); 450 451 echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?delete='.rawurlencode($item['id']). 452 '&sectok='.getSecurityToken().'" '. 453 'onclick="return confirm(\''.$ask.'\')">'. 454 '<img src="'.DOKU_BASE.'lib/images/trash.png" alt="'.$lang['btn_delete'].'" '. 455 'title="'.$lang['btn_delete'].'" class="btn" /></a>'; 456 } 457 458 // edit button 459 if($auth >= AUTH_UPLOAD && $item['isimg'] && $item['meta']->getField('File.Mime') == 'image/jpeg'){ 460 echo ' <a href="'.DOKU_BASE.'lib/exe/mediamanager.php?edit='.rawurlencode($item['id']).'">'. 461 '<img src="'.DOKU_BASE.'lib/images/pencil.png" alt="'.$lang['metaedit'].'" '. 462 'title="'.$lang['metaedit'].'" class="btn" /></a>'; 463 } 464 465} 466 467/** 468 * Formats and prints one file in the list 469 */ 470function media_printfile($item,$auth,$jump){ 471 global $lang; 472 global $conf; 473 474 // Prepare zebra coloring 475 // I always wanted to use this variable name :-D 476 static $twibble = 1; 477 $twibble *= -1; 478 $zebra = ($twibble == -1) ? 'odd' : 'even'; 479 480 // Automatically jump to recent action 481 if($jump == $item['id']) { 482 $jump = ' id="scroll__here" '; 483 }else{ 484 $jump = ''; 485 } 486 487 // Prepare fileicons 488 list($ext,$mime) = mimetype($item['file']); 489 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 490 $class = 'select mediafile mf_'.$class; 491 492 // Prepare filename 493 $file = utf8_decodeFN($item['file']); 494 495 // Prepare info 496 $info = ''; 497 if($item['isimg']){ 498 $info .= (int) $item['meta']->getField('File.Width'); 499 $info .= '×'; 500 $info .= (int) $item['meta']->getField('File.Height'); 501 $info .= ' '; 502 } 503 $info .= '<i>'.strftime($conf['dformat'],$item['mtime']).'</i>'; 504 $info .= ' '; 505 $info .= filesize_h($item['size']); 506 507 // ouput 508 echo '<div class="'.$zebra.'"'.$jump.'>'.NL; 509 echo '<a name="h_'.$item['id'].'" class="'.$class.'">'.$file.'</a> '; 510 echo '<span class="info">('.$info.')</span>'.NL; 511 media_fileactions($item,$auth); 512 echo '<div class="example" id="ex_'.str_replace(':','_',$item['id']).'">'; 513 echo $lang['mediausage'].' <code>{{:'.$item['id'].'}}</code>'; 514 echo '</div>'; 515 if($item['isimg']) media_printimgdetail($item); 516 echo '<div class="clearer"></div>'.NL; 517 echo '</div>'.NL; 518} 519 520/** 521 * Prints a thumbnail and metainfos 522 */ 523function media_printimgdetail($item){ 524 // prepare thumbnail 525 $w = (int) $item['meta']->getField('File.Width'); 526 $h = (int) $item['meta']->getField('File.Height'); 527 if($w>120 || $h>120){ 528 $ratio = $item['meta']->getResizeRatio(120); 529 $w = floor($w * $ratio); 530 $h = floor($h * $ratio); 531 } 532 $src = ml($item['id'],array('w'=>$w,'h'=>$h)); 533 $p = array(); 534 $p['width'] = $w; 535 $p['height'] = $h; 536 $p['alt'] = $item['id']; 537 $p['class'] = 'thumb'; 538 $att = buildAttributes($p); 539 540 // output 541 echo '<div class="detail">'; 542 echo '<div class="thumb">'; 543 echo '<a name="d_'.$item['id'].'" class="select">'; 544 echo '<img src="'.$src.'" '.$att.' />'; 545 echo '</a>'; 546 echo '</div>'; 547 548 // read EXIF/IPTC data 549 $t = $item['meta']->getField(array('IPTC.Headline','xmp.dc:title')); 550 $d = $item['meta']->getField(array('IPTC.Caption','EXIF.UserComment', 551 'EXIF.TIFFImageDescription', 552 'EXIF.TIFFUserComment')); 553 if(utf8_strlen($d) > 250) $d = utf8_substr($d,0,250).'...'; 554 $k = $item['meta']->getField(array('IPTC.Keywords','IPTC.Category','xmp.dc:subject')); 555 556 // print EXIF/IPTC data 557 if($t || $d || $k ){ 558 echo '<p>'; 559 if($t) echo '<strong>'.htmlspecialchars($t).'</strong><br />'; 560 if($d) echo htmlspecialchars($d).'<br />'; 561 if($t) echo '<em>'.htmlspecialchars($k).'</em>'; 562 echo '</p>'; 563 } 564 echo '</div>'; 565} 566 567/** 568 * Print the media upload form if permissions are correct 569 * 570 * @author Andreas Gohr <andi@splitbrain.org> 571 */ 572function media_uploadform($ns, $auth){ 573 global $lang; 574 575 if($auth < AUTH_UPLOAD) return; //fixme print info on missing permissions? 576 577 // The default HTML upload form 578 $form = new Doku_Form('dw__upload', DOKU_BASE.'lib/exe/mediamanager.php', false, 'multipart/form-data'); 579 $form->addElement('<div class="upload">' . $lang['mediaupload'] . '</div>'); 580 $form->addElement(formSecurityToken()); 581 $form->addHidden('ns', hsc($ns)); 582 $form->addElement(form_makeOpenTag('p')); 583 $form->addElement(form_makeFileField('upload', $lang['txt_upload'].':', 'upload__file')); 584 $form->addElement(form_makeCloseTag('p')); 585 $form->addElement(form_makeOpenTag('p')); 586 $form->addElement(form_makeTextField('id', '', $lang['txt_filename'].':', 'upload__name')); 587 $form->addElement(form_makeButton('submit', '', $lang['btn_upload'])); 588 $form->addElement(form_makeCloseTag('p')); 589 590 if($auth >= AUTH_DELETE){ 591 $form->addElement(form_makeOpenTag('p')); 592 $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check')); 593 $form->addElement(form_makeCloseTag('p')); 594 } 595 html_form('upload', $form); 596 597 // prepare flashvars for multiupload 598 $opt = array( 599 'L_gridname' => $lang['mu_gridname'] , 600 'L_gridsize' => $lang['mu_gridsize'] , 601 'L_gridstat' => $lang['mu_gridstat'] , 602 'L_namespace' => $lang['mu_namespace'] , 603 'L_overwrite' => $lang['txt_overwrt'], 604 'L_browse' => $lang['mu_browse'], 605 'L_upload' => $lang['btn_upload'], 606 'L_toobig' => $lang['mu_toobig'], 607 'L_ready' => $lang['mu_ready'], 608 'L_done' => $lang['mu_done'], 609 'L_fail' => $lang['mu_fail'], 610 'L_authfail' => $lang['mu_authfail'], 611 'L_progress' => $lang['mu_progress'], 612 'L_filetypes' => $lang['mu_filetypes'], 613 614 'O_ns' => ":$ns", 615 'O_backend' => 'mediamanager.php?'.session_name().'='.session_id(), 616 'O_size' => php_to_byte(ini_get('upload_max_filesize')), 617 'O_extensions'=> join('|',array_keys(getMimeTypes())), 618 'O_overwrite' => ($auth >= AUTH_DELETE), 619 'O_sectok' => getSecurityToken(), 620 'O_authtok' => auth_createToken(), 621 ); 622 $var = buildURLparams($opt,'&'); 623 // output the flash uploader 624 ?> 625 <div id="dw__flashupload" style="display:none"> 626 <div class="upload"><?php echo $lang['mu_intro']?></div> 627 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" 628 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> 629 <param name="movie" value="multipleUpload.swf?t=<?=time()?>" /> 630 <param name="quality" value="high" /> 631 <param name="bgcolor" value="#ffffff" /> 632 <param name="FlashVars" value="<?php echo $var?>" /> 633 <embed src="multipleUpload.swf?t=<?=time()?>" quality="high" bgcolor="#ffffff" 634 width="100%" height="100%" name="fileUpload" align="middle" 635 play="true" loop="false" quality="high" FlashVars="<?php echo $var?>" 636 allowScriptAccess="sameDomain" 637 type="application/x-shockwave-flash" 638 pluginspage="http://www.macromedia.com/go/getflashplayer"> 639 </embed> 640 </object> 641 </div> 642 <?php 643} 644 645/** 646 * Build a tree outline of available media namespaces 647 * 648 * @author Andreas Gohr <andi@splitbrain.org> 649 */ 650function media_nstree($ns){ 651 global $conf; 652 global $lang; 653 654 // currently selected namespace 655 $ns = cleanID($ns); 656 if(empty($ns)){ 657 $ns = dirname(str_replace(':','/',$ID)); 658 if($ns == '.') $ns =''; 659 } 660 $ns = utf8_encodeFN(str_replace(':','/',$ns)); 661 662 $data = array(); 663 search($data,$conf['mediadir'],'search_index',array('ns' => $ns, 'nofiles' => true)); 664 665 // wrap a list with the root level around the other namespaces 666 $item = array( 'level' => 0, 'id' => '', 667 'open' =>'true', 'label' => '['.$lang['mediaroot'].']'); 668 669 echo '<ul class="idx">'; 670 echo media_nstree_li($item); 671 echo media_nstree_item($item); 672 echo html_buildlist($data,'idx','media_nstree_item','media_nstree_li'); 673 echo '</li>'; 674 echo '</ul>'; 675} 676 677/** 678 * Userfunction for html_buildlist 679 * 680 * Prints a media namespace tree item 681 * 682 * @author Andreas Gohr <andi@splitbrain.org> 683 */ 684function media_nstree_item($item){ 685 $pos = strrpos($item['id'], ':'); 686 $label = substr($item['id'], $pos > 0 ? $pos + 1 : 0); 687 if(!$item['label']) $item['label'] = $label; 688 689 $ret = ''; 690 $ret .= '<a href="'.DOKU_BASE.'lib/exe/mediamanager.php?ns='.idfilter($item['id']).'" class="idx_dir">'; 691 $ret .= $item['label']; 692 $ret .= '</a>'; 693 return $ret; 694} 695 696/** 697 * Userfunction for html_buildlist 698 * 699 * Prints a media namespace tree item opener 700 * 701 * @author Andreas Gohr <andi@splitbrain.org> 702 */ 703function media_nstree_li($item){ 704 $class='media level'.$item['level']; 705 if($item['open']){ 706 $class .= ' open'; 707 $img = DOKU_BASE.'lib/images/minus.gif'; 708 $alt = '−'; 709 }else{ 710 $class .= ' closed'; 711 $img = DOKU_BASE.'lib/images/plus.gif'; 712 $alt = '+'; 713 } 714 return '<li class="'.$class.'">'. 715 '<img src="'.$img.'" alt="'.$alt.'" />'; 716} 717