1<?php 2 /** 3 * bibtex-Plugin: Parses bibtex-blocks 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Christophe Ambroise <ambroise@utc.fr> 7 * @date 2005-08-10 8 * 9 * Modifications: 2006-07-03 Jean-Francois Lalande. 10 * Adding: 11 * - Chronological ordering support 12 * - Type of references groups 13 * - PDF and POSTSCRIPT links 14 * 15 * Modifications: 2006-08-22 Jean-Francois Lalande. 16 * - Fix for hyphaned name in OSBib (reported to developers) 17 */ 18 19 /** 20 * Parameters for the plugin: 21 * 22 * - $conf['bibtex_format'] 23 * default: "APA" 24 * This control the formatting output of the bibtex plugin. 25 * Options are: APA, ieee, britishmedicaljournal, chicago, harvard, mla, turabian 26 * 27 * - $conf['bibtex_sort_year'] 28 * default: no value (no sorting by date) 29 * Controls the sorting of the references by year. 30 * Options are: 1 (most recent) or -1 (oldest first) 31 * 32 * - $conf['bibtex_sort_type'] 33 * default: no value (no sorting by type) 34 * Controls the sorting of the references by type. 35 * Options are: 1 (ascending order) or -1 (descending order) 36 * The values for each type of reference is controlled by 37 * the array of $conf["bibtex_types_order"]. You can overide this array 38 * in your local configuration. You can find an example of this array in 39 * the syntax.php file of this plugin. 40 * 41 * - $conf["bibtex_types_order"] 42 * default: see below 43 * If the 'bibtex_sort_type' has been activated, this array controls 44 * the order of appearing of the different type of references. For each kind 45 * of reference a value is associated. For example a book is 10, an article 7 46 * and a techreport 1. If the same value is given for two kinds of references 47 * they are grouped (in the example inproceedings and conference are grouped) 48 * 49 * Example of array: 50 * $conf["bibtex_types_order"] = array ( 51 * "book"=> 10, 52 * "inbook"=> 9, 53 * "phdthesis"=> 8, 54 * "article"=> 7, 55 * "inproceedings"=> 3, 56 * "conference"=> 3, 57 * "techreport"=> 1, 58 * ); 59 * 60 * - $conf["bibtex_types_names"] 61 * default see below 62 * If the 'bibtex_sort_type' has beec activated, this array controls 63 * the name of the section for each group of references. The idea 64 * is to personalize the titles for exemple for the entries 'inbook' by 65 * putting a label "Chapter in books". For each level defined in the 66 * array $conf["bibtex_types_order"], we associate a label. 67 * 68 * Example of array: 69 * $conf["bibtex_types_names"] = array ( 70 * 10 => "Books", 71 * 9 => "Chapters in books", 72 * 8 => "Phd Thesis", 73 * 7 => "Articles", 74 * 3 => "Proceedings", 75 * 1 => "Technical reports", 76 * ); 77 * 78 * - $conf['bibtex_types_title_level'] 79 * default: 2 80 * This parameter sets the level of the label of each section of reference. 81 * By default the level is 2 corresponding to h2 tags. 82 * 83 * 84 * Example of parameters for activating all features: 85 * 86 * $conf['bibtex_format'] = "ieee"; 87 * $conf['bibtex_sort_year'] = 1; 88 * $conf['bibtex_sort_type'] = 1; 89 * $conf['bibtex_sort_type_title'] = 1; 90 * 91 * Special parameters in the bibtex entry: 92 * 93 * - The tag 'file' is considered as an internal document of dokuwiki 94 * - The tag 'pdf' is considerd as an external url 95 * - The tag 'postscript' is considered as an external url 96 */ 97 98// Default values 99global $conf; 100if(!isset($conf["bibtex_types_order"])) 101{ 102 $conf["bibtex_types_order"] = array ( 103 "book"=> 10, 104 "inbook"=> 9, 105 "phdthesis"=> 8, 106 "article"=> 7, 107 "inproceedings"=> 3, 108 "conference"=> 3, 109 "techreport"=> 1, 110 ); 111} 112if(!isset($conf["bibtex_types_names"])) 113{ 114 $conf["bibtex_types_names"] = array ( 115 10 => "Books", 116 9 => "Chapters in books", 117 8 => "Phd Thesis", 118 7 => "Articles", 119 3 => "Proceedings", 120 1 => "Technical reports", 121 ); 122} 123if(!isset($conf["bibtex_types_title_level"])) 124{ 125 $conf['bibtex_types_title_level'] = 2; 126} 127 128if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 129if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 130require_once(DOKU_PLUGIN.'syntax.php'); 131 132/** 133* usort callback for years 134*/ 135function compare_year($a, $b) { 136 global $conf; 137 138 // No sorting 139 if ($conf['bibtex_sort_year'] == "") 140 return 0; 141 142 $adist = $a['year']; 143 $bdist = $b['year']; 144 145 if ($adist == $bdist) { 146 return 0; 147 } 148 return ($adist < $bdist) ? $conf['bibtex_sort_year'] : -$conf['bibtex_sort_year']; 149} 150 151/** 152* usort callback for types 153*/ 154function compare_type($a, $b) { 155 global $conf; 156 157 // No sorting 158 if ($conf['bibtex_sort_type'] == "") 159 return 0; 160 161 $adist = $conf["bibtex_types_order"][$a['bibtexEntryType']]; 162 $bdist = $conf["bibtex_types_order"][$b['bibtexEntryType']]; 163 164 if ($adist == $bdist) { 165 // If the year sorting is activated... 166 if ($conf['bibtex_sort_year'] != "") 167 { 168 return compare_year($a,$b); 169 } 170 else 171 { 172 return 0; 173 } 174 } 175 return ($adist < $bdist) ? $conf['bibtex_sort_type'] : -$conf['bibtex_sort_type']; 176} 177 178/** 179 * All DokuWiki plugins to extend the parser/rendering mechanism 180 * need to inherit from this class 181 */ 182class syntax_plugin_bibtex extends DokuWiki_Syntax_Plugin { 183 184 function getInfo(){ 185 return array( 186 'author' => 'Christophe Ambroise', 187 'email' => 'ambroise@utc.fr', 188 'date' => '2006-06-29', 189 'name' => 'Bitext Plugin', 190 'desc' => 'parses bibtex blocks', 191 'url' => 'http://www.hds.utc.fr/~ambroise/doku.php?id=softwares:dokuwikibibtexplugin' 192 ); 193 } 194 195 /** 196 * What kind of syntax are we? 197 */ 198 function getType(){ 199 return 'protected'; 200 } 201 202 /** 203 * Where to sort in? 204 */ 205 function getSort(){ 206 return 102; 207 } 208 209 /** 210 * Connect pattern to lexer 211 */ 212 function connectTo($mode) { 213 $this->Lexer->addEntryPattern('<bibtex(?=.*\x3C/bibtex\x3E)',$mode,'plugin_bibtex'); 214 } 215 216 function postConnect() { 217 $this->Lexer->addExitPattern('</bibtex>','plugin_bibtex'); 218 } 219 220 /** 221 * Handle the match 222 */ 223 function handle($match, $state, $pos) { 224 if ( $state == DOKU_LEXER_UNMATCHED ) { 225 $matches = preg_split('/>/u',$match,2); 226 $matches[0] = trim($matches[0]); 227 if ( trim($matches[0]) == '' ) { 228 $matches[0] = NULL; 229 } 230 return array($matches[1],$matches[0]); 231 } 232 return TRUE; 233 } 234 /** 235 * Create output 236 */ 237 function render($mode, &$renderer, $data) { 238 global $conf; 239 if($mode == 'xhtml' && strlen($data[0]) > 1) { 240 $renderer->doc .= $this->createCitations($data[0]); 241 return true; 242 } 243 } 244 245 246 247 function createCitations(&$data) { 248 global $conf; 249 $pathToOsbib = DOKU_PLUGIN.'bibtex/OSBib/'; 250 include_once($pathToOsbib.'format/bibtexParse/PARSEENTRIES.php'); 251 include_once( $pathToOsbib.'format/BIBFORMAT.php'); 252 253 // Getting conf (JFL) 254 if ($conf['bibtex_format'] != "") 255 { 256 $bibtex_format = $conf['bibtex_format']; 257 } 258 else 259 { 260 $bibtex_format = "APA"; 261 } 262 263 /* Get the bibtex entries into an associative array */ 264 $parse = NEW PARSEENTRIES(); 265 $parse->expandMacro = TRUE; 266 $parse->fieldExtract = TRUE; 267 $parse->removeDelimit = TRUE; 268 $parse->loadBibtexString($data); 269 $parse->extractEntries(); 270 list($preamble, $strings, $entries) = $parse->returnArrays(); 271 272 /* Format the entries array for html output */ 273 $bibformat = NEW BIBFORMAT($pathToOsbib, TRUE); 274 $bibformat->cleanEntry=TRUE; // The entries will be transformed into nice utf8 275 list($info, $citation, $styleCommon, $styleTypes) = $bibformat->loadStyle(DOKU_PLUGIN.'bibtex/OSBib/styles/bibliography/', $bibtex_format); 276 $bibformat->getStyle($styleCommon, $styleTypes); 277 278 $citations='<dl>'; 279 280 // Sorting ? 281 if ($conf['bibtex_sort_year'] != "") 282 { 283 usort($entries, "compare_year"); 284 } 285 286 if ($conf['bibtex_sort_type'] != "") 287 { 288 usort($entries, "compare_type"); 289 } 290 291 foreach ($entries as $entry){ 292 // Get the resource type ('book', 'article', 'inbook' etc.) 293 $resourceType = $entry['bibtexEntryType']; 294 295 if ($conf['bibtex_sort_type_title'] == 1) 296 { 297 if ($conf['bibtex_types_order'][$resourceType] != $conf['bibtex_types_order'][$resourceTypeLast]) 298 { 299 $resourceTypeLast = $resourceType; 300 $value = $conf['bibtex_types_order'][$resourceType]; 301 $citations.="<h" . $conf['bibtex_types_title_level'] . ">"; 302 $citations.=$conf['bibtex_types_names'][$value]; 303 $citations.="</h" . $conf['bibtex_types_title_level'] . ">"; 304 } 305 } 306 307 // In this case, BIBFORMAT::preProcess() adds all the resource elements automatically to the BIBFORMAT::item array... 308 $bibformat->preProcess($resourceType, $entry); 309 // Finally, get the formatted resource string ready for printing to the web browser or exporting to RTF, OpenOffice or plain text 310 $citations.= '<dt><div id="bibtexdt">[' . $entry['year'] . ", " . $entry['bibtexEntryType'] . $this->toDownload($entry) . ']</div></dt><dd><div id="bibtexdd">'. $bibformat->map() . "</div></dd> \n" ; 311 } 312 $citations.= "</dl>"; 313 return $citations; 314 315 //$entry['bibtexCitation'] 316 317 } 318 319 320 321 function toDownload($entry) { 322 $string=""; 323 if(array_key_exists('file',$entry)){ 324 $string.= " | ".$this->internalmedia($entry['file']); 325 } 326 if(array_key_exists('url',$entry)){ 327 $string.= " | ".$this->externallink($entry['url'],"www"); 328 } 329 if(array_key_exists('pdf',$entry)){ 330 $string.= " | ".$this->externallink($entry['pdf'],"pdf"); 331 } 332 if(array_key_exists('postscript',$entry)){ 333 $string.= " | ".$this->externallink($entry['postscript'],"ps"); 334 } 335 return $string; 336 } 337 338 339 function externallink($url, $name = NULL) { 340 global $conf; 341 342 $name = $this->_getLinkTitle($name, $url, $isImage); 343 344 // add protocol on simple short URLs 345 if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')) $url = 'ftp://'.$url; 346 if(substr($url,0,3) == 'www') $url = 'http://'.$url; 347 348 if ( !$isImage ) { 349 $class='urlextern'; 350 } else { 351 $class='media'; 352 } 353 354 //prepare for formating 355 $link['target'] = $conf['target']['extern']; 356 $link['style'] = ''; 357 $link['pre'] = ''; 358 $link['suf'] = ''; 359 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 360 $link['class'] = $class; 361 $link['url'] = $url; 362 $link['name'] = $name; 363 $link['title'] = $this->_xmlEntities($url); 364 if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"'; 365 366 list($ext,$mime) = mimetype($url); 367 if(substr($mime,0,15) == 'application/pdf' || substr($mime,0,24) == 'application/octet-stream'){ 368 // add file icons 369 $link['class'] = 'urlextern'; 370 if(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')){ 371 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.png)'; 372 }elseif(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.gif')){ 373 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.gif)'; 374 }else{ 375 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/file.gif)'; 376 } 377 //$link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true); 378 } 379 380 //output formatted 381 return $this->_formatLink($link); 382 } 383 384 385 function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL, 386 $height=NULL, $cache=NULL, $linking=NULL) { 387 global $conf; 388 global $ID; 389 resolve_mediaid(getNS($ID),$src, $exists); 390 391 $link = array(); 392 $link['class'] = 'media'; 393 $link['style'] = ''; 394 $link['pre'] = ''; 395 $link['suf'] = ''; 396 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 397 $link['target'] = $conf['target']['media']; 398 $link['title'] = $this->_xmlEntities($src); 399 list($ext,$mime) = mimetype($src); 400 if(substr($mime,0,5) == 'image'){ 401 // link only jpeg images 402 // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = TRUE; 403 $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),($linking=='direct')); 404 }elseif($mime == 'application/x-shockwave-flash'){ 405 // don't link flash movies 406 $noLink = TRUE; 407 }else{ 408 // add file icons 409 $link['class'] = 'urlextern'; 410 if(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')){ 411 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.png)'; 412 }elseif(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.gif')){ 413 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.gif)'; 414 }else{ 415 $link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/file.gif)'; 416 } 417 $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true); 418 } 419 $link['name'] = $this->_media ($src, $title, $align, $width, $height, $cache); 420 421 //output formatted 422 if ($linking == 'nolink' || $noLink){ 423 return $link['name']; 424 } else { 425 return $this->_formatLink($link); 426 } 427 } 428 429 430 function _formatLink($link){ 431 //make sure the url is XHTML compliant (skip mailto) 432 if(substr($link['url'],0,7) != 'mailto:'){ 433 $link['url'] = str_replace('&','&',$link['url']); 434 $link['url'] = str_replace('&amp;','&',$link['url']); 435 } 436 //remove double encodings in titles 437 $link['title'] = str_replace('&amp;','&',$link['title']); 438 439 $ret = ''; 440 $ret .= $link['pre']; 441 $ret .= '<a href="'.$link['url'].'"'; 442 if($link['class']) $ret .= ' class="'.$link['class'].'"'; 443 if($link['target']) $ret .= ' target="'.$link['target'].'"'; 444 if($link['title']) $ret .= ' title="'.$link['title'].'"'; 445 if($link['style']) $ret .= ' style="'.$link['style'].'"'; 446 if($link['more']) $ret .= ' '.$link['more']; 447 $ret .= '>'; 448 $ret .= $link['name']; 449 $ret .= '</a>'; 450 $ret .= $link['suf']; 451 return $ret; 452 } 453 454 /** 455 * Construct a title and handle images in titles 456 * 457 * @author Harry Fuecks <hfuecks@gmail.com> 458 */ 459 function _getLinkTitle($title, $default, & $isImage, $id=NULL) { 460 global $conf; 461 462 $isImage = FALSE; 463 if ( is_null($title) ) { 464 if ($conf['useheading'] && $id) { 465 $heading = p_get_first_heading($id); 466 if ($heading) { 467 return $this->_xmlEntities($heading); 468 } 469 } 470 return $this->_xmlEntities($default); 471 } else if ( is_string($title) ) { 472 return $this->_xmlEntities($title); 473 } else if ( is_array($title) ) { 474 $isImage = TRUE; 475 return $this->_imageTitle($title); 476 } 477 } 478 479 function _xmlEntities($string) { 480 return htmlspecialchars($string); 481 } 482 483 function _simpleTitle($name){ 484 global $conf; 485 486 if($conf['useslash']){ 487 $nssep = '[:;/]'; 488 }else{ 489 $nssep = '[:;]'; 490 } 491 $name = preg_replace('!.*'.$nssep.'!','',$name); 492 //if there is a hash we use the ancor name only 493 $name = preg_replace('!.*#!','',$name); 494 return $name; 495 } 496 497 /** 498 * Renders internal and external media 499 * 500 * @author Andreas Gohr <andi@splitbrain.org> 501 */ 502 function _media ($src, $title=NULL, $align=NULL, $width=NULL, 503 $height=NULL, $cache=NULL) { 504 505 $ret = ''; 506 507 list($ext,$mime) = mimetype($src); 508 if(substr($mime,0,5) == 'image'){ 509 //add image tag 510 $ret .= '<img src="'.ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache)).'"'; 511 $ret .= ' class="media'.$align.'"'; 512 513 if (!is_null($title)) { 514 $ret .= ' title="'.$this->_xmlEntities($title).'"'; 515 $ret .= ' alt="'.$this->_xmlEntities($title).'"'; 516 }elseif($ext == 'jpg' || $ext == 'jpeg'){ 517 //try to use the caption from IPTC/EXIF 518 require_once(DOKU_INC.'inc/JpegMeta.php'); 519 $jpeg =& new JpegMeta(mediaFN($src)); 520 if($jpeg !== false) $cap = $jpeg->getTitle(); 521 if($cap){ 522 $ret .= ' title="'.$this->_xmlEntities($cap).'"'; 523 $ret .= ' alt="'.$this->_xmlEntities($cap).'"'; 524 } 525 }else{ 526 $ret .= ' alt=""'; 527 } 528 529 if ( !is_null($width) ) 530 $ret .= ' width="'.$this->_xmlEntities($width).'"'; 531 532 if ( !is_null($height) ) 533 $ret .= ' height="'.$this->_xmlEntities($height).'"'; 534 535 $ret .= ' />'; 536 537 }elseif($mime == 'application/x-shockwave-flash'){ 538 $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'. 539 ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"'; 540 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 541 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 542 $ret .= '>'.DOKU_LF; 543 $ret .= '<param name="movie" value="'.ml($src).'" />'.DOKU_LF; 544 $ret .= '<param name="quality" value="high" />'.DOKU_LF; 545 $ret .= '<embed src="'.ml($src).'"'. 546 ' quality="high"'; 547 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 548 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 549 $ret .= ' type="application/x-shockwave-flash"'. 550 ' pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'.DOKU_LF; 551 $ret .= '</object>'.DOKU_LF; 552 553 }elseif(!is_null($title)){ 554 // well at least we have a title to display 555 $ret .= $this->_xmlEntities($title); 556 }else{ 557 // just show the sourcename 558 $ret .= $this->_xmlEntities(noNS($src)); 559 } 560 561 return $ret; 562 } 563 564 565} 566?> 567