Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm proficient with HTML and CSS but I'm still pretty shaky when it comes to Javascript. That said, I've been able to build a site using the Internet Archive Book Reader, which relies on reader.js

Here's a copy of one of my versions of reader.js https://gist.github.com/dylan-k/ed4efed2384e221d46cc

It's a good site, but I find I have to repeat things a lot. Basically, I have one copy of reader.js for every page/book featured on the site. It seems there must be a better way. I re-use the script, making copies, just so that I can change lines 28, 80, 83, 84.

Is there a way I could include just one copy of reader.js and then use a <script> tag to define these 4 lines for the individual pages?

share|improve this question

2 Answers 2

As you've noticed, the basic problem is that - as written - that script isn't reusable. It's hardcoded for a specific case. There's no straightforward way to pass in different settings on different pages.

So you'll need to modify that script to make it reusable.

There are any number of ways you could do that, but here's one that involves minimal modifications to the original code:

<script>

// Define a global object containing the BookReader parameters for this
// page. Make sure this appears in your markup *before* the <script> tag
// that loads reader.js.
var BookReaderParams = {
    urlStart: "/exhibitions/bythebook/book8/W922/W922_",
    urlEnd: "_sap.jpg",
    numLeafs: 328,
    bookTitle: "Liber Amicorum (Friendship Book) of Joannes Carolus Erlenwein",
    bookUrl  = "http://thewalters.org/exhibitions/bythebook/book8/"
};

</script> <script src="reader-modified.js"></script>

Then, change the following lines in your modified version of reader.js:

Line 28 becomes:

var url = BookReaderParams.urlStart + leafStr.replace(re, imgStr) + BookReaderParams.urlEnd;

Line 80 becomes:

br.numLeafs = BookReaderParams.numLeafs;

And lines 83 and 84 become:

br.bookTitle = BookReaderParams.bookTitle; br.bookUrl = BookReaderParams.bookUrl;

This isn't how I would structure things if I were writing this functionality from the ground up; there are much cleaner patterns for reusable code. However, given the codebase you're working with, this is a quick-and-dirty way to inject values into the script without needing a separate copy of reader.js for every page.

share|improve this answer
    
+1 for much cleaner patterns. The hardcoded urls in the script is a clear sign that an amateur wrote the script. I would rewrite it my way, though this solution is decent for one with not a lot of knowledge of javascript for sure. –  Neil Jun 11 at 7:51
    
I should add that my source for this is the openreader bookreader. I started from the demo script which does also include hardcoded URLs but which also uses a more sophisticated script, which apparently also includes hardcoded URLs? Without being able to rewire the whole thing to avoid this, I agree that this solution should work for me. I'll mark it as "answer" soon. –  Dylan Kinnett Jun 11 at 17:26

Absolutely! Modifying javascript libraries is practically a time-honored tradition.

Take a look at one of the lines:

br.getPageURI = function(index, reduce, rotate) {
    // reduce and rotate are ignored in this simple implementation, but we
    // could e.g. look at reduce and load images from a different directory
    // or pass the information to an image server
    var leafStr = '000000';            
    var imgStr = (index+1).toString();
    var re = new RegExp("0{"+imgStr.length+"}$");
    var url = '/exhibitions/bythebook/book8/W922/W922_'+leafStr.replace(re, imgStr) + '_sap.jpg';
    return url;
}

A simple and unintrusive way to alter the URL would be to add a parameter. Consider the following:

br.getPageURI = function(index, reduce, rotate, baseurl) {
    baseurl = baseurl|| '/exhibitions/bythebook/book8/W922/W922_';
    var leafStr = '000000';            
    var imgStr = (index+1).toString();
    var re = new RegExp("0{"+imgStr.length+"}$");
    var url = baseurl + leafStr.replace(re, imgStr) + '_sap.jpg';
    return url;
}

This means, replace the base URL with the parameter passed as the fourth parameter. The first line is essentially a failsafe to ensure that it has a value if no fourth parameter is passed. You can apply this modification immediately without causing problems elsewhere. Whenever this method is called, provide the proper fourth parameter.

For lines 80, 83, and 84, you will need to be able to dynamically provide these parameters. Since this is a static js file, you could either remove the section:

br.init();

$('#BRtoolbar').find('.read').hide();
$('#textSrch').hide();
$('#btnSrch').hide();

And execute it yourself in a script after having included the javascript static file, altering parameters as you see fit:

<script src="static.js"></script>
<script>
    br.bookTitle= 'Dynamic book title here ' + new Date();
    br.bookUrl  = 'http://thewalters.org/exhibitions/bythebook/book8/';

    br.init();

    $('#BRtoolbar').find('.read').hide();
    $('#textSrch').hide();
    $('#btnSrch').hide();
</script>

Or, you could wrap the entire object in its own function and call it with the parameters to change:

// In static js
function MyBookReader(bookTitle, bookUrl) {
    br = new BookReader();

    ...

    br.bookTitle= bookTitle;
    br.bookUrl  = bookUrl;

    br.init();

    $('#BRtoolbar').find('.read').hide();
    $('#textSrch').hide();
    $('#btnSrch').hide();
}

// In script on page
MyBookReader('Tale of two cities', 'http://bookreader-url.com');

Hope that helps.

share|improve this answer
    
Then, how would the HTML look, to call the script and then to pass in these variables? I see that your fourth example begins to resemble the solution I had in mind, but it doesn't include the same four variables as your first two examples. –  Dylan Kinnett Jun 10 at 15:49
    
@DylanKinnett Well consider that I use ... to indicate all the source that goes in between in order to save space. The HTML would be the same, except you'd have to include additional script on the HTML page which provides these parameters. Or, if you have this data available on the page, you can simply load that information from inside the static js. That would certainly be the cleanest solution, if you knew that that information would always be available. –  Neil Jun 10 at 16:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.