Adding randomized barcodes to Koha’s holding (item) records (in Bengali)

Last Saturday, while conducting the online training for Parama Sarkhel di (Librarian, Ramakrishna Sarada Mission Vivekananda Vidyabhavan) and her team members on how to add randomized barcodes to their holding (items) records i.e. 952, we recorded their remote Teamviewer session. The voice over is in Bengali, though one can easily follow the screen to understand what is happening here. Their OPAC is at http://rksmvvlibrary.in/

Released under CC 4.0 – Attribution – ShareAlike by L2C2 Technologies

Changing languages in the drop-down for Google Transliterate API

Choose the list of languages to transliterate on the Koha OPAC

This tends to be frequent question that we often end up fielding from colleagues and customers. But before we get into this, please remember that this feature is probably at the end of it shelf-life. There are two reasons for this – the Transliterate API that this feature depends on was deprecated many, many years back, and secondly how badly this API was put together – it fetches the necessary JavaScript library from Google’s servers over HTTP! So, if you are using HTTPS on your Koha OPAC, you can kiss this feature good bye right now! Being deprecated there is almost zero chance that Big G will do anything to change that.

Life sucks right?? ūüėČ But as long as it is still there, here’s “one for the road”! ūüėÄ So, read on!

Turning on Google Transliteration

googleindic

It all starts with setting GoogleIndicTransliteration system preference to “Show” from the default of “Don’t show”.

By default that provides us with this short language drop-down:
googlist

For users from India, a country with 22 official language at the last count, that default list is woefully too little, too less. The good news is that Google’s Transliteration API supports several dozens of languages. Which ones? Well you need to dig around LanguageCode and SupportedDestinationLanguages enumerations in the documentation.

Show me the money!

The code to support the function is loaded via googleindictransliteration.js file that resides under /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/js/ on a Debian package based installation.

The screen grab below shows exactly that changes we needed to make in order to show on Hindi and Bengali as the list of languages, *and* with Bengali as default language option on the select drop-down.

googchanger

So how did I know that I needed to use “bn” for Bengali? Well, that LanguageCode enum list I’ve linked to above. Simple really!

One more fact about this tip that will bug a few

Change(s) to the LanguagesCode enum like this within the googleindictransliteration.js file would cause *all* instances on a multi-tenanted Koha installation to display the same list of languages. So, if you need different sets of languages lists in different OPACs, you are probably out of luck.

Customizing Koha’s MARC21 frameworks? Know the rules or get help!

Either you know what you are doing or take time to learn or invest in quality support. Fail on all three counts and you are quite literally asking for an operational nightmare.

Recently a young colleague Sri Ashkar K. from Thiruvananthapuram, Kerala (India) ran into a problem. He works as a librarian with Mathrubhumi, a major media house from Kerala. Specifically he needed to have a LMS solution to efficiently manage their collection of entertainment (mostly movies) related CDs and DVDs. For him the LMS was hosted Koha. However when he tried to issue an item i.e. a movie CD, he was stumped by this error every time:

Software error
No branchcode argument passed to koha::Calender->new at /var/koha_all/mathrubhumi/lib/C4/Circulation.pm line 3558

Being on a hosted Koha platform, he approached his service provider for support. He shared with them all the relevant screenshots leading to error detailed above.

The provider’s tech support could not identify the issue and instead informed him that they could perform checkouts (issue) without any errors. As Ashkar persisted, the service provider’s support desk asked him to provide remote desktop sharing using Teamviewer so that they could see “his problem” in action. Installing Teamviewer needed clearance from his IT department which required time and thus Ashkar’s checkout problem continued to linger. Finally about 10 days back he posted about it on the official Facebook page of Koha Library System Project, asking for suggestions to resolve it.

The first flag was raised by fellow Koha dev Mark Tompsett when he asked:

“/var/koha_all/mathrubhumi/lib/C4/Circulation.pm” — That is not a standard installation path. How did you install this? And what version?

Ashkar replied that since the software was hosted, he did not know the installation details. This got my attention! If he was on hosted Koha, why was he turning to the community for support? What was his service provider doing in the first place? I decided to find out more. That’s when I discovered the details of his situation. Desperate for help, he provided me with superlibrarian access to his hosted Koha’s staff client interface. I logged in and found that the problem was very real. In fact, I found out a few rather *disturbing* things.

The hosted Mathrubhumi Koha instance wasn’t running on the stable version (which is 16.05.05 at the time of writing) of Koha ILS. In fact, it was running on an unstable development version (at the time of this writing it was using Koha 16.0600023). Development versions are not GA releases and are *never* meant for production use, they are meant for use by testers and developers. And secondly, I could not do a MARC21 export for his bibliographic data.

That set alarm bells ringing in my head and so with Ashkar’s approval, I created a backup of his Koha database and installed the backup¬†on L2C2’s test server running the latest stable 16.05.x version.

The first clear indication of what was wrong came soon after running sudo koha-rebuild-zebra -v -f mathrubhumi successfully without any error. A wildcard search from both OPAC as well as the staff client failed to return a single result, even though the Zebra indexer and output logs showed no error. However, it was possible to access a record by directly accessing it by biblionumber.

Running the “MARC Bibliographic framework test” to check the MARC structure provided the answer. Sure enough there were two major errors as shown below:

homebranch NOT mapped the items.homebranch field MUST :

  • be mapped to a MARC subfield,
  • the corresponding subfield MUST have “Authorized value” set to “branches”
holdingbranch NOT mapped the items.holdingbranch field MUST :

  • be mapped to a MARC subfield,
  • the corresponding subfield MUST have “Authorized value” set to “branches”

The question now was to identify *which* MARC21 framework since he had three (03) of them.

marcframe1
Ashkar’s MARC21 frameworks

Checking the “MOVIES” framework, it was found that both 952 $a (homebranch) and $b (holdingbranch) were set to ignore¬†in the Managed in tab¬†dropdown. This explained the error displayed by “MARC Bibliographic framework test”. To know more about the the 952 MARC21 field in Koha, please read Holdings data fields (9xx) from the Koha community wiki.

The Fix

It was a simple matter of setting both 952 $a and $b to “items(10)” for the option Managed in tab. This took care of the “MARC Bibliographic framework test” error.

However, that was only the first part of the solution. Except two, none of his other 23 bibliographic records had their homebranch and holdingbranch defined. It was time for a batch item modification from the Tools page (Home > Tools). This has been covered in details in an earlier blog post – “Koha‚Äôs MARC modification templates comes to the rescue“, so if the topic sounds unfamiliar, it is suggested that you read that post first.

In order to find out all the barcodes that needed to be used to update the records, the following SQL report was used:

SELECT items.barcode 
  FROM items 
  LEFT JOIN biblioitems ON (items.biblioitemnumber=biblioitems.biblioitemnumber) 
  LEFT JOIN biblio ON (biblioitems.biblionumber=biblio.biblionumber);

With the list of barcodes in hand, it was time for the final steps:

  1. Load up barcodes for the records to be bulk modified
    marcframe4
  2. Select the two fields that we wanted to update – homebranch and holdingbranch
    marcframe2
  3. Select the actual branch option for both and click on Save
    marcframe3
And we were done! ūüôā

The Explanation

Understanding the error is quite simple if you know how circulation works inside Koha. A checkout operation needs to know a few basic things – (a) who owns the item; (b) where is the item presently located; (c) what to set as the issue and due dates and (d) who is taking it. Since the items attached to bibliographic records created using the MOVIES MARC21 framework did not have their homebranch and holdingbranch defined, at the time of checkout, as Koha tried to set the issue date and calculate the due date, using the date functions from the Koha::Calender object, it failed to do so. That’s what gave Ashkar his error and prevented him from checking out an item.

This still left one question unanswered – why did Ashkar’s hosting provider keep insisting that everything was working OK at their end and wanted him to provide them with Teamviewer access instead. My best guess is they were checking out the system using only the MARC21 frameworks which *they* had shipped i.e. default and fast add (FA) frameworks. Since records generated using these two frameworks (quite correctly) had 952 $a and $b set, none of these triggered Ashkar’s error during checkout. They certainly did not need Teamviewer access, the error in Ashkar’s framework should have been easily detected and quickly fixed. In fact, it took less than 3 mins to take care of it. But they failed, which is why it is important to either invest in your own skill development (read RTFM) OR invest in quality support.

“If you pay peanuts, you get monkeys” – James Goldsmith

Moral of the story: If you work with service providers whose front line tech-support is staffed with inexperienced people, be prepared for the long haul and self support yourself. Caveat Emptor!

Setting specific ‘lockdown’ of Koha’s system preference options

Individual ‘lockdown’ of Koha’s system preference settings using a bit of jQuery and CSS.

The current stable version of Koha 16.05.4 ships with some 548 system preferences. These are stored in the ‘systempreferences‘ table in the database. Inside the Koha staff client, they are accessed by visiting the Home >¬†Administration > Global system preferences menu link. If this is the first time you are hearing about system preferences in Koha or you are not deeply familiar with them, it is suggested¬†that you familiarize yourself with this chapter section of the Koha 16.05 manual.

The objective here is not prevent someone’s use of Free Software, but rather to ensure they are only committing pre-validated changes to the production server. Changes have consequences and whoever makes them should be fully aware of the impact of these changes.

While Koha’s per user access control feature does provide a way to allow or withhold an user’s access to view / edit the system preferences, it does so with an “all or none” approach i.e. either the user has access to *all* the system preferences or none. This lack of access control granularity can prove to be slightly undesirable under certain circumstances. For example, you want that certain settings should *not* be changed or not changed accidentally or not changed without first testing and validating the change on a staging system. In our case, on our managed systems we do not want the designated superlibrarian user at the client’s end to make changes to say the opacheader, opaccredits, OPACUserJS, OPACUserCSS, IntranetUserJS, IntranetUserCSS and OpacNavBottom system preferences on the production VM, without first testing the changes on a test VM.

The implementation

We implemented the setting specific ‘lockdown’ in the system preference settings using a bit of jQuery and CSS.

Step #1

First we identified the selectors we needed in order to enable the lockdown. The easiest (and recommended) way to do this is to ‘inspect‘ your target (i.e. ones you want to lock down) DOM elements on the System Preference administration page(s). As mentioned before we want to lockdown the following sysprefs: IntranetUserJS, IntranetUserCSS, OPACUserJS, OPACUserCSS, opacheader, opaccredits, OpacNavBottom. Looking at the DOM made it clear that we needed to work with the following id based selectors – pref_IntranetUserJS, pref_IntranetUserCSS, pref_OPACUserJS, pref_OPACUserCSS, pref_opacheader, pref_opaccredits and pref_OpacNavBottom respectively.

Step #2

The next step was to decide how tight we want to make the ‘lockdown’. We did not want it airtight, so here is what we did. We left the IntranetUserJS and IntranetUserCSS only disabled, but the rest we removed their respective textarea elements from the loaded DOM. Had we wanted things really tight, we could have do that same for the two disabled ones.

lockdown_01
Click on the image to view it at full size

Note: Should you use .remove() on all the elements above instead of setting the attribute to disabled, then the only way to get access to them would be by directly editing the IntranetUserJS syspref’s value in the database.

Step #3

We will also add hints to the label so that users can understand why they are not able to access the setting. See the green arrow on the left above for the code. Once done, save the IntranetUserJS syspref and exit. We are done.

Checking our work so far

Let us search for the OPACUserCSS system preference. We will see (as given below) that the editable textarea element is no longer present. Note the “Click to collapse” text without the editable textarea element holding the actual setting value. Also there is now a small lock icon against the label with the text explaining why the edit window is not present.
lockdown_00a

Unlocking the ‘lockdown’

What we have implemented so far will prevent someone with system preference edit permission from¬†accidentally editing the ‘locked’ system preferences from the Admin page. In order to “unlock“, first we need to access the¬†IntranetUserJS syspref which we had only disabled in this case.

Unlocking – Step #1

Right click on the IntranetUserJS syspref and select Inspect

lockdown_00b
If you did it correctly then element with id as pref_IntranetUserJS with be highlighted. Note the disabled attribute which is pointed to with the red arrow in the screenshot below:

lockdown_00c

Unlocking – Step #2

Double-click to select the disabled="disabled" attribute of the textarea element.

lockdown_00d

Unlocking – Step#3

Delete the disabled attribute, the textarea element should now look like this.

lockdown_00e

Unlocking – Step #4

Close the Developer tools window, but *do not* move out of the IntranetUserJS syspref yet! We still have work to do. You will see that the textarea is no longer disabled and is now open for editing. In order to remove the ‘lockdown’ on our system preferences, we need to comment out the jQuery code we had added earlier. We do this simply by wrapping the relevant code inside a C style /* [...] */ comment block. See the green arrows in the image below:

lockdown_00f
Click on the image to view it at full size

Unlocking – Step#5

Save the IntranetUserJS syspref and now try to access the OPACUserCSS syspref again. As you can see from the image below, the system preference is no longer locked and now open for editing.

lockdown_00g

Re-locking

Once we are done with making necessary changes we may wish to again ‘lockdown‘ the settings. We simply need to go back and edit the IntranetUserJS syspref and un-comment the locking code by removing the C style comment markers. Easy Peasy!

Switching content language on Koha OPAC with user interface locale switching

How to display custom content in the user’s own language on the OPAC.

Last week Mr. Ahmad Nasser¬†from¬†the¬†Future University of Egypt reached out for a bit of help. The Koha OPAC provides certain sections / blocks on the OPAC e.g. OpacNav, OpacNavBottom, OpacNavBottom and OpacMainUserBlock etc. where libraries can add custom content / instructions / links / widgets to aid¬†and inform¬†their users¬†better about their library and its services. Nasser’s case was interesting since he needed to cater to a bi-lingual readership where some users may prefer to read the information presented in Arabic rather than in English.

Development of language was the greatest break through of human technology. It helps us to communicate. But the same language when it is not the same for a group of people can create problem. How do a Bengali communicate with a Tamil, a Malayali with an Assamese when they do not understand the others’ language and they do not happen to speak English the global lingua-franca?¬†Sort of like this line from¬†this famous song pictured¬†on Raj Kapoor in his super hit 1955 super hit – ¬†Shree 420 that goes “mera joota hain Japani, yeh patloon engleesthani, saar pe topi russi….” (‘My shoes are Japanese, these pants are from England, the red hat on my head is Russian…’) – indeed how do we cater to this diversity!

trans_raj
Still image copyright: Shemaroo Videos

When it comes to a software like say Koha, the answer lies in localization Рa process which allows a software to present information to its users in their own language of choice.

Koha’s user interface (UI) locale switching allows for users to switch the user interface language e.g. from default English to say Chinese (Taiwanese) or Hindi (India) as long as the language pack exists for Koha. However, this switching is not designed to tackle switching the language of the content in these custom blocks which we mentioned in the previous paragraphs.

Nasser wanted a way to display the content of say OpacMainUserBlock in Arabic when the user switched the user interface to Arabic and back in English when another user wanted to use the default language (i.e. english). This post highlights one ways by which Koha administrators / librarians can let their users a way to see the content in the language of their choice rather than an arbitrary default language or even worse a mish-mash of two or more languages.

This case is relevant to libraries in India as well, with our multitude of languages Р22 official languages at the last count РHow do we serve content in English to our top 10 Р15% population, at the same time how do we address the rest of our population who are literate in their own language, all who may be some day be using Koha. Our records may be in the local regional language, but how about the added custom content? This solution works by looking at present locale[1] selected the user on the Koha OPAC.

The Solution

As I’ve mentioned this is not the only way to solve this problem. But it is probably the simplest *and*¬†the cleanest one. And it does so by using three things:

  • The selected locale language of the Koha OPAC
  • One line of custom CSS placed into OpacUserCSS system preference
  • Exactly 3 lines of Javascript added to OpacUserJS system preference

In this blog post, we’re¬†only looking at managing the OpacMainUserBlock – the central block on the OPAC, but the solution can be applied to every other blocks that access custom HTML markup – including OpacHeader, OpacCredits ¬†as well as on “Koha as CMS” pages etc.

If you have never setup multiple language support on Koha, you can read up – “Installation of additional languages for OPAC and INTRANET staff client” and familiarize yourself first.

The Demo

I’ve set up a multiple language demo Koha installation with the following languages aside from the default English:

(a) Arabic (ar-Arab)
(b) Czech (cs-CZ)
(c) German (de-DE)
(d) Hindi (hi)
(e) Slovak (sk-SK)
(f) Chinese (Taiwanese: zh-Hans-TW)

The URL is https://demo-opac.l2c2academy.co.in/cgi-bin/koha/opac-main.pl¬†where you can see this working in action. As you change the selected language and right click to see source code of the page, you will notice that the “lang” attribute of the “html” element changes to the language codes given inside the parentheses above. Below is a snapshot of 6 of the 7 languages as rendered in the HTML source once you change the language.

trans_all_src

Hint: That lang attribute is our locale identifier and it changes every time we select a different language. Try it out on the demo and see it for yourself.

Since this depends on using CSS to toggle the visibility of our local language content we are going to define a disabled class in our OpacUserCSS system preference like this:

/* disabled class */

.disabled {
   display: none;
}

In this example we will use a <div> element like given below:

<div class="en disabled">

 your local language content goes here

</div>

However we can use this technique on *any* HTML element whose visibility can be toggled by accessing its display CSS property [2]. We will need to add two extra classes to our HTML element – the first one class will be named as our lang attribute and the second class will be the disabled class. We’ll need to repeat this definition for each language that we want to deal with.

For your reference here is a listing of my OpacMainUserBlock for this example, please download and study it in order to understand the process better.

NOTE: For this example, I’ve selected a single paragraph from the entry on “Wikipedia” from the Arabic, Czech, German, English, Hindi, Slovak and Chinese Wikipedia.

Once, our custom HTML is in place, we will need a way to toggle their visibility (CSS display property) based on the user selected language locale via the lang attribute. For this we’ll use the following JQuery snippet in our OpacUserJS system preference:

$(document).ready(function() {

  var selectedlang = $('html')[0].lang;

  var buildClassString = ".".concat(selectedlang);

  $(buildClassString).removeClass('disabled');

});

The first line finds out the lang attribute of our <html> element. In the next line we build a string to hold the selector for the class (since classes are notified in JQuery selectors using a dot in front of the class name). And finally, in the third line, we remove the disabled class from the content whose language class matches the lang attribute. By removing the class from the element, we automatically cause its display CSS property to become visible.

What really happens behind the scenes

The custom HTML markup is first loaded with its visibility turned off. Once the page is loaded the document.ready() JQuery call looks up the current language selected and removes the display: none; CSS style from the element by removing the disabled class. As a result, the element and the content it is designated to display becomes visible. This whole cycle is repeated when we select another language. Thus, we are now able to provide our users with custom HTML markup and content based on the language they selected.

Reference

[1] “Locale (computer software) – Wikipedia, the free encyclopedia

[2] “CSS/Properties/display – W3C Wiki

CSS Quicktips : Removing RSS feed links from the Koha OPAC

Earlier today a fellow Koha user had asked :

“How to deactivate the News RSS link in OPAC?”

news rss feed link

The RSS feed link is contained in a <div> with the id named rssnews-container. In order to handle its visibility we need to simply add the following line to our OPACUserCSS system preference:

#rssnews-container {
    display: none !important;
}

And while we are on the topic, there is also another location where the RSS feed link shows up and that is in our OPAC search results page.

rssfeed

In this case however our approach needs to be slightly different as the link is presented as an anchor (a) element with the associated class rsssearchlink. Other than using a different CSS selector, rest of it is same i.e. we need to turn off the visibility of the element like this:

a.rsssearchlink { display: none !important; }

As we commonly say in Bengaluru (erstwhile Bangalore) – Enjoy maaDi ūüôā

Hiding “Authority search” and “Tag cloud” search options on Koha OPAC using CSS.

CSS one-liner to hide Authority search & Tag cloud options on the Koha OPAC.

Client partners not using authority files and tag cloud features of Koha, often insist that we remove the options – “Authority seach” and “Tag cloud” from the OPAC. Now, if we look at the DOM (Document Object Model) of the OPAC main page, we will see that these searches are located inside a <div> element named moresearches.

<div id="moresearches">
  <ul>
    <li>
      <a href="/cgi-bin/koha/opac-search.pl">Advanced search</a>
    </li>
    <li>
      <a href="/cgi-bin/koha/opac-authorities-home.pl">Authority search</a>
    </li>
    <li>
      <a href="/cgi-bin/koha/opac-tags.pl">Tag cloud</a>
    </li>
  </ul>
</div>

The other important thing to note here is the CSS (Cascading stylesheet) rules for the div,li elements and the li:after pseudo class [1].

div {
    display: block;
}
#moresearches li {
    display: inline;
}
#moresearches li:after {
    content: " | ";
}

Note: That li:after is what adds the ” | ” (pipe) separator between the options.

So, we are going to “hide” them and we will mainly use the CSS3 :nth-child() pseudo class selector to do this.

CSS3 :nth-child simplified

If you want a formal definition, go ahead and read this CSS/Selectors/pseudo-classes/:nth-child from the W3C (World Wide Web Consortium) wiki.

Let us see if it is better understood with an actual example! In our case, we can see that our <ul> (unordered list) element has 03 (three) <li> (list item) child elements. The nth-child is a counter that starts from 1 (one). Thus, nth-child(2) signifies the second “child” element. Here this would point to the second <li> i.e. the “Authority search”. Thus n in nth-child is simply a way to refer to a specific child.

The term “selector” is simply a rule / ruleset (i.e. code) that helps us to latch on to a particular element (or its content) by using either it’s (a) name; (b) id; (c) class, (d) contents, (e) position OR a combination of these or other attributes, and then do whatever we want to do with it. When selectors are used with CSS, we are usually talking about styling them.

Hint: making an element (or group of elements) in your DOM invisible (as in this case) will also be considered as styling.

The solution

While we can write the ruleset in a single line, here we have broken it up into two lines for better readability and understanding.

#moresearches > ul > li:nth-child(n+2) { display: none; }

#moresearches > ul > li:after { display: none; }

n by itself references the first child element. The notation n+2 in this case means select the other two <li> elements *after* the first one i.e. “Advanced search”. Once selected we set then to display: none;. This turns off their visibility while still retaining this elements in the DOM. The second line is more cosmetic in nature and turns off the visibility of the li:after pseudo class so that there is no dangling “|” displayed after Advanced search.

References

[1] http://www.w3schools.com/css/css_pseudo_classes.asp

Quick tip: Add “barcode” lookup to your OPAC’s search index selection downdown

If you wish to add an option to the OPAC search dropdown e.g. “Barcode”, you can achieve it with a single line of jquery. There is absolutely NO need to edit masthead.inc as suggested in BUG #8302 – http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=8302.This jquery one-liner does the job rather well, simply place it inside your OPACUserJS system preference.

$("select[name='idx']").append("<option value='bc'>Barcode</option>");

If you wish to know how I set the value to bc, I suggest you take a dive into this file ccl.properties in your Koha installation.

P.S. You can also search as bc: <your barcode number> in the search box. That works too, even without adding the option to the drop-down as you are directly passing a CCL query option back to the Koha search module.

This post is based on an earlier Facebook post published here https://www.facebook.com/l2c2technologies/posts/775648639191038 on Feb 23, 2015.

The 5-Minute Series: Adding Lightbox support to your Koha OPAC

Ever wanted to add a Lightbox enabled custom gallery page to your Koha ILS installation? Here’s how you can do it, with a bit of background and a brief touch on caveats and afterthoughts of implementing it.

Recently one of our client partners, Ms. Parama Sarkhel, Librarian, Ramakrishna Sarada Mission Vivekananda Vidyabhavan, requested us to add an image gallery with photos of the library and library events to her OPAC. We promised her that we’ll to look into it.

gallery_01

While we had setup image galleries for others, this time we decided to do something different. As any seasoned Koha user will know, you can add custom pages to your Koha OPAC. Adding a gallery typically means adding a new custom page with a bunch of photos and the nessecary CSS styles along with (usually) some Javascript to handle it. In fact, if you are not too bothered about supporting older browsers you can set up a gallery using *only* CSS3 alone.

NOTE 1: If you are a new user of Koha, you may wish read up Appendix H. Using Koha as a Content Management System (CMS) from the Koha 16.05 Manual (en). Be advised that the instructions for Koha as a CMS are slightly out of sync, so you need to change where it says “pages.tmpl” to “pages.tt” to be able to actually use these instructions.

NOTE 2: Prior to release of Koha v 3.4.3 [1] on July 25, 2011, Koha used the HTML::Template perl module for handling its template requirements. Via Bug id #5917 [2], Koha 3.4.3 switched over to Template::Toolkit templating system [3]. The reference to “pages.tmpl” is a relic from Koha’s HTML::Template past.

Introducing Lightbox2

To an average Web UI designer / programmer, Lightbox usually needs no introduction. However since the target audience of this blog includes people who do not neccesarily program, either for passion or a living, let us introduce the main “protagonist” of our post here i.e. Lightbox! Lightbox2 is a successor to the the original lightbox [4] script by Lokesh Dhakar. As described by it’s author Lokesh :

“Lightbox is small javascript library used to overlay images on top of the current page. It’s a snap to setup and works on all modern browsers.”

Users who are new to the term lightbox (you have probably used it online, without knowing that it is called a ‘lightbox’) can have a look at [4] below in the reference sub-section.

Making Lightbox2 work with Koha

Before we get out hands dirty and share with you what we did, here are a few things that we must keep in mind.

First the things that one must know

1. As on date the Koha OPAC uses an older version of Jquery javascript library i.e. version 1.7.2 (released [5] on March 21, 2012) AND a rather old version of the Twitter Bootstrap framework i.e. 2.3.1. So whatever lightbox script / library we choose to use, it *must* work correctly with these two software’s version as shipped with Koha.

2. Luckily Lightbox2 works with jquery 1.7.x or higher, which puts us in the clear about our choice of lightbox library.

3. When Lokesh’s Lightbox was released about 8 years ago, the world of web development was vastly different from today. Different browser versions (mainly IE) implementing “quirky” mode vs. “strict” modes differently, support of HTML5 / CSS3 often varied significantly from W3C standards, desktop PCs rather than smartphones and tablets ruled the world. In fact, we were also witnessing the closing moments of the second browser wars [6]. By selecting the up-to-date version of the original lightbox script, we ensure that we are using a mature javascript library with the largest possible cross-browser, cross-device compatibility *including* backward compatibility.

Now that we have all these history lessons out of the way, let us proceed with the actual steps to get this show on the road.

Step #1 – Downloading Lightbox2

Following the instructions on the Lightbox2 site, we proceeded to download the latest version of the library https://github.com/lokesh/lightbox2/archive/master.zip on our server and proceeded to unzip it.

Step #2 – Installing Lightbox2 inside our OPAC’s DocumentRoot

Since we are using Debian 8.4 on our server with Koha being installed via the .deb package route, our OPAC’s DocumentRoot is located by default at /usr/share/koha/opac/htdocs. As our server is multi-tenanted [7], we are going to create a new folder lightbox2 under this location so that every Koha instance running off this server can take advantage of the Lightbox installation.

sudo mkdir /usr/share/koha/opac/htdocs/lightbox2

Next we shall copy over the folders under the /dist folder from inside our unzipped copy of Lightbox2.

sudo cp -R dist/* /usr/share/koha/opac/htdocs/lightbox2/.

Three folders should be copied over css,images and js. The important files that we will need for our work are:

/usr/share/koha/opac/htdocs/lightbox2/css/lightbox.css
/usr/share/koha/opac/htdocs/lightbox2/js/lightbox.js
/usr/share/koha/opac/htdocs/lightbox2/images/close.png
/usr/share/koha/opac/htdocs/lightbox2/images/loading.gif
/usr/share/koha/opac/htdocs/lightbox2/images/next.png
/usr/share/koha/opac/htdocs/lightbox2/images/prev.png
Step #3 – Getting Koha to work with Lightbox

Now that we have the Lightbox2 library installed on our server, it is time to tell Koha how to use it. And the way we are going to do that using the very important OPAC system preference OPACUserJS[8] and some jQuery magic that will help us load up the library into our OPAC’s Document Object Model (DOM)[9]. This is how we will do it:

$(document).ready(function () {
  $("head").append("");
  $.getScript('/lightbox2/js/lightbox.js').done(function( script, textStatus ) {
    console.log( textStatus );
  })
});

The first line $("head").append(""); inserts the necessary stylesheet (lightbox.css) into the <head> section of the OPAC. The second line uses $.getScript[10] to dynamically load lightbox.js into the page using an AJAX based HTTP GET request when the OPAC page’s DOM has been fully loaded. The last line is used to log the success or failure of the attempt to load the file lightbox.js.

Step #4 – Using Lightbox

Adding the data-lightbox attribute a image link activates the lightbox capability for the image of our choice. The value of the data-lightbox attribute should be unique on the page on which the image is, unless we want to create a set of images on that page which should all be served by Lightbox . Basically, using the same value for a set of image links creates a manual carousal for that page. Since we are creating an image gallery we will use the same value for the entire set of images placed on and linked to from our gallery page. In fact, in our case, we wanted to show *two* galleries on the same page – one showing every day activities, another showing a recent event organised by the library. So, we ended up using *two* data-lightbox values – one for each of the sets.

This is where we define our custom page and the custom CSS styles to set things up and ready for Lightbox to take over.

A snippet of our custom page’s markup as follows, the data-title attribute adds the captions to displayed by Lightbox. As you can see, all the four example images share the same data-lightbox attribute i.e. “gallery-1” marking them as a part of a single set or gallery of images.

<div class="span3 l2c2galimg">
  <a href="gallery/rksmvv_gallery_02.jpg" data-lightbox="gallery-1" data-title="Reading Room - Journal Section">
    <img src="gallery/rksmvv_gallery_02.jpg" alt="Reading Room - Journal Section" />
  </a>
  <div class="desc">Reading Room - Journal Section</div>
</div>

<div class="span3 l2c2galimg">
  <a href="gallery/rksmvv_gallery_03.jpg" data-lightbox="gallery-1" data-title="Circulation Counter">
    <img src="gallery/rksmvv_gallery_03.jpg" alt="Circulation Counter" />
  </a>
  <div class="desc">Circulation Counter</div>
</div>

<div class="span3 l2c2galimg">
  <a href="gallery/rksmvv_gallery_04.jpg" data-lightbox="gallery-1" data-title="E-Resource Centre">
    <img src="gallery/rksmvv_gallery_04.jpg" alt="E-Resource Centre" />
  </a>
  <div class="desc">E-Resource Centre</div>
</div>

<div class="span3 l2c2galimg">
  <a href="gallery/rksmvv_gallery_05.jpg" data-lightbox="gallery-1" data-title="Photocopy Service">
    <img src="gallery/rksmvv_gallery_05.jpg" alt="Photocopy Service" />
  </a>
  <div class="desc">Photocopy Service</div>
</div>

In the following snippet note that the data-lightbox attribute is different, thus marking these entries as a separate set or gallery.

<div class="span3 offset3 l2c2galimg"><a href="gallery/rksmvv_gallery_01.jpg" data-lightbox="gallery-2" data-title="Inauguration of Research and Resource Centre - #1"> <img src="gallery/rksmvv_gallery_01.jpg" alt="Reading Room - Journal Section" />
</a>
<div class="desc">Inauguration - #1</div>
</div>
<div class="span3 l2c2galimg"><a href="gallery/rksmvv_gallery_10.jpg" data-lightbox="gallery-2" data-title="Inauguration of Research and Resource Centre - #2"> <img src="gallery/rksmvv_gallery_10.jpg" alt="Circulation Counter" />
</a>
<div class="desc">Inauguration - #2</div>
</div>

The custom CSS classes l2c2galimg and desc as seen in the above snippets are simply used to style the images and the captioning <div> and are not related to lightbox’s CSS declarations and so you are free to define your own styling.

Show me the money!

See the Lightbox enabled galleries in action here https://rksmvvlibrary.in/pages.pl?p=gallery. Simply click on any of the images and watch Lightbox take it over. As these are galleries you can scroll through the images by touching / taping / clicking the left or right side of any image in the set or even the left/right arrow keys on your keyboard to go back or forward. Clicking or touching the “XCLOSE widget or for that matter anywhere on the screen outside the lightbox popup will take you back to the gallery page.

Caveats and afterthoughts

1. You do not neccesarily need to put your list of images into separate divs of spanX class as we have done here. Lightbox will work equally well with unordered lists <ul> classed with Bootstrap 2.3.1’s thumbnail styles.

2. This set of instruction will work with all the previous versions of Koha that uses Bootstrap 2.3.1 and jQuery 1.7.2 for the OPAC. Basically that means all versions of Koha which have shipped with the bootstrap theme i.e. Koha 3.14 and above.

3. Lazy loading[11] the lightbox.js library using getScript AJAX call comes with *one* penalty though. The script is loaded timestamped and hence not cached, meaning it gets loaded each time this gallery page is opened by a visitor. You may be able to workaround the lack of caching by using the jQuery.ajax call and setting the datatype to script and indicating an expiry value for lightbox.js. We haven’t tried it, so YMMV!

4. Of course, if you deem this to an important enhancement (we don’t) then you can of course file a new enhancement bug and submit a patch to Koha community.

References:

[1] Koha 3.4.3 is now available

[2] Bug 5917 – Switch Koha to use Template::Toolkit

[3] http://template-toolkit.org/

[4] Lightbox (JavaScript) – From Wikipedia, the free encyclopedia

[5] jQuery 1.7.2 Released

[6] Second browser war – From Wikipedia, the free encyclopedia

[7] Multitenancy – From Wikipedia, the free encyclopedia

[8] 1.11.2.50. OPACUserJS – Koha 16.05 (En)

[9] Document Object Model – From Wikipedia, the free encyclopedia

[10] jQuery.getScript()

[11] Lazy loading – From Wikipedia, the free encyclopedia

Koha on an OpenVZ VPS? Better make sure you have the right time!

If your Koha ILS is on a OpenVZ VPS located in another country, then you need to specifically tell MySQL about your timezone… i.e. if you value your sanity!

The heart of everything to do with computers lies in the most intangible of things – time!¬†We all want to know at what time was a record entered, when did our patron borrow / return a book, when is fine to be calculated, when are our IndexData Zebra re-indexing is supposed to run, when are our email / sms notifications supposed to go out etc. Mostly Koha keeps track of all these (and much more) using datetime data in the database tables. Most of these fields are set by default to CURRENT_TIMESTAMP. As a result when we transact using Koha or update our records, the MySQL server automatically fills in the exact datetime values using the system time. This “automatic” business can be an aid or a hindrance – as you will get to see in a moment.

The backstory a.k.a how we ended up with this

We were using an OpenVZ based VPS located in the US east coast for a client who is located in India. Since OpenVZ VPSes have their time controlled by the host system, there is not much we can do (unlike we can with KVM or Xen based virtualization). Luckily the host itself was setup with ntpdate, so at least the time was accurate. We took the next best route, setting up the timezone using ‘Asia/Kolkata’, which is the TZ definition for India on Linux.

$ sudo dpkg-reconfigure tzdata

It exited successfully showing the following output:

Current default time zone: 'Asia/Kolkata'
Local time is now:      Wed Sep  7 04:00:01 IST 2016.
Universal Time is now:  Tue Sep  6 22:30:01 UTC 2016.

The problem

Restarting the VPS, we proceeded with our task and things looked OK. Around 4:39 AM while importing a .mrc file we saw something that clearly showed we had missed something. The lcoal time was September 07, 2016 4:41 AM and yet Koha told us that we had uploaded the .mrc file yesterday – September 06, 2016 at 7:11 PM! Woah!

wrong-time

We quickly referred to the super awesome Koha database schema website and looked up the “import_batches” table. Sure enough, the upload_timestamp was defined as timestamp with the default set as CURRRENT_TIMESTAMP. Thus, while our timezone correction had worked with the rest of system *and* Koha, MySQL was using something else as its time.

Switching to a terminal we fired up the command-line mysql client and took a closer look.

mysql> SELECT @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| EDT                |
+--------------------+
1 row in set (0.00 sec)

Hmmmm… Eastern Daylight time is -4:00 hours behind GMT, just as we are +5:30 hours ahead. A second query further confirmed this.

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2016-09-06 19:29:17 |
+---------------------+
1 row in set (0.00 sec)

The solution

A quick read of http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html and a cross-check inside our /etc/mysql/my.cnf – the mysql configuration file, confirmed that we needed to setup our default timezone and move our MySQL server from the system timezone defaults coming in from the host system’s EDT timezone.

“The value can be given as a named time zone, such as ‘Europe/Helsinki’, ‘US/Eastern’, or ‘MET’. Named time zones can be used only if the time zone information tables in the mysql database have been created and populated.” – MySQL documentation

Going back to our mysql client, we decided to check the time_zone and time_zone_name tables inside the mysql system database. Both turned out to be blank.

mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> select * from time_zone;
Empty set (0.00 sec)

mysql> select * from time_zone_name;
Empty set (0.00 sec)

Since we must have the time_zone_name table populated with our zoneinfo data (which resides under /usr/share/zoneinfo/) we turned to the nifty utility mysql_tzinfo_to_sql.

$ mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

It went through and we checked the time_zone_name table again. This time time_zone_name returned 1808 rows. With our timezone reference setup, we turned to /etc/mysql/my.cnf and added the following line under the [mysqld] section in the file:

default-time-zone='Asia/Kolkata'

Restarting the MySQL server with sudo service mysql restart we re-checked select now() and SELECT @@system_time_zone. The results were:

mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2016-09-07 05:44:00 |
+---------------------+
1 row in set (0.00 sec)

mysql> SELECT @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| IST                |
+--------------------+
1 row in set (0.00 sec)

Success!

We reloaded the Manage staged MARC records page in Koha and sure enough it now showed the correct date and time of the upload.
right-time