How to Write a Zotero Translator:
A Practical Beginners Guide for Humanists

By: Adam Crymble

 

Chapter 7: JavaScript Methods & Math

 previous button  next button

This Chapter

So, you've got a bunch of Variables containing some values. They're not very interesting or useful just yet. Now you've got to learn what you can do to those values. This will be important when you write your translator and need to manipulate bibliographic data so that it is in the correct format for Zotero. A website may put their author names all in CAPITAL LETTERS and you'll have to convert that to a More Suitable format. You can do this and much more with your second JavaScript building block: Methods.

Methods allow you to do just about anything to the contents of your Variables. You can change 'em, stick 'em together, cut 'em, move 'em, split 'em, capitalize 'em, do just about anything you can imagine to 'em. Methods are largely predefined, which makes your job of coding much easier. It's kind of like a magic box that turns rabbits into telephones. Don't worry about how it works, just decide which one you want to use and the computer does all the work.

The word "Method" can be a bit deceiving in this context. It doesn't refer to a set of instructions to accomplish a task. Rather, in JavaScript, you apply a Method to a Variable and get a result.

String Methods

Methods always take the form of:

variableToBeTested.methodName(whatYouWantDone); where the type of Method is listed, followed in parenthesis by what you want the Method to do/look for/change, etc. The information between the parentheses is called an "Argument." The name comes from mathematics terminology; don't think of it as two people in a heated discussion, think of it as an input Variable that will be used as your test principle to come up with the desired result.

Let's try out the indexOf() Method on a Variable in Scaffold. This is one of the many prepackaged Methods you can use.

indexOf("this") checks a string for a specified value and returns the first numerical location of the value within the string. Counting starts at 0; if the value is not found, -1 is returned. indexOf() will tell you the position in your String of the tested value.

For instance, in the string "Climate" the letter "m" is at index position 3, since you start counting at 0. "t" is at index position 5.

To try this, you must first declare a Variable to test. Then you can apply the Method to it. You will have to put the result of the Method into another Variable, or else it will be lost and you won't be able to find it.

Example 7.1

var x = "Snow storm 2pm";
var y = x.indexOf("t");
Zotero.debug(y);

The result is:

===>6<===(number)

This tells you that the match was successful and that the first instance of "t" is in the 6th position. Remember to start counting from 0, and you can see that this is in fact correct.

We could also put the result of your Method back into the original Variable, but this will mean the original String is lost. This may or may not be desirable. If you're never going to need that String again, you can probably overwrite it to keep your Number of Variables down.

Example 7.2

var x = "Snow storm 2pm";
x = x.indexOf("t");
Zotero.debug(x);

Note that you can reassign a String Variable and make it a numeric value, or vise-versa.

Try changing the String Method to "Snow" and debugging again. You should see:

Example 7.3

===>0<===(number)

Even though there are multiple letters in your String, indexOf() only tells you the position of the first letter in your String.

Try "snow" or "Snowy" and then debug.

Example 7.4

===>-1<===(number)

A returned value of -1 is the same as saying "false." Neither of those two Strings appear in x. The indexOf() method is case sensitive.

Now try "o". There are two of these in the String, but when you debug, you get

Example 7.5

===>2<===(number)

because indexOf() will only get the first instance of the value you have tested.

Lastly, try changing the value to "2" and 2 (as a Number).

Example 7.6

===>11<===(number)
===>11<===(number)

JavaScript is able to distinguish the Number, even though it is part of a String. While it worked this time, you may run into instances when mixing Strings and Numbers causes problems. It is always best to search for digits that are part of a String by including the quotation marks around them. While JavaScript is fairly forgiving when it comes to using Strings and Numbers together, it is best not to mix the two unless you know what you are doing.

Further reading on String and Number compatibility in JavaScript

More String Methods:

Let's look at some of the other most commonly used String Methods for writing a Zotero translator.

Example 7.7

  • match()
  • replace()
  • lastIndexOf()
  • slice()
  • substr()
  • split()
  • toLowerCase()
  • toUpperClass()
  • length

You will use these methods on a URL to see what they do. This will be good practice for your Zotero translator.

If you do not have Scaffold running, open it and reload your translator by clicking on the Load from Database button and then scroll through until you see your name. If you have not already made a translator, you can start a new one.

First, let's declare a Simple Variable containing the URL; you can use the same URL I have chosen, or one of your own. Don't forget the quotation marks so the computer knows you are dealing with a String. Feel free to choose your own name for the Variable.

Example 7.8

var myURL = "http://www.thestar.com/News/GTA/article/482613";

Now let's try each of the different String Methods.

1) match()

checks the String for your specified value. Will return a true or false (known as a Boolean).

Example 7.9

var x = myURL.match("article");
Zotero.debug(x);

Returns:
'0' => "article"
'index' => "32"
'input' => http://www.thestar.com/News/GTA/article/482613

Try it again using "car" as the argument. Now you should be able to distinguish between a match and a failed match.

When writing a Zotero translator, this Method is useful for determining if the URL of a page matches a certain pattern, or to determine what type of information your XPath captured. For instance, does the XPath's returned String match "title"? If so, you can likely assume the piece of information you are dealing with is the book's title.

2) Replace()

.replace("this", "withThis"). Will change whatever is before the comma with whatever comes after. You can replace() something with nothing by putting nothing between the second set of quotation marks.

a) Replace a word with a word

Example 7.10

var x = myURL.replace("article", "crickets");
Zotero.debug(x);

Returns:

http://www.thestar.com/News/GTA/crickets/482613

b) Replace a word with nothing

Example 7.11

x = myURL.replace("article", "");
Zotero.debug(x);

Returns:

http://www.thestar.com/News/GTA//482613

c) Try to replace a word that does not appear in the string.

Example 7.12

x = myURL.replace("cars", "rabbits");
Zotero.debug(x);

Returns:

http://www.thestar.com/News/GTA/article/482613

In the last example, it may appear as though nothing has happened, but it has actually worked perfectly. There are no instances of "cars" in the String, so JavaScript has changed 0 instances of "cars" to "rabbits". This can make it tricky to determine if you've made a typo in your Arguments.

If you are trying to use the replace() Method and the String is not changing properly, check your spelling.

This will be useful when you want to standardize information or remove unnecessary information from a String, should it appear. You might find that your Author's name is presented as "Dr. William Turkel". If you don't want the doctoral title, you can apply this method to remove it:

Example 7.13

var x = "Dr. William Turkel";
x = x.replace('Dr. ', '');
Zotero.debug(x);

3) lastIndexOf()

.lastIndexOf("this") is the same as indexOf() but will return the location of the last occurrence of the value.

a) Find last index of a letter

Example 7.14

var x = myURL.lastIndexOf("t");
Zotero.debug(x);

Returns:

===>34<===(number)

b) Find last index of a longer String.

Example 7.15

var x = myURL.lastIndexOf("article");
Zotero.debug(x);

Returns:

===>32<===(number)

c) Look for last index of a letter that does not appear.

Example 7.16

var x = myURL.lastIndexOf("z");
Zotero.debug(x);

Returns:

===>-1<===(number)

This is useful when creating translators for poorly formatted sites.

4) slice()

.slice(startingLocation, endingLocation) will return a portion of the original String, starting at the location specified by the first number, and ending with the location specified by the second. You must input Numbers rather than Strings into this Method. Keep in mind that in JavaScript, the location index starts counting at 0. The second Number is optional; if you want to slice to the end of the String, simply leave it out.

Example 7.17

var x = myURL.slice(7, 21)
Zotero.debug(x);

Returns:

www.thestar.co

Try changing the first Argument to -5. What happens? What happens if you change the first Argument to 28?

This is useful for writing Zotero translators when you have a String that is always written in the same format and you know which spaces in the String you want to keep. For example, if you know that all letters after a comma are useless to you, then you could use the indexOf() Method to find the index of the first comma, then slice off only the portion of the String before the comma.

Example 7.18

var x = "I like dogs, they are very friendly"
var y = x.indexOf(",");
var z = x.slice(0, y);
Zotero.debug(z);

This will return:

I like dogs

No matter where the comma appears in the String, the above code will return only the part before it.

5) substr()

.substr(startingLocation, howManySpacesToGoForward) is much like slice(), but instead of going to a specific location position, it moves ahead from the original position by the number of spaces specified by the second Argument.

Example 7.19

var x = myURL.substr(7, 21);
Zotero.debug(x);

Returns:

www.thestar.com/News/

Try changing the first Argument to -5. What happens? Try changing the first Argument to 28. What happens? Why is this different from what happens when you do this using slice()?

6) split()

.split("this", thisManyTimes) splits a String into an Array based upon the value of 'this'. The second value is optional; if left out, the Method will split the String as many times as possible. You specify the variable where the result will be stored.

Example 7.20

var x = myURL.split("/");
Zotero.debug(x);

Returns:
x[0] = "http:"
x[1] = ""
x[2] = "www.thestar.com"
x[3] = "News"
x[4] = "GTA"
x[5] = "article"
x[6] = "482613"

Notice that the slash has been removed in the process of splitting. Let's try the same, but add a second Argument so that it only splits three times.

Example 7.21

var x = myURL.split("/", 3);
Zotero.debug(x);

When you run this, you can see that the program has cut away the last sections of the URL, leaving only the first three. This is an extremely powerful tool when writing Zotero translators. Often you will find that multiple authors are separated by a semicolon. Being able to split() them allows you to input each author easily into Zotero.

Remember that the result of a split() is an Array, not a Simple Variable. Therefore you can debug it as you would an Array to get a single result.

Using the above example, debug to find the value of the third entry only.

7) toLowerCase() & toUpperCase()

As you might have guessed, this will change the contents of a string to lower or upper cases, respectively. This is handy, particularly in databases which display author names in all upper case.

Example 7.22

var x = myURL.toUpperCase();
Zotero.debug(x);

Returns:

HTTP://WWW.THESTAR.COM/NEWS/GTA/ARTICLE/482613

You will learn how to use these methods to change text like "ADAM CRYMBLE" or "adam crymble" to "Adam Crymble" in Chapter 17.

length

This will return the length of a String (or a Number).

Example 7.23

var x = myURL.length;
Zotero.debug(x);

Returns:

===>46<===(number)

This is not a Method, but a property of the String. Therefore, the parentheses are not required because length does not require any Arguments. I have included this with the other Methods because you use it in much the same way as you use Methods.

The length property is most useful for deciding how many times to do something. If you have an Array with multiple items in it, you can use length to determine how many items there are. This can then be used to tell the program to run the same chunk of code once for each item in the Array. For example, if you had five authors and wanted to save each one into Zotero, the length property would help you do this. So will Loops (Chapter 9).

Practice

Create an Array and use Zotero.debug() to figure out how many items are in it. Now try to check the length of the String held in the first position of the Array. If you get stuck, think about how you debug an Array versus debugging a specific position in an Array.

Try the same with a Simple Variable holding a number, and then an Object. Why might this not work with an Object? Does it work on a specific item held in an Object?

Note: removing the " " from Methods that expect a String may result in a JavaScript error, or the Method will search for a Number, rather than a String and might give unintended results. Always double check if the quotes are present.

A complete list of String Methods is available on the W3 Schools site.

Math

In JavaScript, you can do all sorts of math; just about anything your grade 12 math teacher taught you is possible in JavaScript.

However, you can only use Numbers to do math.

Values used in Math

Type the following into Zotero.debug and see what happens.

Example 7.24

Zotero.debug(9+9);
Zotero.debug("9" + "9");
Zotero.debug("9" + 9);

The second and third cases produce the String, "99" as the result. This is known as Concatenation, which joins two Strings together.

Example 7.25

Zotero.debug(9 + "Adam");

This also produces Concatenation, since you cannot add letters and numbers in mathematical equations.

Finally:

Example 7.26

Zotero.debug(9 – "Adam");

The result is:

===>NaN<===(number)

This stands for Not a Number. The mathematical operation failed.

You do not have to perform math within Zotero.debug(). You could have applied the values to Variables and then put those Variables into debug() as you did with String Methods.

What type of Math

A complete table of the types of math you can do in JavaScript can be found on the W3Schools site.

For the most part, you'll stick to adding and subtracting, but it's handy to know what is available.

Arithmetic

We can use any of the four basic arithmetic operators in JavaScript: + — * / as well as % which stands for modulus. Modulus is the remainder of two numbers when divided. There may be instances where you find modulus useful when writing a Zotero translator, but these are uncommon.

Example 7.27

Examples:

var x = 5 + 3;
var y = x + 8;
var z = y % (x + 3);

Use debug to see what each Variable holds.

Math is done from left to right in JavaScript and follows standard order of operation rules. Therefore, make sure you use parentheses if you wish to perform addition before multiplication.

Other important operators include increment (add 1) and decrement (subtract 1). You can increment and decrement using ++ or –– respectively.

Example 7.28

var x = 1;
x++;
Zotero.debug(x);

Returns:

===>2<===(number)

This does exactly the same thing as x = x + 1; but requires less characters. Incrementing and decrementing is very useful when creating Loops (Chapter 9) as you can keep track of how many times the Loop has run.

What you should understand before moving on

Further Reading