diff --git a/bibtexbrowser.bibliography.php b/bibtexbrowser.bibliography.php new file mode 100644 index 0000000..591afbc --- /dev/null +++ b/bibtexbrowser.bibliography.php @@ -0,0 +1,84 @@ +?'; } + return '' . $a . '' ; +} + +// Create citations from bibtex entries. One argument per bibtex entry. +/* Example: As shown in , one can use bibtex within HTML/PHP. +*/ +function cite() { + global $citations; + global $DB; + $entries = func_get_args(); // list of bibtex entries + $refs = array(); // corresponding references + foreach ($entries as $entry) { + $bib = $DB->getEntryByKey($entry); + if ( empty($bib) ) { + $ref = array(); // empty ref for detection by linkify, while getting last with sort() + $txt = "Unknown key «$entry»"; + $refs[$txt] = $ref; + continue; + } + if (ABBRV_TYPE != 'index') { + $ref = $bib->getAbbrv(); + $citations[$entry] = $ref; + } else { + if ( array_key_exists ( $entry , $citations ) ) { + $ref = $citations[$entry] ; + } else { + $ref = count( $citations ) + 1 ; + $citations[$entry] = $ref ; + } + } + $txt = $bib->getVeryCompactedAuthors() . ", «" . $bib->getTitle() . "», " . $bib->getYear() ; + $refs[$txt] = $ref; + } + asort( $refs ); + $links = array(); + foreach ( $refs as $txt => $ref ) { + $links[] = linkify($txt,$ref); + } + echo "[" . implode(",",$links) . "]" ; +} + +// Function to print out the table/list of references +function make_bibliography() { + global $citations; + $bibfile = $_GET[Q_FILE]; // save bibfilename before resetting $_GET + $_GET = array(); + $_GET['bib'] = $bibfile; + $_GET['bibliography'] = 1; // also sets $_GET['assoc_keys']=1 + $_GET['keys'] = json_encode(array_flip($citations)); + //print_r($_GET); + include( 'bibtexbrowser.php' ); +?> + + diff --git a/bibtexbrowser.local.php b/bibtexbrowser.local.php new file mode 100644 index 0000000..12a6f77 --- /dev/null +++ b/bibtexbrowser.local.php @@ -0,0 +1,161 @@ +display(); + if (BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT) { + javascript(); + } + } +} + + +function MGBibliographyStyle(&$bibentry) { + $title = $bibentry->getTitle(); + $type = $bibentry->getType(); + + // later on, all values of $entry will be joined by a comma + $entry=array(); + + + // thumbnail + if (USEBIBTHUMBNAIL && $bibentry->hasField(BIBTHUMBNAIL)) { + $thumb = '';} + else $thumb = ''; + + // title + // usually in bold: .bibtitle { font-weight:bold; } + $title = ''.$title.'
'."\n"; + if ($bibentry->hasField('url')) $title = ''.$title.''; + + + // author + if ($bibentry->hasField('author')) { + $coreInfo = $title . ''.$bibentry->getFormattedAuthorsImproved().'';} + else $coreInfo = $title; + + // core info usually contains title + author + $entry[] = $thumb.$coreInfo; + + // now the book title + $booktitle = ''; + if ($type=="inproceedings") { + $booktitle = 'In '.$bibentry->getField(BOOKTITLE); } + if ($type=="incollection") { + $booktitle = 'Chapter in '.$bibentry->getField(BOOKTITLE);} + if ($type=="inbook") { + $booktitle = 'Chapter in '.$bibentry->getField('chapter');} + if ($type=="article") { + $booktitle = 'In '.$bibentry->getField("journal");} + + //// we may add the editor names to the booktitle + $editor=''; + if ($bibentry->hasField(EDITOR)) { + $editor = $bibentry->getFormattedEditors(); + } + if ($editor!='') $booktitle .=' ('.$editor.')'; + // end editor section + + // is the booktitle available + if ($booktitle!='') { + $entry[] = '
'.$booktitle.''; + } + + + $publisher=''; + if ($type=="phdthesis") { + $publisher = 'PhD thesis, '.$bibentry->getField(SCHOOL); + } + if ($type=="mastersthesis") { + $publisher = 'Master\'s thesis, '.$bibentry->getField(SCHOOL); + } + if ($type=="bachelorsthesis") { + $publisher = 'Bachelor\'s thesis, '.$bibentry->getField(SCHOOL); + } + if ($type=="techreport") { + $publisher = 'Technical report, '.$bibentry->getField("institution"); + } + + if ($type=="misc") { + $publisher = $bibentry->getField('howpublished'); + } + + if ($bibentry->hasField("publisher")) { + $publisher = $bibentry->getField("publisher"); + } + + if ($publisher!='') $entry[] = ''.$publisher.''; + + + if ($bibentry->hasField('volume')) $entry[] = "volume ".$bibentry->getField("volume"); + + + if ($bibentry->hasField(YEAR)) $entry[] = $bibentry->getYear(); + + $result = implode(", ",$entry).'.'; + + // some comments (e.g. acceptance rate)? + if ($bibentry->hasField('comment')) { + $result .= " (".$bibentry->getField("comment").")"; + } + if ($bibentry->hasField('note')) { + $result .= " (".$bibentry->getField("note").")"; + } + + // add the Coin URL + //$result .= "\n".$bibentry->toCoins(); + $result .= "
\n"; + + // we add biburl and title to be able to retrieve this important information + // using Xpath expressions on the XHTML source + $result .= $bibentry->getBibLink(); + // returns an empty string if no pdf present + $result .= $bibentry->getLink('pdf'); + // returns an empty string if no url present + $result .= $bibentry->getLink('url'); + // returns an empty string if no slides present + $result .= $bibentry->getLink('slides'); + // returns an empty string if no poster present + $result .= $bibentry->getLink('poster'); + // Google Scholar ID. empty string if no gsid present + $result .= $bibentry->getGSLink(); + // returns an empty string if no doi present + $result .= $bibentry->getDoiLink(); + + $result .= '
'; + + return $result; +} // end style function + +/** Class to display a bibliography of a page. */ +class BibliographyDisplay { + function setDB(&$bibdatabase) { $this->setEntries($bibdatabase->bibdb); } + + /** sets the entries to be shown */ + function setEntries(&$entries) { $this->entries = $entries; } + + function setTitle($title) { $this->title = $title; return $this; } + function getTitle() { return @$this->title ; } + + /** Displays a set of bibtex entries in an HTML table */ + function display() { + ksort($this->entries); // sort the keys, not the values + layoutHeaderHTML(); + foreach ($this->entries as $ref => $bib) { + $bib->setIndex($ref); + $bib->toHTML(); + } // end foreach + layoutFooterHTML(); + } // end function +} // end class + + + +?> + diff --git a/bibtexbrowser.php b/bibtexbrowser.php index 45f7513..1d3e6e7 100644 --- a/bibtexbrowser.php +++ b/bibtexbrowser.php @@ -1,8 +1,9 @@ + URL: http://www.monperrus.net/martin/bibtexbrowser/ Feedback & Bug Reports: martin.monperrus@gmail.com +(C) 2013 Matthieu Guillaumin (C) 2006-2012 Martin Monperrus (C) 2005-2006 The University of Texas at El Paso / Joel Garcia, Leonardo Ruiz, and Yoonsik Cheon This program is free software; you can redistribute it and/or @@ -16,7 +17,7 @@ License, or (at your option) any later version. // added on Wednesday, June 01 2011, bug found by Carlos Bras if (!defined('BIBTEXBROWSER')) { // this if block ends at the very end of this file, after all class and function declarations. -define('BIBTEXBROWSER','v20121205'); +define('BIBTEXBROWSER','v20130206'); // *************** CONFIGURATION @@ -99,10 +100,13 @@ define('BIBTEXBROWSER','v20121205'); @define('Q_ALL', 'all'); @define('Q_ENTRY', 'entry'); @define('Q_KEY', 'key'); +@define('Q_KEYS', 'keys'); // select entries using a JSON array of bibtex keys +@define('Q_ASSOCKEYS', 'assoc_keys'); // consider Q_KEYS as an associative array, and use the keys of Q_KEYS as item abbrv @define('Q_SEARCH', 'search'); @define('Q_EXCLUDE', 'exclude'); @define('Q_RESULT', 'result'); @define('Q_ACADEMIC', 'academic'); +@define('Q_BIBLIOGRAPHY', 'bibliography'); @define('Q_DB', 'bibdb'); @define('Q_LATEST', 'latest'); @define('AUTHOR', 'author'); @@ -117,6 +121,10 @@ define('BIBTEXBROWSER','v20121205'); @define('METADATA_DC',true); @define('METADATA_EPRINTS',false); +@define('LAYOUT','table'); // may be table/list/deflist. defines the HTML rendering options (,
    ,
    , resp.). 'list' only works with 'ABBRV_TYPE'='index'. +@define('ICONS','[]'); +@define('Q_ICONS','icons'); + // in embedded mode, we still need a URL for displaying bibtex entries alone // this is usually resolved to bibtexbrowser.php // but can be overridden in bibtexbrowser.local.php @@ -147,6 +155,7 @@ See also zetDB(). function setDB() { list($db, $parsed, $updated, $saved) = _zetDB(@$_GET[Q_FILE]); $_GET[Q_DB] = $db; + $_GET[Q_ICONS] = (array) json_decode(ICONS); return $updated; } @@ -240,14 +249,14 @@ function _zetDB($bibtex_filenames) { && is_readable($compiledbib) && filesize($compiledbib)>0 ) { - $f = fopen($compiledbib,'r'); + $f = fopen($compiledbib,'r+'); //we use a lock to avoid that a call to bibbtexbrowser made while we write the object loads an incorrect object if (flock($f,LOCK_EX)) { $s = filesize($compiledbib); $ser = fread($f,$s); $db = @unserialize($ser); flock($f,LOCK_UN); - } else { die('could not get the lock'); } + } else { die("could not get the lock for reading $compiledbib"); } fclose($f); // basic test // do we have an correct version of the file @@ -299,7 +308,7 @@ function _zetDB($bibtex_filenames) { fwrite($f,serialize($db)); flock($f,LOCK_UN); $saved = true; - } else { die('could not get the lock'); } + } else { die("could not get the lock for writing $compiledbib"); } fclose($f); } // end saving the cached verions //else echo ''; @@ -999,12 +1008,73 @@ class BibEntry { return "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME']).'/'.$this->getURL(); } - /** returns a "[pdf]" link if relevant */ + /** Read the bibtex field $bibfield and return a link with icon or text + * e.g. given the bibtex entry: @article{myarticle, pdf={myarticle.pdf}}, + * $bibtexentry->getLink('pdf') creates a link to myarticle.pdf using the text '[pdf]' or the pdf icon specified in the bibtex file (cf. getIconOrTxt) + * getLink($bibfield,$icon,$def) specifies the icon key $icon and default text $def. + */ + function getLink($bibfield,$icon=NULL,$def=NULL) { + if ($icon==NULL) { $icon=$bibfield; } + $str = $this->getIconOrTxt($icon,$def); + if ($this->hasField($bibfield)) { + return ' '.$str.''; + } + return ''; + } + + /* a few specializations of getLink */ + + /** returns a "[url]" link if relevant. modified to exploit the new method, while keeping backward compatibility */ function getUrlLink() { - if ($this->hasField('url')) return ' [pdf]'; + return $this->getLink('url'); + } + + /** returns a "[bib]" link if relevant */ + function getBibLink() { + $bibstr = $this->getIconOrTxt('bib'); + $href = 'href="'.$this->getURL().'"'; + $link = "getKey()."\" {$href}>$bibstr"; + return $link; + } + + + /** DOI are a special kind of links, where the url depends on the doi */ + function getDoiLink() { + $str = $this->getIconOrTxt('doi'); + if ($this->hasField('doi')) { + return ' '.$str.''; + } return ''; + } + + /** GS are a special kind of links, where the url depends on the google scholar id */ + function getGSLink() { + $str = $this->getIconOrTxt('gsc','cites'); + // Google Scholar ID + if ($this->hasField('gsid')) { + return ' '.$str.''; + } + return ''; + } + + /** replace [$ext] with an icon whose url is defined in a string + * e.g. getIconOrTxt('pdf') will show the icon defined in $_GET[Q_ICONS]['pdf'] or print '[pdf]' + * or getIconOrTxt('pdf','paper') will show the icon defined by $_GET[Q_ICONS]['pdf'] or print '[paper]' + * The replacement text is also used if the url does not point to a valid file (using the "alt" property of the "img" html tag) + */ + function getIconOrTxt($ext,$def=NULL) { + if ($def==NULL) { $def=$ext; } + $icons = $_GET[Q_ICONS]; + if ( array_key_exists($ext,$icons) ) { + $str='['.$def.']'; + } else { + $str='['.$def.']'; + } + return $str; } + + /** Reruns the abstract */ function getAbstract() { if ($this->hasField('abstract')) return $this->getField('abstract'); @@ -1182,6 +1252,16 @@ class BibEntry { return $this->formatAuthor($authors[0]) . $etal; } + /** + * Returns a compacted string form of author names by throwing away + * all author names except for the first one and appending ", et al." + */ + function getVeryCompactedAuthors(){ + $authors = $this->getRawAuthors(); + $etal = count($authors) > 1 ? ', et al.' : ''; + list($firstname, $lastname) = splitFullName($authors[0]); + return $lastname . $etal; + } /** add the link to the homepage if it is defined in a string * e.g. @string{hp_MartinMonperrus="http://www.monperrus.net/martin"} @@ -1296,6 +1376,16 @@ class BibEntry { } + /** Outputs HTML line according to layout */ + function toHTML() { + switch(LAYOUT) { + case 'list': $this->toLI(); break; + case 'table': $this->toTR(); break; + case 'deflist': $this->toDD(); break; + } + } + + /** Outputs an HTML line (
)with two TDS inside */ function toTR() { @@ -1306,27 +1396,23 @@ class BibEntry { echo $this->getAbbrv().' '; echo '\n"; + } - $href = 'href="'.$this->getURL().'"'; - if (BIBTEXBROWSER_BIBTEX_LINKS) { - // we add biburl and title to be able to retrieve this important information - // using Xpath expressions on the XHTML source - echo " getKey()."\" {$href}>[bibtex]"; - } - - // returns an empty string if no url present - echo $this->getUrlLink(); + /** Outputs an LI line (
  • ) with spans for each element, using the value attribute the abbrev. (does not work with x-abbrv) */ + function toLI() { + echo '
  • '; + echo ''; + echo bib2html($this); + echo "
  • \n"; + } - if ($this->hasField('doi')) { - echo ' [doi]'; - } - - // Google Scholar ID - if ($this->hasField('gsid')) { - echo ' [cites]'; - } - echo "\n"; + /** Outputs an DL line (
    +
    ) */ + function toDD() { + echo '
    '.$this->getAbbrv().'
    '; + echo bib2html($this); + echo "
    \n"; } /** Outputs an coins URL: see http://ocoins.info/cobg.html @@ -1436,6 +1522,34 @@ class BibEntry { } +function layoutHeaderHTML() { + switch(LAYOUT) { /* switch for different layouts */ + case 'list': + echo '
      '; + break; + case 'table': + echo '
    '; echo bib2html($this); + echo "
    '; + break; + case 'deflist': + echo '
    '; + break; + } +} + +function layoutFooterHTML() { + switch(LAYOUT) { + case 'list': + echo ''; + break; + case 'table': + echo '
    '; + break; + case 'deflist': + echo ''; + break; + } +} + /** this function encapsulates the user-defined name for bib to HTML*/ function bib2html(&$bibentry) { $function = BIBLIOGRAPHYSTYLE; @@ -2127,6 +2241,9 @@ else $page = 1; if (!function_exists('query2title')) { /** transforms an array representing a query into a formatted string */ function query2title(&$query) { + // special case + if (isset($query[Q_BIBLIOGRAPHY])) return 'Publications in ' . htmlspecialchars($_SERVER['PHP_SELF']); + $headers = array(); foreach($query as $k=>$v) { if($k == Q_INNER_AUTHOR) { $k = 'author'; } @@ -2301,21 +2418,87 @@ class SimpleDisplay { echo 'Options: '.@implode(',',$this->options).'
    '; } - ?> + layoutHeaderHTML(); - - entries); $i=0; foreach ($this->entries as $bib) { // by default, index are in decrasing order // so that when you add a publicaton recent , the indices of preceding publications don't change $bib->setIndex('['.($count-($i++)).']'); - $bib->toTR(); + $bib->toHTML(); } // end foreach - ?> -
    - '; + return ''.$label.''; +} + + +/** + * Displays the summary information of each bib entries of the + * current page. For each entry, this method displays the author, + * title; the bib entries are displayed grouped by the + * publication years. If the bib list is empty, an error message is + * displayed. + */ +class DefaultContentStrategy { + + /** $display: an instance of PagedDisplay */ + function display(&$display) { + // create a year -> entries map to display by years + $years = array(); + foreach ($display->result as $e) { + $y = trim($e->getField(YEAR)); + $years[$y][$e->getKey()] = $e; + } + krsort($years); + + layoutHeaderHTML(); + + $index = 0; + $refnum = count($display->result)-(($display->page-1)*PAGE_SIZE); + foreach ($years as $year => $entries) { + + if ($display->isDisplayed($index)) { + switch(LAYOUT) { + case 'deflist': + case 'list': + ?> +
    + + + + + isDisplayed($index)) { + $bib->setAbbrv($refnum--); + $bib->toHTML(); + } + $index++; + + } // end foreach + } + layoutFooterHTML(); + } // end function } // end class @@ -2370,10 +2553,10 @@ class AcademicDisplay { uasort($entries, ORDER_FUNCTION); if (count($entries)>0) { - echo "\n".'
    '.$title.'
    '."\n"; - echo ''."\n"; + echo "\n".'
    '.$title.'
    '."\n"; + layoutHeaderHTML(); - // by default the abbreviation is incermented over all + // by default the abbreviation is incremented over all // searches // since we don't know before hand all section, we can not index in decreasing order @@ -2381,11 +2564,11 @@ class AcademicDisplay { if ($count == NULL) { $count = 1; } // init $id = $count; foreach ($entries as $bib) { - $bib->setIndex('['.($id++).']'); - $bib->toTR(); + $bib->setIndex($id++); + $bib->toHTML(); } // end foreach $count = @$count + count($entries); - echo '
    '; + layoutFooterHTML(); } } @@ -2397,7 +2580,7 @@ class AcademicDisplay { foreach (_DefaultBibliographySections() as $section) { $this->search2html($section['query'],$section['title']); - } + } } } @@ -2827,21 +3010,35 @@ class BibDataBase { if (count($query)<1) {return array();} if (isset($query[Q_ALL])) return array_values($this->bibdb); + if (array_key_exists( Q_KEYS, $query )) { + $keylist = (array) $query[Q_KEYS]; + $reflist = array_flip($keylist); + $is_assoc = array_key_exists( Q_ASSOCKEYS, $query ); //array_values($query[Q_KEYS]) !== $query[Q_KEYS]; + //if ($is_assoc) echo "Assoc"; + //print_r($keylist); + } else { + $is_assoc = false; + } + unset($query[Q_ASSOCKEYS]); // not used for filtering the bibtex entries + $result = array(); foreach ($this->bibdb as $bib) { $entryisselected = true; + $akey = ''; foreach ($query as $field => $fragment) { $field = strtolower($field); if ($field==Q_SEARCH) { // we search in the whole bib entry if (!$bib->hasPhrase($fragment)) { $entryisselected = false; + break; } } else if ($field==Q_EXCLUDE) { if ($bib->hasPhrase($fragment)) { $entryisselected = false; + break; } } else if ($field==Q_TYPE || $field==Q_INNER_TYPE) { @@ -2852,20 +3049,36 @@ class BibDataBase { // moved here so that it is also used by AcademicDisplay:search2html() if (!$bib->hasPhrase('^('.$fragment.')$', Q_INNER_TYPE)) { $entryisselected = false; + break; + } + } + else if ($field==Q_KEYS) { + if ( ! in_array( $bib->getKey(), $keylist ) ) { + //echo $bib->getKey() . " not in list
    \n"; + $entryisselected = false; + break; } + //echo $bib->getKey() . " in list
    \n"; } else { if (!$bib->hasPhrase($fragment, $field)) { $entryisselected = false; + break; } } } if ($entryisselected) { - $result[] = $bib; + if ( $is_assoc ) { + $result[$reflist[$bib->getKey()]] = $bib; + } else { + $result[] = $bib; + } + } else { + //echo "entry ".$bib->getKey()." not selected\n"; } } - + //foreach ($result as $ref=>$bib) {echo $ref." => ".$bib->getKey()." ";} return $result; } } // end class @@ -3018,7 +3231,7 @@ echo ' - + getRSS()!='') echo ''; ?> @@ -3176,18 +3389,18 @@ class PagedDisplay { } $this->menu($less, $more); - echo ''; + layoutHeaderHTML(); for ($i = 0; $i < PAGE_SIZE; $i++) { $index = ($this->page-1)*PAGE_SIZE + $i; if (isset($this->entries[$index])) { $bib = $this->entries[$index]; - $bib->toTR(); + $bib->toHTML(); } else { //break; } } // end foreach - echo '
    '; + layoutFooterHTML(); $this->menu($less, $more); } @@ -3281,7 +3494,7 @@ class RSSDisplay { http:// - bibtexbrowser v20121205 + bibtexbrowser v20130226 entries as $bibentry) { @@ -3382,8 +3595,8 @@ class Dispatcher { } // default order - uasort($selectedEntries, ORDER_FUNCTION); - $selectedEntries = array_values($selectedEntries); + //uasort($selectedEntries, ORDER_FUNCTION); + //$selectedEntries = array_values($selectedEntries); //echo '
    ';print_r($selectedEntries);echo '
    '; @@ -3478,7 +3691,7 @@ class Dispatcher { function keywords() { $this->query[Q_TAG]=$_GET[Q_TAG]; } - function author() { + function author() { // Friday, October 29 2010 // changed from 'author' to '_author' // in order to search at the same time "Joe Dupont" an "Dupont, Joe" @@ -3535,11 +3748,30 @@ class Dispatcher { else { nonExistentBibEntryError(); } } + function bibliography() { + $this->displayer='BibliographyDisplay'; + $this->query[Q_ASSOCKEYS]=1; + } + + function layout() { $this->query[LAYOUT]=$_GET[LAYOUT]; } + + function keys() { + if (preg_match('/utf-?8/i',ENCODING)) { + // Create array from list of bibtex entries + $_GET[Q_KEYS] = json_decode($_GET[Q_KEYS]); + } + $this->query[Q_KEYS]=$_GET[Q_KEYS]; + } + + function assoc_keys() { + $this->query[Q_ASSOCKEYS]=$_GET[Q_ASSOCKEYS]; + } + /** is used to remotely analyzed a situation */ function diagnosis() { header('Content-type: text/plain'); echo "php version: ".phpversion()."\n"; - echo "bibtexbrowser version: 20121205\n"; + echo "bibtexbrowser version: 20130226\n"; echo "dir: ".decoct(fileperms(dirname(__FILE__)))."\n"; echo "bibtex file: ".decoct(fileperms($_GET[Q_FILE]))."\n"; exit; @@ -3551,7 +3783,7 @@ class Dispatcher { - + You are browsing <?php echo $_GET[Q_FILE]; ?> with bibtexbrowser @@ -3573,4 +3805,4 @@ class Dispatcher { $class = BIBTEXBROWSER_MAIN;// extension point $main = new $class(); $main->main(); -?> \ No newline at end of file +?>