Prev << >> On to the next chapter: Pascal's Triangle.
This example continues the custom-poem idea, using CSS and jQuery to color the random words and change the poem continuously. Let it run for a minute:
The choices attributes that we have put on all the <span> tags are not part of the HTML standard and would normally be ignored by the browser. But here the CSS stylesheet at the top and the script at the bottom of our page explicitly look for the choices attributes to do something special.
The script at the bottom does three things when loading the page:
In addition, the CSS at the top of the page colors each of our choice span elements red.
We have seen functions like Math.random() and document.write(x) that are attached to objects like the Math and the document objects. These objects are not unusual: any object in Javascript may have functions attached to it. These "attached" functions are called methods of the object. They usuusally do some operation on the object, and you call them by using a dot after the object: object.methodname(...).
For example, every string object has a method called split(sep) that returns an array of substrings that result if you split of the original string using the given separator. Here is an example that you should try:
'hello-howdy-goodbye'.split('-')
If you are using Chrome, bring up the Javascript console (control-shift-J) to try it out. When you type it in, it results in the array value:
['hello', 'howdy', 'goodbye']
We often want to call a method on the output of a function. For example, The jQuery library defines the $ function that make a jQuery object for inspecting and manipulating any number of HTML elements. Once we get the jQuery object, we usually want to call methods on it. We can do it one step at a time like this:
var jq = $(element); | 1. Get the jquery for an HTML element. |
var choices = jq.attr('choices'); | 2. Use the jquery to read the 'choices' attribute. |
var list = choices.split(' '); | 3. Split the choices string into an array using space as the separator. |
Or, using parentheses, we can call all the methods one after another like this:
var list = (($(element)).attr('choices')).split(' ');
The parentheses around each result are not needed because the normal order for a sequence of "dot" method calls is left-to-right. So we normally write the following code:
var list = $(element).attr('choices').split(' ');
This style of code is called chained method calls, and it is a quick way to write a pipeline of data transformations. It allows us to write a single javascript statement that corresponds to the sentence: "Using a jquery on 'element', read the choices attribute, and split it at each space."
The basic idea behind this program is the same as custom-poem.html, but instead of using document.write to change the document while it is being loaded, it is changing the document after it is loaded. The program uses a setInterval timer to run code over time, and it uses the jQuery library to simplify the code that modifies the document.
The jQuery library is just 72 kilobytes of compressed javascript that defines a $(...) function that produces jQuery objects that have more than 100 very useful methods (full list) for manipulating HTML elements. We include the jquery library by writing a <script src=..."> element with a src attribute that tells the browser where to load the jquery javascript code.
Some explanations of the jQuery and Javascript used in the example above:
$(element).attr('choices') | read the choices attribute from the object in the element variable |
$(element).attr('choices').split(' ') | split the string into a list of words, using space as the delimiter. |
$(element).html(list[n]) | set the html inside the object in the element variable to the text from list[n] |
$('span[choices]') | get the list of every HTML object that is a <span> tag that has a choices attribute. |
$('span[choices]').each(fn) | execute the following function repeatedly for every HTML <span> tag with a choices attribute. |
setInterval(fn, 1000) | call the given function repeatedly every 1000 milliseconds |
When calling setInterval, we need to provide a function that can be called repeatedly. But instead of passing it a named function, we happen to pass an anonymous function defined directly inline. Anonymous functions let us say "setInterval, do this code every 1 second" all at once instead of first having to write a separate function definition to give a name to "this code" first.
When we pass a function to jQuery each, we do the same thing. It calls our function repeatedly for each matching element. Each time the function is called, the special variable this is set to one of the matching elements.
The CSS in the stylesheet contains a selector span[choices] that applies the rule color:red to every <span> element that has a choices attribute.
The jQuery code in the script also contains the same selector $('span[choices]'), to get a list of all <span> elements that have a choices attribute.
There is a whole language for CSS selectors. Here is a summary of a few CSS selector idioms:
span { color: red } | turns every <span> element red. |
span[choices] { color: red } | colors every <span> that has a choices attribute. |
span[choices~=pirate] { color: red } | colors every <span> that has a choices attribute containing the word "pirate". |
span[choices=pirate] { color: red } | colors every <span> that has a choices attribute exactly equal to "pirate". |
h2 span { color: red } | colors every <span> that is contained within a <h2> element. |
#pirate { color: red } | colors the element that has an id="pirate" attribute. (The attribute id is special.) |
.pirate { color: red } | is equivalent to [class~=pirate]: it looks for "pirate" in the class attribute. (The attribute class is special.) |
There are about a dozen operators in the CSS selector language, but most of what you will see in practice is listed above.
We will be using CSS and jQuery in many more examples in these pages, so it is worthwhile to take a moment to try to understand and experiment with the jQuery calls here. Try the following:
So far our computer-generated programs are not as good as we might like because they are just made of random words that don't have anything to do with each other. It would be nice to make a longer poem where some of the words are consistent within the poem.
For example, if the poem begins by talking about an "old man", it would be nice to add a second sentence that is also about the same "old man".
In the last example, jQuery was used to read an attribute and change the HTML within an element. It can also be used to read HTML text within a specific element. For example:
$('#protagonist').html()
returns the HTML text within the element that has an attribute id="protagonist" attribute.
We could use this to define a new attribute that causes HTML to be copied from a specific spot in the document to another, to repeat a choesn word. For example, we would like to be able to write:
The <span id="protagonist" choices="man woman girl boy">?</span> was home.
The <span reference="#protagonist">?</span> was happy.
This should end up giving me "The man was home. The man was happy," where the word "man" repeats a noun that was chosen randomly.
Here is a starting point: the following function reads the 'reference' attribute of an element, uses it to find another element, and then copies the html of the other element.
function refer(element) { var jq = $(element); var path = jq.attr('reference'); var originaltext = $(path).html(); $(element).html(originaltext); }
Since this project is a little bit more involved than just writing
one line of code, you may want to download the code to your computer's
hard drive in order to edit it so that you do not lose your work
partway through. To run it directly from your hard drive, you will
want to also download a copy of the jquery.js file
into the same directory.