February 24, 2012

Receipt Editing in Evergreen 2

Alternate title: Yo dawg, I heard you like spans…

So what is the deal with all of those spans and their seemingly useless CSS classes? To answer that, we'll have to take a brief detour into how receipt editing used to work in Evergreen before 2.1.

Ine Ye Olde Paste
It used to be that you could simply in-line JavaScript whenever necessary to achieve an effect that wasn't possible with simple HTML and substitution. Such as:

Your item is due:
<script type="text/javascript">
var dt = new Date("%date_due%");
document.write(dt.getUTCMonth() + "/" + dt.getUTCDate() + "/" + dt.getUTCFullYear());

Which would print Your item is due 02/29/2012.

While it may not be great practice on a web page to inline a bunch of document.write()'s all over the place, it worked just fine in this case. It's not as if we had to worry about how Internet Explorer would render it or a screen reader; if it worked in the preview, it worked, the end.

At any rate, these heady times have come to a close, any script tags are stripped out as of 2.1. There is a new method for running JavaScript in receipts, but it's well hidden since there was no documentation when this hit me and the setting required to enable custom scripts didn't even exist by default. There's a little work to do, so let's leave the past behind and get back to the future.

It is possible that the setting oversight has been corrected by the time you read this; to check, log in to the Evergreen client, click the Admin menu, Server Administration, and Organization Unit Setting Types. Click next a dozen or so times, until you reach the types beginning with 'p'. If there is a setting type with the name of print.custom_js_file, remember its name and rejoice, the hard part is finished. If not, create one with that type, give it a name you can remember and give it a description (the other options aren't required). To actually set the option, go to the Admin menu, Local Administration, Library Settings Editor. Edit the setting with the name matching the print.custom_js_file type, and set it to a URL you control. http://example.com/receipt/custom.js or something similar would be great. Keep the location in mind because this is where you'll be putting your javascript file with all of your custom code. Now, to the heart of the matter.

What is the point of this? Instead of inline JavaScript, you get 1 file in which to work your magic, its URL stored in the above setting, and one function in it that will be called: print_custom(type). This means that whatever you're going to do has to be based on element ids, DOM inspection, or CSS class names.

I had a few requirements with regard to the effects I wanted to achieve. As of 2.1, receipt replacements still aren't global, so if you have two %PATRON_FIRSTNAME% replacements, only one of them is replaced with a name. Not great. So I needed a way to signal that one value should be copied to another location. And because a value that is repeated may need additional processing, the method used needed to allow multiple effects to be specified. Adding the fact that you can't easily use ids in the line item section (you could append %LINE_NO% to an id if you must, but only to one of them!), the simplest method then is using CSS classes. Because you can't tell the difference between placeholder and template text, each replacement that requires any modification is best wrapped directly in a tag. That's why there are so many of those spans running around, any effect or transformation requires a tag directly around its target.

So, here are the CSS classes that trigger the transforms and modifications that I use to bend receipts to my will. A copy of this custom_format.js will be available in another post; use them as they are, or bend your receipts a different way.

This doesn't actually do anything, it's only a signal. All of the elements that need further processing are grabbed and then tested for the remaining classes.

src-(NAME) and dest-(NAME)
Classes that begin with src- have their contents copied into a dictionary keyed with the rest of the class name. Classes beginning with dest- signal that the dictionary should be checked for a key that matches the rest of it's name, and if a value exists, it's put into that tag. Fortunately, these tags are only temporary, because multiple receipt replacement is supposed to be fixed in Evergreen 2.2. I can't wait to get rid of them; they're irritating and incapable of handling certain situations. (not so easy to use in a URL, for instance.)

<span class="rcpt src-author">Petroski, Henry.</span><br/><span class="rcpt dest-author"></span>Petroski, Henry. Petroski, Henry.

The default representation of a circulation modifier is code : name : description, which can range from book : book : book to  book : Book : A monograph item. No, sir.

<span class="rcpt mod-CircModToCode">book : Book : monograph</span>book

Sometimes you don't want the extra punctuation that AACR2 or ISBD demand. (Some might argue that you never want it in this day and age, but that's for another time.) Extra hanging spaces are particularly maddening if you're adding your own punctuation, though, so this strips them out.

<span class="rcpt xf-Trim">To Engineer Is Human </span>;To Engineer Is Human;

Bring patron information into the Title Cased Future, with only a minor chance of mangling their names. Since we only use first names on our receipts, I could avoid the whole "What to do about Mc and O'?" question entirely.

<span class="rcpt xf-TitleCase">SUZIE</span>Suzie

I don't believe I've ever bragged about my skill at picking names… Anyway, when was the last time you told someone that your favorite author was King, Stephen? Never? Then it shouldn't be printed that way either. This transform also removes any silly vestigial punctuation used for printing catalog cards. ("Stephen. King," isn't any great improvement.)

<span class="rcpt xf-LastFirstToFirstLast">King, Stephen.</span>Stephen King

This is just how we get by using 1 set of templates for multiple locations and different phone numbers. It obviously requires customization before it will help anyone else.

<span class="rcpt xf-ShortNameToPhone">YRLIB</span>867-5309

This will take a date of the form YYYY-MM-DD (etc.) and change it to "DayName, MonthAbbrv Date, Year" form, dropping any time component.

<span class="rcpt xf-DateToLongDate">2012-02-29 11:59:59 PM</span>Wednesday, Feb 29, 2012

Here's one that takes a little explanation. Our receipts print "Title, circ mod by Author" but if the circ modifier or author is blank, it turns ugly. So, the best way to fix that is to remove any unnecessary punctuation and spacing. Because you can't really use ids in line items, that means the simplest thing to do is to make use of relative DOM nodes, so this one requires 2 span tags, one that includes the punctuation and still within that, the one that contains the placeholder.

Title<span>, by<span class="rcpt mod-EmptyHideParent"></span></span>Title

So that's what is required to put together the updated checkout receipt I've shown, but there is one more receipt that sees a lot of use inside the library, and I think improving it makes a major difference behind the checkout desk. It's coming up next.