JavaScript & jQuery Articles

RSS Feed - JavaScript & jQuery

jQuery Enlightenment is a Worthy Purchase

Tags: jQuery, Books | Written on Oct 26, 2009

If you haven't heard of or read jQuery Enlightenment, then you probably should go subscribe to more jQuery blogs, this one has been posted everywhere. Simply because this book is an excellent read with excellent examples, worth the $15 purchase. It has live links to code examples you might need down the road.

And no, I wasn't paid to do this post. All the dough goes straight to Cody Lindley on this self-published e-book, and he deserves every penny. Go Cody go! *cheers*

Preserving Existing Events in JavaScript

Tags: JavaScript | Written on Jul 08, 2009

If you are creating a JavaScript library for people to use, you want to make sure that you aren't overriding existing JavaScript events that your users may have already attached.

Existing Event

JavaScript:
  1. window.onclick = function(e) {
  2.     alert('existing event');
  3. }

Creating a New Event

If we want to preserve that existing event, we need to follow these steps:

  1. Wrap the new event definition in a closure to capture the existing event.
  2. Fire the existing event if it is defined, making sure it has not returned false.
  3. Continue with new event.
JavaScript:
  1. window.onclick = (function(e){
  2.     var windowClick = window.onclick;
  3.     return function(e){
  4.         if (windowClick != null && windowClick() === false) {
  5.             return false;
  6.         }
  7.         alert('new event');
  8.         return true;
  9.     }
  10. })();

This  will alert, "new event" so long as the existing event does not return false. If we want to prevent the new event, we can simply return false on our original event like so..

JavaScript:
  1. window.onclick = function(e) {
  2.     alert('existing event');
  3.     return false;
  4. }

Happy library development to you!

jQuery Tools vs jQuery UI

Tags: jQuery, jQuery UI | Written on Jun 05, 2009

  VS

A new library has come out called, "jQuery Tools" that is packed with some visually appealing plugins built on top of jQuery. Here is their opening line to grab your interest:

Let's face it: do you really need drag-and-drop, resizables, selectables or sortable tables in your web applications? Websites are not desktop applications. They are different.

This is obviously a jab at jQuery UI, but before we dismiss what they have to say let's read on...

What you really need are tabs, tooltips, accordions, overlays, smooth navigation, great visual effects and all those "web 2.0" goodies that you have seen on your favourite websites.

This library contains six of the most useful JavaScript tools available for today's website. The beauty of this library is that all of these tools can be used together, extended, configured and styled. In the end, you can have hundreds of different widgets and new personal ways of using the library.

While there is some truth to the fact that you don't need each component that jQuery UI provides in most websites. You still have to keep in mind that jQuery UI's focus is to bring a set of components to the table that you can pick and chose from.

I agree with what the jQuery Tools author in saying that everybody needs overlays and visual effects that this library provides. I just don't understand the arrogance of attacking jQuery UI right off the bat, instead of augmenting the library and working together with them. 

Note: the author says he isn't attacking the jQuery UI library (in comments). But I think he should still be looking for ways to add the good parts of his plugins onto jQuery UI.

From an outside perspective, this library shines and has great potential. However as I dig deeper into the API and intensions it just looks bad.

Note: Tero from jQuery Tools has updated the API to fix this issue I'm pointing out here. You can see the result of the update in the jQuery Tools release notes. This type of thing should be sorted out behind the scenes from now on, but it was a good learning experience for me personally about where the public / private line should be.

Tooltip

Demo (hover over box):

Definition of Pride

Tooltip Implimentation

HTML:
  1. <!-- trigger element -->
  2. <a href="#" id="trigger">
  3.     Move the mouse over this box to see the tooltip in action.
  4. </a>
  5.  
  6. <!-- tooltip element -->
  7. <div class="tooltip">
  8.     <h3>The Tooltip</h3>
  9.  
  10.     <p>
  11.         <strong>A great tool for designing better layouts and more intuitive user-interfaces.</strong>
  12.     </p>
  13.  
  14.     <p>
  15.         Tooltips can contain any HTML such as links, images, forms and tables.
  16.         This tooltip is vertically centered on the top edge of the trigger element.
  17.     </p>
  18. </div>
JavaScript:
  1. $('#tooltip').tooltip();

It doesn't make sense within the context of jQuery.

So apparently, you have to grab the tooltip div, then turn it into a tooltip? Um... what? How do I get multiple tooltips on the page?

Quick, here is the philosophy behind jQuery:

  1. Find element(s) on the page
  2. Do something to them

Is the tooltip on the page? nope, not yet. Ok, failed #1. Where do we go from here? Typically you would grab elements on the page and then attach the tooltips to them. This is just common jQuery sense.

Note: After reading this article, the author of jQuery Tools updated his tooltip API.

As I dive into more examples of the tooltip, it continues to make no sense. The form example have no way to target inputs that you desire with custom classes or ids. You have to modify the markup before page load to change tooltips. After you load up the tooltips, you are stuck and cannot ditch tooltips, or make new ones from within the JavaScript.

Please, just use the jQuery Tooltip plugin or ClueTip.

Non-jQuery API

So now look at the API where it talks about returning the API instead of a jQuery object by passing api: true .... WHAT?! We are now forced to exit out of jQuery into a seperate jQuery Tools API by passing a variable?

JavaScript:
  1. var api = $("#myDiv").scrollable({size: 3, api: true});
  2. api.onClick = function(){ ...

Contrast this to using jQuery UI, you can stay within' jQuery and modify all settings.

JavaScript:
  1. var $myDiv = $("#myDiv").accordion({ 'header': 'h3' });

Then if later we want to change an option we can use that same div jQuery object.

JavaScript:
  1. $myDiv.accordion('option', 'changestart', function(){ ... });

With jQuery UI, all the plugins work with jQuery and it's philosophy. Working with John Resig's supervision and incite. Working together. Returning a seperate API has some potential, but not the way it is implimented here.

jQuery Tools flying solo

All this means (from what I've seen) is that the author did not take the time to learn the why behind jQuery and decided to go his own route, then flame jQuery UI and give you some shiny effects. The effects have potential, but the author needs to open up the code and start collaborating instead of going it solo.

Note: discussion has been opened up between jQuery UI and jQuery Tools teams.

Keep it real, y'all

First Look at Google Maps API v3

Tags: Google Maps, JavaScript | Written on May 28, 2009

Google announced version 3 of the google maps API.

Some things I noticed right away:

  • no API key required! before you had to sign up for an API key, but now you can shed your API key woes (I know I had them) and not have to sign up for one again.
  • mobile browser support (iphone and android)
  • You now have to specifiy the sensor variable in your include of google maps
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true">
    the sensor is for detecting user's location with mobile sensors like GPS
  • No more polluting the global namespace with tons of variables. Google is moving over to their google namespace. so instead of new GMap2 you do new google.maps.map
  • New mouse event object.
  • Default UI so that as Google maps updates their UI, you get to enjoy the new interface without updating code.
  • it is like 3AM now so that is enough changes to see before I go to bed. =P

The only thing I couldn't figure out is where is the directions object? A lot of my maps applications use driving directions, so I'll be holding off on migrating over until I figure that out with the new API.

jQuery and Google Maps #2: AJAX Storing and Retrieving Points

Tags: jQuery, Google Maps | Written on Apr 28, 2009

Note on April 30th: This article was updated do to feedback from Google Maps API team to use the Client Geocoder instead of encoding on the server.

Continuing the series on jQuery and Google Maps, I will teach you how to store and retrieve points with using AJAX and a server-side language. This tutorial will use PHP/MySQL on the server, but it is basic enough that re-writing in another language should not be difficult.

View Final Demo

Google maps add point with jQuery

First, let me share with you the design-pattern behind the tutorial. My design pattern has two steps. The first is to use a simple HTML form to create new locations by posting the data to the server via AJAX. The second step is to fetch those locations from the server also via AJAX. Sound simple? Well, then lets get started...

Note: This tutorial builds on the first tutorial's code, so all code I am showing you here will be added onto it.

Step #1: Create the, "Add Location" Form

To allow users to add locations to the map, let's create a basic form. This will include the parts of an address, as well as the name of the location.

HTML:
  1. <form id="add-point" action="map-service.php" method="POST">
  2.     <input type="hidden" name="action" value="savepoint" id="action">
  3.     <fieldset>
  4.         <legend>Add a Point to the Map</legend>
  5.         <div class="error" style="display:none;"></div>
  6.         <div class="input">
  7.             <label for="name">Location Name</label>
  8.             <input type="text" name="name" id="name" value="">
  9.         </div>
  10.         <div class="input">
  11.             <label for="address">Address</label>
  12.             <input type="text" name="address" id="address" value="">
  13.         </div>
  14.         <button type="submit">Add Point</button>
  15.     </fieldset>
  16. </form>

A couple things to note about the form:

  • The form's action is pointed to map-service.php, which is where we will process the form data.
  • A hidden input <input type="hidden" name="action" value="savepoint" id="action"> will be used on the server to flag that we want to save a point to the database. This is just a personal preference on how to do things, there are many other ways to flag the intended action.
  • An empty div with class error <div class="error" style="display:none;"></div> is placed in the form to be used in a later step to display errors.

Step #2: Add Styles to the Form

By adding a few CSS rules to our page, we will set our form next to the map and spruce up the form a bit.

Css:
  1. #add-point { float:left; }
  2. div.input { padding:3px 0; }
  3. label { display:block; font-size:80%; }
  4. input, select { width:150px; }
  5. button { float:right; }
  6. div.error { color:red; font-weight:bold; }

Step #3: Geoencode Address Before Submiting Data

3a) Override default form submit

At this point we'll override the form's default submit action by selecting the form $("#add-point"), then using jQuery's submit event method. This method accepts a function that will run on submit of the form.

JavaScript:
  1. $("#add-point").submit(function(){
  2.     geoEncode();
  3.     return false;
  4. });

3b) Add GeoCoder

Then, inside the submit we will post the form data with AJAX using jQuery's ajax post method.

JavaScript:
  1. var geo = new GClientGeocoder();
  2.                
  3. var reasons=[];
  4. reasons[G_GEO_SUCCESS]            = "Success";
  5. reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address";
  6. reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address.";
  7. reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address";
  8. reasons[G_GEO_BAD_KEY]            = "Bad API Key";
  9. reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries";
  10. reasons[G_GEO_SERVER_ERROR]       = "Server error";

3c) Get geocode from address

JavaScript:
  1. function geoEncode() {
  2.     var address = $("#add-point input[name=address]").val();
  3.     geo.getLocations(address, function (result){
  4.         if (result.Status.code == G_GEO_SUCCESS) {
  5.             geocode = result.Placemark[0].Point.coordinates;
  6.             savePoint(geocode);
  7.         } else {
  8.             var reason="Code "+result.Status.code;
  9.             if (reasons[result.Status.code]) {
  10.                 reason = reasons[result.Status.code]
  11.             }
  12.             $("#add-point .error").html(reason).fadeIn();
  13.             geocode = false;
  14.         }
  15.     });
  16. }

Step #4: Submit Data to Server

JavaScript:
  1. function savePoint(geocode) {
  2.     var data = $("#add-point :input").serializeArray();
  3.     data[data.length] = { name: "lng", value: geocode[0] };
  4.     data[data.length] = { name: "lat", value: geocode[1] };
  5.     $.post($("#add-point").attr('action'), data, function(json){
  6.         $("#add-point .error").fadeOut();
  7.         if (json.status == "fail") {
  8.             $("#add-point .error").html(json.message).fadeIn();
  9.         }
  10.         if (json.status == "success") {
  11.             $("#add-point :input[name!=action]").val("");
  12.             var location = json.data;
  13.             addLocation(location);
  14.             zoomToBounds();
  15.         }
  16.     }, "json");
  17. }

The $.post method accepts parameters.

  1. URL to post data to: $(this).attr('action') will get the action attribute from the form that was submitted in the previous step.
  2. Data in name, value pairs i.e. { name: "inputname", value: "inputvalue" } we will get all the inputs using the :input selector in jQuery, then use the serialize array function to turn those inputs into name, value pairs. Then add the two geocode name/value pairs to the data object.
  3. Function to run after AJAX response is received. This function has one parameter which contains the response of the AJAX request.
  4. Type of data to be returned (optional). In this case we will use JSON.

Step #5: Use PHP on the Server to Process the Form

Once the data is posted with jQuery, we can handle it on the server with PHP.

5a) Check the action and validate the name

Let's simply check if the action variable is posted as, "savepoint". Then validate that the name has the proper characters with a regular expression and also that it is not empty. If any data is invalid, let's call a fail method (defined in next sub-step) with the message we want to show to the user.

PHP:
  1. <?php
  2. if ($_POST['action'] == 'savepoint') {
  3.     $name = $_POST['name'];
  4.     if(preg_match('/[^\w\s]/i', $name)) {
  5.         fail('Invalid name provided.');
  6.     }
  7.     if(empty($name)) {
  8.         fail('Please enter a name.');
  9.     }
  10. }
  11. ?>

Save the file as map-service.php or whatever you named your form's action attribute.

5b) Output the error message as a JSON object

Our fail function will use PHP's die method to stop the script from executing and output an error message to the client. Since the front-end (jQuery) is expecting a JSON object, we want to make sure to always send back a JSON response. To output JSON with PHP, you simply pass an array into the json encode method (json_encode is PHP 5.2+ only, if you are using less than 5.2 then use the JSON PHP library).

PHP:
  1. function fail($message) {
  2.     die(json_encode(array('status' => 'fail', 'message' => $message)));
  3. }

For the JSON array we want to use the JSEND specification for sending back a response. Basically, you have a key/value pair of status equals success or fail. That way the response can easily be checked on the front-end. I'm deviating from the JSEND spec a little bit by only sending a string back instead of a key/value pair of messages.

Using Firebug and Firefox, we can inspect the Ajax requests easily within the browser.

You can see here I submitted the form without entering a name and it sent me back an error message in the form of JSON.

Step #6: Display the Error Messages with jQuery

Hopping back to the jQuery code, we will write the error handling.

Inside the post code, we will first use the hide method to hide the error div in case it is already displaying. Then check if json.status is showing, "fail". If it is, we'll place the json.message inside the error div with jQuery's html attribute method and then fade it in with the fade in method.

JavaScript:
  1. $("#add-point .error").hide();
  2. if (json.status == "fail") {
  3.     $("#add-point .error").html(json.message).fadeIn();
  4. }

Step #7: Create a Database and Store the Locations

Using SQL, create a database table named locations which has a "name", "latitude", "longitude" and an "id" in it. If you need help with this, you will have to consult w3schools php and mysql for more help.

7a) Create the table with SQL

Mysql:
  1. CREATE TABLE `locations` (
  2.   `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  3.   `name` VARCHAR(100) DEFAULT NULL,
  4.   `lat` FLOAT(15,11) DEFAULT NULL,
  5.   `lng` FLOAT(15,11) DEFAULT NULL,
  6.   PRIMARY KEY  (`id`)
  7. )

7b) Insert name and location into the database with PHP and MySQL

We will use PHP and MySQL to insert the new location into the database. Directly after, we will either flag a success or fail message to the user.

PHP:
  1. $query = "INSERT INTO locations SET name='$_POST[name]', lat='$lat', lng='$lng'";
  2. $result = map_query($query);
  3.  
  4. if ($result) {
  5.     success(array('lat' => $_POST['lat'], 'lng' => $_POST['lng'], 'name' => $name));
  6. } else {
  7.     fail('Failed to add point.');
  8. }

If you noticed, I created a custom function called map_query to abstract out the database stuff. Here is the function definition. Make sure to update the, "MYSQL" stuff with your credentials.

PHP:
  1. function map_query($query) {
  2.     mysql_connect('MYSQL_HOST', 'MYSQL_USER', 'MYSQL_PASSWORD')
  3.         OR die(fail('Could not connect to database.'));
  4.     mysql_select_db ('MYSQL_DATABASE');
  5.     return mysql_query($query);
  6. }

I also created a similar method to "fail" called "success" which looks like:

PHP:
  1. function success($data) {
  2.     die(json_encode(array('status' => 'success', 'data' => $data)));
  3. }

An example of a succesful response in firebug:

Step #8: Map the New Point

Going back to the jQuery code, we can now add the success response handling. The response is a JSON object with "lat", "lng" and "name" properties. I'll give you the code inside the success handling, then later show you what each custom function is doing.

JavaScript:
  1. if (json.status == "success") {
  2.     $("#add-point :input[name!=action]").val("");
  3.     var location = json.data;
  4.     addLocation(location);
  5.     zoomToBounds();
  6. }

After a location is successfully added to the database, we want to clear the form to prevent duplicate entry. Do this by selecting the inputs with the :input selector. Then we need to filter out the  action input, do this by using the attribute not equal selector [name!=action].

My addLocation(location) function is simply our code from the last tutorial placed into a function to be reusable later.

JavaScript:
  1. function addLocation(location) {
  2.     var point = new GLatLng(location.lat, location.lng);       
  3.     var marker = new GMarker(point);
  4.     map.addOverlay(marker);
  5.     bounds.extend(marker.getPoint());
  6.    
  7.     $("<li />")
  8.         .html(location.name)
  9.         .click(function(){
  10.             showMessage(marker, location.name);
  11.         })
  12.         .appendTo("#list");
  13.    
  14.     GEvent.addListener(marker, "click", function(){
  15.         showMessage(this);
  16.     });
  17. }

It has a few things you might want to note:

  • using location.name, location.lat and location.lng means that we will be passing in a location object with those properties to the function.
  • Ignore bounds.extend(marker.getPoint()); and zoomToBounds for now or skip to #13 quickly to find out what they do.

Step #9: Load and Display the Locations from in the Database

When the page initially loads, we want to load all of our stored points. The simplest way to do this (in my opinion) is to do a GET request to fetch a JSON object from the server after the page loads.

To make a, "GET" request to the server, we can use jQuery's getJson method. We will send the server a, "get" variable called action with value, "listpoints".

JavaScript:
  1. $.getJSON("php/map-service.php?action=listpoints", function(json) {
  2.     // do stuff in step #11
  3. });

Step #10: Get the Locations from the Database

Simply check the, "GET" action in the PHP and run this code to fetch the locations records. Pretty straight-forward code here. We are creating an array of points and then sending them back to the client as JSON.

PHP:
  1. if ($_GET['action'] == 'listpoints') {
  2.     $query = "SELECT * FROM locations";
  3.     $result = map_query($query);
  4.     $points = array();
  5.     while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
  6.         array_push($points, array('name' => $row['name'], 'lat' => $row['lat'], 'lng' => $row['lng']));
  7.     }
  8.     echo json_encode(array("Locations" => $points));
  9.     exit;
  10. }

Step #11: Display the Locations

Iterate through the JSON object that contains the locations inside the getJson response function.

jQuery Essentials Presentation at MinneWebCon

Tags: jQuery, Conference | Written on Apr 07, 2009

At the University of Minnesota's web conference, MinneWebCon I gave a talk on, "jQuery Essentials" and it seemed well-received. I enjoyed giving the presentation and I particularly enjoyed it because I finally was able to present in my home state of Minnesota!

Enjoy the slides! Keep it real, y'all.

jQuery and Google Maps Tutorial: #1 Basics

Tags: jQuery, Google Maps | Written on Mar 04, 2009

There are many times I want to leverage jQuery's strengths to create a custom Google Maps mashup. In this tutorial, I will walk you through how to get started using jQuery inside the Google Maps environment. I will assume nothing, and explain each piece in detail.

View Final Demo

If you are already familiar with Google Maps API, skip to step #5, or so.

Step #1: Get API key

First, grab yourself an API key for Google Maps, you will need this in the next step.

Step #2: Load Google Maps and jQuery

We want to load up jQuery and Google Maps with the Google AJAX Libraries API.

JavaScript:
  1. <script type="text/javascript" src="http://www.google.com/jsapi?key=YOUR_API_KEY_HERE">
  2. <script type="text/javascript" charset="utf-8">
  3.     google.load("maps", "2.x");
  4.     google.load("jquery", "1.3.1");
  5. </script>

Make sure to replace YOUR_API_KEY_HERE with your API key. By using the Google AJAX Libraries API, it allows you to load the JavaScript libraries you need right from Google's servers. This increases the chance that your users will be able to load the scripts faster from their browser cache, as well as shuffle the jQuery script loading off your server.

Step #3: Create the Google Map

Google Maps Basic

To create our Google Map, we need to create a container div and use CSS to give it a width and a height.

HTML:
  1. <div id="map"></div>
Css:
  1. <style media="screen" type="text/css">
  2.     #map { width:500px; height:500px; }
  3. </style>

Use the GMap2 function to make a map instance. Then, set the center of the map. I wrapped this code block in jQuery's document ready function so that the code is run after the page has loaded.

JavaScript:
  1. $(document).ready(function(){
  2.     var map = new GMap2(document.getElementById('map'));
  3.     var burnsvilleMN = new GLatLng(44.797916,-93.278046);
  4.     map.setCenter(burnsvilleMN, 8);
  5. });

Here, I used Burnsville, MN's latitude and longitude because it is where I live right now. There are many ways to get the latitude and longitude of an address, like this simple service by iTouchMap.

The second parameter for setCenter is the zoom level, which is a number. I set the zoom level to "8" here because it is about in the middle.

At this point we should have a simple map.

Step #4: Load the Google Maps Example

To have some points to work with, let's paste in the google maps example.

JavaScript:
  1. // setup 10 random points
  2. var bounds = map.getBounds();
  3. var southWest = bounds.getSouthWest();
  4. var northEast = bounds.getNorthEast();
  5. var lngSpan = northEast.lng() - southWest.lng();
  6. var latSpan = northEast.lat() - southWest.lat();
  7. var markers = [];
  8. for (var i = 0; i < 10; i++) {
  9.     var point = new GLatLng(southWest.lat() + latSpan * Math.random(),
  10.         southWest.lng() + lngSpan * Math.random());
  11.     marker = new GMarker(point);
  12.     map.addOverlay(marker);
  13.     markers[i] = marker;
  14. }

Note that I added a markers array to the example code. This will be used in the next step.

Step #5: Loop Through Markers and Add Basic Click Event to Markers

In this step, we start to use jQuery and Google Maps together. We want to be careful to use Google Map's built-in API as much as possible, leaving jQuery only for what it is best at.

Let's take that array of markers and loop through them with jQuery's each method.

JavaScript:
  1. $(markers).each(function(i,marker){
  2.     GEvent.addListener(marker, "click", function(){
  3.         map.panTo(marker.getLatLng());
  4.     });
  5. });

Inside the loop, let's use Google Maps's GEvent namespace to attach a click event to each marker. Then, we will add a panTo behavior to center the map on the marker. marker.getLatLng(); returns the latitude and longitude of the marker, while map.panTo(GLatLng) allows us to center the map on that latitude and longitude.

Step #6 - Make a Clickable List of Markers

Let's add a clickable list next to the map. Insert a ul.

HTML:
  1. <ul id="list"></ul>

Then let's style it up a bit by floating the map left and float our list element next to it. We also want to add a hover effect to the list items to give visual feedback to the user that they can click on each item in the list.

Css:
  1. <style type="text/css" media="screen">
  2.     #map { float:left; width:500px; height:500px; }
  3.     #list { float:left; width:200px; background:#eee; list-style:none; padding:0; }
  4.     #list li { padding:10px; }
  5.     #list li:hover { background:#555; color:#fff; cursor:pointer; cursor:hand; }
  6. </style>

In our jQuery each loop from last step, let's append the clickable list items to the list.

JavaScript:
  1. $("<li />")
  2.     .html("Point "+i)
  3.     .click(function(){
  4.         map.panTo(marker.getLatLng()); 
  5.     })
  6.     .appendTo("#list");

Here I am just setting the content to "Point (the count)", adding that same panTo action from before, then appending the list item to our list.

Step #7 - Add a Custom Message

When I create a Google Maps mashup, I usually want to replace the built-in info window with something custom. With jQuery, we can add any arbitrary HTML in place of the info window. This is great when you want complete control over what the info window looks like.

Add a message div with some test text.

HTML:
  1. <div id="message" style="display:none;">
  2.     Test text.
  3. </div>

Then add some basic styling to the message.

Css:
  1. #message { position:absolute; padding:10px; background:#555; color:#fff; width:75px; }

We have to place the message div inside the map. To do this, we can use jQuery to append it to an object. The map view is seperated into panes. Each pane is a div layered on top of the other. To get the div object that we want to attach our message div to, we can use map.getPane(PANE). The G_MAP_FLOAT_SHADOW_PANE is the layer that I find works best for attaching custom messages.

JavaScript:
  1. $("#message").appendTo(map.getPane(G_MAP_FLOAT_SHADOW_PANE));

To show the message div in place of the info window, we need to separate the click action into a separate function. Replace the map.panTo(marker.getLatLng(); with displayPoint(marker, i);, a call to the new displayPoint function shown below.

JavaScript:
  1. function displayPoint(marker, i){
  2.     map.panTo(marker.getPoint());
  3.    
  4.     var markerOffset = map.fromLatLngToDivPixel(marker.getPoint());
  5.     $("#message").show().css({ top:markerOffset.y, left:markerOffset.x });
  6. }

We put the panTo action in our new function. Then the magic function here is the map.fromLatLngToDivPixel(GLatLng); which converts the latitude/longitude of the marker into a pixel on the map div.  This returns a  object containing x (amount of pixels from the left of the map) and y (amount of pixels from the top of the map).

Final Step #8 - Add Some Spice

To finish up, we will add an event when the map stops panning. We can do this by attaching the "movend" event map object. This way, after panning to the marker you've clicked on we can use jQuery's fadeIn method to add some spice.

JavaScript:
  1. function displayPoint(marker, index){
  2.     $("#message").hide();
  3.    
  4.     var moveEnd = GEvent.addListener(map, "moveend", function(){
  5.         var markerOffset = map.fromLatLngToDivPixel(marker.getLatLng());
  6.         $("#message")
  7.             .fadeIn()
  8.             .css({ top:markerOffset.y, left:markerOffset.x });
  9.    
  10.         GEvent.removeListener(moveEnd);
  11.     });
  12.     map.panTo(marker.getLatLng());
  13. }

There you have it. We've come a long ways by adding our own custom click event, a clickable list and a custom info window. In the next tutorial, I'll show you how to store and retrieve points with a server-side language.

View Final Demo

Resizable WYMEditor with jQuery UI Resizable

Tags: jQuery UI | Written on Jan 14, 2009

I took pyjax's WYMEditor resizable plugin and turned it into something that works for me using jQuery UI 1.6.

To use this, include jQuery, jQuery UI core and resizable, WYMEditor, then this. In that order.

JavaScript:
  1. WYMeditor.editor.prototype.resizable = function(options) {
  2.     var wym = this;
  3.     // Define some default options
  4.     var default_options = {
  5.             start: function(e, ui) {
  6.                 jQuery(wym._box).data("wym_height",
  7.                     jQuery(wym._box).find("iframe").height()
  8.                 );
  9.             },
  10.             stop: function(e, ui) {
  11.                 jQuery(wym._box).data("wym_height",
  12.                     jQuery(wym._box).find("iframe").height()
  13.                 );
  14.             },
  15.             // resize is called by the jQuery resizable plugin whenever the
  16.             // client area was resized.
  17.             resize: function(e, ui) {
  18.                 var diff = ui.size.height - ui.originalSize.height;
  19.                 jQuery(wym._box).find("iframe").height(jQuery(wym._box).data("wym_height") + diff);
  20.                 // If the plugin has horizontal resizing disabled we need to
  21.                 // adjust the "width" attribute of the area css, because the
  22.                 // resizing will set a fixed width (which breaks liquid layout
  23.                 // of the wymeditor area).
  24.                 if( !ui.options.handles['w'] && !ui.options.handles['e'] ) {
  25.                     ui.size.width = "inherit";
  26.                 }
  27.             },
  28.             handles: "s,e,se",
  29.             minHeight: 250,
  30.             maxHeight: 600
  31.         };
  32.  
  33.     // Merge given options with default options. Given options override
  34.     // default ones.
  35.     var final_options = jQuery.extend(default_options, options);
  36.  
  37.     jQuery(wym._box).resizable(final_options);
  38.  
  39. };

From this point, you can use a resizable WYMEditor by adding this to your postInit setting when you create a WYMEditor on the page.

JavaScript:
  1. wymeditor({postInit: function(wym) {
  2.         wym.hovertools(); // other plugins&hellip;
  3.         wym.resizable({handles: &ldquo;s,e&rdquo;,
  4.         maxHeight: 600});
  5.     }
  6. })

Go ahead and view the demo.

5 Tips for Better jQuery Code

Tags: jQuery, Tutorial | Written on Nov 14, 2008

I've been coding using jQuery since shortly after it came out, and well -- I've been using it almost every work day. Here is a few tips that have saved me time.

#1: Use data method instead of storing data inside the DOM.

The mistake I see people making all the time is this:

JavaScript:
  1. $('selector').attr('alt', 'this is the data that I am storing');
  2. // then later getting that data with
  3. $('selector').attr('alt');

Why is this a bad thing?  Because "alt" has absolutely no meaning whatsoever, as well as HTML is not meant to store data.

Instead use the data method in jQuery. It allows you to associated data with an element on the page. 

JavaScript:
  1. $('selector').data('meaningfullname', 'this is the data I am storing');
  2. // then later getting the data with
  3. $('selector').data('meaningfullname');

This allows you to store data with meaningful names and as much data as you want on any element on the page. It is a really amazing utility and something I've come to rely on.

#2: Take advantage of jQuery's built-in custom selectors.

jQuery has a plentiful amount of selectors that are beyond basic CSS selectors, so use them. Some that I use are:

  • :input   example: get all the inputs on the page regardless if they are checkbox, textarea or select list - use :input
  • [attribute=value]   example: find an input with the name, "container" - use input[name='container']
  • :eq(index)  example: get the fourth table on the page - use table:eq(3)

#3: If you are Manipulating the DOM a lot, use livequery.

Note on March 21st, 2009: New in jQuery 1.3, the live method has adopted many of the same events of livequery into the core of jQuery.

Note on November 16th, 2008: If you understand event delegation, use it as an alternative to using livequery for attaching events.

When you add elements to the page a lot, attaching events to them and running functions on them then use Brandon Aaron's livequery plugin. This way you can do things like:

JavaScript:
  1. $('div.edit').livequery('click', function(){
  2. //go into edit mode
  3. });

Then whenever you add a div to the page with class "edit" it will attach that click event. This works for all other events, as well as if you want to run a function on an element right when it is added you can do this:

JavaScript:
  1. $('span.flag').livequery(function(){
  2. // run this function when a span with class "flag" is added to the page
  3. });

#4: Use jQuery form plugin to submit files via Ajax.

If you use Mike Alsup's jQuery form plugin you can use it to submit files via Ajax. It uses a trick with an iframe to submit the data. Just put in an input type file, then use $(form).ajaxSubmit(); and you are good to go.

#5: Use classes as flags.

If you aren't storing data, but need to set a flag on an element use a class. What do I mean by a flag? Well, for instance if you are in "edit mode" of a form you might use the class, "editing".  With jQuery you can add a class with the addClass method and then check later if an element has the class with the hasClass method.

 

jQuery UI Datepicker Themes

Tags: jQuery, JavaScript, My Work | Written on Aug 08, 2008

Note on March 9th, 2010: The datepicker themes are customizable through the jQuery UI Themeroller.

jQuery Tip - Getting Select List Values

Tags: jQuery, Tutorial | Written on Jul 22, 2008

Chris Hartjes asked me a simple question today, but it is worth noting because I have asked the same before, "How do you get the current value from a select list?"

To get the current value is very simple using val().

JavaScript:
  1. $('#selectList').val();

But sometimes you may need to get the selected option's text. This is not as straight forward. First, we get the selected option with :selected selector. Then once we have the option, we can get the text with the function, text().

JavaScript:
  1. $('#selectList :selected').text()

View Demo:

Note on July 23 @9:14AM: HoyaSaxa93 wrote in to ask how to get values from select multiples. I will create the demo and code below. This would be how to set a select multiple to an array called, "foo".

JavaScript:
  1. var foo = [];
  2. $('#multiple :selected').each(function(i, selected){
  3.     foo[i] = $(selected).text();
  4. });

Make a "Scroll To Next Article" Button with jQuery

Tags: jQuery | Written on Jul 18, 2008

If you view my articles page, you will see a, "next" button on the bottom left of the browser window that looks like this:
Click the arrow, and it will take you to the next article on the page.

To create this, first lets setup the CSS.  The key in here is the position: fixed; bottom: 2%; left: 2%; statement.  This pins the arrow to the bottom left of the browser window.  Since position fixed doesn't work in IE6, I just hide the div with the * html hack - I know I'm bad ;)  Since Apple dropped support for IE6, I might as well for the advanced features.

Css:
  1. #next_arrow {
  2.     width: 50px;
  3.     padding-top: 50px;
  4.     background: url(../img/structure/backgrounds/next_arrow.gif) no-repeat top left;
  5.     text-align: center;
  6.     position: fixed;
  7.     bottom: 2%;
  8.     left: 2%;
  9.     z-index: 999;
  10. }
  11. * html #next_arrow {
  12.     display: none;
  13. }
  14. #next_arrow:hover {
  15.     cursor: pointer;
  16. }

Using the scrollTo plugin, this is a fairly straight forward task to make the window scroll to the next article.  Here is the code I am using:

JavaScript:
  1. jQuery(function($){
  2.        
  3.     $('<div id="next_arrow">Next</div>')
  4.         .prependTo("body") //append the Next arrow div to the bottom of the document
  5.         .click(function(){
  6.             scrollTop = $(window).scrollTop();
  7.             $('#content h2').each(function(i, h2){ // loop through article headings
  8.                 h2top = $(h2).offset().top; // get article heading top
  9.                 if (scrollTop < h2top) { // compare if document is below heading
  10.                     $.scrollTo(h2, 800); // scroll to in .8 of a second
  11.                     return false; // exit function
  12.                 }
  13.             });
  14.         });
  15.    
  16. });

If you read my comments in the code, you should be able to know what's going on here. The only thing you have to worry about is changing the selector #content h2 to your article heading selector.

That's it, now you have a skip to next article button!

Published on LearningjQuery.com - Introduction to jQuery UI

Tags: jQuery, jQuery UI | Written on Jul 02, 2008

I published an article on learningjquery.com titled, "Introduction to jQuery UI" - I hope you enjoy the article!

As a member of the jQuery UI team, I felt compelled to write this introduction because I didn't see any tutorials starting from the ground level.  I'm hoping the article will help people get their feet wet with jQuery UI.

Compress Query Strings in JavaScript

Tags: JavaScript | Written on Mar 23, 2008

Since query strings are limited depending on the browser, I wrote this function to grab redundant data variables and consolidate them into comma-separated values. For instance:

JavaScript:
  1. foo=1&foo=2&foo=3&blah=a&blah=b

would turn into...

JavaScript:
  1. foo=1,2,3&blah=a,b

This saves some room in the query string. Of course you need to write a trivial line to parse it on the server side, but this saves you some room for more variables in a query string. Here is my attempt at a JavaScript function that does this: (don't use this, use John's revised function below)

JavaScript:
  1. function compress(query) {
  2.     s = {type:[],value:[]}
  3.     $.each(data.split('&'), function(n){
  4.         parts = this.split('=');
  5.         s.type[n] = parts[0];
  6.         s.value[n] = parts[1];
  7.     });
  8.     var csv = '';
  9.     while(s.type.length > 0) {
  10.         value = s.value.shift();
  11.         type = s.type.shift();
  12.        
  13.         while((pos = $.inArray(type, s.type)) > -1) {
  14.             value += ',' + s.value.shift();
  15.             s.type.shift();
  16.         }  
  17.         csv += type + '=' + value + '&';
  18.     }
  19.     return csv.substring(0, csv.length-1);
  20. }

Sorry, forgot to mention that $.each and $.inArray are jQuery functions.

I messaged John Resig, and he wrote the function that was much smaller, and faster.

JavaScript:
  1. function compress(data){
  2.     var q = {}, ret = "";
  3.     data.replace(/([^=&]+)=([^&]*)/g, function(m, key, value){
  4.         q[key] = (q[key] ? q[key] + "," : "") + value;
  5.     });
  6.     for ( var key in q )
  7.         ret = (ret ? ret + "&" : "") + key + "=" + q[key];
  8.     return ret;
  9. }

UPDATE: John Resig followed up with a post of his own, titled search and don't replace.

How John's Script Works

You may be asking, but how does this work? - let me explain. First, the replace function accepts a regular expression as the first parameter, and the second parameter can be a string or a function.

JavaScript:
  1. replace(/([^=&]+)=([^&]*)/g, function(m, key, value){

As far as I'm concerned, that lines is the magic of the script so I will go furthur.

JavaScript:
  1. /([^=&]+)=([^&]*)/g

This is the regular expression that matches data that starts with ampersand and goes until the end or until the next ampersand. This extracts the data. The /g part loops through each match instead of just one, and does a replace on it.

The function he is passing in has the three parameters set by the regexp. "m" is the match, "key" is the unique identifier, and "value" is the entire string that the regexp is running against.

Next he sets the object based on the key, if it exists already than add a comma between after the current value followed by the next value.

JavaScript:
  1. q[key] = (q[key] ? q[key] + "," : "") + value;

The last part of the code is simply looping through the, "q" object and outputting our new compressed query string. Brilliant.

jQuery Plugin Actions vs Utilities

Tags: jQuery | Written on Jan 24, 2008

Jonathan Snook posted about developing a jQuery plugin. I started a comment and it turned into a post.

One question I've gotten from people moving to jQuery from other libraries is, "How do you extend a native object?" This is something you never do in jQuery, in fact it is against the philosophy of jQuery. One of the goals with jQuery is to be as unobtrusive to the native JavaScript language as possible - that way it plays nicely with other libraries and code. In this case you would want to create a utility plugin instead of an action plugin. Here is an example of using a utility plugin:

JavaScript:
  1. $.formatDate(new Date(), 'm d Y')

This would return a string, not an object for chaining. So now if we want to perform an action with it... such as insert the value into a div we would use:

JavaScript:
  1. $('#myDiv').html($.formatDate(new Date(), 'm d Y'));

I just wanted to point out a common pitfall when making a plugin. Some are utilities, and some are actions. A utility plugin returns a result, but an action plugin is something that returns an object for chaining. Take the method attachDatepicker, for instance:

JavaScript:
  1. $('#myInput').datepicker().val('select a date');

It can be chained because it returns the input with the datepicker attached. You can see more examples of actions vs utilities in the Datepicker Documentation or look at the jQuery Utilities (example of utilities) vs jQuery Manipulation (example of actions).

Ultimate List of Datepickers

Tags: JavaScript, Open Source, Free Tools | Written on Dec 11, 2007

Here is my ultimate list of almost 50 datepickers (popup calendars) each rated each based on useful features, documentation, customization options and internationalization.

If you see anything inaccurate in this table please let me know.

Script Name JavaScript Library Rating (1-5) Price
Vista-like Ajax Calendar script MooTools 1 Free
DateChooser Prototype 1 Free
time/datePicker jQuery 2 Free
Jason's Date Input Calendar Standalone 2 Free
PBBDatePicker MooTools 3 Free
DatePicker using Prototype and Scriptaculous Prototype/Scriptaculous 3 Free
Yahoo! UI Library Calendar YUI 5 Free
Swazz Javascript Calendar Standalone 2 Free
MooTools Date Picker MooTools 3 Free
jQuery UI Datepicker jQuery 5 Free
Clean Calendar Standalone 1 Free
Dynarch jscalendar Standalone 5 Free
jCalendar jQuery 2 Free
jQuery date picker jQuery 4 Free
Unobtrusive Date-Picker Widgit Standalone 3 Free
Calendar Date Select Prototype 3 Free
Rails DatePicker Standalone 1 Free
Lotus Notes Web Datepicker Standalone 2 Free
Jason Moon's Calendar Standalone 3 Free
Intuitive Date Input Selection (Rails) Standalone 3 Free
JS Calendar Standalone 4 Free
Basic Date Picker Lite Standalone 2 Free
Basic Date Picker Standalone 3 $199
ASP.NET AJAX Calendar ASP.NET AJAX 2 Free
CalendarXP Standalone 4 $108
Tigra Calendar Standalone 2 Free
Rich Faces Calendar JBoss RichFaces 3 Free
JavaScript DatePicker Control (BlueShoes) Standalone 3 Free
JavaScript DatePicker (ASP.NET) Standalone 2 Free
Zapatec Date Picker/calendar Standalone 5 LinkBack or $99
Javascript Date Selector (Future Shock) Standalone 2 Free Version or £25.00
Simple Calendar Widget Standalone 3 Free
DateChooser Standalone 3 Free
JavaScript Datepicker made with scriptaculous Scriptaculous 2 Free
JavaScript Date Picker Standalone 2 Free
Corion Javascript Datepicker Standalone 1 Free
Travelethos Datepicker Standalone 2 Free
Javascript Popup Date Picker Standalone 2 Free
Popup date picker Standalone 1 Free
Bookmarklet library calendar Standalone 1 Free
Pear Web Javascript Date Picker Standalone 1 Free
Six Side Date Picker Calendar Standalone 1 Free
SparrowScripts Date Picker Standalone 2 $10
NoGray Calendar Component Standalone 4 Free
Epoch JavaScript Calendar Standalone 3 $69.95
Calendario accesible en javascript Standalone 3 Free
Calendar for Moootools MooTools 4 Free

I have gathered this list over the last year that I have been developing jQuery UI Datepicker with Keith. I never used anyone else's code, but I certainly have gotten feature ideas from other datepickers - as I'm sure others have used features ideas that Keith and I have made.

If you feel I have rated a datepicker unfairly low or missed one from the list, let me know. I have probably overlooked something - there are so many great scripts out there it is hard to be perfectly objective and fair.

Getting jQuery into Big Corporations

Tags: jQuery, JavaScript, Business | Written on Dec 05, 2007

Corporation Buildings

Big Corporation IT

Big corporations are typically resistant to adopting change - and for good reason. They have to work at keeping stable a large amount of applications in one environment. Internal IT teams will usually only adopt something if it doesn't interfere with their jobs or make them more difficult. You must have a really good reason to bring something new in. I understanding that, so how do you get them to approve you using a relatively new library like jQuery?

The Easy Way

The simplest way I've found to get jQuery into projects is use it for doing something very specialized. Creating tabbed panes, graphing data, or maybe some simple animation effects that are normally created in Flash. Either way, from that point on you can use it in the application. But what if you want to build a project from the get-go, from scratch in jQuery?

Big Corporation Project, Built on jQuery

Currently I am building a Google Maps application for one of the biggest banks in the world, HSBC. It is almost done, and I used jQuery to build the application with my manager's approval. As expected, when we handed the code off to HSBC's internal IT team in India they asked why we used jQuery:

"Is there any advantage of using jquery as google is already providing Ajax api for the same purpose. Also please clarify whether there is any licensing issues with jquery. If it is free, then can we use in commercial projects?"

My response:

jQuery is used is for parsing XML and adding behavior to the page elements in a faster and more compatible way. jQuery eliminates the problems that JavaScript has with inconsistent rendering between browsers and jQuery also improves the rendering speed / performance of the application. The code is arguably easier to maintain because it reduces the overall code size of the application because you do not have to code in different ways depending on the browser.

jQuery is dual licensed under the MIT and GPL licenses (http://docs.jquery.com/License), which means that it is 100% free for commercial use.

Note that jQuery is used by: Google, NBC, MSNBC, Bank of America, Amazon, Intel, BBC, Newsweek, AOL and Intuit - just to name a few. Full list: http://docs.jquery.com/Sites_Using_jQuery

A very vibrant and active community surrounds jQuery and it will continue to be well documented and maintained.

My response was very well received - feel free to use that explanation in your own corporation. I have to say though it has been much easier to get accepted since Google uses jQuery. My feeling is that internally to use jQuery you really only need your manager's approval. Once you sell him and your immediate team around you on the idea, you shouldn't have a problem using jQuery for projects. After all, it makes all of our lives easier. jQuery has saved me countless hours and the client's work is going to be better because of it. Thanks, John and the jQuery team.

DateJS JavaScript Library

Tags: JavaScript | Written on Nov 28, 2007

DateJS Logo

A JavaScript date library lands with a, "Kaboom". Built with brilliant colors, I mean strings, or strings, dates and numbers, whatever. The point is that you can pass in human readable text and it will convert it into a JavaScript date object. For example I entered in, "Next February" and it returned February 2008:

Next February Example

This date library can read practically everything in 150 cultures/countries! Okay well maybe not everything. "Your Mom" doesn't work, who figured:

Your Mom Example

I am really pumped to integrate this date library with jQuery UI Datepicker. In fact, the author of datejs came up to me at The Ajax Experience in Boston to tell me about his date library and talked about working together. It has been released, and I am impressed.

jQuery Makes Parsing XML Easy

Tags: jQuery, JavaScript, XML | Written before Dec, 2007

I am building a Google Maps project and jQuery is making my life so much easier when parsing XML.

Regular JavaScript XML Parsing

JavaScript:
  1. var xmlDoc = request.responseXML;
  2. try // Build Markers, if available
  3. {
  4.     var markers = xmlDoc.getElementsByTagName("marker") ;
  5.     for ( var i = 0; i < markers.length ; i++ )
  6.     {
  7.         var point = {
  8.             markers[i].getAttribute("lat")),
  9.             markers[i].getAttribute("lng")
  10.         };
  11.     }
  12. } catch(e) {}

jQuery XML Parsing

JavaScript:
  1. $(request.responseXML).find("marker").each(function() {
  2.     var marker = $(this);
  3.     var point = {
  4.         marker.attr("lat"),
  5.         marker.attr("lng")
  6.     };
  7. });

The jQuery code is so much easier to read and understand. This is a basic example, but imagine when things get complex. After writing a few complex statements, you will realize the jQuery code will still be understandable, where as the JavaScript code will become hard to maintain. Thank you jQuery for making my job easier and more fun.

List of Useful jQuery Plugins

Tags: jQuery, JavaScript | Written before Dec, 2007

I viewed each of the jQuery plugins in the jQuery plugins repository. I couldn't believe how many there were! So I decided to make this master list to weed out any plugins that were either broken or I didn't find any practical application for. You will notice I added, "EXCELLENT" to the plugins that I thought were exceptional.

  • Accessibility Stylesheet and text size switcher.
  • Accordion Accordion interface with a few variations.
  • AlphaNumeric Prevent users from inputing special characters.
  • Ajax File Upload Loading graphic displays while file is uploaded.
  • appendDom Write HTML with JavaScript, great for displaying Ajax results.
  • appendText Converts text into post friendly html.
  • blockUIEXCELLENT Create a message overlay while blocking user interaction on elements or the entire page.
  • BogoFolders View text through a 'file menu' interface.
  • BogoTabs Basic tabbed interface.
  • Bubble Demo highlights selected table rows in groups of tables..
  • Calendar Aids date entry.
  • Checkbox manipulation Select, unselect and toggle checkboxes.
  • ChiliEXCELLENT Syntax highlighting for displaying code on webpages.
  • Choose Component Select data from a table row through a modal window.
  • Click Menu Generates dropdown menus.
  • clueTip Tooltips with many variations.
  • Color Animations Add color animations to div backgrounds.
  • Color Picker Pass in color choices and attach custom events to each color block.
  • columnHover Highlight table rows and columns.
  • columnManager Add, remove and toggle table columns.
  • ContextMenu - Menus that show when you right click specified elements.
  • Confirmer Adds a listener to check if user confirms their action.
  • CycleEXCELLENT Add flash-like image effects to rotating image galleries.
  • date picker Aids date entry.
  • Delicious Read delicious bookmarks from a user to display on a webpage.
  • Dimensions Get accurate window and document attributes across browsers.
  • Equalize Columns Make columns the same height as the longest column.
  • FCKEditor Plugin Adds a rich text editor to a textarea.
  • Field Expand the ability to retrieve and set values in forms.
  • FormEXCELLENT Change HTML forms to submit via Ajax.
  • Gallery Viewer JavaScript image gallery.
  • getUrlParam Function to get url parameters.
  • Google Feed Plugin Display any RSS feed to a webpage.
  • Gradient Adds a gradient to a div without needing an image.
  • Grid Column Sizing Table column draggable resizing.
  • Grid Row Sizing Expand and collapse table rows.
  • hoverIntent Prevents unintended hover events.
  • idTabs Add tabbed interface to a website.
  • Impromptu Create modal windows and messages.
  • jQuery Localisation Applies localisation packages based on the user's language preference.
  • jBox UI dialog widget.
  • jCalendar Aids selecting of dates inline on a page.
  • jCarousel Lite Simple carousel for images and HTML content.
  • jCodeViewer Syntax highlighting for displaying code on webpages.
  • jdMenu Hierarchical Menu Generates dropdown menus.
  • jEditable Live editing of elements on a webpage.
  • jFeed XML feed parser.
  • jPanView Replaces big images with a zoom viewer in HTML.
  • jqDnR Drag'n'Resize elements on a page.
  • jQMaps Interact with Google maps.
  • jqModal Display notices, dialogs, and modal windows in a web browser.
  • Treetable Make a tree view out of an HTML table.
  • Tree ViewEXCELLENT Tree view controls.
  • Suggest Add autocomplete to input fields.
  • YAV Form validation library.
  • jqUploader Provides a status bar for uploading images.
  • jScrollPane Customize your scrollbars.
  • jTagEditor EXCELLENT Turn a textarea into a tag editor.
  • jVariations Create a control panel to manipulate elements on a page.
  • Keyboard Navigation Dynamically determine which element to focus on based on it's position on the screen.
  • labelOver Overlay labels over an input field.
  • LavaLamp Navigation menu with a 'lava' effect.
  • Lazy Load Only load images that are in the current window.
  • Live Query Adds event listeners to elements.
  • Masked Input Add mask to inputs to aid user data entry (phone numbers, etc).
  • Media EXCELLENT Unobtrusive conversion of standard markup into rich media content.
  • Extra selectors for JQuery Add more selectors to jQuery.
  • Mousewheel Mousewheel event handler.
  • Mousehold Event Add repeating event as the user holds down the mouse.
  • Multiple File Upload Select multiple files one by one as it adds to a queue list.
  • newsticker Create a fading news ticker.
  • Password Strength Meter Indicator to show the strength of a users password.
  • PopupWindow Creates an preview popup of destination link.
  • Query String Object Useful for sending URL parameters.
  • Select box manipulation Remove and add options from a select list or dropdown in many ways.
  • selectCombo Tool for making dependant dropdowns with Ajax.
  • Star Rating Generates star rating from input fields
  • Grid Dynamic ajax grid control.
  • slideViewer Image gallery as slides.
  • Spoilers Hide content behind an image until user action is taken.
  • tableHover Row and column highlighting with variations.
  • tableFilter Search box is added to each column header to filter table.
  • tablesorter Client side table sorting.
  • Taconite EXCELLENT Easily make multiple DOM updates using the results of a single AJAX call.
  • Textgrad Add gradients to whole blocks of text.
  • Time Entry Sets an input field up to accept a time value.
  • Tooltip Add tooltips from title page.
  • Validation EXCELLENT Add live validation to forms.
  • WYMeditor EXCELLENT Web-based XHTML WYSIWYM editor.
  • Zoomi Zoomable thumbnails.
  • XSLT Transform XML/XSL from JavaScript.
  • XAP Ajax library.

JavaScript Cross-Browser Repositioning

Tags: JavaScript | Written before Dec, 2007

Calendar Reposition

We added a feature to jQuery calendar that repositions the calendar back into the viewable window. It wasn't working right so I took it into my hands to figure out why.

First, I needed to determine if the calendar is outside the browser window:

Calendar Heights

  • BrowserY - The browser's window position from the top of the document.
  • Browser Height - The height of the browser window.
  • CalendarY - The calendar's position from the top of the document.
  • Calendar Height - The height of the calendar.

Once we get these values, then we can compare the two pairs together to determine if the calendar is outside the window. For instance:

JavaScript:
  1. if ( (BrowserY + BrowserHeight) > (CalendarY + CalendarHeight) )

This would tell us if the calendar is outside the window.

Seems easy? Well, no because of the browser differences. I will show you that in a bit.

So lets get the two easy values. Since the calendar is a div, these simple attributes work accross the tested browsers (IE6+, FF, Opera and Safari):

  • CalendarY = calendarDiv.offsetTop
  • CalendarHeight = calendar.offsetHeight

Getting the browser height and browserY was more challenging. Browsers were getting different heights for the same property! Go figure (sarcasm).

In trying to find out what browsers used to calculate heights, I found a great resource at quirksmode to test browser height and width variables. Thank God for that page, I was able to figure out exactly what the browser was doing with each variable. This JavaScript Window Size and Height tutorial was also helpful.

In testing I found out a few things. To get the browser height, window.innerHeight worked pretty well for most browsers. Then to get the browser height in the rest of the browsers, document.documentElement.clientHeight worked.

I wound up with this function:

JavaScript:
  1. if( typeof( window.innerHeight ) == 'number' ) {
  2.     browserHeight = window.innerHeight;
  3. } else {
  4.     browserHeight = document.documentElement.clientHeight;
  5. }

Likewise, I did the same for the browser Y and came up with this function:

JavaScript:
  1. if ( document.documentElement && (document.documentElement.scrollTop)) {
  2.     browserTopY = document.documentElement.scrollTop;
  3. } else {
  4.     browserTopY = document.body.scrollTop;
  5. }

Using these functions, I tested each browser in a test document and resized the browsers to each about the same size. Here is what the numbers showed up as:

Browser offsetTop offsetHeight browserTopY browserHeight
IE6 354 166 165 751
FireFox 369 170 167 761
IE7 354 166 154 749
Opera 332 162 145 802
Safari 331 160 144 808

There, that worked! The differences you see are mostly because I didn't have the browsers exactly the same size. I tried out my new functions and everything worked perfect! The feature will be added in v2.8 of jQuery Calendar.

Note: For the width these functions are the same. Instead, I used: window.innerWidth, document.documentElement.clientWidth, document.documentElement.scrollLeft and document.body.scrollLeft.

If you liked this article, please subscribe to my RSS feed or let me know by posting a comment.

A Must-Read for Javascript Developers

Tags: JavaScript, Resources | Written before Dec, 2007

Object Oriented Javascript

Objectifying JavaScript is a must-read for Javascript developers. Jonathan Snook does a great job explaining how to use Object Oriented scripting by using the object literal, prototype, and returning an object in the constructor. You may also want to check out Show love to the object literal by Chris Heilmann as well.

It didn't take long for me to grasp the object literal - which you can see by viewing my calendar source file - but it is going to take time before I use more complex object oriented methods in my scripts. Enjoy the reads!

Other Categories