Monday, 9 April 2012

bibtexbrowser... Music for Publication Lists (Part II)

Embed bibtexbrowser in your web page

« Part I - A journey through the realms of boredom...

In Part I of this post I shared my thoughts on personal publication lists and I documented my reasons for using Martin Monperrus' bibtexbrowser in my web page.

The script is very simple to install and works off-the-shelf. However, with a bit of tweaking we can achieve better integration with the rest of our site. In this part, I shall share my experiences from customising it, hoping that it might help others who decide to use it.


We can run bibtexbrowser in 3 modes:
  • Stand Alone: When you directly invoke bibtexbrowser.php and let it generate an entire page. This will look like this or like this (frameset display).
  • Embedded: When you use it inside your own page and you get it to generate a section. A page like that can be seen here.
  • As a library: In this mode, it parses your bib DB and populates its data structures but it doesn't generate any HTML until you ask it to do so at a later stage. More on that later.

Basic Configuration

bibtexbrowser.php includes bibtexbrowser.local.php. This is your chance to override the default configuration and make local changes. So for example if you want to turn off Javascript progressive enhancement, you'd add the line below to your bibtexbrowser.local.php:
It's documented quite well here, so not a lot to say. It's being mentioned here cause we'll use it plenty later on.

Embedded Mode

This is also well documented in bibtexbrowser's page. Let's assume that you have a php script called pubs.php and you want to embed your publications list. You will do something like this:
  $_GET['author']='Your Name';
  include( 'bibtexbrowser.php' );
That's it. The only thing to do afterwards is write CSS styles to make the generated output looks like the rest of your page.

Library Mode

But in frameset mode there are great and handy authors, years, types and other menus on the left. Why can't I have them in embedded mode?

If you browse through bibtexbrowser's code, you will see something about a 'New undocumented feature' (in version v20111211 this is near line 1746). In your embedding pubs.php script where you include bibtexbrowser, you can do this (notice line 1):
include( 'bibtexbrowser.php' );
/* We have included bibtexbrowser but it's not generated anything yet */

setDB(); /* Read the bibliography and populate data structures */

new IndependentYearMenu(); /* Generate the years menu */

/* Do more stuff */

new Dispatcher(); /* Generate bibtexbrowser HTML */
This IndependentYearMenu() function generates the HTML for the year menu (it does, honest!). Remember, your bibtexbrowser.local.php is your friend. You can copy this function over from bibtexbrowser.php and modify it as you please. This is how I'm generating my custom authors menu:
    class CustomAuthorsMenu {
        function CustomAuthorsMenu() {
            if (!isset($_GET[Q_DB])) {die('Did you forget to call setDB() before instantiating this class?');}
            $authorIndex = $_GET[Q_DB]->authorIndex();
            <div id="authormenu" class="filterbox toolbox">
                <div class="filterprop">
                    <a href="#authormenu" title="Expand/Collapse" onclick="toggle_toolbox('authorlist'); return false;">±</a>
                <span class="this">Authors:</span>
                <div class="filterlist" id="authorlist">
                    echo '<span><a '.makeHref(array(Q_AUTHOR=>'.*')).'>All</a></span>'."\n";
                    foreach($authorIndex as $author) {
                        echo '<span><a '.makeHref(array(Q_AUTHOR=>$author)).'>'.$author.'</a></span>'."\n";
Between setDB() and new Dispatcher() you can do whatever you like. So this is how I'm loading bibtexbrowser (in my pubs.php):


    new CustomAuthorsMenu();
    new CustomYearMenu();

<div id="bodyText">

    new Dispatcher();

The process is similar for the years menu. The outcome can be seen here. Check out the author and year menus on the left.

But, what about the search form?

The form is generated by function searchView(), which doesn't get called in embedded mode. Similar process, we can copy it over to our pubs.php and modify it.
<form action="?Academic" method="get">
    <div class="sortbox toolbox">
        <a href="#" onclick="toggle();return false;">Raw List / Grouped<br /></a>
        <a href="?Academic">By Type<br /></a>
        <a href="?Year">By Year<br /></a>
        <div class="search">
            <input type="text" name="search" class="input_box" id="searchtext"/>
            <input type="hidden" name="bib" value="geo.bib"/>
            <input type="submit" value="search" class="input_box"/>
Those of you who are observant will have noticed that, compared to the original:
  • I've replaced bibtexbrower's constants with hard-coded values. This is because I'm generating the form at the wrong position in the script, we can do it after including bibtexbrowser.php and keep the constants. I'll be changing that soon...
  • I'm putting the entire <div> inside the <form> and not the other way round. This is for XHTML 1.1 compliance. More on that later.

Individual Publication Pages

bibtexbrowser can also display an individual page for a publication, such as for example this one. If you look at this page's source, you will notice many lines like these:
<meta name="DC.Title" content="A Model-driven Measurement Approach"/>
<meta name="citation_title" content="A Model-driven Measurement Approach"/>
These lines are my favorite bibtexbrowser feature: bibliographic metadata. The first one is Dublin Core, the second is google scholar metadata. The problem here is that if you run bibtexbrowser embedded, the script that generates the page's head is the embedding script, not bibtexbrowser. Bottom line, I advise against running individual pages embedded.

An idea that I'm planning to have a stab at is to change the bibtexbrowser script so that when it encounters the argument key,  it will generate the metadata headers and COinS before bailing out. Then, the embedding script can call suitable methods, retrieve the values and add them to the generated page's head.


bibtexbrowser generates valid XHTML 1.0 Transitional. That's great but that rest of my site is XHTML 1.1. If we try to validate the page as 1.1, we get the following error:

Line X, Column Y: there is no attribute "name"
<td class="bibref"><a name= " 2">

The workaround to this one is simple, just change name="foo" to id="foo", like so:
--- /Users/cexgo/Documents/ 2012-04-05 14:23:24.000000000 +0100
+++ bibtexbrowser.php   2012-04-09 00:54:01.000000000 +0100
@@ -1336,28 +1338,41 @@ class BibEntry {
   function toTR() {
         echo '<tr class="bibline">';
-        echo '<td  class="bibref"><a name="'.$this->getId().'"></a>['.$this->getAbbrv().']</td> ';
+        echo '<td  class="bibref"><a id="id'.$this->getId().'"></a>['.$this->getAbbrv().']</td> ';
         echo '<td class="bibitem">';
         echo bib2html($this);
We're not done yet. Even if the markup is valid XHTML 1.1, we need to make sure that page is served as such. When running in embedded more, things are easy since the headers are generated by our own script. In stand-alone mode though, this is what the server sends:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html xmlns="">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
We need to change the DOCTYPE and a few other bits and bobs. Although technically Content-type:text/html will work, according to the specs it may not be used and should be replaced by application/xhtml+xml. Here's how I've patched bibtexbrowser.php:
--- /Users/cexgo/Documents/ 2012-04-05 14:23:24.000000000 +0100
+++ bibtexbrowser.php   2012-04-09 00:54:01.000000000 +0100
@@ -2878,13 +2916,13 @@ function HTMLWrapper(&$content,$metatags=array()/* an array name=>value*/) {
 // when we load a page with AJAX
 // the HTTP header is taken into account, not the <meta http-equiv>
-header('Content-type: text/html; charset='.ENCODING);
-echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">'."\n";
+    header ("Content-Type:application/xhtml+xml; charset=utf-8");
+    echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"
-<html xmlns="">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "">
+<html xmlns="" xml:lang="en">
-<meta http-equiv="Content-Type" content="text/html; charset=<?php echo ENCODING ?>"/>
+<meta http-equiv="Content-Type" application/xhtml+xml; charset=UTF-8"/>
 <meta name="generator" content="bibtexbrowser v20111211" />
 <?php if ($content->getRSS()!='') echo '<link rel="alternate" type="application/rss+xml" title="RSS" href="'.$content->getRSS().'&amp;rss" />'; ?>
A few more things to keep in mind. By default bibtexbrowser opens individual pages in the same window/tab. If you prefer using a new tab, you can override the default by adding this to your bibtexbrowser.local.php:
If you do that, you will find that some target="foo" will creep in the generated markup. The page will not validate against XHTML 1.1 with errors like this:

Line X, Column Y: there is no attribute "target"
 …an</a>, George Oikonomou, "<a target= " _blank"

I don't have a workaround for the target="_blank" thing since it's a feature that I'm never going to use, I just had to point it out since I noticed it. Lastly, keep in mind that the frameset version will not validate either, due to the differences in framing methods between XHTML 1.0 and 1.1. If you try to solve this, you are probably looking at quite a beast.


In order to better integrate bibtexbrowser with my publication list here, I made a few modifications and tweaks. I believe that bibtexbrowser is an excellent script. In this post I am sharing my observations, hoping to help those of you who want to exploit some of its cool features and who are curious enough to want to take things a few steps further than a vanilla installation.

« Part I - A journey through the realms of boredom...