Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning JavaScript With DOM Scripting And Ajax - From Novice To Professional (2006)

.pdf
Скачиваний:
81
Добавлен:
17.08.2013
Размер:
17.27 Mб
Скачать

406

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

Creating an Image Badge from a Folder

Let’s have a go at another small gallery example using PHP and JavaScript/XHR before we look at some ready-made third-party code and online services in the next chapter.

If you already use Flickr (http://www.flickr.com) or you read blogs a lot, you may have encountered Flickr badges, which are small galleries showing the latest photos the maintainer of the site has uploaded to the system. Figure 10-3 shows my blog as an example.

Figure 10-3. My latest photos on Flickr as a badge on my blog

Let’s spice up the idea of a badge by allowing the user to navigate through the thumbnails with previous and next links and showing the large photo by clicking the thumbnail. The demo exampleBadge.html does this, and Figure 10-4 shows how it looks with two badge galleries in Firefox on Windows XP.

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

407

Figure 10-4. Two image folders as badge galleries

When creating scripts like these, it is a good idea to keep the HTML as easy as possible. The less you expect from the maintainer, the more likely it is that people will use your script. In this case, all the maintainer needs to do to add a badge gallery to the HTML document is to add an element with the class badge and a link pointing to the folder containing the images:

exampleBadge.html (excerpt)

<p class="badge"><a href="galleries/animals/">Animals</a></p>

<p class="badge"><a href="galleries/buildings/">Buildings</a></p>

As JavaScript cannot check a folder on the server for files, you need a PHP script to do this for you. The file badge.php does so and returns thumbnails as list items.

408

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

Note The following is a quick explanation of the PHP script. This is not JavaScript, but I hope you appreciate some insight into the workings of the tools the upcoming badge script uses.

badge.php

<?php

$c = preg_match( '/\d+/', $_GET['c'] ) ? $_GET['c'] : 5; $s = preg_match( '/\d+/', $_GET['s'] ) ? $_GET['s'] : 0; $cd = is_dir( $_GET['cd'] ) ? $_GET['cd'] : '';

You define three variables: $c, which stores the number of thumbnails to be shown; $s, which is the index of what is currently the first thumbnail in the list of all thumbnails; and $cd, which is the folder URL on the server. The $_GET array of PHP stores all the parameters of the URL, which means that if the URL were to be badge.php?c=3&s=0&cd=animals, $_GET['c'] would be 3, $_GET['s'] would be 0, and $_GET['cd'] would be animals. You can use regular expressions to make sure that $c and $s are integers and preset to 5 and 0, respectively, and the is_dir() function of PHP to make sure that $cd really is an available folder.

badge.php (continued)

if( $cd != '' ) {

$handle = opendir($cd);

if( preg_match( '/^tn_.*(jpg|jpe|jpeg)$/i', $file ) ) { $images[] = $file;

}

}

closedir( $handle );

If the folder is available, you start reading out each file in the folder with the opendir() method and test whether the file is a thumbnail by matching its name with the pattern ^tn_.*(jpg|jpe|jpeg)$ (starts with tn_ and ends with either jpg, jpe, or jpeg). If the file is a thumbnail, add it to the images array. When there are no files left in the folder, close the folder by calling the closedir() method.

badge.php (continued)

$imgs = array_slice( $images, $s, $c );

if( $s

> 0 ) {

echo

'<li class="badgeprev">';

echo

'<a href="badge.php?c='.$c;

echo

'&s=' . ( $s-$c ) . '&cd='.$cd.'">';

echo

'previous</a></li>';

}else {

echo '<li class="badgeprev"><span>previous</span></li>';

}

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

409

You use the array_slice() method of PHP to reduce the array down to the chosen images ($c images starting at $s) and test whether $s is larger than 0. If it is, write out a list element with the class badgeprev that has the right parameters in the link’s href attribute. If it isn’t, write out a SPAN inside the list item instead of a link.

badge.php (continued)

for( $i=0; $i<sizeof($imgs); $i++ ) {

echo '<li><a href="'.str_replace('tn_','',$cd.$imgs[$i]).'">'. '<img src="' . $cd . $imgs[$i] . '" alt="' . $imgs[$i] .

'" /></a></li>';

}

Loop through the images and display an IMG element inside a link pointing to the large image for each array item. You can retrieve the link to the large image by removing the tn_ string of the array element’s value with str_replace().

badge.php (continued)

if( ( $c+$s ) <= sizeof( $images ) ) { echo '<li class="badgenext">';

echo '<a href="badge.php?c=' . $c . '&s=' . ($s + $c); echo '&cd=' . $cd . '">next</a></li>';

}else {

echo '<li class="badgenext"><span>next</span></li>';

}

}

?>

Test whether $c and $s together are less than the number of all images in the folder and display a link if it is or a SPAN if it isn’t.

As you can see, the programming syntax and logic of JavaScript and PHP is pretty similar, which is one of the reasons for the success of PHP. Let’s now create the JavaScript that uses this PHP script to turn the links into image badges.

badge.js

badge = {

badgeClass : 'badge', containerID : 'badgecontainer',

You define the CSS class used to specify the badge links and the ID of the image container showing the large picture as properties of the main object badge.

410 C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

badge.js (continued)

init : function() {

var newUL, parent, dir, loc;

if( !document.getElementById || !document.createTextNode ) { return;

}

var links = document.getElementsByTagName( 'a' ); for( var i = 0; i < links.length; i++ ) {

parent = links[i].parentNode;

if( !DOMhelp.cssjs( 'check', parent, badge.badgeClass ) ) { continue;

}

You test for DOM support and loop through all links in the document, testing whether a particular link’s parent node has the badge class assigned to it. If it doesn’t, you skip this link.

badge.js (continued)

newUL = document.createElement( 'ul' ); newUL.className = badge.badgeClass; dir=links[i].getAttribute( 'href' );

loc = window.location.toString().match( /(^.*\/)/g ); dir = dir.replace( loc, '' );

badge.doxhr( 'badge.php?cd=' + dir, newUL ); parent.parentNode.insertBefore( newUL, parent ); parent.parentNode.removeChild( parent );

i--;

}

You create a new list element and add the badge class to it. You retrieve the link’s href attribute, read the window location, and remove anything in the window.location before the last / from the href attribute value. This is necessary to make the script work in Microsoft Internet Explorer.

Note You might remember that the link is <a href="galleries/animals/">Animals</a>, and if you have the script on your localhost, for example, at http://localhost/book/mybook/ Chapter10_A_Dynamic_gallery/exampleBadge.html, Mozilla returns the href attribute value as galleries/animals/. MSIE, however, returns http://localhost/book/mybook/ Chapter10_A_Dynamic_gallery/galleries/animals/, and you need to remove the excess data, as badge.php expects only the folder name as the URL.

You call the doxhr() method with the correct URL and the newly created list as parameters, and add the list before the parent element of the current link. You then remove the link’s parent element with the DOM method removeChild() and decrease the loop counter by one

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

411

(you loop through all the links of the document, which means that when you remove one of them, the counter needs to decrease to stop the loop from skipping the following link).

badge.js (continued)

badge.container = document.createElement( 'div' ); badge.container.id = badge.containerID; document.body.appendChild( badge.container );

},

You create a new DIV as the container for the large image, set its ID, and add it to the body of the document.

badge.js (continued)

doxhr : function( url, container ) { var request;

try {

request = new XMLHttpRequest();

}catch ( error ) { try {

request = new ActiveXObject("Microsoft.XMLHTTP");

}catch ( error ) { return true;

}

}

request.open( 'get', url, true ); request.onreadystatechange = function() {

if( request.readyState == 1 ) {

}

 

 

 

 

if( request.readyState

==

4 ) {

 

 

if( request.status

&&

/200|304/.test(

request.status ) ) {

badge.retrieved(

request,

container

);

}else{

badge.failed( request );

}

}

}

request.setRequestHeader( 'If-Modified-Since', 'Wed, 05 Apr 2006 00:00:00 GMT');

request.send( null ); return false;

},

retrieved : function( request, container ) { var data = request.responseText; container.innerHTML = data; badge.assignHandlers( container );

},

412

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

failed : function( requester ) {

alert('The XMLHttpRequest failed. Status: ' + requester.status); return true;

},

The Ajax/XHR methods remain largely unchanged, the only difference being that when the data is successfully retrieved, the assignHandlers() method is called with the list item as a parameter.

badge.js (continued)

assignHandlers : function( o ) {

var links = o.getElementsByTagName('a'); for( var i = 0; i < links.length; i++ ) {

links[i].parent = o;

if( /badgeprev|badgenext/.test( links[i].parentNode. className ) ) {

DOMhelp.addEvent( links[i], 'click', badge.load, false );

}else {

DOMhelp.addEvent( links[i], 'click', badge.show, false );

}

}

},

The assignHandlers() method loops through all the links in the element sent as the parameter o. It stores this element as a new property in each link called parent and tests whether the link has the class badgeprev or badgenext, which, as you may remember, are added by badge.php to the previous and next links. If the CSS class is there, assignHandlers() adds an event handler pointing to the load method; otherwise it adds an event handler pointing to the show method, as some links need to navigate through the thumbnails and others need to show the large image.

badge.js (continued)

load : function( e ) {

var t = DOMhelp.getTarget( e );

if( t.nodeName.toLowerCase() != 'a' ) { t = t.parentNode;

}

var dir = t.getAttribute( 'href' );

var loc = window.location.toString().match( /(^.*\/)/g ); dir = dir.replace( loc, '' );

badge.doxhr( 'badge.php?cd=' + dir, t.parent ); DOMhelp.cancelClick( e );

},

C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

413

The load method retrieves the event target and makes sure it is a link. It retrieves the href attribute value of the event target and cleans it up before calling the doxhr method with the element stored in the link’s parent property as the output container. You stop the link from being followed by calling DOMhelp’s cancelClick().

badge.js (continued)

show : function( e ) {

var t = DOMhelp.getTarget( e );

if( t.nodeName.toLowerCase() != 'a' ) { t = t.parentNode;

}

var y = 0;

if( self.pageYOffset ) { y = self.pageYOffset;

} else if ( document.documentElement && document.documentElement.scrollTop ) {

y = document.documentElement.scrollTop;

}else if( document.body ) {

y = document.body.scrollTop;

}

badge.container.style.top = y + 'px'; badge.container.style.left = 0 + 'px';

In the show method you once again retrieve the event target and test that it is a link. You then position the large image container on the screen. As you don’t know where in the document the badge will be, the safest method to show the image is to read out the scroll position of the document. To achieve this, you need to do bit of object detection for different browsers.

Note Firefox, Safari, and Opera store the current vertical scrolling position in a property of the window object called pageYOffset, MSIE without a proper HTML DOCTYPE stores it in the body.scrollTop of the document object, and MSIE with a proper HTML DOCTYPE and Firefox store it in the documentElement.scrollTop property of the document object.

You test for all these eventualities and position the image container accordingly by setting the left and top properties of its style attribute collection. This way you can always be sure that the large image will be visible in the user’s browser window.

414 C H A P T E R 1 0 M O D E R N J A V A S C R I P T C A S E S T U D Y : A D Y N A M I C G A L L E R Y

badge.js (continued)

var source = t.getAttribute( 'href' );

var newImg = document.createElement( 'img' ); badge.deletePic();

newImg.setAttribute( 'src', source ); badge.container.appendChild( newImg );

DOMhelp.addEvent( badge.container, 'click', badge.deletePic, false );

DOMhelp.cancelClick( e );

},

You read the href attribute of the link and create a new IMG element. You remove any large image that may already be shown by calling the deletePic() method and set the new image’s src attribute to the href of the link. You add the new image as a child node to the image container, apply an event handler that calls deletePic() when the user clicks the image, and stop the link from being followed by calling cancelClick().

badge.js (continued)

deletePic : function() { badge.container.innerHTML = '';

}

}

DOMhelp.addEvent( window, 'load', badge.init, false );

All the deletePic method needs to do is to set the innerHTML property of the container element to an empty string, thus removing the large image.

Summary

In this chapter, you learned how to enhance already existing HTML structures or dynamic server-side scripts for thumbnail galleries with JavaScript either to become dynamic or to appear more dynamic by not loading the whole document when the user chooses another image or thumbnail subset.

Galleries are always fun to create and to come up with new and flashier solutions for, and I hope that by learning some of the tricks presented in this chapter you feel confident to play around with them and come up with your own gallery ideas.

C H A P T E R 1 1

■ ■ ■

Using Third-Party JavaScript

As you’ll have gathered by now, when you create a JavaScript application, you don’t need to reinvent the wheel and recode all the functionality from scratch every time—JavaScript has many, many functions available for you to use, and you can create your own reusable functions and objects, too. But it goes even further than that—you can also make use of third-party code libraries and APIs, and there are many available on the Web these days. But it’s knowing where, why, and how that’s the key, and that’s where this chapter comes in.

In this chapter, we will take a look at some ready-made content and code available on the Web these days. We’ll quickly talk about the different kinds of resources you can find on the Web to make your JavaScript development easier: content in RSS format, REST services, APIs, code generators, and libraries. We’ll take a look at a code library and try some examples, check how to add an interactive map to your web site in a matter of minutes using the Google Maps API, and take a closer look at Yahoo’s User Interface Library.

What the Web Offers You

We are currently living in pretty exciting times as developers. Over the last few years, the outlook of companies in terms of sharing content and technology has changed drastically. In the past, every company guarded its content and code as if it were made of platinum, and getting any information about the workings of a system or how to communicate with it was a painful and long-winded process including price negotiations, nonworking demonstrations, PowerPoint presentations, preview code, and other marketing collateral.

A lot of these closed source ideas still prevail, and even maintainers of personal web sites wonder how they can make sure nobody can save their images or copy their code and content. We’ve discussed the issues and misconceptions of this approach over the last chapters and will not dwell on it. Instead, we will look at the modern outlook of forward-thinking companies who are going in quite the opposite direction. For example, many content providers like media agencies have realized that when they offer their news in lightweight, easy-to-syndicate formats like RSS, people will use them to display headlines on their web sites and drive traffic and users to their sites.

Furthermore, e-commerce companies like eBay, PayPal, and Amazon realize that if they allow programmatic access to their services, people will sell more things online, as they can offer content-specific products on their web sites without having to send their visitors to thirdparty web sites. And last but not least, companies have started realizing that if you share the technologies you use with the world, you get a lot of quality feedback, you get your products tested in the most adverse environments (as every developer’s computer and connection is

415