Tuesday, January 5, 2010

Downloading jQuery

About The Code

The code itself is written rather cleanly in an attempt to self-document. If you've spotted some areas of code that could be improved, please feel free to discuss it on the Development mailing list. All input is gladly appreciated!

All of the code is available in two formats:

  • Compressed (which allows you to have a significantly smaller file size) and
  • Uncompressed (good for debugging and to understand what is behind the magic).

If you're interested in downloading Plugins developed by jQuery contributors, please visit the Plugins page.

jQuery is provided under the following MIT and GPL licenses.

Download jQuery

This is the recommended version of jQuery to use for your application. The code in here should be stable and usable in all modern browsers.

The minified versions, while having a larger file size than the packed versions (note: packed version is not available in current release), are generally the best versions to use on production deployments. The packed versions require non-trivial client-side processing time to uncompress (unpack) the code whereas the minified versions do not. The packed versions of jQuery will take less time to download than the minified or uncompressed versions; however, each time the library is loaded (initially or from the browser cache) it will need to be uncompressed which will cause a non-trivial delay in the execution of any jQuery code each time it is loaded.

Current Release

Documentation

API Reference, individual html files, zipped

Past Releases

Nightly Builds

The source code in the Git repository, mentioned below, is also built and made available on a semi-nightly basis. This is mostly for people who either do not have access to the Git repository, or who don't want to go to the trouble of checking out a copy from the repository, and then building jQuery themselves.

Git

Note: The following is quite advanced. If you wish to just use a more-recent version of jQuery, please try one of the nightly builds, mentioned previously.

All source code is kept under Git revision control, which you can browse online. There's a download link available for any file or directory, if you only want to download a portion of the jQuery code.

If you have access to Git, you can connect to the repository here:

git clone git://github.com/jquery/jquery.git

You can also check out a specific version of jQuery from GitHub at:

git clone git://github.com/jquery/jquery.git
git checkout
e.g. git checkout 1.2.6

If you want to build your own copy of jQuery from the Git repository, you will need to build it.

Note: The jQuery UI code is in its own Subversion repository:

svn co http://jquery-ui.googlecode.com/svn/tags

Build Requirements

jQuery currently requires the following components to be installed:

  • A build system (either make or ant works):
    • make: Available on most Unix-based system (Unix, BSD, OSX, Cygwin)
    • ant: Available on any platform with JDK and ANT installed
  • java: A copy of Java, version 1.4.0 or later (required to build the minified version of jQuery).

Build Process

You will now need to use the build system that you chose previously - either make or ant.

If you're using make:

  • To create jQuery: make
    • This will create jquery.js and jquery.min.js in the dist directory
  • free help

If you're using ant:

  • To create jQuery: ant
    • This will create jquery.js and jquery.min.js in the dist directory

A Colorful Clock With CSS & jQuery

Step 1 – XHTML

As usual, we start with the XHTML markup. The difference is, that the XHTML is not contained in demo.html, but is dynamically inserted into the page by jQuery (well there is some markup left there after all we need at least one container div for the clock to be inserted in).

This saves us from having to manually type similar blocks of code for each one of the dials (there are three of them, one for the hours, the minutes and the seconds).

Lets take a look at the XHTML that is inserted by jQuery:

jquery.tzineClock.js



01.<!-- The first class (green in this case) is assigned dynamically -->
02.<div class="green clock"</div>
03.
04.<!-- This div holds the value of the unit monitored - seconds, minutes or hours -->
05.<div class="display"></div>
06.
07.<!-- A black area that hides the underlying background -->
08.<div class="front left"></div>
09.
10.<!-- The left part of the background: -->
11.<div class="rotate left">
12.<div class="bg left"></div>
13.</div>
14.
15.<!-- The right part of the background: -->
16.<div class="rotate right">
17.<div class="bg right"></div>
18.</div>
19.
20.</div>

This code is contained in jquery.tzineClock/jquery.tzineClock.js. It is generated three times – once for the hours, minutes and seconds. Those are later animated and updated every second, as you’ll see in a moment.

There are three classes that are assigned to the topmost container during the generation process – green, blue and orange. Just by assigning one of those classes, we change the color of the dial.

Lets continue with the next step.

A Colorful jQuery & CSS Clock

A Colorful jQuery & CSS Clock

Step 2 – CSS

Before our style sheets can have any effect on the page, we have to include them in the head section of the file:

demo.html


1.<link rel="stylesheet" type="text/css" href="styles.css" />
2.<link rel="stylesheet" type="text/css" href="jquery.tzineClock/jquery.tzineClock.css" />

Those lines import styles.css and jquery.tzineClock.css in the page. The first one styles the demo page, and the second – the colorful dials (it is part of the plugin).

We can now take a closer look at the CSS rules.

styles.css



01.body,h1,h2,h3,p,quote,small,form,input,ul,li,ol,label{
02. /* Simple page reset */
03. margin:0;
04. padding:0;
05.}
06.
07.body{
08. /* Setting default text color, background and a font stack */
09. color:#dddddd;
10. font-size:13px;
11. background: #302b23;
12. font-family:Arial, Helvetica, sans-serif;
13.}
14.
15.#fancyClock{
16. margin:40px auto;
17. height:200px;
18. border:1px solid #111111;
19. width:600px;
20.}

Those few lines are all that is needed to style the demo page. We first implement a simple CSS reset, which will insure that the elements on the page look the same across the different browsers.

Later we style the body of the page and finally the fancyClock div, in which we will later insert the three dials.

jquery.tzineClock.css




01..clock{
02. /* The .clock div. Created dynamically by jQuery */
03. background-color:#252525;
04. height:200px;
05. width:200px;
06. position:relative;
07. overflow:hidden;
08. float:left;
09.}
10.
11..clock .rotate{
12. /* There are two .rotate divs - one for each half of the background */
13. position:absolute;
14. width:200px;
15. height:200px;
16. top:0;
17. left:0;
18.}
19.
20..rotate.right{
21. display:none;
22. z-index:11;
23.}
24.
25..clock .bg, .clock .front{
26. width:100px;
27. height:200px;
28. background-color:#252525;
29. position:absolute;
30. top:0;
31.}
32.
33..clock .display{
34. /* Holds the number of seconds, minutes or hours respectfully */
35. position:absolute;
36. width:200px;
37. font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
38. z-index:20;
39. color:#F5F5F5;
40. font-size:60px;
41. text-align:center;
42. top:65px;
43. left:0;
44.
45. /* CSS3 text shadow: */
46. text-shadow:4px 4px 5px #333333;
47.}
48.
49./* The left part of the background: */
50.
51..clock .bg.left{ left:0; }
52.
53./* Individual styles for each color: */
54..orange .bg.left{ background:url(img/bg_orange.png) no-repeat left top; }
55..green .bg.left{ background:url(img/bg_green.png) no-repeat left top; }
56..blue .bg.left{ background:url(img/bg_blue.png) no-repeat left top; }
57.
58./* The right part of the background: */
59..clock .bg.right{ left:100px; }
60.
61..orange .bg.right{ background:url(img/bg_orange.png) no-repeat right top; }
62..green .bg.right{ background:url(img/bg_green.png) no-repeat right top; }
63..blue .bg.right{ background:url(img/bg_blue.png) no-repeat right top; }
64.
65..clock .front.left{
66. left:0;
67. z-index:10;
68.}

jquery.tzineClock.css is a part of our plugin (alongside jquery.tzineClock.js) and it styles the colorful dials themselves.

One of the more interesting moments is the use of individual rules that style the colors of the dials, as I mentioned in step one.

You can learn more about the animation from the illustration below:

The animation explained

The animation explained

Step 3 – jQuery

Moving all the JavaScript to the plugin makes it really easy to reuse the code and at the same time enables us to leverage the power of jQuery’s selectors and methods.

To be able to use the jQuery library, we first need to include a couple of scripts in the page:

demo.html


1.<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
2.<script type="text/javascript" src="jquery.tzineClock/jquery.tzineClock.js"></script>
3.<script type="text/javascript" src="script.js"></script>

The first file is the library itself, included from Google’s CDN, later we have the plug-in and lastly the script file that runs the demo.

script.js


1.$(document).ready(function(){
2. /* This code is executed after the DOM has been completely loaded */
3.
4. $('#fancyClock').tzineClock();
5.
6.});

If you’ve followed some of our previous tutorials, you are probably expecting to see some 50+ lines of code here, but this time our scripts file contains only one line of code – a call to our plug-in.

This makes it extremely easy to include the code in an existing site (which is the purpose of jquery plugins in the first place).

Lets dig a little deeper into the plugin:

jquery.tzineClock.js – Part 1



01.(function($){
02. // A global object used by the functions of the plug-in:
03. var gVars = {};
04.
05. // Extending the jQuery core:
06.
07. $.fn.tzineClock = function(opts){
08.
09. // "this" contains the elements that were selected when calling the plugin: $('elements').tzineClock();
10. // If the selector returned more than one element, we use the first one:
11. var container = this.eq(0);
12. if(!container)
13. {
14. try{
15. console.log("Invalid selector!");
16. } catch(e){}
17.
18. return false;
19. }
20.
21. if(!opts) opts = {};
22.
23. var defaults = {
24. /* Additional options will be added in future versions of the plugin. */
25. };
26.
27. /* Merging the provided options with the default ones (will be used in future versions of the plugin): */
28.
29. $.each(defaults,function(k,v){
30. opts[k] = opts[k] || defaults[k];
31. });
32.
33. // Calling the setUp function and passing the container,
34. // will be available to the setUp function as "this":
35.
36. setUp.call(container);
37.
38. return this;
39. }
40.
41. function setUp()
42. {
43. // The colors of the dials:
44. var colors = ['orange','blue','green'];
45.
46. var tmp;
47. for(var i=0;i<3;i++)
48. {
49. // Creating a new element and setting the color as a class name:
50.
51. tmp = $('<div>').attr('class',colors[i]+' clock').html(
52. '<div class="display"></div>'+
53. '<div class="front left"></div>'+
54. '<div class="rotate left">'+
55. '<div class="bg left"></div>'+
56. '</div>'+
57. '<div class="rotate right">'+
58. '<div class="bg right"></div>'+
59. '</div>'
60. );
61.
62. // Appending to the fancyClock container:
63. $(this).append(tmp);
64.
65. // Assigning some of the elements as variables for speed:
66. tmp.rotateLeft = tmp.find('.rotate.left');
67. tmp.rotateRight = tmp.find('.rotate.right');
68. tmp.display = tmp.find('.display');
69.
70. // Adding the dial as a global variable. Will be available as gVars.colorName
71. gVars[colors[i]] = tmp;
72. }
73.
74. // Setting up a interval, executed every 1000 milliseconds:
75. setInterval(function(){
76.
77. var currentTime = new Date();
78. var h = currentTime.getHours();
79. var m = currentTime.getMinutes();
80. var s = currentTime.getSeconds();
81.
82. animation(gVars.green, s, 60);
83. animation(gVars.blue, m, 60);
84. animation(gVars.orange, h, 24);
85. },1000);
86. }

Making a plug-in for jQuery comes down to defining a custom function through the jQuery.fn method. This way your function is available on any elements that you normally use jQuery on.

For example, in script.js we select the div width an id of fancyClock and use the tzineClock() method on it: $(‘#fancyClock’).tzineClock();. The elements we selected are later passed to the tzineClock function and are available through the “this” property.

I have left place for future improvements of the plugin, like passing configuration options for the dimensions of the clock, color themes etc. Those will however be implemented in future releases of the plugin.

Because there might be more than one element selected, we extract only the first one of the set with the eq(0) method. Later we have the setUp() function that inserts the markup for the dials and sets up the interval which will update the figures every second.

jquery.tzineClock.js – Part 2


01.(function($){
02. // A global object used by the functions of the plug-in:
03. var gVars = {};
04.
05. // Extending the jQuery core:
06.
07. $.fn.tzineClock = function(opts){
08.
09. // "this" contains the elements that were selected when calling the plugin: $('elements').tzineClock();
10. // If the selector returned more than one element, we use the first one:
11. var container = this.eq(0);
12. if(!container)
13. {
14. try{
15. console.log("Invalid selector!");
16. } catch(e){}
17.
18. return false;
19. }
20.
21. if(!opts) opts = {};
22.
23. var defaults = {
24. /* Additional options will be added in future versions of the plugin. */
25. };
26.
27. /* Merging the provided options with the default ones (will be used in future versions of the plugin): */
28.
29. $.each(defaults,function(k,v){
30. opts[k] = opts[k] || defaults[k];
31. });
32.
33. // Calling the setUp function and passing the container,
34. // will be available to the setUp function as "this":
35.
36. setUp.call(container);
37.
38. return this;
39. }
40.
41. function setUp()
42. {
43. // The colors of the dials:
44. var colors = ['orange','blue','green'];
45.
46. var tmp;
47. for(var i=0;i<3;i++)
48. {
49. // Creating a new element and setting the color as a class name:
50.
51. tmp = $('<div>').attr('class',colors[i]+' clock').html(
52. '<div class="display"></div>'+
53. '<div class="front left"></div>'+
54. '<div class="rotate left">'+
55. '<div class="bg left"></div>'+
56. '</div>'+
57. '<div class="rotate right">'+
58. '<div class="bg right"></div>'+
59. '</div>'
60. );
61.
62. // Appending to the fancyClock container:
63. $(this).append(tmp);
64.
65. // Assigning some of the elements as variables for speed:
66. tmp.rotateLeft = tmp.find('.rotate.left');
67. tmp.rotateRight = tmp.find('.rotate.right');
68. tmp.display = tmp.find('.display');
69.
70. // Adding the dial as a global variable. Will be available as gVars.colorName
71. gVars[colors[i]] = tmp;
72. }
73.
74. // Setting up a interval, executed every 1000 milliseconds:
75. setInterval(function(){
76.
77. var currentTime = new Date();
78. var h = currentTime.getHours();
79. var m = currentTime.getMinutes();
80. var s = currentTime.getSeconds();
81.
82. animation(gVars.green, s, 60);
83. animation(gVars.blue, m, 60);
84. animation(gVars.orange, h, 24);
85. },1000);
86. }


The last two of the functions used by the plug-in are animation and rotateElement. The first one updates the dials according to the value passed (we also pass a parameter with the maximum value so that the function can calculate the rotation).

The next function is the one that actually rotates the passed element. The rotation works only for Firefox, Safari, Chrome and IE6+. Internet Explorer does not support the CSS3 rotation used by the other browsers, but provides a proprietary filter property which allows for a similar transformation.

With this our colorful jQuery clock is complete!

Conclusion

Today we created a colorful clock with the help of CSS, jQuery and our first plug-in. You are free to use the code given here in your own projects. As a bonus, I’ve included the PSD file that I used to make the backgrounds, so you can easily create new colors and designs for the dials.

What do you think? How would you improve this code?

Advanced Event Timeline With PHP, CSS & jQuery

Step 1 – XHTML

First, be sure to grab the example files from the button above, so that you can easily follow what is going on.

The first step of this tut is to create the XHTML structure, as seen in demo.php.

demo.php



01.<div id="timelineLimiter"> <!-- Hides the overflowing timelineScroll div -->
02.<div id="timelineScroll"> <!-- Contains the timeline and expands to fit -->
03.
04.<!-- PHP code that generates the event list -->
05.
06.<div class="clear"></div>
07.</div>
08.
09.<div id="scroll"> <!-- The year time line -->
10.<div id="centered"> <!-- Sized by jQuery to fit all the years -->
11.<div id="highlight"></div> <!-- The light blue highlight shown behind the years -->
12.<?php echo $scrollPoints ?> <!-- This PHP variable holds the years that have events -->
13.<div class="clear"></div>
14.
15.</div>
16.</div>
17.
18.<div id="slider"> <!-- The slider container -->
19.<div id="bar"> <!-- The bar that can be dragged -->
20.<div id="barLeft"></div> <!-- Left arrow of the bar -->
21.<div id="barRight"></div> <!-- Right arrow, both are styled with CSS -->
22.</div>
23.</div>
24.
25.</div>

I have omitted some of the PHP code that generates the events so we can take a better look at the markup (we will get back to it in the next step).

Te main idea is that we have two divs – timelineLimiter and timelineScroll positioned inside it. The former takes the width of the screen, and the latter is expanded to fit all the event sections that are inserted inside it. This way only a part of the larger inner div is visible and the rest can be scrolled to the left and right by a jQuery slider we will be making in step 4.

Now lets take a look at the PHP back-end.

Advanced Event Timeline With PHP MySQL CSS jQuery

Advanced Event Timeline With PHP MySQL CSS jQuery


Step 2 – PHP

PHP selects all the events in the database and groups the events by year in the $dates array. It later loops through it and outputs all the events as

  • elements inside of unordered lists which belong to each of the event years.

    demo.php





  • 01.// We first select all the events from the database ordered by date:
    02.
    03.$dates = array();
    04.$res = mysql_query("SELECT * FROM timeline ORDER BY date_event ASC");
    05.
    06.while($row=mysql_fetch_assoc($res))
    07.{
    08. // Store the events in an array, grouped by years:
    09. $dates[date('Y',strtotime($row['date_event']))][] = $row;
    10.}
    11.
    12.$colors = array('green','blue','chreme');
    13.$scrollPoints = '';
    14.
    15.$i=0;
    16.foreach($dates as $year=>$array)
    17.{
    18. // Loop through the years:
    19.
    20. echo '
    21. <div class="event">
    22. <div class="eventHeading '.$colors[$i++%3].'">'.$year.'</div>
    23. <ul class="eventList">';
    24.
    25. foreach($array as $event)
    26. {
    27. // Loop through the events in the current year:
    28.
    29. echo '<li class="'.$event['type'].'">
    30. <span class="icon" title="'.ucfirst($event['type']).'"></span>
    31. '.htmlspecialchars($event['title']).'
    32.
    33. <div class="content">
    34. <div class="body">'.($event['type']=='image'?'<div style="text-align:center"><img src="'.$event['body'].'" alt="Image" /></div>':nl2br($event['body'])).'</div>
    35. <div class="title">'.htmlspecialchars($event['title']).'</div>
    36. <div class="date">'.date("F j, Y",strtotime($event['date_event'])).'</div>
    37. </div>
    38. </li>';
    39. }
    40.
    41. echo '</ul></div>';
    42.
    43. // Generate a list of years for the time line scroll bar:
    44. $scrollPoints.='<div class="scrollPoints">'.$year.'</div>';
    45.
    46.}

    Thus the complete markup for the page is generated. Now we are ready to apply some styles.

    The Event Sections

    The Event Sections


    Step 3 – CSS

    After we’ve inserted the CSS stylesheet to the head section of the document, we can start laying down the rules. Only the more interesting ones are included here. You can view the rest in styles.css.

    styles.css




    01..event{
    02. /* Contains the section title and list with events */
    03. float:left;
    04. padding:4px;
    05. text-align:left;
    06. width:300px;
    07. margin:0 5px 50px;
    08.}
    09.
    10..eventList li{
    11. /* The individual events */
    12. background:#F4F4F4;
    13. border:1px solid #EEEEEE;
    14. list-style:none;
    15. margin:5px;
    16. padding:4px 7px;
    17.
    18. /* CSS3 rounded corners */
    19. -moz-border-radius:4px;
    20. -webkit-border-radius:4px;
    21. border-radius:4px;
    22.}
    23.
    24..eventList li:hover{
    25. /* The hover state: */
    26. cursor:pointer;
    27. background:#E6F8FF;
    28. border:1px solid #D4E6EE;
    29. color:#548DA5;
    30.}
    31.
    32.li span{
    33. /* The event icon */
    34. display:block;
    35. float:left;
    36. height:16px;
    37. margin-right:5px;
    38. width:16px;
    39.}
    40.
    41./* Individual background images for each type of event: */
    42.
    43.li.news span.icon { background:url(img/icons/newspaper.png) no-repeat; }
    44.li.image span.icon { background:url(img/icons/camera.png) no-repeat; }
    45.li.milestone span.icon { background:url(img/icons/chart.png) no-repeat; }
    46.
    47.#timelineLimiter{
    48. /* Hides the overflowing timeline */
    49. width:100%;
    50. overflow:hidden;
    51. padding-top:10px;
    52. margin:40px 0;
    53.}
    54.
    55.#scroll{
    56. /* The small timeline below the main one. Hidden here and shown by jQuery if JS is enabled: */
    57. display:none;
    58. height:30px;
    59.
    60. background:#F5F5F5;
    61. border:1px solid #EEEEEE;
    62. color:#999999;
    63.}
    64.
    65..scrollPoints{
    66. /* The individual years */
    67. float:left;
    68. font-size:1.4em;
    69. padding:4px 10px;
    70. text-align:center;
    71. width:100px;
    72.
    73. position:relative;
    74. z-index:10;
    75.}

    Here the .event class styles the event years sections (these are the divs that group events that have happened in the same year).

    Near the middle of the code you can see that we’ve used some CSS3 rounded corners which work in the majority of browsers (not supported by IE and Opera).

    We also define individual background images for each of the event types – image, news or milestone.

    Step 4 – jQuery

    The last step is to insert a layer of interactivity into the browser. We will be doing this with the help of the jQuery JavaScript library, included in the head section of demo.php.

    I’ve split the code below in two parts so they are more comprehensible.


    script.js – Part 1



    01.$(document).ready(function(){
    02.
    03. /* This code is executed after the DOM has been completely loaded */
    04.
    05. /* The number of event sections / years with events */
    06.
    07. var tot=$('.event').length;
    08.
    09. $('.eventList li').click(function(e){
    10.
    11. showWindow('<div>'+$(this).find('div.content').html()+'</div>');
    12. });
    13.
    14. /* Each event section is 320 px wide */
    15. var timelineWidth = 320*tot;
    16.
    17. var screenWidth = $(document).width();
    18.
    19. $('#timelineScroll').width(timelineWidth);
    20.
    21. /* If the timeline is wider than the screen show the slider: */
    22. if(timelineWidth > screenWidth)
    23. {
    24. $('#scroll,#slider').show();
    25. $('#centered,#slider').width(120*tot);
    26.
    27. /* Making the scrollbar draggable: */
    28. $('#bar').width((120/320)*screenWidth).draggable({
    29.
    30. containment: 'parent',
    31. drag: function(e, ui) {
    32.
    33. if(!this.elem)
    34. {
    35. /* This section is executed only the first time the function is run for performance */
    36.
    37. this.elem = $('#timelineScroll');
    38.
    39. /* The difference between the slider's width and its container: */
    40. this.maxSlide = ui.helper.parent().width()-ui.helper.width();
    41.
    42. /* The difference between the timeline's width and its container */
    43. this.cWidth = this.elem.width()-this.elem.parent().width();
    44.
    45. this.highlight = $('#highlight');
    46. }
    47.
    48. /* Translating each movement of the slider to the timeline: */
    49. this.elem.css({marginLeft:'-'+((ui.position.left/this.maxSlide)*this.cWidth)+'px'});
    50.
    51. /* Moving the highlight: */
    52. this.highlight.css('left',ui.position.left)
    53. }
    54.
    55. });
    56.
    57. $('#highlight').width((120/320)*screenWidth-3);
    58.}
    59.});

    As you may have noticed in the PHP section of the tut (if not check it out – around line 33) that with each event we include a set of div elements which contain additional information (title, text and date). Those are hidden with display:none in our CSS file, and are accessed by jQuery so that the pop-up window can be populated with data without the need of sending AJAX requests (not to mention that this content is visible to search engines and is great for SEO). So it is a win-win solution.

    The data itself is being fetched in the second part of the script below:

    script.js – Part 2



    01.function showWindow(data)
    02.{
    03. /* Each event contains a set of hidden divs that hold
    04.additional information about the event: */

    05.
    06. var title = $('.title',data).text();
    07. var date = $('.date',data).text();
    08. var body = $('.body',data).html();
    09.
    10. $('<div id="overlay">').css({
    11.
    12. width:$(document).width(),
    13. height:$(document).height(),
    14. opacity:0.6
    15.
    16. }).appendTo('body').click(function(){
    17.
    18. $(this).remove();
    19. $('#windowBox').remove();
    20. });
    21.
    22. $('body').append('<div id="windowBox"><div id="titleDiv">'+title+'</div>'+body+'<div id="date">'+date+'</div></div>');
    23.
    24. $('#windowBox').css({
    25.
    26. width:500,
    27. height:350,
    28. left: ($(window).width() - 500)/2,
    29. top: ($(window).height() - 350)/2
    30. });
    31.}

    In this function we are basically treating the parameter passed from Part 1 above, where the function is called, as regular HTML and use the standard jQuery selectors thus populating the title, date and body variables.

    The Timeline Explained

    The Timeline Explained

    Step 5 – MySQL

    This last step is only needed if you plan to run the demo on your own server, or like an addition to your current site.

    To make it all tick, you have to recreate the timeline MySQL table from timeline.sql, provided in the download archive. You will also need to fill in your database credentials in connect.php.

    With this our Event Timeline is complete!


    Hide a DIV link


    This here DIV will be hidden when you click on the link
    This is the link that hides the DIV

    Here's the HTML I used.

    <div id="hide-this">
    This here DIV will be hidden when you click on
    the link
    </div>
    <a href="#hide-this" class="close">This is the link that hides the DIV</a>

    And the following JavaScript sets up the preview

    $(function() {
    $('a.close').click(function() {
    $($(this).attr('href')).slideUp();
    return false;
    });
    });

    jQuery Hide/Close Link

    It’s Christmas day, and yes, I’m partaking in the usual holiday fun such as watching Basketball, hanging out with the family and eating our traditional Alaskan king crab Christmas dinner. But of course it wouldn’t be a complete day without writing a tiny bit of code!

    code

    Today I’ve been working on improving the UI here and there in Subtext. One common task I run into over and over is using an anchor tag to trigger the hiding of another element such as a DIV. It happens so often that I get pretty tired of hooking up each and every link to the element it must hide. Being the lazy bastard that I am, I thought I’d try to come up with a way to do this once and for all with jQuery and a bit of convention.

    Here’s what I came up with. The following HTML shows a DIV element with an associated link that when clicked, should hide the DIV.


    <div id="hide-this">
    This here DIV will be hidden when you click on
    the link
    </div>
    <a href="#hide-this" class="close">This is the link that hides the DIV</a>


    The convention here is that any anchor tag with a class “close” is going to have its click event hooked up to close another element. That element is identified by the anchor tag’s rel href attribute, which contains the id of the element to hide. This was based on a suggestion by a couple of commenters to the original version of this post where I used a rel attribute. I like this much better for two reasons:

    • The href value is a hash which is already in the correct format to be a CSS selector for an ID.
    • I’m not using the href value in the first place, so might as well make use of it.

    Yeah, this is probably an abuse of this attribute, but in this case it’s one I can live with due to the benefits it produces. The rel attribute is supposed to define the relationship of the current document to the document referenced by the anchor tag. Browsers don’t do anything with this attribute, but search engines do as in the case with the rel value of “no-follow”.

    However in this case, I feel my usage is in the spirit of this attribute as I’m defining the relationship of the anchor tag to another element in the document. Also, search engines are going to ignore the value I put in there unless the id happens to match a valid value, so no animals will be harmed by this.

    Now I just need a little jQuery script to make the magic happen and hook up this behavior.


    $(function() {
    $('a.close').click(function() {
    $($(this).attr('href')).slideUp();
    return false;
    });
    });

    I happened to choose the slide up effect for hiding the element in this case, but you could choose the hide method or fadeOut if you prefer.

    I put up a simple demo here if you want to see it in action.

    I’m just curious how others handle this sort of thing. If you have a better way, do let me know. :)

    Converting an RGB Color To Hex With JavaScript

    color-wheel

    function colorToHex(color) {
    if (color.substr(0, 1) === '#') {
    return color;
    }
    var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);

    var red = parseInt(digits[2]);
    var green = parseInt(digits[3]);
    var blue = parseInt(digits[4]);

    var rgb = blue | (green << 8) | (red << 16);
    return digits[1] + '#' + rgb.toString(16);
    };
    Now, I can compare colors like so.

    equals(colorToHex('rgb(120, 120, 240)'), '#7878f0');

    Death to confirmation dialogs with jquery.undoable

    Confirmation dialogs were designed by masochists intent on making users of the web miserable. At least that’s how I feel when I run into too many of them. And yes, if you take a look at Subtext, you can see I’m a perpetrator.

    Well no longer!

    I was managing my Netflix queue recently when I accidentally added a movie I did not intend to add (click on the image for a larger view).

    netflix-queue Naturally, I clicked on the blue “x” to remove it from the queue and saw this.

    netflix-queue-deleted Notice that there’s no confirmation dialog that I’m most likely to ignore questioning my intent requiring me to take yet one more action to remove the movie. No, the movie is removed immediately from my queue just as I requested. I love it when software does what I tell it to do and doesn’t second guess me!

    But what’s great about this interface is that it respects that I’m human and am likely to make mistakes, so it offers me an out. The row becomes grayed out, shows me a status message, and provides a link to undo the delete. So if I did make a mistake, I can just click undo and everything is right with the world. Very nicely done!

    I started to get curious about how they did it and did not find any existing jQuery plugins for building this sort of undoable interface, so I decided this would be a fun second jQuery plugin for me to write, my first being the live preview plugin.

    The Plugin

    Much like my jQuery hide/close link, the default usage of the plugin relies heavily on conventions. As you might expect, all the conventions are easily overriden. Here’s the sample HTML for a table of comments you might have in the admin section of a blog.



    <table>
    <thead>
    <tr>
    <th>title</th>
    <th>author</th>
    <th>date</th>
    <th></th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td>This is an interesting plugin</td>
    <td>Bugs Bunny</td>
    <td>12/31/2009</td>
    <td><a href="#1" class="delete">delete</a></td>
    </tr>
    <tr>
    <td>No, it's a bit derivative. But nice try.</td>
    <td>Derrida</td>
    <td>1/1/2010</td>
    <td><a href="#2" class="delete">delete</a></td>
    </tr>
    <tr>
    <td>Writing sample data is no fun at all.</td>
    <td>Peter Griffin</td>
    <td>1/2/2010</td>
    <td><a href="#3" class="delete">delete</a></td>
    </tr>
    </tbody>
    </table>

    And the following is the code to enable the behavior.

    $(function() {
    $('a.delete').undoable({url: 'http://example.com/delete/'});
    });


    By convention, when one of the delete links is clicked, the value in href attribute is posted as form encoded data with the key “id” to the specified URL, in this case http://example.com/delete/.

    If you have more form data to post, it’s quite easy to override how the form data is put together and send whatever you want. The following examples pulls the id from a hidden input and sends it with the form key “commentId”.

    $(function() {
      $('a.delete').undoable({
    url: 'http://example.com/delete/',
    getPostData: function(clickSource, target) {
    return {
    commentId: target.find("input[type='hidden'][name='id']").value(),
    commentType: 'contact'
    };
    }
    });
    });


    When the data is posted to the server, the server must respond with a JSON object having two properties, subject and predicate. For example, in ASP.NET MVC you might post to an action method which looks like:


    public ActionResult Delete(int id) {
    // Delete it
    return Json(new {subject = "The comment", predicate = "was deleted"});
    }


    The only reason I broke up the response message into two parts is to enable nice formatting like Netflix’s approach.

    This of course is is easily overridden. For example, it may be simpler to simply return I can override the formatStatus method to expect other properties in the response from the server. For example, suppose you simply want the server to respond with one message property, you might do this.



    $(function() {
    $('a.delete').undoable({
    url: 'http://example.com/delete/',
    formatMessage: function(response) {
    return response.message;
    }
    });
    });


    I wrote the plugin with the TABLE scenario in mind as I planned to use it in the comment admin section of Subtext, but it works equally well with other elements such as DIV elements. For example, the user facing comments of a blog are most likely in a list of DIV tags. All you need to do to make this work is make sure the DIV has a class of “target” or override the getTarget method.










    I need your help!

    I really hope some of you out there find this plugin useful. Writing these plugins has been a great learning experience for me. I found the following two resources extremely valuable.

    • jQuery Plugin Authoring Guide This is the beginners guide on the jQuery documentation page. I found it to be very helpful in learning the basics of plugin development.
    • A Plugin Development Pattern by Mike Alsup. Mike outlines a pattern for writing jQuery plugins that has worked well for him based on his extensive experience. I tried to follow this pattern as much as I could.

    However, I still feel there’s room to improve. I’m not sure that I fully grasped all the tips and wrote a truly idiomatic usable extensible clean jQuery plugin. So if you have experience writing jQuery plugins, please do enumerate all the ways my plugin sucks.

    If you simply use this plugin, please tell me what does and doesn’t work for you and how it could be better. I’m really having fun writing these plugins and would find your constructive feedback very helpful.


    The Source

    As with my last plugin, the source is hosted on GitHub. Git is another tool I’m learning. I can’t really make a judgment until I use it on a project where I’m collaborating with others *hint* *hint*. :) Please do fork it and provide patches and educate me on writing better plugins. :)