Talis Aspire / Primo integration (old UI)

Preamble

Making use of the ELTA it is possible to add tabs to a Primo results page.
The original ELTA waited for each call to EXLTA_addTab() to finish and blocked the page from loading smoothly. We’ve extended the original functionality to allow the evaluator to run asynchronously. This does mean that tabs will appear after a short while, but this could be re-written to include the tab in a disabled state which becomes enabled depending on the result of the evaluator.
We then store all our methods inside the ABWASPIRE object which is pulled in by the Primo footer.

So, how does it all work?

First we need to know a few things about our Aspire environment and our future tab.

    label: "Aspire Reading Lists",
    tabclass: 'AspireTab',
    aspire: {
        baseurl: 'http://aspire.aber.ac.uk/',
        urlsuffix: '/lists.json',
        outputstringprefix: '<li><span class="EXLDetailsLinksBullet"></span><span class="EXLDetailsLinksTitle"><a target="_blank" href="',
        outputstringsuffix: '</a></span></li>'
    }
  • label: The name of the tab
  • tabclass: Class for the tab, becomes the value of tabType in EXLTA_addTab()
  • baseurl: Your aspire tenency URL. If you are using Primo over HTTPS you need to use your HTTPS aspire URL
  • urlsuffix: Leave as is, should probably be a const inside the ABWASPIRE object tbh.
  • outputstring*: The pre & post HTML. As above should be left alone, I should probably replace these with bulletclass and linkclass tbh

When we init our ABWASPIRE object we’re adding a load event with the ELTA which is an anonymous function which calls EXLTA_addTab().
This is what I’ve been able to deduce about ELTA_addTab():

function EXLTA_addTab(tabName, tabType, url, tabHandler, firstTab, evaluator)

  • tabName: As described
  • tabType: additional class to be added along side EXLResultTab
  • url: URL for the tab (if it has no content?)
  • tabHandler: js to run when the tab is clicked. Use the return value of a call to EXLTA_createWidgetTabHandler(function(element /*The tab content area*/) {}, boolean)
  • tabFirst: trilean: true – Prepend the existing first tab, false / undefined – Add as the last tab, any other value – replace the first tab.
  • evaluator: callback with the tab as the parameter, returns true if the tab is to be created, false if not.

The original EXLTA_addTab was blocking, so we have added an async parameter to the existing EXLTA_addTab to modify the evaluator call from:
evaluator(tab) to evaluator(tab,callback), where callback operates with the existing evaluator logic for adding the tab.

(This was before promises were discovered so this could probably be done much nicer now!).

Our modified evaluator works by:
Getting the recordId from the tab // EXLTA_recordId(tab);
Getting the ISBNs from the recordId // EXLTA_isbn_all(recordId); /* This is an additional local modification to the ELTA */
Getting the local collection number for the recordId // EXLTA_lcn(recordId); /* This is an additional local modification to the ELTA */

If we have a LCN (why wouldn’t we?), we fire off an asynchronous jsonp request to the Aspire reverse LCN lookup at {{urlbase}}/lcn/{{our lcn}}/{{urlsuffix}}
Our success jsonp callback then checks for any other lists that the record’s ISBNs may be included on (this is for where Aspire’s LCN matching hasn’t refreshed but a list with a matching ISBN exists). The process is the same as checking the LCN with the lookup taking place at {{urlbase}}/isbn/{{our isbn}}/{{urlsuffix}}
Our failure jsonp callback returns ‘false’ to indicate we don’t need the tab creating at this time.

(It should be noted that we’re using jquery.jsonp.js, as that catches error codes and executes a callback, rather than just terminating like the vanilla jQuery jsonp).

At this point, we should now have a new tab appearing if an item is on a reading list (based on LCN and ISBN matching).

Now, when we click that tab our createWidgetTabHandler callback is fired.
We created this with EXLTA_createWidgetTabHandler(function(tab){}, true /*reentrant*/);

In our anonymous function we fire off more asynchronous jsonp requests to fetch the details of the lists this item has been found on and return a new, empty unsorted list (<ul>) with a unique id of aspireListFor{{recordId}}.
The callback then populates the names of the lists a record is associated with, or in the event of an error (e.g. if a list is private) just adds a link to the list without any extra detail.

And that’s about all there is to it.

Examples

The local modifications to EXLTabAPI.03a.js

--- local_EXLTabAPI.03a.js	2018-03-28 11:48:06.348645100 +0100
+++ local_EXLTabAPI.03a.aew.js	2018-03-28 11:48:09.690645100 +0100
@@ -9,7 +9,6 @@
  ** or email: jacob.hanan@exlibrisgroup.com
  **
  ****************************************************/
-
 function EXLTA_addHeadlessTab(tabType, content, evaluator) {
     $('.EXLResultTabs').each(function () {
         if (!evaluator || (evaluator && evaluator(this))) {
@@ -36,36 +35,67 @@
     EXLTA_addTab(tabName, tabType, url, tabHandler, firstTab);
     $('.' + tabType).click();
 }
-function EXLTA_addTab(tabName, tabType, url, tabHandler, firstTab, evaluator) {
-    EXLTA_addTabBySelector('.EXLResultTabs', tabName, tabType, url, tabHandler, firstTab, evaluator);
+
+function EXLTA_addTab(tabName, tabType, url, tabHandler, firstTab, evaluator, async) {
+    async = async || false;
+    EXLTA_addTabBySelector('.EXLResultTabs', tabName, tabType, url, tabHandler, firstTab, evaluator, async);
 }
-function EXLTA_addTabBySelector(selector, tabName, tabType, url, tabHandler, firstTab, evaluator) {
+
+function EXLTA_addTabBySelector(selector, tabName, tabType, url, tabHandler, firstTab, evaluator, async) {
     $(selector).each(function () {
         var customTab = $('<li class="EXLResultTab ' + tabType + '"><a href="' + url + '">' + tabName + '</a>');
         var customTabContainer = $('
'); - if (!evaluator || (evaluator && evaluator(this))) { - if (firstTab == true) { - $(this).find('li').removeClass('EXLResultFirstTab'); - $(customTab).addClass('EXLResultFirstTab'); - $(this).prepend(customTab); - } else if (firstTab == undefined || firstTab == false) { - $(this).find('li').removeClass('EXLResultLastTab'); - $(customTab).addClass('EXLResultLastTab'); - $(this).append(customTab); - } else { - $(this).find(firstTab).replaceWith(customTab); - - } - // Modification to make customTabContainer to be correctly - // appended on Full View - if ($(this).parents('.EXLResult').find('.EXLSummary').length == 0) { - $(this).parents('.EXLResult').append(customTabContainer); - } else { - $(this).parents('.EXLResult').find('.EXLSummary').append(customTabContainer); + if (!async) { + if (!evaluator || (evaluator && evaluator(this))) { + if (firstTab == true) { + $(this).find('li').removeClass('EXLResultFirstTab'); + $(customTab).addClass('EXLResultFirstTab'); + $(this).prepend(customTab); + } else if (firstTab == undefined || firstTab == false) { + $(this).find('li').removeClass('EXLResultLastTab'); + $(customTab).addClass('EXLResultLastTab'); + $(this).append(customTab); + } else { + $(this).find(firstTab).replaceWith(customTab); + } + // Modification to make customTabContainer to be correctly + // appended on Full View + if ($(this).parents('.EXLResult').find('.EXLSummary').length == 0) { + $(this).parents('.EXLResult').append(customTabContainer); + } else { + $(this).parents('.EXLResult').find('.EXLSummary').append(customTabContainer); + } + // End modification + $('#' + $(this).attr('id') + ' .' + tabType + ' a').click(function (e) { + tabHandler(e, this, tabType, url, $(this).parents('.EXLResultTab').hasClass('EXLResultSelectedTab')); + }); } - // End modification - $('#' + $(this).attr('id') + ' .' + tabType + ' a').click(function (e) { - tabHandler(e, this, tabType, url, $(this).parents('.EXLResultTab').hasClass('EXLResultSelectedTab')); + } else { + evaluator(this, function (res, myself) { + if (res) { + if (firstTab == true) { + $(myself).find('li').removeClass('EXLResultFirstTab'); + $(customTab).addClass('EXLResultFirstTab'); + $(myself).prepend(customTab); + } else if (firstTab == undefined || firstTab == false) { + $(myself).find('li').removeClass('EXLResultLastTab'); + $(customTab).addClass('EXLResultLastTab'); + $(myself).append(customTab); + } else { + $(myself).find(firstTab).replaceWith(customTab); + } + // Modification to make customTabContainer to be correctly + // appended on Full View + if ($(myself).parents('.EXLResult').find('.EXLSummary').length == 0) { + $(myself).parents('.EXLResult').append(customTabContainer); + } else { + $(myself).parents('.EXLResult').find('.EXLSummary').append(customTabContainer); + } + // End modification + $('#' + $(myself).attr('id') + ' .' + tabType + ' a').click(function (e) { + tabHandler(e, this, tabType, url, $(this).parents('.EXLResultTab').hasClass('EXLResultSelectedTab')); + }); + } }); } $(this).parents('.EXLSummary').find('.' + tabType + '-Container').hide(); @@ -86,6 +116,7 @@ var body = '
' + htmlcontent + '
'; return header + body; } + function EXLTA_closeTab(element) { if (!EXLTA_isFullDisplay()) { $(element).parents('.EXLResultTab').removeClass('EXLResultSelectedTab'); @@ -93,6 +124,7 @@ $(element).parents('.EXLResult').find('.EXLResultTabContainer').hide(); } } + function EXLTA_openTab(element, tabType, content, reentrant) { $(element).parents('.EXLTabsRibbon').removeClass('EXLTabsRibbonClosed'); $(element).parents('.EXLResultTab').siblings().removeClass('EXLResultSelectedTab').end().addClass('EXLResultSelectedTab'); @@ -133,9 +165,11 @@ function EXLTA_isFullDisplay() { return $('.EXLFullView').size() > 0; } + function EXLTA_searchTerms() { return $('#search_field').val(); } + function EXLTA_recordId(element) { return $(element).parents('.EXLResult').find('.EXLResultRecordId').attr('id'); } @@ -179,10 +213,26 @@ } return undefined; } + function EXLTA_isbn(recordId) { var pnx = EXLTA_getPNX(recordId); - return $(pnx).find('isbn').eq(0).text(); + return $(pnx).find('isbn').eq(0).text().toUpperCase(); +} + +function EXLTA_isbn_all(recordId) { + var pnx = EXLTA_getPNX(recordId); + var isbns = []; + $(pnx).find('isbn').each(function () { + isbns.push($(this).text().toUpperCase()); + }); + return isbns; +} + +function EXLTA_lcn(recordId) { + var pnx = EXLTA_getPNX(recordId); + return $(pnx).find('lsr29').eq(0).text(); } + function EXLTA_issn(recordId) { //contributed by Karsten Kryger Hansen var pnx = EXLTA_getPNX(recordId); return $(pnx).find('issn').eq(0).text();