Tag Archives: UI

Showing item type counts on the checkout screen

Does your library limit your patrons to a certain number of checkouts for certain item types? At the Athens County Public Libraries, for instance, we limit patrons to 10 audio books, 10 music CDs, 10 videos, and 5 DVDs at a time. If a patron tries to check out more than 5 DVDs, Koha will show a warning. But what if you want to be able to tell at a glance how many a patron has?

This functionality was available to us in our 2.x installation, but when we upgraded to 3.0 our support company at the time told us it wasn’t a customization they would support. This wasn’t a feature we were willing to give up, so I set out to duplicate it using the tools available to me: system preferences and JavaScript.

Information there for the taking

All the information we need can be found on the patron checkout screen, we just need to figure out how to get it. The page lists all the items checked out to the patron, and it shows the item type for each:

List of items checked out on the checkout screen

With this available to us we can use jQuery to count each instance of each item type. We need to build a count for each item type in our system, so the script isn’t very portable. It looks for table cells (“<td>“) containing the description of each of our item types:


var itypes = {'circ': 0, 'avid': 0, 'avbk': 0, 'avmu': 0, 'advd':0 };
$("#issuest td:contains('Circulating')").each(function(){
itypes["circ"]++;
});
$("#issuest td:contains('Videos')").each(function(){
itypes["avid"]++;
});
$("#issuest td:contains('DVDs')").each(function(){
itypes["advd"]++;
});
$("#issuest td:contains('Audio Books')").each(function(){
itypes["avbk"]++;
});
$("#issuest td:contains('Music CDs')").each(function(){
itypes["avmu"]++;
});

The script starts by setting up an array of all my item types (“circ,” “avid,” etc.) and giving each a value of zero. Then the script looks for instances of each item type description on the page,  “Circulating,” “Videos,” etc., using jQuery’s :contains selector. Each time it finds an instance of one of those text strings the script increments the count for that item type. At the end of the process the script will have the count for each item type.

Displaying the counts on the page

In order to show the item type counts on the page we need to lay some groundwork by adding some markup. I want to add the count information right after the “Checking out to…” heading, so I’ll find that element’s ID using FireBug and jQuery’s after() function:


$("#circ_circulation_issue label[for='barcode']").after( ... );

The HTML I’m going to add is the default state, so it shows a zero count for everything:


<p style="margin-top:1em">
<span id="avmuout">0</span> Music CDs out, <span id="avmuok">10</span> More Allowed
</p>
<p>
<span id="avbkout">0</span> Audio Books out, <span id="avbkok">10</span> More Allowed
</p>
<p>
<span id="avidout">0</span> Videos out, <span id="avidok">10</span> More Allowed
</p>
<p style="margin-bottom:1em">
<span id="advdout">0</span> DVDs out, <span id="advdok">5</span> More Allowed
</p>

I’ve  included unique IDs for the “count” spans so that I can easily update them with my script:


$("#avidout").html(String(itypes["avid"]));
$("#advdout").html(String(itypes["advd"]));
$("#avbkout").html(String(itypes["avbk"]));
$("#avmuout").html(String(itypes["avmu"]));

$("#avidok").html( 10 - itypes["avid"] );
$("#advdok").html( 5 - itypes["advd"] );
$("#avbkok").html( 10 - itypes["avbk"] );
$("#avmuok").html( 10 - itypes["avmu"] );

In the first of the two sections above I take the count I got earlier, itypes['avid'] and set the content of the corresponding <span> using the html() function. I also want to show how many more the patron can check out, so I subtract the count from the limits I’ve set in my Koha installation.

If you have patrons who have exceeded their checkout limit you’ll see a problem: The page will tell you they’re allowed to check out a negative number more items. We can correct the script to accommodate:


$("#avidok").html((10-itypes["avid"] &gt; 0) ? 10-itypes["avid"] : 0);
$("#advdok").html((5-itypes["advd"] &gt; 0) ? 5-itypes["advd"] : 0);
$("#avbkok").html((10-itypes["avbk"] &gt; 0) ? 10-itypes["avbk"] : 0);
$("#avmuok").html((10-itypes["avmu"] &gt; 0) ? 10-itypes["avmu"] : 0);

Final version

Here’s what the results look like:

The final version includes proper escaping of the HTML content and wraps the whole process into a function (“itemTypeCount”). This function will be called on page load only if jQuery finds that the table of checkouts, which has an ID “issuest” is being displayed. The whole script goes into Koha’s intranetuserjs system preference.


function itemTypeCount(){
$("#circ_circulation_issue label[for='barcode']").after("<p style="margin-top:1em" class="icount"><span id="avmuout">0</span> Music CDs out, <span id="avmuok">10</span> More Allowed</p> <p class="icount"><span id="avbkout">0</span> Audio Books out, <span id="avbkok">10</span> More Allowed</p> <p class="icount"><span id="avidout">0</span> Videos out, <span id="avidok">10</span> More Allowed</p> <p style="margin-bottom:1em" class="icount"><span id="advdout">0</span> DVDs out, <span id="advdok">5</span> More Allowed</p>");

var itypes = {'circ': 0, 'avid': 0, 'avbk': 0, 'avmu': 0, 'advd':0 };
$("#issuest td:contains('Circulating')").each(function(){
itypes["circ"]++;
});
$("#issuest td:contains('Videos')").each(function(){
itypes["avid"]++;
});
$("#issuest td:contains('DVD')").each(function(){
itypes["advd"]++;
});
$("#issuest td:contains('Audio Books')").each(function(){
itypes["avbk"]++;
});
$("#issuest td:contains('Music CDs')").each(function(){
itypes["avmu"]++;
});
$("#avidout").html(String(itypes["avid"]));
$("#advdout").html(String(itypes["advd"]));
$("#avbkout").html(String(itypes["avbk"]));
$("#avmuout").html(String(itypes["avmu"]));
$("#avidok").html((10-itypes["avid"] &gt; 0) ? 10-itypes["avid"] : 0);
$("#advdok").html((5-itypes["advd"] &gt; 0) ? 5-itypes["advd"] : 0);
$("#avbkok").html((10-itypes["avbk"] &gt; 0) ? 10-itypes["avbk"] : 0);
$("#avmuok").html((10-itypes["avmu"] &gt; 0) ? 10-itypes["avmu"] : 0);
}
$(document).ready(function(){
if(document.getElementById("issuest")){
itemTypeCount();
}
});

Caveats

This system works very well for my library, but it comes with a few caveats:

It requires that you hard-code, in the script, handling for each of your Koha item types.

Besides being tedious, it also requires that you modify the script each time you change your item types.

It requires that you hard-code the correct item type limits.

Also tedious, and requires that you modify the script each time you change your circulation rules.

It creates a potential collision with both call numbers and titles.

If my item type description is “DVD” and my call number includes the text “DVD” as well I’ll get an inaccurate count. If my item type description is “Audio Books” and a patron has checked out a print book entitled Audio Books for long trips I’ll get an inaccurate count.

For us the disadvantages are not unwieldy and the collision problem has never caused a problem. The advantage we get is being able to tell at a glance whether the patron is going to be able to check out that stack of DVDs or whether we need to ask them to put some back. Better to ask them to pick their favorites up front rather than after we’ve already checked out some of them.

Interface test: Placing a quick hold

I was thinking about ease of use, and what we could to to improve the Koha OPAC from the point of view of the patrons, and the first thing my mind jumped to was the process of placing holds. For many patrons placing a hold is the goal of their visit to the OPAC. They’re looking for something they want, they find it in the catalog, and they want to get it. On Amazon.com the next step would be to buy it. In the OPAC they can place a hold.

What’s the first thing they see when they click one of those “place hold” links? Potentially this:

Place hold interface with all options turned on

I hate it. It’s an ugly table with too many options. True, you can turn off some of those options for a simpler process. Turn off the OPACItemHolds system preference to eliminate the option of choosing a specific copy. Turn off OPACAllowHoldDateInFuture to hide the Hold Starts on Date column. Turn off OPACDisplayRequestPriority to hide the hold request’s rank in the queue. Now it’s a little simpler:

With optional settings turned off

I’m still not crazy about it, and that’s why holds came to mind when I thought about what we could do to improve interactions in Koha. How can we make that interaction simpler? How about [almost] one-click “ordering?”

Click the "Place hold" link in the right sidebar

When you click the “Place hold” link you can see my idea demonstrated. Clicking the link would use JavaScript to display a simple form: Place hold? Yes/No. Embedded in the HTML would be all the required form fields, hidden, for placing a single hold with no options set, using the patron’s home library as the destination for the hold. If the patron wanted to set additional options they could click the “more options” link and be taken to the standard form.

How hard would this be to implement? It depends how far you want to take it. I could see  this being a JavaScript-only enhancement, assuming all the information we need is found on this page. In this version clicking the “Yes” button would submit the form to the same script the standard form does, but bypass the hold confirmation screen. The user would be redirected to their summary page showing current holds.

A fancier version would submit the form in the background. Clicking the “Yes” button would triggers a sequence of events:

  1. The hold would be submitted in the background.
  2. The interface would display some kind of “Working” indicator.
  3. Upon completion of the background submission, the interface would indicate success.

This is more complicated because the reserve script would have to be modified to work in new way. Error-handling would have to be incorporated so that if for some reason the hold couldn’t be processed the user could be warned. The advantage to this interaction is that the user never leaves the page, making it easier for them to find their way back to their original search–something which, incidentally, is also on our to-do list of ways to make things easier for the user.

Enlittling the OPAC’s login form

Seems like lots of people hate the login form on Koha’s OPAC.  I understand many have a problem with it because their users look at and think they must log in to use the catalog. There’s no switch to flip to turn off display of the login form on the main page, but you can use a little custom CSS to hide it.

Add this to your OpacUserCSS system preference:

#login {
display: none;
}

One disadvantage to this technique is that it doesn’t allow your main page content to take up the whole width of the front page. The right-hand column of the OPAC’s main page remains pretty much inflexible in terms of content.

What if you don’t want to eliminate the option of logging in from the home page but you don’t like the big login form? Recently someone posed this question on the Koha mailing list.

Any thoughts on where to look to move the “Login to Your Account” and the Username and Password blanks to the top and replace the link there for “Login to Your Account” with Username and Password?

I started jumping in with some JavaScript when I realized this could be accomplished using just CSS. Here’s the result:

Click to enlarge image

Click to enlarge image

Here’s a rundown of what’s going on in the custom CSS:

  • Styling the form container with position: absolute and placing it in the top right corner. The form overlaps and hides the default login link in the top right corner.
  • Styling all the form contents as inline instead of block.
  • Adjusting margins, padding, font-size, and width.
  • Hiding the login form’s title (“legend”).

Why did I hide the form’s title? It wasn’t for aesthetic reasons. I found that Internet Explorer 6 refused to display the title (which is a <legend> inside a <fieldset>) in line with the rest of the form. IE6 wanted to give the <legend> its own line. Some conditional comments could alleviate the problem if you wanted to deliver the title to browsers that can display it correctly.

To give the form some room there at the top of the page I added a little bit of margin to the top of the main search bar. If your OPAC design includes custom header content you might have to adjust that margin.

I’ve tested this in these browsers on Windows XP: Internet Explorer 6, Firefox 3.5, Safari 4, Opera 10, and Chrome 3. Below is the CSS in its entirety. Add it to your custom stylesheet or to your OpacUserCSS system preference.

#login {
background-color : #FFF;
position : absolute;
top : 0;
right : 0;
padding-top : 5px;
width : 22em;
}
#auth fieldset,
#auth fieldset.brief {
border : none;
display : inline;
margin : 0;
padding : 0;
}
#auth input {
font-size : 75%;
}
#auth legend {
display : none;
}
#auth label {
display : inline;
font-size : 85%;
}
#auth li,
#auth ol {
display : inline;
}
#login #userid, #login #password {
width:auto;
}
#auth fieldset.action input {
margin: 0;
padding : 0;
}
#auth fieldset.action {
margin-bottom : -5px;
}
#opac-main-search {
margin-top : 1.5em;
}
Any thoughts on
where to look to move the “Login to Your Account” and the Username and
Password blanks to the top and replace the link there for “Login to
Your Account” with Username and Password?

Quick patron add?

Someone posted an enhancement request today requesting a change to the way the patron entry form is arranged in the Koha staff client. By default the patron entry form is pretty long, and the request asks that required fields be grouped at the top.

It seems like a reasonable request, but there’s a big disadvantage to trying to solve this problem with a template-only change: Libraries can customize which fields are mandatory when entering patrons. The system preference for that is  BorrowerMandatoryField (“borrower” being the term used in place of “patron” at the time of the preference’s creation).

What alternatives might there be to a template-only solution?

  1. Alter the script which generates the patron entry form so that any required fields (no matter which ones they are) are displayed at the top.
  2. Create a “quick-add” form which shows only required fields.
  3. Add a filter to the full patron entry form to toggle display of non-mandatory fields.

I like option two as a long-term solution, but option three could be implemented now with some custom JavaScript. Here’s a proof-of-concept script to show that using the markup which exists in the form now we can pull only required fields:


$(document).ready(function(){
var list = "<fieldset class="rows"><legend>Quick Add<ol>";
$("label.required").each(function(){
item = $(this).parent().html()
item = "<li>"+item+"</li>";
list += item;
});
list += "</ol></fieldset><fieldset class="action"><a href="/cgi-bin/koha/members/member.pl" class="cancel">Cancel</a></fieldset>";
$("#entryform").prepend(list);
});

Paste that into your intranetuserjs system preference or into Firebug’s command line to give it a try. Note that this solution assumes two things:

  1. You’ve already specified a patron category (by choosing one from the “new” menu).
  2. You’re adding patrons to the default branch for your logged-in user.

Of course the form could be customized to include these choices, but they’re probably safe assumptions for quick adds. A better implementation of this would probably allow you to toggle between either view: quick or standard.

YUI Grids and the Koha OPAC

Koha uses the Yahoo! UI Library Grids CSS framework for both the OPAC and the staff client. When we revamped the Koha interface for 3.0 the Grids framework was chosen because it would simply the process of structuring pages while giving us a pretty good selection of possible layouts.

A nice feature of the Grids framework is that you can control the layout of your page with relatively minor changes in markup. Here’s an example for one of the basic layouts:


<div id="doc">
<div id="bd">

<div id="yui-main">
<div class="yui-b">
<p>Main Content</p>
</div>
</div>

<div class="yui-b">
<p>Sidebar</p>
</div>

</div>
</div>

You can see that YUI’s Grids framework suffers from the same problem a lot of CSS frameworks  have: the class names are pretty nonsensical if you’re not used to them. I consider this to be par for the course: Better that they be nonsensical than have semantic-sounding names which aren’t appropriate for your actual page structure.

How does the framework make it easy for us to change page layouts? I’ve put together a simple example. This example uses JavaScript to swap out one class name. Try it and see how much can change based on one class name:

yui-layout-demo1

Click to try the demo

The above example shows how the “primary” page structure can be changed. I say primary because you can only choose one of those layouts at a time. If you want to have additional columns or blocks within that layout you can use “grids” and “units” within that main page structure:

Just like with the page structure, there is a set of pre-defined grid structures you can use within your page. The simplest is a set of two equal-width containers:


<div id="doc">
<div id="bd">
<div class="yui-g">

<div class="yui-u first">
<p>First grid unit</p>
</div>

<div class="yui-u">
<p>Second grid unit</p>
</div>

</div>
</div>
</div>

Just like with the page structure example, a change to the grid’s class name can affect the layout of the units within it. Notice that the grid/unit structure is changing within the page structure we defined before: a single main block with a left-hand sidebar:

Click the try the demo

Click the try the demo

The power of the framework’s grid/unit structure really comes into play when you start nesting grids within grids. Start with a grid which creates two equal columns, and then nest the same two-column grid within each of those columns:

<div id="doc">
<div id="bd">
<div class="yui-g">

<div class="yui-g first">

<div class="yui-u first">
<p>Unit one, sub-unit one</p>
</div>
<div class="yui-u">
<p>Unit one, sub-unit two</p>
</div>
</div>

<div class="yui-g">

<div class="yui-u first">
<p>Unit two, sub-unit one</p>
</div>
<div class="yui-u first">
<p>Unit two, sub-unit two</p>
</div>
</div>
</div>

</div>
</div>

In the markup above, instead of nesting a unit (‘<div class=”yui-u”>’) inside a grid (‘<div class=”yui-g”>’), we’re nesting a grid inside a grid. The containing grid can still be altered to change the layout of the units inside it:

Click to try demo

Click to try demo

The Koha OPAC’s grid structure

How is this implemented in the Koha OPAC? Koha has to take advantage of  the Grids framework’s flexibility when obeying different conditions in the OPAC. Take, for example, the main page of the OPAC. There are four possible layouts the user might see based on state and system preferences:

opac-layout-no-opacnav-logged-out

No OpacNav, not logged in

opac-layout-no-opacnav-logged-in

No OpacNav, logged in

opac-layout-with-opacnav-logged-out

OpacNav, not logged in

opac-layout-with-opacnav-logged-in

OpacNav, logged in


Using some logic in the Koha templates, the layout can be easily altered based on each of those conditions. And because the Grids framework makes it so easy to switch between those different layouts, the template can be much simpler:


<!-- TMPL_IF NAME="OpacNav" -->
<div id="doc3" class="yui-t1">
<!-- TMPL_ELSE -->
<div id="doc3" class="yui-t7">
<!-- /TMPL_IF -->

The template logic can check one condition (whether the OpacNav system preference is populated) and alter the page layout accordingly.

What does this mean to me?

Unless you’re hacking Koha templates you won’t many opportunities to build your own grids. However, there are a couple of instance where you might want to try it, and I’ll talk about that in my next post.