You are here: Home | teaching | Spring 2012

PopUp MP3 Player (New Window)

CMP 342-Internet Programming

Final Project

Project Idea #1: jQuery Research and Application

There are plenty of very cool things you can do with jQuery: games, web applications, rich interactive websites... the list is practically endless. 

Some examples of topics include:

  1. Build a game: [click here for a tutorial of a memory game made with jQuery()]
  2. Build a jQuery lightbox
  3. Build a cool login form
  4. Build an iOS-like website with your own content

Project Idea #2: Create your own jQuery enabled website 

Many of you already created websites for your midterm in HTML and CSS. Seeing as you have already put so much effort into it,  you might like to continue on with this website. If so, you will need to add some functionality to it using jQuery. Of course, there are many ways to do this:

  1. You could write your own custom functions to enrich to the interactive experience.
  2. You could drop in and implement a prebuilt jQuery plugin that you found somewhere online.
  3. You could make use of the many, amazing jQuery UI components to be found online.

A Word on Research

A good portion of this project is the research requirement. I have outlined some examples and suggestions above for what you could do for your project, but the real strength of your project will lay in its exploration of what's available online. The harder you look on your own for something interesting to do, the better grade you will get.

Project Submission: Send me a link!

You may have noticed that all these projects require the creation of HTML and CSS, to be posted on the server. I will not be checking your accounts to see if you have submitted your projects by the due date. In fact: I can't!  You will need to submit the project to me in the form of a URL (or URLs in the case of projrect #3, which includes a wireframe image and and HTML document as deliverables). 

Project Due Date: Thursday, May 24th

This gives you ample time from today (Apil 25) to complete these projects.  Email me with any questions.

Midterm Project

Project Idea #1: Research

Because we're sort of on the road in between old HTML4.01 and the new HTML5 (not to mention JavaScript and JQuery!), I think that an appropriate midterm should really test your research skills. Specifically, I want to challenge you to find new HTML5/CSS3 and/or JavaScript technologies that you would like to learn more about and then provide your own implementation or test of. The best part: you won't be sending me your research reports in some stinky Word document. Rather you will make a simple webpage that displays your research clearly and beautifully.  

Some examples of topics include:

  1. The HMTL <canvas> element. Research how it's used and try to create something interesting with it.
  2. The HTML <video> and <audio> elements: what do you need to know to make it work properly. Try to get some video and audio playing in a web page.
  3. Related to #2, try to build a video website that uses a prebuilt media player plugin like LeanBack Player.
  4. On your own, explore some of the many new CSS3 effects that are available and use them in a small website example.
  5. Or choose your own topic to research: Just make sure to run it by me first!

Project Idea #2: CSS Zen Garden

The CSS Zen Garden is hallowed ground for any web designers. Since 2005, the Zen Garden has been a showcase for what is possible with Cascading Style Sheets. Should you choose to take on this assignment, your job is to create your own stylesheet to accompany the sample HTML page the CSS Zen Garden gives you. Click here for a sample CSS document to help get you started.

Please note that I will be looking for originality in your designs, so you'll get more points for at least trying to create an original design that isn't so nice looking than you will if you just copy another Zen Garden design and change a few values. A completed project will include the HTML, CSS and all realted images/files posted on your server account.

 

 

 

Project Idea #3: Create your own website 

This project is essentially a repeat of the exercise we began in Week 5, except now you are in the driver's seat: you need to design your own wireframe (either in a design program like Photoshop or Illustrator, or by hand), your own HTML and your own CSS file. It's a big project, so keep it simple. A completed project will include the wireframe image (PNG or JPEG please), and the completed HTML, CSS and all related files, all posted in your server account.

 

Project Submission: Send me a link!

You may have noticed that all these projects require the creation of HTML and CSS, to be posted on the server. I will not be checking your accounts to see if you have submitted your projects by the due date. In fact: I can't!  You will need to submit the project to me in the form of a URL (or URLs in the case of projrect #3, which includes a wireframe image and and HTML document as deliverables). 

 

Project Due Date: Thursday, April 5th

This gives you ample time from today (March 21) to complete these projects. If you are going to need extra time, please let me know no later than Wednesday, April 4. Otherwsie, your project will just be late...never a good thing. Email me with any questions.

Course Details

The purpose of this course is to learn the technics needed to hand-coding HTML5 and CSS3, as well as gain familiarity in JavaScript and current trends in JavaScript frameworks and server-side scripting. Topics covered will include: HTML tags, Cascading Style Sheets (CSS) and tricks, JavaScript/JQuery and possibly PHP/MySQL.

Read more:

Class Policies

In life I try to be very lax about rules. In fact, you'll learn in this class that design rules should definitely be broken whenever possible, just to make things interesting. But this does not apply to the class itself, and I have a few rules that you must follow, listed in order of importance:

Read more:

Materials + Resources

“Wait, no software or textbooks?! You straight trippin!” Actually, I’m not tripping.  The cool thing about the Web is that is was designed to run on different types of servers, subsist of nothing more than text documents (and the occasional image or video) and was developed as an open source movement by some pretty smart people who didn’t want HTML to be owned by anyone. This means that all the information, most of the code and the software needed to use the Web, and develop the Web, are on the Web – for free:

Read more:

Week 1

Class 1:Welcome to class. We have a lot to cover, we need to determine who has their own computer, and we probably need to change rooms. But I insist that we enjoy ourselves!

Read more:

Week 2

Class 3:

  • What's URL and why they sometimes suck?
    • scheme://domain:port/path?query_string#fragment_id
    • the scheme we're using it HTTP (HyperText Transfer Protocol)
    • A domain is something like "art.lehman.edu", the port is always 80, which the browsers assumes. This section could also be an IP address of the host machine.
    • after the next section is the filepath
    • the ?query#fragment_idrefers to any variables that are being passed in the URL and a anchor position in the target document
    • Example: I placed some software on the server for you. It can be accessed at the following URL: http://art.lehman.edu/~sadmin/shared/CMP342_software.zip
    • http://art.lehman.edu/~sadmin/shared/CMP342_software.zip
  • More HTML tags
    • <hr />
    • <div>
    • <span>
    • <form> and associated tags
      • <input>
        • Checkbox, Radio button, Drop-down, etc.
      • <textarea>
      • <button>
      • <select>
      • <option>
      • <optgroup>
      • <fieldset>
      • <label>
  • HTML attributes

Read more:

Week 3

Lincoln’s Bday | 02.13.12

  • Homework: think about how dope a president Lincoln was; lament his passing.

Class 5 | 02.15.12

CSS Syntax
SelectorDeclarationDeclaration
p
{text-decoration: underline; padding: 15px;}
property value property value
  • CSS (inline, embedded and external)
  • CSS inheritance
  • Text Styling
  • Classes and ID
  • Over-riding inheritance with dot notation
  • Images in CSS

Week 4

Class 6 - February 21, 2012

In Class Assignment: Make a short bio page and upload it to the server.

Include the following:

    1. Your Name
    2. Where you are from
    3. What you want most out of this class
    4. In list form, your top 5 favorite things

Read more:

Week 5

Class 8 - February 27

  • Building a basic 3-column layout
  • The 3 column layout is a staple of web design. It contains all the basic layout elements you'll find in a typical web page:
  • The header
  • The left and right columns
  • The main column (where all the main content goes)
  • And the footer

Today we'll build the layout piece by piece and then try plugging in other elements, like the navigation tool we built last class. Here are the files from today's class.

Read more:

Week 6

Class 10 - March 5

Read more:

Week 7

Class 12+13 - March 12 + 14

Week 8

Class 14+15 - March 19 + 21

Week 9

Class 16+17 - March 26 + 28

Week 10

Class 18+19 - April 2 + 4

Week 11

Class 20+21 - April 16 + 18

JavaScript! Yay!!!

So, we've finally gotten to the portion of the class where we get to work with JavaScript. JavaScript is a browser or client-side, interpretive, scripting language that has been around since 1995, when it was called LiveScript and it was maintained by the browser company Netscape as a way of adding interactivity to web pages. We're going to be exploring JavaScript via jQuery, a very popular JavaScript framework that is currently blowing up huge. 

framework, in this sense, is a comprehensive library of shortcut methods (a.k.a. functions) and objects that are all built with JavaScript. In other words, developers took many of the functions and classes they had already been using in JavaScript, stuck them all in a single library file, and made them accessible with shortcut syntax that we call jQuery.

Example #1

We'll start with a simple example. Create an HTML doc with the following code and call it index.html:

<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
 <meta name="description" content="">
 <meta name="author" content=""> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="/css/style.css"> <script src="/js/libs/modernizr-2.5.3.min.js"></script>
</head>
<body>
 <p>
 jQuery is not loaded.
 </p>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script>window.jQuery || document.write('<script src="/js/libs/jquery-1.7.2.js"><\/script>')</script> <script src="/js/plugins.js"></script>
<script src="/js/script.js"></script>
</body>
</html>
 

Then create the following CSS file and name it style.css:

body { font: 16px sans-serif; }
p { color: red; border: 1px solid red; padding: 5px; margin: 5px; }
p.tmpFrameworkLoaded { color: green; border: 1px solid green; }

and place the following JavaScript in a js/script.js file:

if ($) {
$(document).ready( function() {
$('p').addClass('tmpFrameworkLoaded');
$('p').text('jQuery successfully loaded and running!');
} );
}
 


Example #1 in action

In the previous code, we created a simple HTML5 document with nothing special in the body: 

jQuery is not loaded.

But if we then load this into a browser, we will see the following:  

jquery not loaded

This shouldn't be all that suprising, since that message appears in the HTML. But the jQuery code we place in script.js should have given us the following: 

jquery loaded

This example is a simple test to see if jQuery has loaded properly. Since we didn't download the jQuery library, it should be no surprise that it doesn't work. Downloading jQuery is easy: simply go to jQuery.com and click the btn downloadLarge button. Or just click the button image I have provided to open up the jQuery library file. However you retrieve it, you'll see that it is contained inside a single JavaScript file. This file will be saved into the js/libs folder:

jquery install

Once you have installed (a.k.a. saved) jQuery, open up your index.html file in a browser again to test it.


Example #1 Explained

So here's what is going on the previous example. The HTML is pretty simple: just a simple <p> tag with a default message in it. In the CSS file we created, this simple style declaration:

p { color: red; border: 1px solid red; padding: 5px; margin: 5px; }

which applies to all <p> tags in the HTML document, including the aforementioned <p> tag, and the message text within it. In the script.js file we have the following code: 

$('p').addClass('tmpFrameworkLoaded');

This code uses the jQuery object selector ($) and, in this case, it is selecting all HTML <p> elements. It is then calling the jQuery addClass function on all <p> tags, which attaches whatever CSS class name the function is passed as a parameter, adding to (and, in this case, overiding) whatever styles the tag had prior. In this case the class is .tmpFrameworkLoaded , the definition of which is defined in our CSS file:

p.tmpFrameworkLoaded { color: green; border: 1px solid green; }

The next line of jQuery uses the jQuery text function to change the text within all <p> and </p> tags to whatever string of characters is passed as a parameter: 

$('p').text('jQuery successfully loaded and running!');
 

If jQuery has indeed be loaded successfully, the $s, the addClass and text functions, and all that other jQuery syntax in our script.js file should work and we will be presented with an HTML document, altered directly in the browser, to look like this:

jquery loaded


How Is This Better Than Good Ole' JavaScript? 

I'm so glad you asked! Well, this is a simple example – realy only a couple of choice lines – that changes a few things around in our DOM (Document Object Model).  As simple as it is, however, if we wanted to do the same thing using standard JavaScript, with no APIs or frameworks, it would look like this:

window.onload = function() {
var $p = document.getElementsByTagName('p')[0];
$p.className = 'tmpFrameworkLoaded';
if($p.innerText) {
$p.innerText = 'jQuery successfully loaded and running!';
} else {
$p.textContent = 'jQuery successfully loaded and running!';
}
};

Yikes! Variable declarations?! getElementsBy TagName?! If/else statements?! That code is a hot mess! However, before jQuery was invented in 2006, this was the only way to do it. 


So What Makes jQuery Better? 

One thing that makes jQuery far easier to implement than standard Javascript is its selectors API. We're already quite familar with the concept of a selector: we've been using them constantly in our CSS files. In the following code snippet, body, a, and .highlight and all selectors:

body{ padding: 0px; margin: 0px; background: url("images/bg.gif") #ccc no-repeat; }
a:link, a:hover{ color: red; }
.highlight{ color: black; background-color: yellow; }

As you can see, selectors are what CSS uses to reference HTML elements in general, and class names and ID tag specifically, with the intent of making them look and feel a certain way. In jQuery the concept is the same, but rather than determine styling, jQuery determines behavior. Take the following HTML code...go on, literally take it, and save it as an HTML document.

Example #2: Controlling Links

<!doctype html><!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]--><!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]--><!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]--><!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--><head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title></title>
    <meta name="description" content="">
    <meta name="author" content="">
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="/css/style.css"> <script src="/js/libs/modernizr-2.5.3.min.js"></script></head><body>
  <ul id=’tmpFavorites’>  <li><a href=’<a href="http://www.google.com">http://www.google.com</a>’>Google</a></li>  <li><a href=’<a href="http://www.facebook.com">http://www.facebook.com</a>’>FaceBook</a></li>  <li><a href=’<a href="http://www.apple.com">http://www.apple.com</a>’>Apple</a></li> <li><a href=’<a href="http://instagr.am/">http://instagr.am/</a>’>Instagram</a></li>  </ul> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script><script>window.jQuery || document.write('<script src="/js/libs/jquery-1.7.2.js"><\/script>')</script><script src="/js/plugins.js"></script><script src="/js/script.js"></script></body></html>

The HTML above contains a simple un ordered list of common links. Nothing special... We're going to add a stylesheet containing the following code:

body { font: 16px sans-serif; }ul { list-stlye: none; margin: 0; padding: 0; }a{ text-decoration: none; }

and finally we're going to place the following jQuery code in our script.js file

//create a new js object called tempExamplevar tmpExample = { 
    //create a member method called ready
    ready : function() {
        // Find and return all links in ul#tmpFavorites, found in the jQuery object ($)...
        //attach a click event to each link 
        $(‘ul#tmpFavorites li a’).click( 
          //pass the click event an anonymous function, with the event object ($e) as a parameter...
          function($e) {
            //use the preventDefault() function to inhibit the default link click action
            $e.preventDefault();
            //and instead open a new browser window (or tab)
            window.open(this.href, ‘CoolLinks’, ‘’); }
            //first parameter: the URL opened in the new window
            //second parameter: the name of the window or tab
            //third paramterL: a string containing window options, which we're leaving blank for now.
        );
    } };/*the above object and function doesn't get called until the entire document, and thus the DOM, has loaded. To make sure of this, we'll pass a reference to the tmpExample's ready function using the built-in jQuery $(document).ready*/$(document).ready(tmpExample.ready);

Example #2: Explained

The jQuery code above is fully commented, but here is a rundown of what it's doing: 1.) The tmpExample object is created, along with a member method entitled ready. Then it just sits there in memory. 2.) As soon as the DOM is fully loaded, jQuery calls the $(document).ready() function we placed inside our script.js file. But notice we also passed it a reference to the tmpExample.ready object method, declared above. 3.) Because we did this, the browser will also execute this code.   

This example demonstrates the essence of the jQuery selector API: after the DOM is fully loaded into the browser's memory, this bit of code:

$(‘ul#tmpFavorites li a’).click()

uses the main jQuery selector ($) and then more specifically selects all links with each list item of the unnumbered list with the #tmpFavorites ID. It looks a lot like CSS, and this is not a coincidence: the jQuery selector API was developed to be familiar to CSS developers…like us!


Example #3: Toggling a Popup Div

So let's try another example using selectors. Using the following HTML code:

<!doctype html><!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]--><!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]--><!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]--><!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <title></title>
      <meta name="description" content="">
      <meta name="author" content="">
      <meta name="viewport" content="width=device-width">
      <link rel="stylesheet" href="/css/style.css"> <script src="/js/libs/modernizr-2.5.3.min.js"></script>
  </head>
  <body id='tmpDialogueExample'>
      <form action='javascript:void(0);' method='post'>
        <p>
          In jQuery, the selector API allows you to select elements from
          the DOM, just like you do in CSS stylesheets.  This simple dialogue
          contains a few selector API examples.
        </p>
        <p>
          <input type='submit' name='tmpDialogueOpen' id='tmpDialogueOpen' value='Open Dialogue' />
        </p>
        <div id='tmpDialogue'>
          <input type='submit' name='tmpDialogueClose' id='tmpDialogueClose' value='Close Dialogue' />
        </div>
      </form> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script> <script>window.jQuery || document.write('<script src="/js/libs/jquery-1.7.2.js"><\/script>')</script>
     <script src="/js/plugins.js"></script> <script src="/js/script.js"></script>
  </body></html>

and the following styles in a css/style.css file:

@charset "UTF-8";
/* CSS Document */body { font: 16px sans-serif; }div#tmpDialogue { display: none; position: absolute; top: 50%; left: 50%; width: 500px; height: 500px; margin: -251px 0 0 -251px; border: 1px solid blue; background: lightblue; }body#tmpDialogueExample div.tmpDialogueOn { display: block; }input#tmpDialogueClose { position: absolute; bottom: 5px; right: 5px; width: 100px; }

In our scripts.js file, place the following javascript:

var tmpExample = {
  ready : function() {
    $('input#tmpDialogueOpen').click(
      function($e) {
        $e.preventDefault();
        $('div#tmpDialogue').addClass('tmpDialogueOn');
      }
    );
    $('input#tmpDialogueClose').click(
      function($e) {
        $e.preventDefault();
        $('div#tmpDialogue').removeClass('tmpDialogueOn');
      }
    );
  }};$(document).ready(tmpExample.ready);

Example 3: Explained

On the surface, the above example works similar to the previous example: the jQuery ready function is called after the document loads. Chained to this ready function is our custom tmpExample.ready function. This function does two things:

    $('input#tmpDialogueOpen').click(
      function($e) {
        $e.preventDefault();
        $('div#tmpDialogue').addClass('tmpDialogueOn');
      }

1.)It attaches a jQuery click() event function to the first submit button in the HTML, labeled with the #tmpDialogueOpen ID attribute. This click function takes as its parameter an anonymous function. The event object ($e) is passed to it so that we can prevent the default action of this event:
$e.preventDefault();
. Finally, we add a class to the tmpDialogue div:
$('div#tmpDialogue').addClass('tmpDialogueOn');

This new class, you may notice, simply unhides the div#tmpDialogue, set to display:none; in the css.

    $('input#tmpDialogueClose').click(
      function($e) {
        $e.preventDefault();
        $('div#tmpDialogue').removeClass('tmpDialogueOn');
      }
    );


2.)tmpExample.ready also attaches a second click() event, as seen in the code just above. This event does something similar to the previous click() event, but in this case it is attached the submit button labelled #tmpDialogueClose, and it removes the .tmpDialogueOn class from the #tmpDialogue div. As #tmpDialogue's native style is to display none, this line of code essentially re-hides it.

The result is something like a kind of toggling popup window:

Screen Shot 2012-04-14 at 5.07.09 PM


Example #4: Refining Selectors

One more example, this time a little more advanced. [Click here] to see it in action. You can find the code [here].

Example #4: Explained

The HMTL is fairly straightforward: Two unnumbered lists and a section of links below it. Upon closer inspection, you will notice that nearly every tag is classed and/or IDed. For example: <ul id='tmpPlants'> and <li class='tmpVegetables' id='tmpOnion'>Onion</li>. This is done to achieve granular selection in jQuery (described below).

The CSS is also straightforward, with the only interesting style being this one:

.tmpExample {
          border: 1px solid rgb(200, 200, 200);
          background: #cbe5f8;
}

This is essentially a class that provides a light blue highlight to an element.

The jQuery code, inside the script.js file, uses the same surface logic as the previous examples: creating an object with a ready function, then calling that object.function when the document is fully loaded:

   var tmpExample = {
    ready : function() {
    (…)
}
$(document).ready(tmpExample.ready);

But it's the stuff after the tmpExample.ready function definition that is most interesting. tmpExample.ready is actually just a one line function:

      $('a').click(tmpExample.findElements);

It attaches a click() event to each link in the HTML, with the tmpExample.findElements function call passed as the click event parameter. This ensures that tmpExample.findElements function, defined below tmpExample.ready, is called whenever a link is clicked.

The Switch Statement

findElements() is actually pretty simply too, it just uses a code construct we haven't seen before: the switch statement. Switch statements are pretty universal throughout the programming world. They can be thought of as switchboards: the statement checks the given input value and, based on this value, fires off a specific set of instructions. In our example, the switch statement is looking for the ID of whatever link called the findElements() function:

 switch (this.id)

Then the statement defines eventualities for every link ID case we're interested in with case statements. Every case statement ends with the break; command. This exits the case, thereby exiting the swtich statment as well. Some examples of the case statements in our code: 
 case 'tmpSiblings':
 {
   $('li#tmpCarrot').siblings().addClass('tmpExample');
   break;
 }

–and–
 case 'tmpVegetables':
 {
  $('li#tmpOrange').prevAll('li.tmpVegetables').addClass('tmpExample'); 
  break;
 }

These cases simply add the .tmpExample class to specific list items, but notice how jQuery is going about selecting them: siblings(), prevAll(), children(), parents(), etc. These methods allow you to search and filter the selection results you obtain. More on this below.


A Rundown of the jQuery Filters

The previous example is really designed to show you all of the jQuery Selector API's filtering functions in a single script. Let's examine each on a case by case basis.

find(): The find() method lets you search for elements within a selection you’ve already made. Below, we select all ul tags, then find() all li tags within them so we can add the .tmpExample class to each one:

  case 'tmpFind':
 {
 // If the id of "this" <input> element contains "Find",
 // Do the find() example.
   $('ul').find('li').addClass('tmpExample');
   break;
 }

siblings(): The siblings() method lets you select all elements on the same hierarchical level as your main selection, in this case all other list items in the same list as <li id="tmpCarrot">:

 case 'tmpSiblings':
 {
   $('li#tmpCarrot').siblings().addClass('tmpExample');
   break;
 }

next(): The next() method lets you select the next sibling element in the HTML document:

 case 'tmpNext':
 {
   $('li#tmpBroccoli').next().addClass('tmpExample');
 break;
 }

prev(): Like next(), the prev() method lets you select the preceding sibling element in the HTML document:

 case 'tmpPrev':
 {
   $('li#tmpBroccoli').prev().addClass('tmpExample');
   break;
 }

nextAll() and prevAll(): these two methods work similarly to next() and prev(), except they select all sibling elements after and before your main selection respectively:

 case 'tmpNextAll':
 {
   $('li#tmpBroccoli').nextAll().addClass('tmpExample');
 break;
 }
 case 'tmpPrevAll':
 {
   $('li#tmpOrange').prevAll().addClass('tmpExample');
   break;
 }

This instance of the prevAll() method has been passed a parameter, which further narrows its searching power to only select those previous siblings of #tmpOrange that happened to have the .tmpVegetables class:

 case 'tmpVegetables':
 {
   $('li#tmpOrange').prevAll('li.tmpVegetables').addClass('tmpExample');
   break;
 }

parents(): not surprisingly, parents() selects all parents of a selected element. In this example, however, parents() is being passed a selector for the tmpSelection div, further narrowing it to just that parent:

 case 'tmpParents':
 {
   $('li#tmpCarrot').parents('div#tmpSelection').addClass('tmpExample');
   break;
 }

parent(): Note that parent() is different than parents() in that it only selects the most immediate parent of the select element:

 case 'tmpParent':
 {
   $('li').parent('ul').addClass('tmpExample');
 break;
 }

children(): this method can be used to select specific children elements of a selected element, in this case all h4 tags in the tmpList div:

 case 'tmpChildren':
 {
   $('div.tmpList').children('h4').addClass('tmpExample');
   break;
 }

not(): The not() method allows to essentially deselect specific elements. In the case below, we want to select all list items, except those with the .tmpVegetables class:

 case 'tmpNot':
 {
   $('ul li').not('li.tmpVegetables').addClass('tmpExample');
   break;
 }

slice(): this method takes a beginning index value and ending index value as its parameters, allowing you to select a range of elements within a selection.

 case 'tmpSlice':
 {
   $('ul#tmpAnimals li').slice(1, 4).addClass('tmpExample');
   break;
 }

add(): The add() method allows to make a selection and then add elements to it, useful for constructing complicated selections of elements. Below we make a standard jQuery selection of all list items in the tmpAnimals unnumbered list, then we add the tmpBroccoli and tmpPepper list items.

 case 'tmpAdd':
 {
   $('ul#tmpAnimals li').add('li#tmpBroccoli, li#tmpPepper').addClass('tmpExample');
   break;
 }

eq(): this method allows you to reduce a selection based on its index number. In the following example, we select all list items, which returns an array of all list items in the DOM. The then eq() method is chained to our selection and passed an index number of 10. Because indexes always start at 0, eq(10) selects the 11th list item in the DOM, i.e. "Buffalo":

 case 'tmpEq':
 {
   $('ul li').eq(10).addClass('tmpExample');
   break;
 }


Events in jQuery

Not surpisingly, event handlers in any programming language exist to deal with events: mouse clicks, mouse moves, drags, drops. In short, user interaction. Creating event handlers in oldschool JavaScript used to be really difficult, but jQuery makes it much easier. There are a few ways to deal with events in jQuery, but the bind() method is by far the easiest. 

The bind() method accepts two parameters: 

  1. the event name, such as ‘ready’, ‘mouseover’, ‘mouseout’, or ‘click’  
  2. a function call or anonymous function declaration (i.e. the entire body of the function is passed in as one lone parameter) 

Try the following example:

Example 5: the jQuery bind() method

[click here to see example 5 in action] [click here to download the Example 05 files]

 The bind() method simply attaches some other function or method to a particular event. In the case below, we have a very basic HTML5 document:

<!doctype html>

<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->

<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->

<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->

<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->

<head>

 <meta charset="utf-8">

 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>

 <meta name="description" content="">

 <meta name="author" content=""> <meta name="viewport" content="width=device-width"> 

 <link rel="stylesheet" href="/css/style.css"> 

 <script src="/js/libs/modernizr-2.5.3.min.js"></script>

</head>

  <body>

    <div></div>

    <div></div>

    <div></div>

    <div></div>

    <div></div>

    <div></div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>

<script>window.jQuery || document.write('<script src="/js/libs/jquery-1.7.2.min.js"><\/script>')</script>

<script src="/js/plugins.js"></script>

<script src="/js/script.js"></script>

</body>

</html>

And some simple CSS:


div {

    border: 1px solid rgb(200, 200, 200);

    width: 100px;

    height: 100px;

    margin: 5px;

    float: left; 

}

div.tmpExampleOver {

    background: #5092c5;

}

div.tmpExampleOn {

    background: #165b91;

}

 

and the following  jQuery code in our script.js file:


$(document).bind(

  'ready',

  function() {

    $('div').bind(

      'mouseover',

      function() {

        $(this).addClass('tmpExampleOver');

      }

    );

 
    $('div').bind(

      'mouseout',

      function() {

        $(this).removeClass('tmpExampleOver');

      }

    );

 
    $('div').bind(

      'click',

      function() {

        if ($(this).hasClass('tmpExampleOn')) {

          $(this).removeClass('tmpExampleOn');

        } else {

          $(this).addClass('tmpExampleOn');

        }

      }

    );

    

  }

);

 

The resulting index.html file, rendered in a browser, should look something like this:

example 05

[click screenshot to see the actual page in a browser]

As you can see, the six divs change background color as you hover the mouse over them (mouseover events), change back to their original background color when the mouse moves out (mouseout events) and toggles a dark blue background color when you click on any of them(click event). Let’s see how it works, shall we? 

Example 5: Explained

The HTML and CSS is fairly straightforward: six anonymous divs in the HTML, styled as six squares by the CSS. The CSS also has two additional classes: they add background colors for the mouseover state and the clicked state, respectively:

 

div.tmpExampleOver {

    background: #5092c5;

}

div.tmpExampleOn {

    background: #165b91;

}

 As per usual, the jQuery is where the interaction happens. The first thing that occurs is a use of the bind() method to attach further functions to the entire document when the ready event is detected:


$(document).bind( 'ready', ...)

The bind() method accepts two parameters: 1.)the event name, in this case ready and 2.) a function call or anonymous function declaration. We’ll be passing an entire anonymous function as one big parameter. The function we’re passing is really just three simple subroutines:

1.)To each div tag we’re binding a mouseover event function that adds the tmpExampleOver upon detecting any mouse over event:


    $('div').bind(

      'mouseover',

      function() {

        $(this).addClass('tmpExampleOver');

      }

    );

2.)Then to each div we’ll bind an event that essentially undoes what we just did when the mouse leaves the div area: 


    $('div').bind(

      'mouseout',

      function() {

        $(this).removeClass('tmpExampleOver');

      }

    );

 

And finally we’ll bind a click event to each div that adds tmpExampleOn class if it isn’t attached, and removes the class if it is attached: 


    $('div').bind(

      'click',

      function() {

        if ($(this).hasClass('tmpExampleOn')) {

          $(this).removeClass('tmpExampleOn');

        } else {

          $(this).addClass('tmpExampleOn');

        }

      }

    );


Advanced Event Handling 

As I said before, there a plenty of interesting ways to handle events in jQuery. The following example covers four of them:

Example 6: Advanced Event Handling Examples

[click here to play with this example in a browser] [click here to get the example code]

The HTML and CSS for this example is very similar to that of example 05 above, i.e. some anonymous divs styled to be 100px by 100px squares. The code found in the script.js file provides four different examples of the innovative and simple ways to deal with events. Each of these functions is declared when the document has loaded via this line of jQuery:


$(document).ready( function(){...});

Let’s examine each example. The first uses the standard bind() method we used in the previous example, but notice that it combines, or chains, three bind() methods together like so: $('div.tmpBind').bind(...).bind(...).bind(...); You may also notice that we’re using the find() method to find all children div tags within the div.tmpBind.

Example 06.01:


  function() {

    //Example 06.01: handling events with the bind() method:

    $('div.tmpBind').bind(

      'mouseover',

      function() {

        $(this).find('div').addClass('tmpExampleOver');

      }

    ).bind(

      'mouseout',

      function() {

        $(this).find('div').removeClass('tmpExampleOver');

      }

    ).bind(

      'click',

      function() {

        if ($(this).find('div').hasClass('tmpExampleOn')) {

          $(this).find('div').removeClass('tmpExampleOn');

        } else {

          $(this).find('div').addClass('tmpExampleOn');

        }

      }

    );

    //end of Example 01

 

Rather than bind(), Example 06.02 uses jQuery’s mouseover(), mouseout(), and click() methods directly to add event functions, chaining them together like so:

$('div.tmpIndividual').mouseover(...).mouseout(...).click();

 

Example 06.02:

 


/*Example 06.02: handling events with built-in jQuery event methods like mouseover(), mouseout(), and click():*/

    $('div.tmpIndividual').mouseover(

      function() {

        $(this).find('div').addClass('tmpExampleOver');

      }

    ).mouseout(

      function() {

        $(this).find('div').removeClass('tmpExampleOver');

      }

    ).click(

      function() {

        if ($(this).find('div').hasClass('tmpExampleOn')) {

          $(this).find('div').removeClass('tmpExampleOn');

        } else {

          $(this).find('div').addClass('tmpExampleOn');

        }

      }

    );

    //end of Example 02

 

Example 06.03 uses the very convenient jQuery hover() and toggle() methods.

The hover() methods takes two functions as parameters, following this pattern:

$(‘the_element’).hover(the function to be called when the mouse is moved over the_element,  the function to be called when the mouse is moved away from the_element);

 

The toggle() method is similar, except it deals with clicks rather than mouseover events:

$(‘the_element’).toggle(the function to be called when the mouse is clicked on the_element,  the function to be called when the mouse is clicked a again on the_element);

 

Example 06.03:


    /*Example 06.03: handling events with the jQuery's hover() and toggle methods:*/

    $('div.tmpPattern').hover(

      function() {

        $(this).find('div').addClass('tmpExampleOver');

      },

      function() {

        $(this).find('div').removeClass('tmpExampleOver');

      }

    ).toggle(

      function() {

        $(this).find('div').addClass('tmpExampleOn');

      },

      function() {

        $(this).find('div').removeClass('tmpExampleOn');

      }

    );

 

And finally Example 06.04, which uses JavaScript methods focus() and blur() to deal with what happens when a browser gives focus (or removes it) from different user interface elements. In this case, we have a simple <textarea> tag. Users can ‘focus’ on things like textareas or input boxes by using the tab key on their keyboard, or by clicking on them directly. ‘blur’ refers to what happens when the user tabs away or clicks somewhere else. Using the focus() and blur() methods, we can define event functions for precisely this type of user interaction:

Example 06.04:


    /*Example 06.04: handling focus and blur events with the focus and blur methods:*/

    $('div.tmpTrigger textarea').focus(

      function($e) {

        $(this).addClass('tmpFocused');

      }

    ).blur(

      function() {

        $(this).removeClass('tmpFocused');

      }

    );

 
    $('div.tmpTrigger textarea').focus();

  }

 

Above we are essentially adding the class .tmpFocused when a user focuses on the textarea in div#tmpTrigger, then removing that class when focus is removed, or blurred, as it is called. Also notice the last line in the function: 


$('div.tmpTrigger textarea').focus();

This forces browser focus on our textarea. Just calling the focus() method on a focussable element like <textarea> will give it immediate focus in the browser. (Note that with HTML5, this can be done without any JavaScript at all, as it is a built-in property of the new HTML5 form elements. However, it’s always nice to have fallbacks.) 

Week 12

Class 22 - April 23


Putting our newfound jQuery knowledge to some good use

Ok, so we've learned a few important jQuery fundementals, and some interesting tricks. Now it is time to apply this knowledge to a project we've already worked on: The Farm at Richville site we recently converted to HTML5. Let's put a working slideshow into the site using a custom jQuery plugin we're going to write. 

[click here to take a look at the Farm at Richville site with working slideshow]

[click here to download the exercise files]

[click here to download the tutorial PDF

 


 Class 23 - April 25

jQuery Animations


We already used prebuilt jQuery animtaion methods in the last exercise whehter we were aware of it or not. The  .fadeIn() and .fadeOut() methods we used for our slideshow are simple jQuery functions that increase or reduce respectively the CSS opacity property of an element. As we can see, these prebuilt methods are very useful.  But jQuery provides a very useful method for the custom animation of certain CSS properties. A proper implementation of the .animate() method will have the following structure:

$("#some_element").animate( {some_property: value; some_other_property: value;}[, duration] [, easing] [, call back function] );

You can pass any CSS properties with numeric values and animate() will all chnage them together from the selected element's original properties to the new values you choose.  [Click here] to download the following simple examples:

Example 01: Simple animation

This demo simply calls two .animate() methods: 

  1.  $("#clickhere").click(function() {
  2.    $("#animate1").animate({
  3.     height: "20px",
  4.     width: "10px",
  5.    }, 1000);
  6.    $("#animate2").animate({
  7.     height: "50px",
  8.     width: "500px"
  9.    }, 1000);
  10.  });

Example 02: Animating Multiple CSS Properties

[See the demo]. Any CSS property with a numeric value can be animated with jQuery. Font-size, border-width, margin, padding, top, left, bottom, and right can be animated simply by passing the desired end point to jQuery.animate(). These properties can be expressed either as %, px, or in ems:

  1.     $("#clickhere").click(function() {
  2.         $("#animate1").animate({
  3.             height: "20px",
  4.             width: "50%",
  5.             padding: "5em",
  6.             marginLeft: "40px",
  7.             borderWidth: "5px"
  8.         }, 1000);
  9.     });

 


Example 03: Animation Callback Functions

[See the demo]. The .animate() method can also accept a callback function, to be called when the animation has finished:

  1.     $("#clickhere").click(function() {
  2.         $("#animate1").animate({
  3.             height: "12px",
  4.             width: "50px"
  5.         }, 1000, function() {
  6.             alert('done!');
  7.         });
  8.     });

 


Example 04: Animation Chaining

[See the demo]. Like any other jQuery method, .animate() can be chained to other animations. Unless otherwise specified, each subsequent call to .animate() will fire only after the previous call in completed.  

  1.    $("#clickhere").click(function() {
  2.     $("#animate1").animate({
  3.      width: "200px"
  4.     }, 600).animate({
  5.      height: "200px"
  6.     }, 600).animate({
  7.      width: "120px",
  8.      height: "120px"
  9.     }, 600).animate({
  10.      marginLeft: "100px",
  11.      borderWidth: "5px"
  12.     }, 600);
  13.    });

Example 05: Easing

[See the demo]. Assuming you include the jQueryUI library into your script, you make use of awesome animation easing properties.

  1.    $("#clickhere").click(function() {
  2.     $("#animate1").animate({
  3.      width: "200px"
  4.     }, 1000, "easeOutSine");
  5.     $("#animate2").animate({
  6.      width: "200px"
  7.     }, 2000, "easeOutExpo");
  8.     $("#animate3").animate({
  9.      width: "200px"
  10.     }, 3000, "easeOutBounce");
  11.    });

Putting Animation to Good Use

I have updated the Farm at Richville site to include a simple popup window when someone clicks on any of the in-content buttons. This is preferable to having them click to another page as it keeps them in the same space.

[Take a look at the demo] [Download the Exercise Files]


Homework: try the .animate() for yourself

Now that you have seen the .animate() function in action, try adding a more involved animation (or series of animations) for the yellow menu button in the Farm at Richville exercise files above. Additionally, you'll notice that, to close the jQuery popup, a user must click outside the rounded rectangle area. It may confuse people if there are no indications that this is how you close the popup. Therefore, attach a close button to the popup div that animates the popup out to the main website.

Here are the two things you need to do:

  1. Add a creative animation of your won the third (yellow) content button in the exercise files above.
  2.  Add a close button to the popup div so that a user knows how to close it down. 

Post the entire site in your own Sites folder and send me a link. This homework is due Wednesday, May 2nd. Contact me with any questions.  

Week 13

Class 24 - April 30


 

The jQuery Plugins API

We already dealt with plugins last week when we created the slideshow for our Farm at Richville site. In that exercise, we placed the plugin in our script.js document. From now on, we will place any custom plugins into a plugins.jsfile to keep them separate and manageable. 

Plugins are simply reusable, modular collections of objects and custom methods that work together and that anyone can write, share and add to their sites. Because of the vast network of developes who write plugins, there are now entire plugin libraries in existence for adding really interesting functionality to your code. In fact, many of the methods we will be using in the jQuery UI library are plugins.


 

Just a Note: the .data() method

Today's lesson makes use of a previously unintroduced jQuery method called .data(). Like any method, .data() works differently depending on the parameters passed to it, but its real advantage lies in the ability to attach data values to elements in the DOM, thereby avoiding global variables, circular references and memory leaks. Here are examples of how it is used, from the jQuery API reference website:

Usage 1.) $('body').data('some_value', 98);

Attaches an arbitrary value name 'foo' and its value '98'.

Usage 2.) $('body').data('bar', { myType: 'test', count: 40 });

Attaches an arbitrary value name and a group, or 'map' of values.

Usage 3.) $('body').data('some_value');

Retrieves the value for 'foo'. When the above snippet evalutes, the return result will be 98.

Usage 4.$('body').data();

 The above snippet will simply return all data key/value, i.e. {some_value: 98, bar: { myType: 'test', count: 40 }}

Here's a quick example of how it works:

  1. <!DOCTYPE html>
  2.   <style>
  3.   div { color:blue; }
  4.   span { color:red; }
  5.   </style>
  6.   [removed][removed]
  7. </head>
  8.   <div>
  9.     The values stored were
  10.     <span></span>
  11.     and
  12.     <span></span>
  13.   </div>
  14. [removed]
  15. $("div").data("test", { first: 16, last: "pizza!" });
  16. $("span:first").text($("div").data("test").first);
  17. $("span:last").text($("div").data("test").last);
  18. [removed]
  19.  
  20. </body>
  21. </html>

 That's Awesome...Now How Do I Make a Plugin?

The overall requirements for creating a plugin are rather simple. Essentially, every plugin extends the jQuery object with new children objects and methods. Therefore, to properly create a jQuery plugin, one must use the $.fn.extend() method. Let's build a simple plugin that adds a context-specific menu when a user right clicks somewhere in the browser window.

[Click here for a demo of this plugin] [Click here for the exercise files]

We'll start with some simple HTML. I'll just show the important bits in the body:

  1.     <div>
  2.       <p>
  3.         jQuery plugins give you the ability to extend jQuery's functionality,
  4.         quickly and seamlessly.  In this example you see how to make a context
  5.         menu plugin, that handles everything you need to make a context menu
  6.         widget in self-contained jQuery plugin.
  7.       </p>
  8.       <ul class="contextMenu">
  9.         <li>This is  a context menu item.</li>
  10.       </ul>
  11.      
  12.       <ul>
  13.        <li>This is just a regular list</li>
  14.       </ul>
  15.     </div>

Just some basic text and a &lt;ul> tag with a "contextMenu" class. Then some basic CSS:

  1. @charset "UTF-8";
  2. /* CSS Document */
  3. body {
  4.     font: 12px "Lucida Grande", Arial, sans-serif;
  5.     background: #fff;
  6.     color: rgb(50, 50, 50);
  7. }
  8. body,
  9. html {
  10.     width: 100%;
  11.     height: 100%;
  12.     margin: 0;
  13.     padding: 0;
  14. }
  15. div {
  16.     position: absolute;
  17.     width: 100%;
  18.     height: 100%;
  19. }
  20. {
  21.     padding: 5px;    
  22. }
  23. ul.tmpContextMenu {
  24.     list-style: none;
  25.     margin: 0;
  26.     padding: 5px;
  27.     border: 1px solid rgb(200, 200, 200);
  28.     position: absolute;
  29.     top: 0;
  30.     left: 0;
  31.     background: lightblue;
  32.     width: 200px;
  33.     min-height: 200px;
  34.     display: none;
  35. }
  36. li {
  37.     padding: 3px;
  38. }

And finally we need to place this code in our plugins.js document:

  1. // JavaScript Document
  2. $.fn.extend({
  3.   ContextMenu: function() {  
  4.     this.each(
  5.       function() {
  6.         $(this).addClass('tmpContextMenu');
  7.  
  8.         $(this).hover(
  9.           function() {
  10.             $.data(this, 'ContextMenu', true);
  11.           },
  12.           function() {
  13.             $.data(this, 'ContextMenu', false);
  14.           }    
  15.         );
  16.  
  17.         // Only attach the following event once.
  18.         if (!$.data(document, 'MouseDown')) {
  19.           $.data(document, 'MouseDown', true);
  20.           $(document).mousedown(
  21.             function() {
  22.               $('.tmpContextMenu').each(
  23.                 function() {
  24.                   if (!$.data(this, 'ContextMenu')) {
  25.                     $(this).hide();  
  26.                   }
  27.                 }
  28.               );
  29.             }
  30.           );
  31.         }
  32.  
  33.         $(this).parent().bind(
  34.           'contextmenu',
  35.           function($e) {
  36.             $e.preventDefault();
  37.  
  38.             // FYI: The contextmenu doesn't work in Opera.
  39.             var $menu = $(this).find('.tmpContextMenu');
  40.  
  41.             $menu.show();
  42.  
  43.             // The following bit gets the dimensions of the viewport
  44.             var $vpx, $vpy;
  45.          
  46.             if (self.innerHeight) {
  47.               // all except Explorer
  48.               $vpx = self.innerWidth;
  49.               $vpy = self.innerHeight;
  50.             } else if (document.documentElement && document.documentElement.clientHeight) {
  51.               // Explorer 6 Strict Mode
  52.               $vpx = document.documentElement.clientWidth;
  53.               $vpy = document.documentElement.clientHeight;
  54.             } else if (document.body) {
  55.               // other Explorers
  56.               $vpx = document.body.clientWidth;
  57.               $vpy = document.body.clientHeight;
  58.             }
  59.          
  60.             // Reset offset values to their defaults
  61.             $menu.css({
  62.               top:    'auto',
  63.               right:  'auto',
  64.               bottom: 'auto',
  65.               left:   'auto'
  66.             });
  67.  
  68.             /**
  69.             * If the height or width of the context menu is greater than the amount
  70.             * of pixels from the point of click to the right or bottom edge of the
  71.             * viewport adjust the offset accordingly
  72.             */
  73.             if ($menu.outerHeight() > ($vpy - $e.pageY)) {
  74.               $menu.css('bottom', ($vpy - $e.pageY) + 'px');
  75.             } else {
  76.               $menu.css('top', $e.pageY + 'px');
  77.             }
  78.  
  79.             if ($menu.outerWidth() > ($vpx - $e.pageX)) {
  80.               $menu.css('right',  ($vpx - $e.pageX) + 'px');
  81.             } else {
  82.               $menu.css('left', $e.pageX + 'px');
  83.             }
  84.           }
  85.         );
  86.       }
  87.     );
  88.  
  89.     return $(this);
  90.   },
  91.   MyPlugin: {
  92.     Ready: function() {
  93.       $('ul.contextMenu').ContextMenu();
  94.     }
  95.   }
  96. });
  97.  
  98. $(document).ready(
  99.   function() {
  100.     $.fn.MyPlugin.Ready();
  101.   }
  102. );
Phew! Tha was long. Let's unpack it all, shall we?  The first line of code is important because it calls the jQuery extending function $.fn.extend(...), establishing that what comes next is a plugin. When this plugin is instantiated later on in the code, it run through the remaining code: a method ContextMenu() is declared and an initial function is immediately called:
  1. $.fn.extend({
  2.   ContextMenu: function() {  
  3.     this.each(
  4.       function() {

Using the jQuery .each() method, this function iterates over all the items in the this keyword. In this case, this is referencing whatever HTML elements were selected upon calling ContextMenu() later on in the plugin. It could be multiple items, or just one.

The next lines add a .tmpContextMenu class each element in this and sets an arbitrary data value to determine whether the mouse is hovering over the selected elements or not:

  1.         $(this).addClass('tmpContextMenu');
  2.  
  3.         $(this).hover(
  4.           function() {
  5.             $.data(this, 'ContextMenu', true);
  6.           },
  7.           function() {
  8.             $.data(this, 'ContextMenu', false);
  9.           }    
  10.         );

$.data() is a temporary method for storing a value that takes three arguments: 1.) a reference to the element the value is associated with, 2.) a name for the value and 3.) the value itself. We won't be creating a boolean value and setting it with .hover(). A global variable would only allow single context menu. By using the temporary $.data() method, we associate individual true/false values with any number of contex menus.

The next few lines are sandwiched between an if statement:

  1.         // Only attach the following event once.
  2.         if (!$.data(document, 'MouseDown')) {
  3.           $.data(document, 'MouseDown', true);
  4.           $(document).mousedown(
  5.             function() {
  6.               $('.tmpContextMenu').each(
  7.                 function() {
  8.                   if (!$.data(this, 'ContextMenu')) {
  9.                     $(this).hide();  
  10.                   }
  11.                 }
  12.               );
  13.             }
  14.           );
  15.         }

 

The initial if statement tests to see if a 'MouseDown' flag has been attached to he document via $.data(). The $.data(document, 'MouseDown') conditional will evaluate as false because 'MouseDown' hasn't been created yet, but the not operator (!) in front of it will make it true, thus the initial run through this if statement will execute the code inside. Once we're in the if statement, we immediately create and set 'document MouseDown' to true via the $.data()  method, ensuring this if statement will hereafter break without running. This is all to ensure that the mousedown() event handler within is only attached to the document once.

The mousedown event $(document).mousedown() fires during a mouse click, iterates over each element with the .tmpContextMenu class, checks to see if the mouse is over it, and if it isn't, hides the element. This will hide any open context menus with a single mouse click. The next bit of code is important too and is related to the right-click functionality of our context menu:

  1.         $(this).parent().bind(
  2.           'contextmenu',
  3.           function($e) {
  4.             $e.preventDefault();

The'contextmenu'  is JavaScript event keyword, in the same category as mousedown or click, and it fires whenever the user right clicks. By binding this event hanlder to the parent of whatever element(s) we're attaching the ContextMenu plugin to, and preventing the default action, we're essentially hijacking the right-click. Argh!!

We then create a variable called $menu and pass it a reference to any element with the .tmpContextMenu attached to it (i.e. each element we attached our ContextMenu() method to):

  1.             var $menu = $(this).find('.tmpContextMenu');
  2.  
  3.             $menu.show();

The rest of the code merely deals with positioning the context menu popup inside the viewport of the browser window. This isn't all that exciting, but becomes important if a user clicks near the edge of the window. Try doing this and you'll see what I mean. Finally, we end our ContextMenu() function by returning the jQuery object, with the this keyword selected.

  1.     return $(this);

In other words, we're returning the object that ContextMenu() was called upon to begin with. This comes in handy if a developer wants to pass or chain the $('some_element').ContextMenu() with additional jQuery code.  Before ending this plugin, we to create the main plugin object, whose responsibility it is to call plugin methods like ContextMenu:

  1.   MyPlugin: {
  2.     Ready: function() {
  3.       $('ul.contextMenu').ContextMenu();
  4.     }
  5.   }
 

MyPlugin: {...} creates the object, and Ready: function(){...} is an object method that initializes the whole thing. All Ready does is attach our ContextMenu() method to every &lt;ul> tag with the .contextMenu class associated with it to distinguish them from regular unnumbered lists in the document. This MyPlugin: {...} code is really more of a constructor, however. It just sits there, like an idiot, waiting to be called. So let's call it!

We'll invoke the MyPlugin object (which, in turn, calls  ContextMenu(method) by calling $.fn.MyPlugin.Ready() method directly when the document finishes loading :

  1. $(document).ready(
  2.   function() {
  3.     $.fn.MyPlugin.Ready();
  4.   }
  5. );

And that is all you need to know to create your own plugins! Oh wait, there's actually one more guideline: always write your plugins to account for one or more items to be passed in, and to always return the jQuery object, whenever you can. 


Class 25 - May 2

Introducing the jQuery UI Library: What Is It?

The jQuery UI library is a set of special extensions to the main jQuery library we've been using. These reusable components are essentially plugins that allow us as developers to quickly impart high-level user interactions to our web sites and web applications.   

How Do I Get It?

Do keep in mind that the jQuery UI Library is separate from the jQuery core, which means we'll need to download a separate library. You can download a custom implementation here: jqueryui.com—download

Example 01: Simulating a Finder Window with The .draggable() Plugin

[Click Here for the demo] [Click Here for the exercise files]

For this example we'll be using the .draggable() plugin, which allows the user to drag around DOM elements, changing their positions. We'll be using this HTML:

<!doctype html>
&lt;!--[if lt IE 7]> &lt;html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> &lt;![endif]-->
&lt;!--[if IE 7]> &lt;html class="no-js lt-ie9 lt-ie8" lang="en"> &lt;![endif]-->
&lt;!--[if IE 8]> &lt;html class="no-js lt-ie9" lang="en"> &lt;![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> &lt;!--&lt;![endif]-->
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
 <meta name="description" content="">
 <meta name="author" content=""> <meta name="viewport" content="width=device-width"> 
 <link rel="stylesheet" href="css/style.css"> 
 <script src="/js/libs/modernizr-2.5.3.min.js"></script>
</head>
  <body>
    <div id="hFinderFiles">
      <div class="hFinderDirectory" title="/Applications">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>Applications</span>
        </div>
      </div>
      <div class="hFinderDirectory" title="/Library">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>Library</span>
        </div>
      </div>
      <div class="hFinderDirectory" title="/Network">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>Network</span>
        </div>
      </div>
      <div class="hFinderDirectory" title="/Sites">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>Sites</span>
        </div>
      </div>
      <div class="hFinderDirectory" title="/System">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>System</span>
        </div>
      </div>
      <div class="hFinderDirectory" title="/Users">
        <div class="hFinderIcon"><div></div></div>
        <div class="hFinderDirectoryName">
          <span>Users</span>
        </div>
      </div>
    </div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script>window.jQuery || document.write('&lt;script src="/js/libs/jquery-1.7.2.min.js">&lt;\/script>')</script>
<script type='text/javascript' src='js/libs/jquery-ui-1.8.20.custom.min.js'></script>
<script src="js/script.js"></script>
</body>
</html>


Here is our CSS:

  1. @charset "UTF-8";
  2. /* CSS Document */
  3. html,
  4. body {
  5.     width: 100%;
  6.     height: 100%;    
  7. }
  8. body {
  9.     font: 12px "Lucida Grande", Arial, sans-serif;
  10.     background: rgb(189, 189, 189)
  11.       url('../images/finder/Bottom.png') repeat-x bottom;
  12.     color: rgb(50, 50, 50);
  13.     margin: 0;
  14.     padding: 0;
  15. }
  16. div#hFinderFiles {
  17.     border-bottom: 1px solid rgb(64, 64, 64);
  18.     background: #fff;
  19.     position: absolute;
  20.     top: 0;
  21.     right: 0;
  22.     bottom: 23px;
  23.     left: 0;
  24.     overflow: auto;
  25. }
  26. div.hFinderDirectory {
  27.     float: left;
  28.     width: 150px;
  29.     height: 100px;
  30.     overflow: hidden;
  31. }
  32. div.hFinderIcon {
  33.     height: 56px;
  34.     width: 54px;
  35.     margin: 10px auto 3px auto;
  36. }
  37. div.hFinderIcon div {
  38.     background: url('../images/finder/Folder 48x48.png')
  39.       no-repeat center;
  40.     width: 48px;
  41.     height: 48px;
  42.     margin: auto;
  43. }
  44. div.hFinderIconSelected {
  45.     background-color: rgb(196, 196, 196);
  46.     -moz-border-radius: 5px;
  47.     -webkit-border-radius: 5px;  
  48. }
  49. div.hFinderDirectoryName {
  50.     text-align: center;
  51. }
  52. span.hFinderDirectoryNameSelected {
  53.     background: rgb(56, 117, 215);
  54.     -moz-border-radius: 8px;
  55.     -webkit-border-radius: 8px;
  56.     color: white;
  57.     padding: 1px 7px;
  58. }

And finally, the jQuery code:
  1. $(document).ready(
  2.   function() {
  3.     $('div.hFinderDirectory').mousedown(
  4.       function() {
  5.         $('div.hFinderDirectory').not(this)
  6.           .find('div.hFinderIcon')
  7.             .removeClass('hFinderIconSelected');
  8.  
  9.         $('div.hFinderDirectory').not(this)
  10.           .find('div.hFinderDirectoryName span')
  11.             .removeClass('hFinderDirectoryNameSelected');
  12.  
  13.         $(this).find('div.hFinderIcon')
  14.           .addClass('hFinderIconSelected');
  15.  
  16.         $(this).find('div.hFinderDirectoryName span')
  17.           .addClass('hFinderDirectoryNameSelected');
  18.       }
  19.     ).draggable();
  20.   }
  21. );
Most of the code above deals with highlighting through CSS classes the folder icon that was clicked on. The UI library dosn't come into play until the very end (line 19), where we chain the .draggable() plugin to our elements. The .draggable() plugin has many options, however, to influence how the drag actually behaves. Two of these options – helper and opacity – can be used to further simulate an actual Finder window:

Example 02: Ghosting

You may notice that when you drag a real folder in a Finder window, it shows you a slightly transparent clone of the original folder to provide you with visual feedback. To mimic this, we'll using the helper and opacity options in .draggable():  in your original script.js file for the previous example, simply add the options to the call to .draggable(). The updated .draggable() call will look like the following:

  1.  .draggable({
  2.   helper: 'clone',
  3.   opacity: 0.5
  4.  });
 This is cool and all, but you may notice that we can no longer 'drop' the items. Instead, we're just dragging a clone that disappears when we release it. Booo! Let's try one more example.

Example 03: Implementing Drag and Drop

In addition to the .draggable() plugin, there is also a rather robust .droppable() plugin. This plugin will make any element you chain it to a so-called 'drop zone". In addition to draggable elements, we can also make our Finder icons drop zones using this plugin.

[Click Here for the demo] [Click Here for the exercise files

The HTML is the same as above, so we can use the same example. The CSS has a few additions, specifically a .hFinderDirectoryDrop class that we'll be using later:

  1. html,
  2. body {
  3.     width: 100%;
  4.     height: 100%;    
  5. }
  6. body {
  7.     font: 12px "Lucida Grande", Arial, sans-serif;
  8.     background: rgb(189, 189, 189)
  9.       url('../images/finder/Bottom.png') repeat-x bottom;
  10.     color: rgb(50, 50, 50);
  11.     margin: 0;
  12.     padding: 0;
  13. }
  14. div#hFinderFiles {
  15.     border-bottom: 1px solid rgb(64, 64, 64);
  16.     background: #fff;
  17.     position: absolute;
  18.     top: 0;
  19.     right: 0;
  20.     bottom: 23px;
  21.     left: 0;
  22.     overflow: auto;
  23. }
  24. div.hFinderDirectory {
  25.     float: left;
  26.     width: 150px;
  27.     height: 100px;
  28.     overflow: hidden;
  29.     -khtml-user-drag: element;
  30. }
  31. div.hFinderDirectory:-khtml-drag {
  32.     opacity: 0.5;    
  33. }
  34. div.hFinderIcon {
  35.     height: 56px;
  36.     width: 54px;
  37.     margin: 10px auto 3px auto;
  38. }
  39. div.hFinderIcon div {
  40.     background: url('../images/finder/Folder 48x48.png')
  41.       no-repeat center;
  42.     width: 48px;
  43.     height: 48px;
  44.     margin: auto;
  45. }
  46. div.hFinderIconSelected,
  47. div.hFinderDirectoryDrop div.hFinderIcon {
  48.     background-color: rgb(196, 196, 196);
  49.     -moz-border-radius: 5px;
  50.     -webkit-border-radius: 5px;  
  51. }
  52. div.hFinderDirectoryDrop div.hFinderIcon div {
  53.     background-image:
  54.       url('../images/finder/Open Folder 48x48.png');
  55. }
  56. div.hFinderDirectoryName {
  57.     text-align: center;
  58. }
  59. span.hFinderDirectoryNameSelected,
  60. div.hFinderDirectoryDrop span {
  61.     background: rgb(56, 117, 215);
  62.     -moz-border-radius: 8px;
  63.     -webkit-border-radius: 8px;
  64.     color: white;
  65.     padding: 1px 7px;
  66. }

As for the jQuery: you'll want to place this updated code in the script.js folder: 

  1. $(document).ready(
  2.   function() {
  3.     $('div.hFinderDirectory').mousedown(
  4.       function() {
  5.         $('div.hFinderDirectory').not(this)
  6.           .find('div.hFinderIcon')
  7.             .removeClass('hFinderIconSelected');
  8.  
  9.         $('div.hFinderDirectory').not(this)
  10.           .find('div.hFinderDirectoryName span')
  11.             .removeClass('hFinderDirectoryNameSelected');
  12.  
  13.         $(this).find('div.hFinderIcon')
  14.           .addClass('hFinderIconSelected');
  15.  
  16.         $(this).find('div.hFinderDirectoryName span')
  17.           .addClass('hFinderDirectoryNameSelected');
  18.       }
  19.     );
  20.  
  21.       $('div.hFinderDirectory').draggable({
  22.         helper: 'clone',
  23.         opacity: 0.5
  24.       })
  25.       .droppable({
  26.         accept: 'div.hFinderDirectory',
  27.         hoverClass: 'hFinderDirectoryDrop',
  28.         over: function(e, ui) {
  29.           if ($.browser.msie && $.browser.version == 6.0) {
  30.             $(this).find('div.hFinderIcon div').css({
  31.               background: 'none',
  32.               filter:
  33.                 "progid:DXImageTransform.Microsoft.AlphaImageLoader" +
  34.                 "(src='../images/finder/Open Folder 48x48.png', sizingMethod='crop')"
  35.             });
  36.           }
  37.         },
  38.         drop: function(e, ui) {
  39.           var $path = ui.draggable.attr('title');
  40.           // Do something with the path
  41.     alert($path);
  42.           // Remove the element that was dropped.
  43.           ui.draggable.remove();
  44.         }
  45.       });
  46.      }
  47. );
 The only thing different from our previous examples can be found in the above code at line 25. Let's take a look:
  1.       .droppable({
  2.         accept: 'div.hFinderDirectory',
  3.         hoverClass: 'hFinderDirectoryDrop',
As before, we need to call to the droppable plugin, chaining it to the selection of div.hFinderDirectory made up at the top. This will make every div.hFinderDirectory draggable and droppable. We're also passing an object containing options for this instance of the droppable plugin: accept is set to div.hFinderDirectory, hence it will only accept drops of elements like itself;  the hoverClass option will set the item being dropped on to whatever CSS class you pass it, in this case that .hFinderDirectoryDrop class mentioned in the CSS above (although you'll notice that, in this example, .hFinderDirectoryDrop is passed the same stylrs as our original selected class div.hFinderIconSelected).
 
 There are two other options present in this options object we're passing to droppable above: over and drop. Here is the over option in its entireity:
  1.         over: function(e, ui) {
  2.           if ($.browser.msie && $.browser.version == 6.0) {
  3.             $(this).find('div.hFinderIcon div').css({
  4.               background: 'none',
  5.               filter:
  6.                 "progid:DXImageTransform.Microsoft.AlphaImageLoader" +
  7.                 "(src='../images/finder/Open Folder 48x48.png', sizingMethod='crop')"
  8.             });
  9.           }
  10.         },
You may surmise that over is unnecessary because we passed the droppable element a hoverClass, which will take care of how it looks when something is – you know – hovered over it. But over is not traditionally used for how something looks. Rather, it is in the over option that you would pass functions, thereby determining the behavior of the code when you hover over the droppable element. Here you could put all kinds of interesting things, like an animation, a sound playing, or anything you can dream up. 
In the case of over above, however, we're not putting anything cool. In fact, it's decidedly uncool:  $.browser.msie && $.browser.version == 6.0  determines whether our browser is Internet Explorer AND is version 6.0.  Then, using the css() method, we're setting the currently hovered-over element with custom styles. This takes care of a little problem in IE6 where it doesn't handle PNG image transparency. Instead of relying on the hoverClass option (which adds a PNG background image to the .droppable element, something all modern browsers can handle), we're adding some special CSS to the .droppable that uses MicroSoft's proprietary image loader. Boring...
 
And finally the drop option, which handles what happens when an element is dropped on our droppable element: 
  1.         drop: function(e, ui) {
  2.           var $path = ui.draggable.attr('title');
  3.           // Do something with the path
  4.           alert($path);  // <-- something...
  5.           // Remove the element that was dropped.
  6.           ui.draggable.remove();
  7.         }
  8.       });
In the code above, we're essentially creating an event handler function (with an event object 'e' and a reference to what is being dragged sand dropped, 'ui'. Upon dropping and releasing the element, we grab the element's  'title  attribute ( var $path = ui.draggable.attr('title') ) and then put it on screen as an alert. Finally, to mimic the behavior of a real Finder folder dropped onto another, we simply .remove() the dragged element from the DOM. Ideally we would do something a little more useful, but this is merely a demonstration. 
 
 
 
 
 

Week 14

Class 26 - May 7



Let's first run through the homework involving the .animation() API and a close button the Farm at Richville popup.


Continuing the jQuery UI: .sortable()

 The .sortable() plugin is another example of what makes jQuery so useful: it takes a job that would normally be a nightmare in normal JavaScript and simplifies it, in this case to just a single line. Not even a line, really - just 11 characters. Let's try an example:

Example 01: A Movable Feast

[Click here for the demo]  [Click here for exercise files]

As you can see from the above demo, it behaves very similar to what we did last week with the draggable and droppable plugins. After all, it's letting us drag and drop elements in the browser window. But this example does us one better: it keeps the elements sorted. Let's look at the code. A word of caution, though: it's rediculously easy.

The HTML is very straightforward. Here I have created a list of Ernest Hemingway novels that the user can reorder based on preference. Full disclosure: I haven't read any of these. I started A Movable Feast like 7 years ago, but I'll be honest: it was kind of boring. As far as the HTML is concerned, however, it's very sparse...like Hemingway's prose:

 HTML

  1. <!doctype html>
  2. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  3. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  4. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  5. <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  6.  <meta charset="utf-8">
  7.  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
  8.  <meta name="description" content="">
  9.  <meta name="author" content=""> <meta name="viewport" content="width=device-width">
  10.  <link rel="stylesheet" href="css/style.css">
  11. <script src="/js/libs/modernizr-2.5.3.min.js"></script>
  12. </head>
  13.   <body>
  14.   <h3>A Movable Feast: List Your Favorite Hemingway Novels!</h3>
  15.   <ul>
  16.    <li>Old Man and the Sea</li>
  17.  <li>The Sun Also Rises</li>
  18.     <li>For Whom the Bell Tolls</li>
  19.     <li>A Movable Feast</li>
  20.     <li>A Farewell to Arms</li>
  21.   </ul>    
  22. <script src="/js/libs/jquery-1.7.2.min.js"></script>
  23. <script src="/js/libs/jquery-ui-1.8.19.custom.min.js"></script>
  24. <script src="/js/plugins.js"></script>
  25. <script src="/js/script.js"></script>
  26. </body>
  27. </html>

Note that we are including both the jQuery core AND the jQuery UI library above, just after the body content. The CSS is also pretty simple, just some styling to make it look presentable

CSS

  1. @charset "UTF-8";
  2. /* CSS Document */
  3.  
  4. body{
  5.  font: "Lucida Sans Unicode", "Lucida Grande", Arial, sans-serif;
  6.  background: #FFF;
  7.  color: rgb(50, 50, 50);
  8.  margin: 0;
  9.  padding: 0;
  10. }
  11.  
  12. h4 {
  13.  margin: 5px;
  14. }
  15.  
  16. ul {
  17.  list-style: none;
  18.  width: 250px;
  19.  margin: 5px;
  20.  padding: 0px;
  21. }
  22.  
  23. li {
  24.  background: grey;
  25.  color: white;
  26.  padding: 3px;
  27.  width: 250px;
  28.  border: 1px solid #CCC;
  29. }

And finally, the jQuery, which we will place in the js/script.js fle:

jQuery

  1. $(document).ready(
  2.  function() {
  3.   $('ul').sortable();    
  4.  }
  5. );

 

Pretty simple, I know. All we're doing here upon $(document).ready() is calling an anonymous function that selects all <ul> tags and attaches the .sortable() plugin to each of them. This plugin essentially makes all children <li> tags draggable, but it also makes siblings reorder when a fellow list item is droped above or below them.


Example 02:

In this example we'll make our sortable list a little bit more interactive. To make it behave a little bit more like an actual application, we'll use essentially the same logic we used in the previous draggable/droppable examples.

[Click here for the demo] [Click here for the exercise files]

We have the HTML below:

HTML

  1. <!doctype html>
  2. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  3. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  4. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  5. <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  6.  <meta charset="utf-8">
  7.  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
  8.  <meta name="description" content="">
  9.  <meta name="author" content=""> <meta name="viewport" content="width=device-width">
  10.  <link rel="stylesheet" href="css/style.css">
  11.   <!--[if lt IE 7]>
  12.    <link type='text/css' href='css/IE_style.css' rel='stylesheet' />
  13.  <![endif]-->
  14. <script src="/js/libs/modernizr-2.5.3.min.js"></script>
  15. </head>
  16.   <body>
  17.       <ul id='finderCategoryFiles'>
  18.       <li class="finderCategoryFile">
  19.         <div class="finderCategoryFileIcon"></div>
  20.         <h5 class="finderCategoryFileTitle">
  21.           The Sun Also Rises
  22.         </h5>
  23.         <div class="finderCategoryFilePath">
  24.             Read About It!
  25.           </a>
  26.         </div>
  27.       </li>
  28.       <li class="finderCategoryFile">
  29.         <div class="finderCategoryFileIcon"></div>
  30.         <h5 class="finderCategoryFileTitle">
  31.           A Farewell to Arms
  32.         </h5>
  33.         <div class="finderCategoryFilePath">
  34.             Read About It!
  35.           </a>
  36.         </div>
  37.       </li>
  38.       <li class="finderCategoryFile">
  39.         <div class="finderCategoryFileIcon"></div>
  40.         <h5 class="finderCategoryFileTitle">
  41.          For Whom the Bell Tolls
  42.         </h5>
  43.         <div class="finderCategoryFilePath">
  44.             Read About It!
  45.           </a>
  46.         </div>
  47.       </li>
  48.       <li class="finderCategoryFile">
  49.         <div class="finderCategoryFileIcon"></div>
  50.         <h5 class="finderCategoryFileTitle">
  51.           The Old Man and the Sea
  52.         </h5>
  53.         <div class="finderCategoryFilePath">
  54.             Read About It!
  55.           </a>
  56.         </div>
  57.       </li>
  58.       <li class="finderCategoryFile">
  59.         <div class="finderCategoryFileIcon"></div>
  60.         <h5 class="finderCategoryFileTitle">
  61.           A Moveable Feast
  62.         </h5>
  63.         <div class="finderCategoryFilePath">
  64.             Read About It!
  65.           </a>
  66.         </div>
  67.       </li>
  68.     </ul>
  69.  
  70. <script src="/js/libs/jquery-1.7.2.min.js"></script> 
  71. <script src="/js/libs/jquery-ui-1.8.19.custom.min.js"></script>
  72. <script src="/js/plugins.js"></script>
  73. <script src="/js/script.js"></script>
  74. </body>
  75. </html>

You can see that each item in our list has a main finderCategoryFile class, an empty finderCategoryFileIcon div that will hold an icon image, a title, and a link to more info on Wikipedia. This is similar to how we created Finder folder icons in the previous draggable/droppable examples. The CSS is also similar to the previous Finder-emulating examples:

CSS

  1. @charset "UTF-8";
  2. /* CSS Document */
  3.  
  4. html,
  5. body {
  6.     width: 100%;
  7.     height: 100%;    
  8. }
  9. body {
  10.     font: 12px "Lucida Grande", Arial, sans-serif;
  11.     background: rgb(189, 189, 189)
  12.       url('../img/Bottom.png') repeat-x bottom;
  13.     color: rgb(50, 50, 50);
  14.     margin: 0;
  15.     padding: 0;
  16. }
  17. ul#finderCategoryFiles {
  18.     position: absolute;
  19.     top: 0;
  20.     bottom: 0px;
  21.     left: 0;
  22.     width: 300px;
  23.     border-bottom: 1px solid rgb(64, 64, 64);
  24.     border-right: 1px solid rgb(64, 64, 64);
  25.     background: #fff;
  26.     list-style: none;
  27.     margin: 0;
  28.     padding: 0;
  29. }
  30. li.finderCategoryFile {
  31.     clear: both;
  32.     padding: 5px 5px 10px 5px;
  33.     min-height: 102px;
  34.     width: 290px;
  35. }
  36. li.finderCategoryFile h5 {
  37.     font: normal 12px "Lucida Grande", Arial, sans-serif;
  38.     margin: 0;
  39. }
  40. div.finderCategoryFileIcon {
  41.     float: left;
  42.     width: 80px;
  43.     height: 102px;
  44.     background:url(../img/hemingway_book.png) no-repeat;
  45. }
  46. h5.finderCategoryFileTitle,
  47. div.finderCategoryFilePath {
  48.     padding-left: 55px;
  49. }
  50. li.finderCategoryFileSelected {
  51.     background: rgb(51, 153, 204);
  52.     color: white;
  53. }
  54. li.finderCategoryFileSelected a {
  55.     color: lightblue;
  56. }

The jQuery follows almost identical logic to the previous Finder example:

jQuery

  1. $(document).ready(
  2.   function() {
  3.     $('li.finderCategoryFile').mousedown(
  4.       function() {
  5.         $('li.finderCategoryFile').not(this)
  6.           .removeClass('finderCategoryFileSelected');
  7.  
  8.         $(this).addClass('finderCategoryFileSelected');
  9.       }
  10.     );
  11.  
  12.     $('ul#finderCategoryFiles').sortable();
  13.   }
  14. );

First we pass an anonymous function that is called when the document is fully loaded into the DOM. Chained to this function is a .mousedown() method, which 1.) takes care of removing the selected class .finderCategoryFileSelected from any previously selected element. It then adds this class to whatever element was clicked on. With this logic taken care of, we then make sortable the unnumbered list with the id  #finderCategoryFiles.


Example 03: Customizing the .sortable() event

Just as we did with .draggable() and .droppable(), .sortable() can be passed an object literal as a parameter. This object serves as nothing more than a wrapper for plugin-specific option keywords and generic, custom functions.

One of the options we'll pass .sortable() is placeholder. In this case, 'placeholder' refers to the space, appearing when an element from a sortable group is dragged, to indicate where the dragged element was grabbed from, or where it will drop into if let go. By default (as in the previous example), this space is white. Kinda boring, so we'll pass placehoder a custom CSS class to make it look a little more interesting.

The second option we'll pass .sortable() is helper. We saw this same option with the .draggable() plugin and that's because helper in jQuery refers to helping the user with feedback. The helper option specifies the element that is displayed during a drag and drop scenario. By default, it's the original element the user dragged on, as in the example above, but there may be instances where you want it to be a different element. helper takes two arguements or paramters: an event object (a referrence to the drag event), and a reference to the element being dragged for resorting.

Now that we know what they are, let's use them. We can use essentially the same code that we used above in Example 02, with a couple temporary classes added to the CSS:

Additional CSS (add to style.css from Example 02) 

  1. li.tmpPlaceholder {
  2.     background: rgb(51, 153, 204);
  3.     height: 102px;
  4. }
  5. li.tmpHelper {
  6.     border: 4px solid rgb(204, 183, 0);
  7. }

 And an object literal passed to our .sortable() call like so:

  1.     $('ul#finderCategoryFiles').sortable({
  2.       placeholder: 'tmpPlaceholder',
  3.       helper: function(e, element) {
  4.       return $(element).clone().addClass('tmpHelper');
  5.       }
  6.     });

 As you can see above, placeholder simply accepts any CSS class as its value. helper, however, has been assigned a function as its value. This function is very simple: all it does is return a clone of the object selected for resorting, with a tmpHelper class added to it. This is only necessary because helper doesn't accept CSS classes as values.


Example 04: Connecting Sortable Lists

Now it gets interesting. The .sortable() plugin also accepts an option that will allow it to interact with other lists. Let's try an example.

[Click here for the demo] [Click here for the exercise files]

The HTML is almost identical to the previously example, with one exception: an additional unnumbered list at the very end:

HTML

  1. <!doctype html>
  2. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  3. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  4. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  5. <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  6.  <meta charset="utf-8">
  7.  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
  8.  <meta name="description" content="">
  9.  <meta name="author" content=""> <meta name="viewport" content="width=device-width">
  10.  <link rel="stylesheet" href="css/style.css">
  11.   <!--[if lt IE 7]>
  12.    <link type='text/css' href='css/IE_style.css' rel='stylesheet' />
  13.  <![endif]-->
  14.  [removed][removed]
  15. </head>
  16.   <body>
  17.       <ul id='finderCategoryFiles'>
  18.       <li class="finderCategoryFile">
  19.         <div class="finderCategoryFileIcon"></div>
  20.         <h5 class="finderCategoryFileTitle">
  21.           The Sun Also Rises
  22.         </h5>
  23.         <div class="finderCategoryFilePath">
  24.             Read About It!
  25.           </a>
  26.         </div>
  27.       </li>
  28.       <li class="finderCategoryFile">
  29.         <div class="finderCategoryFileIcon"></div>
  30.         <h5 class="finderCategoryFileTitle">
  31.           A Farewell to Arms
  32.         </h5>
  33.         <div class="finderCategoryFilePath">
  34.             Read About It!
  35.           </a>
  36.         </div>
  37.       </li>
  38.       <li class="finderCategoryFile">
  39.         <div class="finderCategoryFileIcon"></div>
  40.         <h5 class="finderCategoryFileTitle">
  41.          For Whom the Bell Tolls
  42.         </h5>
  43.         <div class="finderCategoryFilePath">
  44.             Read About It!
  45.           </a>
  46.         </div>
  47.       </li>
  48.       <li class="finderCategoryFile">
  49.         <div class="finderCategoryFileIcon"></div>
  50.         <h5 class="finderCategoryFileTitle">
  51.           The Old Man and the Sea
  52.         </h5>
  53.         <div class="finderCategoryFilePath">
  54.             Read About It!
  55.           </a>
  56.         </div>
  57.       </li>
  58.       <li class="finderCategoryFile">
  59.         <div class="finderCategoryFileIcon"></div>
  60.         <h5 class="finderCategoryFileTitle">
  61.           A Moveable Feast
  62.         </h5>
  63.         <div class="finderCategoryFilePath">
  64.             Read About It!
  65.           </a>
  66.         </div>
  67.       </li>
  68.     </ul>
  69.    
  70.  <!-- Another list we will connect the previous list with in the jQuery -->
  71.     <ul id='finderOtherCategoryFiles'>
  72.     </ul>
  73.  
  74. <script src="/js/libs/jquery-1.7.2.min.js"></script>
  75. <script src="/js/libs/jquery-ui-1.8.19.custom.min.js"></script>
  76. <script src="/js/plugins.js"></script>
  77. <script src="/js/script.js"></script>
  78. </body>
  79. </html>

 The CSS is also very similar to the previous example:

CSS

  1. html,
  2. body {
  3.     width: 100%;
  4.     height: 100%;    
  5. }
  6. body {
  7.     font: normal 12px "Lucida Grande", Arial, sans-serif;
  8.     background: rgb(189, 189, 189)
  9.       url('../img/Bottom.png') repeat-x bottom;
  10.     color: rgb(50, 50, 50);
  11.     margin: 0;
  12.     padding: 0;
  13. }
  14. div#finderCategoryFileWrapper {
  15.     position: absolute;
  16.     top: 0;
  17.     right: 0;
  18.     bottom: 23px;
  19.     left: 0;
  20. }
  21. ul#finderCategoryFiles,
  22. ul#finderOtherCategoryFiles {
  23.     float: left;
  24.     height: 100%;
  25.     width: 210px;
  26.     border-bottom: 1px solid rgb(64, 64, 64);
  27.     border-right: 1px solid rgb(64, 64, 64);
  28.     background: #fff;
  29.     list-style: none;
  30.     margin: 0;
  31.     padding: 0;
  32. }
  33. li.finderCategoryFile {
  34.     clear: both;
  35.     padding: 5px 5px 10px 5px;
  36.     min-height: 102px;
  37.     width: 200px;
  38. }
  39. li.finderCategoryFile h5 {
  40.     font: normal 12px "Lucida Grande", Arial, sans-serif;
  41.     margin: 0;
  42. }
  43. div.finderCategoryFileIcon {
  44.     float: left;
  45.     width: 80px;
  46.     height: 102px;
  47.     background: url('../img/hemingway_book.png') no-repeat;
  48. }
  49. h5.finderCategoryFileTitle,
  50. div.finderCategoryFilePath {
  51.     padding-left: 55px;
  52. }
  53. li.finderCategoryFileSelected {
  54.     background: rgb(24, 67, 243);
  55.  color: white;
  56. }
  57. li.finderCategoryFileSelected a {
  58.     color: lightblue;
  59. }
  60. .finderCategoryFilePlaceholder {
  61.     background: rgb(230, 230, 230);
  62.     height: 120px;
  63. }

And Finally the jQuery, which adds a few options to the .sortable() call:

jQuery

  1. $(document).ready(
  2.   function() {
  3.     var $selectedFile;
  4.  
  5.     $('li.finderCategoryFile').mousedown(
  6.       function() {
  7.         if ($selectedFile && $selectedFile.length) {
  8.           $selectedFile.removeClass('finderCategoryFileSelected');
  9.         }
  10.  
  11.         $selectedFile = $(this);        
  12.         $selectedFile.addClass('finderCategoryFileSelected');
  13.       }
  14.     );
  15.  
  16.     $('ul#finderCategoryFiles').sortable({
  17.       connectWith : [
  18.         'ul#finderOtherCategoryFiles'
  19.       ],
  20.       placeholder: 'finderCategoryFilePlaceholder',
  21.       opacity: 0.8,
  22.       cursor: 'move'
  23.     });
  24.    
  25.     $('ul#finderOtherCategoryFiles').sortable({
  26.       connectWith : [
  27.         'ul#finderCategoryFiles'
  28.       ],
  29.       placeholder: 'finderCategoryFilePlaceholder',
  30.       opacity: 0.8,
  31.       cursor: 'move'
  32.     });
  33.   }
  34. );

The function call we're passing $(document).ready() does something slightly different in the first few lines to deselect any previously selected list item and then select the selected item. First, a global variable ($selectedFile) is declared. Then a .mousedown() event is added to our list item elements. The global variable $selectedFile is tested to see if it exists AND if has something in it (i.e. $selectedFile.length). If these conditions have been met, then we must have set $selectedFile with a reference to one of our list items earlier on in the runtime. Therefore we'll need to remove the selected CSS class from whichever element was previously selected. Though it requires a global variable, removing the selected class in this way is a bit more direct than removing it from all list items and then adding again. And by 'more direct',  I mean more efficient

Once the selected class is removed, we can reset the $selectedFile variable to the currently selected list item and add the selected class to it:

  1.         $selectedFile = $(this);        
  2.         $selectedFile.addClass('finderCategoryFileSelected');

Then we do something interesting for both <ul> elements: we make them sortable, and we pass in an object literal with specific options, the first option being connectWith. This option accepts a reference to another list-item and sets up a one-way connection with it. In other words, a user can now drag a list item from this list to the one specified. We want to make this a two-way connection, so we simply select the other list, make it sortable, and then pass it a connectWith value for the first list. Now the two lists in our HTML are essentially 'connected', and list items can be dragged and dropped between them.

Two of the other options you've seen - placeholder and opacity – and they both accept CSS classes. The fourth option – cursor – mirrors a CSS property of the same name. In both cases, cursor changes the mouse cursor to one of a set of OS supported cursor icons.


The Accordion UI in jQuery 

Broadly speaking, an accordion, in the context of the user interface, is a grouping of content items that open only one pane item at a time, hiding any previously open items or panes. They can be (and have been) built in various scripting languages, including Flash/ActionScript, JavaScript, Python, Java and C++. 

Accordions are relatively simple components for organizing content, but they can be kind of a hassle to code from scratch. They imply mouse click events, animations, and a lot of formatting options. Luckily the jQuery UI library includes a fully customizable accordion plugin, so we don't have to worry about the heavy lifting. Not surprisingly, it is called .accordion()

Let's take a look at an example. [Click here for the demo] [Click here for the exercise files]

The HTML: nothing special – just a simple list with information about the five foods groups. Remember to eat your vegetables!

  1. <!doctype html>
  2. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  3. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  4. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  5. <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
  6.  <meta charset="utf-8">
  7.  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title>
  8.  <meta name="description" content="">
  9.  <meta name="author" content=""> <meta name="viewport" content="width=device-width">
  10.  <link rel="stylesheet" href="css/style.css">
  11. </head>
  12.   <body>
  13.     <h4>The Five Food Groups</h4>
  14.     <ul>
  15.       <li>
  16.         <a href='#'>Bread+Cereals</a>
  17.         <p>
  18.           Grains, also called cereals and sometimes inclusive of potatoes and other starches, is often the largest category in nutrition guides. Examples include wheat, rice, oats, barley, bread and pasta.
  19.         </p>
  20.       </li>
  21.       <li>
  22.         <a href='#'>Fruit+Vegetables</a>
  23.         <p>
  24.           Fruit, sometimes categorized with vegetables, is typically a medium-sized category in nutrition guides, though occasionally a small one. Examples include apples, oranges, bananas, berries and melons. Vegetables, sometimes categorized with fruit and occasionally inclusive of legumes, is typically a large category second only to grains, or sometimes equal to grains, in nutrition guides. Examples include spinach, carrots, onions, peppers, and broccoli.
  25.         </p>
  26.       </li>
  27.       <li>
  28.         <a href='#'>Dairy</a>
  29.         <p>
  30.           Dairy, also called milk products and sometimes categorized with milk alternatives or meat, is typically a smaller category in nutrition guides. Examples of dairy products include milk, yogurt and cheese. Though they are also dairy products, ice cream is typically categorized with sweets and butter is typically classified with fats and oils in nutrition guides.
  31.         </p>
  32.       </li>
  33.       <li>
  34.         <a href='#'>Meat</a>
  35.         <p>
  36.           Meat, sometimes labeled protein and occasionally inclusive of legumes, eggs, meat analogues and/or dairy, is typically a medium- to smaller-sized category in nutrition guides. Examples include chicken, fish, turkey, pork and beef.
  37.         </p>
  38.       </li>
  39.       <li>
  40.         <a href='#'>Fats, Oils+Sweets</a>
  41.         <p>
  42.           Fats and oils, sometimes categorized with sweets, is typically a very small category in nutrition guides, if present at all, and is sometimes listed apart from other food groups. Examples include cooking oil, butter, margarine and shortening. Sweets, also called sugary foods and sometimes categorized with fats and oils, is typically a very small category in nutrition guides, if present at all, and is sometimes listed apart from other food groups. Examples include candy, soft drinks, cake, pie and ice cream.
  43.         </p>
  44.       </li>
  45.     </ul>
  46. <script src="js/libs/jquery-1.7.2.min.js"></script> <script src="js/libs/jquery-ui-1.8.20.custom.min.js"></script> <script src="js/plugins.js"></script> <script src="js/script.js"></script>
    </body>
  47. </html>

The CSS: this is all presentational. However, as we shall see, it will not be sufficient in controlling how the accordion example looks on screen.

  1. @charset "UTF-8";
  2. /* CSS Document */
  3. body {
  4.     font: 12px "Lucida Grande", Arial, sans-serif;
  5.     background: #fff;
  6.     color: rgb(50, 50, 50);
  7.     margin: 0;
  8.     padding: 0;
  9. }
  10. h4 {
  11.     margin: 5px;    
  12. }
  13. ul {
  14.     list-style: none;
  15.     margin: 0;
  16.     padding: 15px 5px;
  17. }
  18. li {
  19.     background: gold;
  20.     padding: 3px;
  21.     width: 244px;
  22.     margin: 1px;
  23. }


Finally, the jQuery: shockingly easy. Take that, Flash!

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion();
  4.   }
  5. );

Let's take a look at it in a browser. As you can see, panes collapse and expand upon user interaction, but the heights of the elements are a little odd:

Screen Shot 2012-05-08 at 3.11.53 PMScreen Shot 2012-05-08 at 3.11.45 PM



 

.accordian() Options

Options: this is where the .accordion() plugin becomes really useful. Like many jQuery UI plugins and widgets, .accordion() accepts options wrapped in an object, passed in as an argument in the code.

autoHeight: one of these options is set to true by default, causing all list items to take the height of the highest list item. We'll set it to false by adding an options object, as in the jQuery below:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.       autoHeight: false  
  5.     });
  6.   }
  7. );

Insert the autoHeight: false option into your .accordion() call and viola! The list items each take on the height of their content…like they usually do.

 


 activeAnother useful option is active, which sets the actively open panel of the .accordion(). To use it, we need only specify the index of the item we want open. Remember that indexes are number 0-n, e.g:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.        autoHeight: false,
  5.        active: 2
  6.     });
  7.   }
  8. );

With updated code in place, refresh your browser and behold the goodness! Note that you can also pass the active option a CSS class name associated with one of the list items in your accordion list. It just takes longer and requires going permanently editing your HTML document if you haven't already done so.


alwaysOpen: Normally an instance of an .accordian() is always open to at least one pane. Setting the alwaysOpen option to false will allow it to be completely closed. This is useful if you want to have it tucked away. Pass this code into our growing collection of options to implement it:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.        autoHeight: false,
  5.        active: 2,
  6.        alwaysOpen: false
  7.     });
  8.   }
  9. );

eventThe event option determines which event triggers the accordion to open to a particular pane: a click on that pane's anchor, or a mouseover that pane's anchor. Let's set it to 'mouseover' make it a little more dynamic:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.        autoHeight: false,
  5.        active: 2,
  6.        alwaysOpen: false,
  7.        event: 'mouseover'
  8.     });
  9.   }
  10. );

header: The .accordion() plugin chooses the first link (or anchor) in each list item as the header for that accordion pane. The header is also the element that is clicked on or moused over to open a panel. Sometimes you may want something other than a hyperlink to do so. If you want to use a custom header element, like an <h3> tag, or even a <div> with a specific class associated with it, you can use the header option and pass it the selector for that element/class. E.g.: 

First we'll need to edit the HTML:

  1.       <li>
  2.         <h3>Bread+Cereals</h3>
  3.         <p>
  4.           Grains, also called cereals ... rice, oats, barley, bread and pasta.
  5.         </p>
  6.       </li>

And the new header option passed to our .accordion() instance:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.        autoHeight: false,
  5.        active: 2,
  6.        alwaysOpen: false,
  7.        event: 'mouseover',
  8.        header: 'h3'
  9.     });
  10.   }
  11. );

Make your .accordion() sortable: this isn't really an option, but more of really cool feature that the jQuery UI offers. Because jQuery makes it easy to chain together methods and plugins, we can easily make our accordion object a sortable object by chaining a .sortable() call to it. We'll pass this .sortable call some options as well:

  1. $(document).ready(
  2.   function() {
  3.     $('ul').accordion({
  4.        autoHeight: false,
  5.        active: 1,
  6.        alwaysOpen: false,
  7.        event: 'mouseover',
  8.     header: 'h3',
  9.     })
  10.     .sortable({
  11.       axis: "y",
  12.       handle: "h3"
  13.     });
  14.   }
  15. );

 

 

o;

You are here: Home | teaching | Spring 2012