Removing E-RES PREVIEW items from e-reserve lists

This jQuery-based modification applies to Springshare’s electronic reserves module.

A method to modify the default display of Springshare e-reserves to hide specific courses

For organizational purposes and to keep control over copyright clearances, we only allow course items on electronic reserve (usually articles) to be visible for the dates the course is active (typically one semester). But understandably, instructors like to be able to see their reserves pages ahead of time and confirm that everything looks and works as expected. In the past, this meant “unhiding” the course page on a specific date so the instructor could check it, and then hiding it again until the official start of the term.

My colleague just came up with a better solution: create a temporary term called “E-RES PREVIEW” which would be open only to the instructor (via password) before the official term begins. Then once the course pages are approved, he would simply move them into the Fall 2018 (e.g.) term, which would become visible to students on the first day of that term. It would serve as a staging site so he could get everything in order behind the scenes before any students could see the content.

It was a great idea, but it led to E-RES PREVIEW courses cluttering up the course lists generated by the e-reserve software. Could I remove or hide the ones with E-RES PREVIEW from the list, my colleague asked?

It turned out to be a really interesting challenge!

The relevant part of the page looks like this:

LibApps E-Reserve Portal with E-RES PREVIEW term
LibApps E-Reserve Portal with E-RES PREVIEW term

My first thought was that it should be easy enough to manipulate the DOM using jQuery (if available, and it is) or vanilla JavaScript to search for the string “E-RES PREVIEW” and remove its parent elements. I tried a few tests and nothing was happening, even with the code enclosed in the $(document).ready function. What’s going on? I tried adding a timer to delay the change by a few seconds, and now I could see the change to the DOM element. Ah. The page is loading its content by JavaScript (ajax) as well, so I need to let it load before I can make changes. The timers will suffice for now, but eventually I’ll probably refactor with setInterval instead.

function removePreviewFromCourses(){  
    var allCourses = $("div div.s-lib-box a");
    var previewCourses = $("div div.s-lib-box a:contains(E-RES PREVIEW)").parent().parent().parent().remove(); 
    $( ".muted" ).text(rewriteHeading(allCourses.length,previewCourses.length,"Course"));
  }

function removePreviewFromTerms(){  
    var allTerms = $("div[id^='s-lib-panel-container-collapse']"); 
    var previewTerms = $("div[id^='s-lib-panel-container-collapse']:contains(E-RES PREVIEW)").remove(); 
    $( ".muted" ).text(rewriteHeading(allTerms.length,previewTerms.length,"Term"));
}

function removePreviewFromInstructors(){  
    var d = $("div[id^='s-lib-panel-container-collapse']"); 
    var counter = 0;

    $.each(d, function() {
        var k = $(this).find('li').length;
        var h = $(this).find("a:contains('E-RES PREVIEW')");

        if (k - h.length == 0) {
            $(this).remove();
            counter++;
        } else {
            $(this).find("a:contains('E-RES PREVIEW')").parent().parent().remove();
        }

        //set badge to new number of courses for each instructor
        $(this).find(".badge").text(k - h.length);
    });

    $( ".muted" ).text(rewriteHeading(d.length,counter,"Instructor"));
}

function removePreviewFromSubjects(){  
    var d = $("div[id^='s-lib-panel-container-collapse']"); 
    var counter = 0;

    $.each(d, function() {
        var k = $(this).find('li').length;
        var h = $(this).find("a:contains('E-RES PREVIEW')");

        if (k - h.length == 0) {
            $(this).remove();
            counter++;
        } else {
            $(this).find("a:contains('E-RES PREVIEW')").parent().parent().remove();
        }

        //set badge to new number of courses for each subject
        $(this).find(".badge").text(k - h.length);
    });

    $( ".muted" ).text(rewriteHeading(d.length,counter,"Subject"));
}

Here you can see that it was pretty simple to remove the text from the Course and Term lists, but the Instructor and Subject lists need a little more work. Specifically, we need to update the count of courses for each instructor and subject that are displayed in the “badge” on the right-hand side of the panel:

LibApps E-Reserve Portal: Instructor tab
LibApps E-Reserve Portal: Instructor tab

Next on the list was to figure out what needs to trigger the changes. Obviously going to the URL needs to be a trigger, but so does clicking any of the buttons (Bootstrap “pills”) to navigate to the other tabs. And we also need to make sure that going to the URL associated with each tab triggers the action, just in case someone has the link to a particular tab used or bookmarked somewhere.

The following code will handle the cases where the URL is visited, or any of the buttons are clicked:

if (window.location.pathname == '/er.php') {

   // remove inline click handlers from all buttons
     function removeButtonHandlers(){
        $("button").prop('onclick', null);
    }
    setTimeout(removeButtonHandlers, 400); 

    function allcourseHandler(){
        $('#s-lg-er-course-btn').on("click",function(e){
                springSpace.erList.loadErList({
                action: 190,
                button_id: 'c',
                is_button_click: true
            });      
        setTimeout(removePreviewFromCourses, 500);    
        });
    }
    setTimeout(allcourseHandler, 600);

    function termHandler(){
        $('#s-lg-er-term-btn button').on("click",function(e){
                springSpace.erList.loadErList({
                action: 192,
                button_id: 't',
                is_button_click: true
            });  
        setTimeout(removePreviewFromTerms, 500);         
        });
    }
    setTimeout(termHandler, 600);

    function instructorHandler(){
        $('#s-lg-er-instructor-btn').on("click",function(e){
                springSpace.erList.loadErList({
                action: 191,
                button_id: 'i',
                is_button_click: true
            });
        setTimeout(removePreviewFromInstructors, 500);          
        });
    }
    setTimeout(instructorHandler, 600);

    function subjectHandler(){
        $('#s-lg-er-subject-btn').on("click",function(e){
                springSpace.erList.loadErList({
                action: 194,
                button_id: 's',
                is_button_click: true
            }); 
        setTimeout(removePreviewFromSubjects, 500); 
        });
    }
    setTimeout(subjectHandler, 600);

And the following will ensure that going to the URL associated with each tab also triggers the action:

// Activate if URL is visited directly, not just if button is clicked

    if (window.location.search == '' || '?b=c') {
        setTimeout(removePreviewFromCourses, 500);
    };
    
    if (window.location.search == '?b=t') {
        setTimeout(removePreviewFromTerms, 500);
    };

    if (window.location.search == '?b=i') {
        setTimeout(removePreviewFromInstructors, 500);
    }; 
    
    if (window.location.search == '?b=s') {
        setTimeout(removePreviewFromSubjects, 500);
    }; 

And finally, the rewriteHeading function referred to above is just a bit more cleanup: we need to make sure the number of courses, instructors, etc. is accurate now that we have removed the E-RES PREVIEW courses.

function rewriteHeading(numTotal,numPreview,trmIdentifier){
    var numVisible = numTotal - numPreview;
    if (numVisible == 1) {
        return "Showing " + numVisible + " " + trmIdentifier;
    } else {
        return "Showing " + numVisible + " " + trmIdentifier + "s";
    }    
}

© 2024 Jennifer Galas. All rights reserved.