Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Tuesday, April 2, 2013

Regex Replacement String Math

I needed a simple method to do math within a regex replacement. Basically, a simple way for someone using a plugin to choose between a zero or one based index.

Yes, I could have just added an additional replacement like this:
var string = '&index0={index}&index1={index+1}'
  .replace(/\{index\}/, index)
  .replace(/\{index\+1\}/, index + 1);


That works! But what you if for some unknown reason needed the index to start at 2, 3 or even 10? Easy, go back in and modify the code.

Or, just use some regex math that allows you to set any number. Try this demo, and change the last input string to use "{index+10}" or even "{index-5}":

The code isn't really that complicated:
var string = '&index0={index}&index1={index+1}'
  .replace(/\{index([-+]\d+)?\}/g, function(fullstring, match){
    return index + (match ? parseInt(match, 10) : 0);
  });
It uses a replace function to take the index and add the first regex matching string obtained from the match argument.

But before that, we need to use a ternary operator to check if there is a match. If there isn't one, then add zero to the index.

We then need to parse the matched string into a numerical value so we can add it to the index. Then return the result.

I hope someone finds this useful :)

Friday, December 21, 2012

Using Google Closure Compiler to write better code

So I ran into a bit of code that I wrote a while back. I thought could be written a lot more efficiently. So I thought, hey Google's Closure Compiler is good at that stuff right? Let see what happens!

So, lets say we started out with this list of contacts:

var list = {
 'friends' : {
  'fred' : '123-4567',
  'lisa' : '123-6789'
 },
 'work' : {
  'joe'  : '234-5678'
 }
}

I need a function to add someone to the list, or update a number, but it need to check if the group already exists or if the person is already listed:

function addName(group, name, number){
 if (list[group] && list[group][name]){
  list[group][name] = number;
 } else {
  if (list[group]){
   list[group][name] = number;
  } else {
   list[group] = {};
   list[group][name] = number;
  }
 }
}

so the addName function starts out by seeing if the group exists, then if the name exists within that group:

if (list[group] && list[group][name]){

if that works, then just add/update the number. If not, then we drop through the else to the next set of evaluations. Does the group exist?

if (list[group]){

Yes? Add the number, if not, keep going to through the next else, from here we know that the group doesn't exist, so we define it, then add the name.

Seems efficient right?... hmm, but I see a lot of list[group][name] = number; in there. Lets see what Google's closure compiler does to it.

But first we need to keep the compiler from changing all the names. Lets pull out the code from within the function and force the compiler to keep our constants (see the first line):

/** @const */ var list = {}, group, name, number;

 if (list[group] && list[group][name]){
  list[group][name] = number;
 } else {
  if (list[group]){
   list[group][name] = number;
  } else {
   list[group] = {};
   list[group][name] = number;
  }
 }

The extra asterisk in the comment is important! (ref). Note, maybe there is a better way to force the compiler to keep your variable names within a function, but I don't know it.

Anyway, click the reset link and paste the code above into the compiler (use the "Simple" setting if it isn't already set). You'll end up with this:

var list={},group,name,number;if(!list[group]||!list[group][name])list[group]||(list[group]={});list[group][name]=number;

If it's too messy for you to clean up yourself, or you have a lot more code, copy that result and paste it into jsbeautifier and you'll end up with nicer formatted code.

Also, it's important to remember that compilers don't necessarily always use curly brackets after if or else statements, so the above code is equivalent to:

var list = {}, group, name, number;
if (!list[group] || !list[group][name]) {
  list[group] || (list[group] = {});
}
list[group][name] = number;

So now we can replace our function wrapper and remove the constants:

function addName(group, name, number){
  if (!list[group] || !list[group][name]) {
    list[group] || (list[group] = {});
  }
  list[group][name] = number;
}

That looks better, but I'm still seeing a bunch of list[group] in there. I'm sure the code can be a bit more DRY (don't repeat yourself). Also do we really need to check list[group][name]? It was checked initially but not checked again...

function addName(group, name, number){
  if (!list[group]) {
    list[group] || (list[group] = {});
  }
  list[group][name] = number;
}

Well now I see that list[group] is checked twice. Let's get rid of that and see what happens:

function addName(group, name, number){
  if (!list[group]) {
    list[group] = {};
  }
  list[group][name] = number;
}

Now lets see what we have. Check if list[group] exists, then add it if it doesn't. Add the number. Wow! Short and sweet. Why didn't I write it like that originally? Oh yeah, I'm still a noob :)

So after some testing, this new cleaned up function works exactly like the original! We went from 10 lines inside of the addName function down to 4! I'm happy, a happy noob!

I threw together this demo for testing.



I hope that my process of learning at least gives you some ideas. I don't claim to be an expert at javascript or jQuery, but I try to learn a little every day :)

As a redneck friend of mine once said, "Dem Google people is smart!"

Monday, October 31, 2011

Get All indexOf From An Array - Array.allIndexOf()

This array function is an extension of Array.indexOf(), if it exists, and will return all indexes of the search element. It's named allIndexOf(). This code extends javascript and does not require jQuery. It is designed to work in older versions of IE as well, albeit a tiny bit slower.

Originally if you wanted the second instance of a search element, you'd have to call "indexOf" twice. The second time with the starting index of the first result (plus one), or once with a guessed starting index. This should simplify the process for getting any or all of the indexes.

/*
Array.allIndexOf(searchElement)
  Array [Array] - the array to search within for the searchElement
  searchElement [String] - the desired element with which to find starting indexes
*/
(function(){
  Array.prototype.allIndexOf = function(searchElement) {
    if (this === null) { return [-1]; }
    var len = this.length,
    hasIndexOf = Array.prototype.indexOf, // you know, because of IE
    i = (hasIndexOf) ? this.indexOf(searchElement) : 0,
    n,
    indx = 0,
    result = [];
    if (len === 0 || i === -1) { return [-1]; }
    if (hasIndexOf) {
      // Array.indexOf does exist
      for (n = 0; n <= len; n++) {
        i = this.indexOf(searchElement, indx);
        if (i !== -1) {
          indx = i + 1;
          result.push(i);
        } else {
          return result;
        }
      }
      return result;
    } else {
    // Array.indexOf doesn't exist
      for (n = 0; n <= len; n++) {
        if (this[n] === searchElement) {
          result.push(n);
        }
      }
      return (result.length > 0) ? result : [-1];
    }
  };
})();
Use it as follows:
var s = ["red","green","blue","red","yellow","blue","green","purple","red"];
s.allIndexOf("r"); // result [ -1 ]
s.allIndexOf("red"); // result [ 0,3,8 ]
s.allIndexOf("blue"); // result [ 2,5 ]
Try out your own strings in the demo below or full screen.

Get All indexOf From A Search String - String.allIndexOf()

This string function is an extension of String.indexOf() and will return all indexes of a search string. It's named allIndexOf. This code extends javascript and does not require jQuery.

Originally if you wanted the second instance of a search string, you'd have to call "indexOf" twice. The second time with the starting index of the first result (plus one), or once with a guessed starting index. This should simplify the process for getting any or all of the indexes. And yes, I woke up with a strange urge to write this function LOL.

/*
String.allIndexOf(searchstring, ignoreCase)
  String [String] - the string to search within for the searchstring
  searchstring [String] - the desired string with which to find starting indexes
  ignoreCase [Boolean] - set to true to make both the string and searchstring case insensitive
*/
(function(){
  String.prototype.allIndexOf = function(string, ignoreCase) {
    if (this === null) { return [-1]; }
    var t = (ignoreCase) ? this.toLowerCase() : this,
    s = (ignoreCase) ? string.toString().toLowerCase() : string.toString(),
    i = this.indexOf(s),
    len = this.length,
    n,
    indx = 0,
    result = [];
    if (len === 0 || i === -1) { return [i]; } // "".indexOf("") is 0
    for (n = 0; n <= len; n++) {
      i = t.indexOf(s, indx);
      if (i !== -1) {
        indx = i + 1;
        result.push(i);
      } else {
        return result;
      }
    }
    return result;
  }
})();
Use it as follows:
var s = "The rain in Spain stays mainly in the plain";
s.allIndexOf("ain"); // result [ 5,14,25,40 ]
s.allIndexOf("the"); // result [ 34 ]
s.allIndexOf("THE", true); // result [ 0,34 ]
Try out your own strings in the demo below or full screen.

Tuesday, April 19, 2011

Vertical Parallax Effect for the Entire Page

I found a game site (Elder Scrolls) that has a really cool vertical scrolling effect that I wanted to duplicate, but it only works in webkit browsers. I didn't make it into a plugin, but instead made this tutorial, because if you understand the basics, you can add more background images or use CSS3 to add multiple background images.



This is a screen shot of the web page while it is at the top. Note the location of the building tower top is near the top of the logo that is under "Generic".


This screen shot shows how the top of "Box 1" is now above the building tower. Blocks in the foreground move slightly faster than the background image.


Here is the final demo of the vertical scrolling effect (see it as a full page).

How it's done

The Images
This effect uses two background images. The top image (bg1.jpg, 1920x1080 pixels) fades to solid black on its bottom edge.

It's made to be a bit blurry, but you can duplicate the game site's background image by keeping the foreground sharp and the background blurry... it's a cooler effect ;)
 

The second background image (bgtile.jpg, 963x1641 pixels) is added as a background image that appears under the above top image. The css is adjusted so that the top of this image appears below the top image so that you don't see a straight black line cut through the top.

This image is blurry and mostly black, it fades to solid black at the edges, with a rock-like texture. It makes the vertical parallax scroll very subtle, so you may want to adjust it as desired.


The other two images that are used are the title/logo image (title.png, 400x300 pixels).



And the box background (bg-black-55.png, 20x20 pixels) which is a png file of solid black with a 55% opacity.


The Markup
This is very basic HTML markup. The body contains the repeating background tile image (bgtile.jpg). A wrapper is immediately inside the body which contains the top background image (bg1.jpg). These two images could be combined in the body tag if you use css3; then you could use the wrapper for additional images. The Header contains the logo (title.png) and each block of content has the box background image (bg-black-55.png) applied. Fill in the "div.content" block with whatever you want.
<body> <!-- contains repeated background image -->
<div id="wrapper"> <!-- contains top image -->

<div id="header"></div> <!-- contains the page title image -->

 <div class="block"> <!-- contains 55% opacity background image -->
  <h3>Block 1</h3>
  <div class="content">Content 1.</div>
 </div>

 <div class="block"> <!-- contains 55% opacity background image -->
  <h3>Block 2</h3>
  <div class="content">Content 2.</div>
 </div>

 <div class="block"> <!-- contains 55% opacity background image -->
  <h3>Block 3</h3>
  <div class="content">Content 3.</div>
 </div>

 <div class="block"> <!-- contains 55% opacity background image -->
  <h3>Block 4</h3>
  <div class="content">Content 4.</div>
 </div>

 <div class="block"> <!-- contains 55% opacity background image -->
  <h3>Block 5</h3>
  <div class="content">Content 5.</div>
 </div>

</div>

</body>

The CSS
The CSS below doesn't have a lot of comments, but the important parts to focus on are the main background image positions.
body {background: #333; color: #ddd;}
a:link { color: #ddd; }
a:hover { text-decoration: underline; }
a:visited,a:active { color: #999; }

/* Tiled background image */
body {
 margin: 0;
 padding: 0;
 /* Use height of header image for top position */
 background: #000 url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7fBBufKSR47RD9ESntGl85BAeIpSrYvQv9JzbnrK6i-jYhidex39OZ6_4lDD3EXxKv7I3pd4XWnOUyzax9evROh_GLcIfkX8I3vQO6Y1FuA0KruXm33MggzrqsSVR91iOFJvTZylHFiM/s200/bgtile.jpg) left 1080px repeat-y;
}
/* Top background image (1920x1200) */
#wrapper {
 position: relative;
 top: 0;
 left: 0;
 height: 100%;
 width: 100%;
 background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizCx7mqIPhdQ10Xgmieaa4PTAR5suXGEi7ezqiiL5G_h0yFCXhvibhec2mTLDBXGnkTbWC-LeqbKT634Ppt40wdciHfm6fq7QuY5v1pDeWJ6nvzv8T7bj3mrOBd-oxDGuhJmIc5daHeA0/s200/bg1.jpg) center top repeat-x;
 z-index: 100;
}
/* Page Title image */
#header {
 height: 350px;
 background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipx4m-HiIJ90H0QrnLtd5DHyP1J29su3Sn1McbkRcQrKu934Z6WjSGM7stMU5RB97-ZVrQ4_zHV7r81NuIXWmTdXIkoNyuTCj19sGjfxGDkLfOpL0Ou_1jE4xWB-NS5WnP_svT4OkqhbQ/s200/title.png) center 40px no-repeat;
}
/* Content Block with 55% opacity background image */
.block {
 width: 400px;
 height: 500px;
 margin: 20px auto;
 border: #333 1px solid;
 padding: 20px;
 background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj82Brf2wM1QpoBT96gFD5ZXiJFpFTBHxKF4ghGPJwMMkkSF_ifPi4PMFM20c5ravbOTe1lhOLzrK0TDmV0Vq_wys_x09oF3VTSPh_sOrup0B5xc7CRR3tqh9zHm3DvQRIL2maSeryZ2us/s1600/bg-black-55.png);
}
.block h3 {
 font-family: 'Arial Black', Gadget, sans-serif;
 font-size: 130%;
}

The Script
jQuery(document).ready(function(){
  // saved values
  var st, 
   // get window and body elements
   win = jQuery(window)[0],
   body = jQuery('body')[0],
   wrap = jQuery('#wrapper')[0],
   // make sure we target the correct document (in IE)
   doc = (jQuery.support.boxModel) ? document.documentElement : document.body,
  
   // Set top background image height here, in pixels
   imgH = 1080;

  // vertical parallax scroll code
  jQuery(win).scroll(function(){
   // get the page scroll top (IE uses doc.scrollTop)
   st = (win.pageYOffset || doc.scrollTop );

   // Limit moving top image (in the "wrap") only when in view (st < imgH)
   // Doing this reduces the amount of DOM activity so it doesn't slow down the scrolling.
   // Here is where the background position of the top image is moved by 1/4 (st/4) of the total amount scrolled
   // Increasing the fraction (making it closer to one) will speed up the background parallax scroll
   // Decreasing the fraction will slow down the parallax scroll
   if (st < imgH) { wrap.style.backgroundPosition = 'center ' + (st/4) + 'px'; }

   // This line limits the tiled background image in the "body"
   body.style.backgroundPosition = 'left ' + ( imgH + st/4) + 'px';
  });
});
Code breakdown
  • The first and last line wrap the code which is run when the document is ready. This is a jQuery method and can be written several different ways. Basically, any code inside is run when the basic structure and code of the page has completed loading. Images may or may not have completed loading at this time.
    jQuery(document).ready(function(){
      // code to run
    });
  • The next few lines save the variables that are repeatedly used in the script. Saving them reduces the amount of time taken to run code inside the scroll function. See the optimization section for more details.
    // saved values
    var st, 
     // get window and body elements
     win = jQuery(window)[0],
     body = jQuery('body')[0],
     wrap = jQuery('#wrapper')[0],
     // make sure we target the correct document (in IE)
     doc = (jQuery.support.boxModel) ? document.documentElement : document.body,
    
    *Note that each line ends with a comma - it is defining multiple variables with one "var".

  • The next saved variable saves the top background image height (bg1.jpg). This is needed so the script can figure out where to start the tiling of the repeated background image (bgtile.jpg). This ensures that the tiled background image isn't overlapped by the top background image making the user see a sharp black edge at the overlap. The script also uses this height to stop the parallax scroll of the top background image when it isn't in view. The reason for this is discussed in the optimization section below.
    // Set top background image height here, in pixels
    imgH = 1080;
  • Now we bind to the window scroll event. This event is fired everytime the browser window is scrolled. So it can be called hundreds of times while scrolling down the page. This is the reason the code inside this function is kept as minimal as possible.
    // vertical parallax scroll code
    jQuery(win).scroll(function(){
    
      // code run each time the page is scrolled
    
    }); // second to last line in the completed script
  • Get the scroll top of the page. Check standard browsers variable, and if not defined (IE) then get the document scroll top.
    // get the page scroll top (IE uses doc.scrollTop)
    st = (win.pageYOffset || doc.scrollTop );
  • Apply the parallax to the top background image. 
    // Here is where the background position of the top image is moved by 1/4 (st/4) of the total amount scrolled
    // Increasing the fraction (making it closer to one) will speed up the background parallax scroll
    // Decreasing the fraction will slow down the parallax scroll
    if (st < imgH) { wrap.style.backgroundPosition = 'center ' + (st/4) + 'px'; }
    • The first thing we do is check if the scroll top (st) is less than the top background image height. If it is, then use parallax on the top background image.
    • "wrap" is one of our saved variables that points to the page wrapper. Here we set the background position using direct DOM manipulation. See optimization section for more details.
    • The background position has two parts - "X Y" positions. We care centering the image from left to right (the X-position), then taking one fourth (1/4) of the scroll top position and making that the background's Y-position. This is basically how the parallax scroll works. It scroll 1/4 less than the actual page. If you add another layer (say wrapper 2), it should be scrolled slightly more (a number closer to one, like 2/3).
    • So here the top background image is scrolled 1/4 less (1/4 * st) than the page itself. Make this number closer to one (i.e. 3/4 * st) to make the scroll more like the page scroll. Or make the number further from one (i.e. 1/8 * st) to make the scroll a tiny bit. Making the number too small may make the background image appear fixed, so don't go too crazy ;)
  • Apply the parallax to the tiled background image.
    // This line limits the tiled background image in the "body"
    body.style.backgroundPosition = 'left ' + ( imgH + st/4) + 'px';
    • Now we are applying the background position to the body of the page, where the tiled background image (bgtile.jpg) is seen.
    • Here we are place the background image on the left edge (centering should be fine too) and again 1/4 of the scroll top of the page. In addition we add the top image height (imgH) to keep the tiled background image aligned to the bottom of the top background image. So we make sure not to see that black image edge.
    • Since the body background image is behind the wrapper background image, you could make this parallax scroll even slower to give more of a feel of it being further off in the distance. This would look especially good with multiple background images available when using css3.
Optimizations
  • This script was optimized so that a minimal amount of code is run inside the scroll function.
  • This ensures that the code doesn't slow down the page scroll, because the scroll function is called constantly. It's probably not a big deal is modern browsers, but is very noticeable in older browsers. 
  • This was done, in part, by saving variables. This limits the amount of look ups that need to be done by the script. Using $(window) or $(document) needs to call several functions to get a value, so saving it in a variable saves time.
  • To set the background position, the script sets the background position directly in the DOM. Again, this was done to minimize function calls. I didn't have any trouble with cross browser compatibility in any browsers, including Opera and IE7+.

    Sunday, November 28, 2010

    jQuery UI Keyboard Widget

    If you need support, please contact me here:

    I found this widget by Jeremy Satterfield which adds an virtual keyboard to any input or text area. I really liked it and had a lot of ideas that I wanted to add :P


    So, I made a github repository, added a few of my ideas to the widget so now I present to you updated keyboard widget! (more updates to come!)


    Here are some of the changes I made to version 1.5:
    • Changed class of preview window from 'ui-state-active' to 'ui-widget-content' because it looks bad in some themes.
    • Added 'ui-widget-content' class to the element (input or textarea).
    • Added International keyboard Layout (AltGr key) and expanded the keysets up to four.
    • Added more special/"action" keys:
      • Previous text only keys now have a companion symbol only key. The abbreviated names contain only a symbol so as to fit the layout style as desired.
      • Added alt key to allow accessing two additional key sets.
      • Changed name of {neg} to {sign}. This key changes the sign of the input.
      • Added tab key
    • Fixed positioning utility problem I added in the last version - show the popup before positioning (duh).
    • Added position option to allow positioning the keyboard anywhere around the input/textarea.
    • Added display option to support multiple languages or change key symbols.
    • Added actionClass option to allow changing the style of the accept and cancel keys.
    • Added lockInput option to lock or unlock the ability to access the preview window.
    • Added keyBinding option to change the keyboard key behaviour.
    • Added useCombos to enable the dead key emulation which allows entering diacritic key combinations.
    • Using the escape key now closes the keyboard.
    • Added mousewheel support to allow scrolling through the other keysets while hovering over a key.
    • Added ARIA support (may not be complete).
    And on my to do list are:
    • Allow inserting text at the caret inside the preview window.
    • Add max length setting.
    • Add additional buttons to change key sets (similar to the alt key).
    • Add callbacks.
    • Add _destroy function.
    • Work on setting up one keyboard per layout to speed up initialization.

    Wednesday, November 17, 2010

    SqueezeBox

    There is a very cool sliding accordion on Apple's Store site to compare various computers (click compare then scroll).

    SqueezeBox is a jQuery plugin written to emulate that effect. It was designed to use the same themes available for jQuery UI, or you can add your own theme.

    Click on the image or go to the demo page.

    Features:
    • Easily change the theme but just loading in a different jQuery UI theme (Redmond theme shown).
    • SqueezeBox works with both collapsible and non-collapsible blocks.
    • Activate a header numerous ways:

      1. Use browser hash marks to target the header ID - used on initial page load.
      2. Click on any header to make it active - all headers above it will collapse using a smooth animation.
      3. Use the script to set the active header.
    Download it from my github repository.

    Wednesday, October 20, 2010

    Web Search Widget

    I started messing around with the jQuery UI widget factory and put together a widget that allows you to easily add a web search button to your site (no server side scripting required).


    There isn't much for me to write here since I put almost all of the needed instructions on the WebSearch github page. I hope someone finds it useful!

    Tuesday, September 28, 2010

    AnythingSlider

    I've been working on improving the AnythingSlider jQuery plugin by Chris Coyier of CSS-Tricks.com. The project was moved to github, so you can always get the latest version there... My version is up to 1.4 and you can check out a demo of it here - try starting both YouTube videos, then start the slideshow (doesn't work in Internet Explorer properly).

    Features include:
    • Panels are HTML Content (can be anything).
    • Multiple AnythingSliders allowable per-page.
    • Infinite/Continuous sliding (always slides in the direction you are going, even at "last" slide).
    • Optionally resize each panel (specified per panel in css).
    • Optional Next / Previous Panel Arrows.
    • Use keyboard navigation or tabs that are built and added dynamically (any number of panels).
    • Link to specific slides or go forward or back one slide from static text links
    • Each panel has a hashtag (can link directly to specific panels).
    • Optional custom function for formatting navigation text.
    • Auto-playing slideshow (optional feature, can start playing or stopped)
    • Pauses playing YouTube videos when not in view and resumes them when in view (only in non-IE browsers & if files are hosted on the web).
    • If slideshow is active, a playing video will complete before the slideshow continues.
    • Pauses slideshow on hover (optional).
    • Optionally play the slideshow once through, stopping on the last page.

    Tuesday, August 24, 2010

    Tooltips - Jatt (Just another tooltip)

    This is an updated version of my other tooltip script. With this version, you can:
    • Dynamically modify the tooltip using metadata.
    • Set a tooltip direction (8 directions: n, ne, e, se, s, sw, w & nw).
    • Tooltip content can be obtained from a selected object attribute, a different object on the same page, or via ajax.
    • Ajax calls can include jquery selectors to target specific page content.
    • Removed support for the dhtmltooltip script (the code is there, but commented out).
    Adding the Tooltips
    First make sure you have jQuery installed on your site, download the latest version from jQuery. Then add the following CSS and script to your site, or you can download the script here.

    Basic setup
    <style type="text/css">
    .tooltip, .preview, .screenshot { cursor:pointer; }
    #tooltip { width: 250px; }
    #tooltip, #preview {
     color:#dddddd;
     background:#222222;
     border: 1px solid #333333;
     padding:5px;
     opacity: 0.9;
     filter: alpha(opacity=90);
     text-align:left;
     border-radius: 1em;
     -moz-border-radius: 1em;
     -webkit-border-radius: 1em;
     display:none;
    }
    </style>
    <script src="jatt.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function(){
     $.jatt();
    });
    </script>
    Using the Tooltips
    • Basic Tooltip

      basic tip (a)<a class="tooltip { direction: n; width: 100px; background: #222; color: #ddd; }" href="#" title="Tooltip (a) Content">basic tip (a))</a>
      External page (a)<a class="tooltip { direction: ne; width: 200px; }" href="http://wowmotty.blogspot.com/2009/06/new-and-improved-jquery-tooltips.html #Blog1_cmt-3390748906554490641">External page (a)</span>
      Object on page (div)
      <div class="tooltip { direction: e; width: 150px; background: #9bff8f; color: #333; }" rel="#tip1">Object on page (div)</div>
      <div id="tip1" style="display:none">Hi</div>
      <img class="tooltip { direction: se; width: 200px; background: #808080; color: #000; opacity: 1; }" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJB6BDlv3S2lwtKXWg7geoqgt0S-d-efE1yluu0NikMlLfjVEFMiq4N_wlTHkPItSGDbT2xPhgvUnIwGsTI0zj9BtKGN8elCL2GTMaRX0NHE-jfjSRtm0sCP_ja9ih3snjzxFNgpuheKA/s320/hideshow.gif" title="Tooltip (img) Content" >
      Link (span)<span class="tooltip { followMouse: false; direction: s; width: 300px; background: #008080; color: #ddd; }" title="Tooltip (span) Content">Link (span)</span>
      • class="tooltip" (required) - This class activates the tooltip
      • class="tooltip { metadata }" (optional) - Add any of the predefined options (listed below) or any css style to apply to the tooltip.
      • title="Tooltip content" (optional) - The title attribute should contain whatever you want to display inside the tooltip. This can include HTML but Do NOT use quotes in the content. If you are using HTML tags, replace the quotes with single quotes, e.g. <img src='hideshow.gif'>. If you must use quotes to surround some text, use the HTML escape code &quot; - this text has &quot;quotes&quot; around it.
      • rel="selector" (optional) - If the "title" attribute is empty, the script will look in the "rel" attribute for a selector that points to an object containing the tooltip content (see the "External object (div)" example above).
      • href="page.htm #target span:first" (optional) - If the "title" and "rel" attributes are both empty, the script will look in the "href" attribute for a URL to an external page. The URL can be followed by an id or class selectors pointing to the tooltip contents (see the "External page (a)" example above).
    • Preview Tooltips

      <a class="preview { direction: e; opacity: 1; text-align: center; }" href="URL to full size image" title="Google's Logo"><img src="URL to image thumbnail"></a>
      • class="preview" (required) - This class activates the tooltip which puts the linked image (from the href) into a tooltip. The tooltip size is adjusted automatically to fit the image.
      • class="preview { metadata }" (optional) - Add any of the predefined options (listed below) or any css style to apply to the tooltip.
      • href="URL to full size image" (required) - URL to the image, for previewing in the tooltip and the URL you go to when you click on the image.
      • title="TOOLTIP CONTENT" (optional) - This content becomes the image caption located below the image inside the tooltip. Note: Do NOT use quotes in the content. If you are using HTML tags, replace the quotes with single quotes, e.g. <img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdOsFaiNIiNqDl5RhAACLxqpiShH9pnrYBFSZqPUpn2hzCiUT8yo99KC8xKqcQMwKywNN6S1jq9bjJRZ-YULgjR-lYdf10O0-dtosiT7UfhBXJnwRuVIKgDZuc0bgkOf4tUoRag0Pp3SA/s320/Nax2-10.gif'>. If you must use quotes to surround some text, use the HTML escape code &quot; - this text has &quot;quotes&quot; around it.
      • <img src="URL to image thumbnail"> (required) - This will be the thumbnail of the URL image (in orange), or you can pick any image as I did here. Or you can replace the <img> with text.
    • Screenshot Tooltips

      LMYC<a class="screenshot { direction: e; opacity: 1; text-align: center; } " href="http://www.guildportal.com/Guild.aspx?GuildID=194525&TabID=1643295" title="<center>Loch Modan Yacht Club</center>" rel="http://www.axiomfiles.com/Images/Spotlight/194525.jpg">LMYC</a>
      Google<a class="screenshot { direction: e; }" href="http://www.google.com" title="<center>Google</center>" rel="#">Google</a>
      • class="screenshot" (required) - This class activates the tooltip that gets the site screenshot image from the rel attribute (in light blue)
      • href="URL" (required) - URL of the target website
      • title="Tooltip content" (optional) - This content becomes the screenshot (image) caption inside the tooltip. Note: Do NOT use quotes in the content. If you are using HTML tags, replace the quotes with single quotes, e.g. <img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdOsFaiNIiNqDl5RhAACLxqpiShH9pnrYBFSZqPUpn2hzCiUT8yo99KC8xKqcQMwKywNN6S1jq9bjJRZ-YULgjR-lYdf10O0-dtosiT7UfhBXJnwRuVIKgDZuc0bgkOf4tUoRag0Pp3SA/s320/Nax2-10.gif'>. If you must use quotes to surround some text, use the HTML escape code &quot; - this text has &quot;quotes&quot; around it.
      • rel="Website_Screenshot.jpg" or rel="#" (required) This attribute can contain either the URL to the screenshot image of the site to which you have the link pointing. Yes, you will have to take, resize and upload the screenshot image yourself OR you can now use rel="#" to have Websnapr.com generate a thumbnail of the site for you.
      • text or image (required) - Text or image that becomes the clickable link to the site.
    Customizing
    • Initializing the script (showing all default settings)

      $(document).ready(function(){
       $.jatt({
        // options that can be modified by metadata
        direction      : 'n',     // direction of tooltip
        followMouse    : true,    // tooltip follows mouse movement
        content        : 'title', // attribute containing tooltip text
        speed          : 300,     // tooltip fadein speed
        local          : false,   // if true, the script attachs the tooltip locally; if false, the tooltip is added to the body
        xOffset        : 20,      // x distance from mouse (no negative values)
        yOffset        : 20,      // y distance from mouse (no negative values)
        zIndex         : 1000,    // z-index of tooltip
      
        // options not supported by metadata
        live           : false,                 // use live event support?
        metadata       : 'class',               // attribute that contains the metadata, use "false" (no quotes) to disable the metadata.
        activate       : 'mouseenter focusin',  // how tooltip is activated
        deactivate     : 'mouseleave focusout', // how tooltip is deactivated
      
        // change tooltip, screenshot and preview class
        tooltip        : '.tooltip',             // tooltip class
        screenshot     : 'a.screenshot',        // screenshot class
        preview        : 'a.preview',           // preview class
      
        // tooltip & preview ID (div that contains the tooltip)
        tooltipId      : 'tooltip',             // ID of actual tooltip
        previewId      : 'preview'              // ID of screenshot/preview tooltip 
       });
      });
    • List of Options


      KeyValue (default shown)Description
      direction'n'Choose the direction of the tooltip (in quotes; choose from n, ne, e, se, s, sw, w, nw).
      followMousetrueWhen hovering over the object with a tooltip, the tooltip will follow the mouse if true. If false, it will be positioned relative to the object.
      content'title'Attribute containing the tooltip content. By default it is the "title" attribute.
      speed300Time in milliseconds for the tooltip to fade in. By design the tooltip has no fade out because it is removed immediately.
      localfalseWhere the tooltip is attached. By default it is false and will attach to the document body; if true, it will be attached before the object.
      xOffset20Number of pixels between the tooltip and the mouse (or object if followMouse = false) in the X direction.
      yOffset20Number of pixels between the tooltip and the mouse (or object if followMouse = false) in the Y direction.
      zIndex1000Adjust this if the tooltip is below another object.
      livefalseSet to true if you add tooltip objects to your page dynamically (added after the page is loaded).
      metadata'class'Location of the tooltip metadata. By default it will look in the class attribute. If set to "false" it will disable the metadata.
      activate'mouseenter focusin'The event that causes the tooltip to display information.
      deactivate'mouseleave focusout'The event that causes the tooltip to be removed.
      tooltip'.tooltip'The class used to activate the tooltip. And the ID of the actual tooltip.
      screenshot'a.screenshot'The class used to activate the screenshot script which shows an image associated with the URL. And this is the ID of both the screenshot & preview tooltips.
      preview'a.preview'The class used to activate the preview script which shows the an image in the tooltip from the href.
      tooltipId'tooltip'The ID of the actual tooltip.
      previewId'preview'The ID of the actual preview/screenshot tooltip (the share the same one).
    Known Issues
    • Fixed:If the tooltip contents go out of the viewport, the script attempt to adjust the tooltip to make it visible. If it moves the tooltip under the mouse, the tooltip will flicker and become unreadable. This occurs when the east or west direction is used, so limit use of 'east' when the tooltip is near the right side and 'west' when it is near the left. I'll look into fixing this problem in future versions.
    • The tooltip script won't obtain cross-domain ajax requests by default, but I have included James Padolsey's cross-domain ajax script (jquery.xdomainajax.js) which should enable it. Just include the script in the head of your document.
    • If you find any other issues, please submit an issue to Jatt's github repository.

    Friday, July 9, 2010

    Visual Navigation

    There are a few sites that have a navigation menu that can highlight / change when the menu's target scrolls into view (e.g. brizk design & Crush + Lovely) . I tried to generalize the script so it would work with any site and I ended making up with this jQuery plugin.


    I set up a demo page here.

    Download: Uncompressed | Minified | Zipped Demo | Github

    I have tested this plugin in IE8, Firefox and Chrome. Please leave me feedback if you any problems with how it works or if it doesn't work in other browsers.

    Setup
    • This plugin requires jQuery in order to function properly.
    • Follow the basic templates below to set this up on your site. For more details, go to the specific section.
    Default Setup
    • HTML
      <div id="sidemenu">
      <ul>
      <li><a href="#home">Home</a></li>
      <li><a href="#work">Work</a></li>
      <li><a href="#blog">Blog</a></li>
      <li><a href="#projects">Projects</a></li>
      <li><a href="#about">About</a></li>
      <li><a href="#contact">Contact</a></li>
      </ul>
      </div>
      • Change the side menu id to whatever you want, just make sure you target it with the script.
      • This side menu example will work with the plugin's default settings. See the alternate example of a different layout.
    • CSS
      #sidemenu { position: fixed; top: 50px; left: 20px; background: #444; width: 120px; }
      #sidemenu ul { list-style-type: none; margin: 0; padding: 0; }
      #sidemenu li { margin: 5px; padding: 5px; width: 100px; text-align: center; }
      #sidemenu li.selected { background: #555; }
      #sidemenu a { text-decoration: none; color: #bbbbff; }
      #sidemenu a:hover { color: #fff; }
      • This CSS highly variable. Change the position, size and colors as desired.

    • Script
      $(document).ready(function(){
      $('#sidemenu').visualNav();
      });
    Alternate Setup
    • HTML
      <div id="menu">
      <div class="link" title="#Home">Home</div>
      <div class="link" title="#work">Work</div>
      <div class="link" title="#blog">Blog</div>
      <div class="link" title="#projects">Projects</div>
      <div class="link" title=".about">About</div>
      <div class="link" title=".contact">Contact</div>
      </div>
      • This side menu uses divs with a title attribute. The value in this attribute can be used to target an Id or a class (which should be unique).
      • It is important to note, that this menu will not work with javascript disabled, whereas the default one will work.
    • CSS
      #menu { position: fixed; top: 50px; left: 20px; background: #444; width: 120px; }
      #menu div.link { margin: 5px; padding: 5px; width: 100px; text-align: center; }
      #menu div.selected { background: #555; }
    • Script
      $(document).ready(function(){
      $('#menu').visualNav({
      link              : 'div.link',
      targetAttr        : 'title',
      selectedAppliedTo : 'div.link'
      });
      });
    Customizing / Options
    This plugin has the following default options, so you will only need to include the line below in the script options if you want to change the default:
    $('#sidemenu').visualNav({
    link              : 'a',        // Add a link class, as necessary
    targetAttr        : 'href',     // added in case you have link = "div" and attribute something like
    selectedClass     : 'selected', // css class applied to menu
    selectedAppliedTo : 'li',       // to only apply to the link, use "a"
    topRange          : 100,        // measure from the top of the viewport to X pixels down
    topMargin         : 100,        // margin above the top where the target updates the menu
    bottomMargin      : 20,         // margin from the end of the page where the last menu item is used
    animationTime     : 1200        // time in milliseconds
    });
    • The first four options should were hopefully made clear in the examples above.
    • To modify how the menu acts, you will need to adjust the "topRange", "topMargin" and "bottomMargin" values. I made this picture to better understand what these values do for you.
    • topRange: The "topRange" is basically the area where target needs to be inside of in order for the menu to update. For example, the target (found in the link attribute) starts under the topRange. As it moves up and crosses into the topRange. The script then updates the side menu to show that the target area is in view (or inside the view port).
    • topMargin: The top edge margin (topMargin) is the area above the view port. The top edge margin is used while the page is being scrolled up - the target is above the view port and as you scroll up, the target moves down. When the target is inside the edge margin, the menu will update and point to that target.
    • bottomMargin: The bottom edge margin is the area below the view port. It is when the page is scrolled down (the contents are moving up). When the bottom of the page is inside the bottom edge margin, the menu will update with the last targeted id. This was necessary to be include in case the last section is too short and unable to reach the top range area.
    • animationTime: The animation time is the time in milliseconds that the menu will scroll to the selected section.
    Known Problems / Bugs / Suggestions
    • The menu will not select (or highlight) the item above the last item if they are both very short. For example, if your browser shows three sections while at the bottom of the page. The third to last may have shown for a brief time just before the bottom of the page reached the bottom edge margin. The menu would then skip directly to the last menu item. This is one reason why the bottom margin value is kept a low number (20 pixels by default).
    • If you click on a menu item, the page contents will automatically scroll to that section and update the browser url with that target. But if you manually scroll the page using the scroll bar or mouse, the web page url will not update with the current position. This was done on purpose, because if the script changes the location, the page will jump to that target automatically. This wouldn't look good if you are quickly scrolling through the page as it would make the movement jittery.
    • To make suggestions or report any bugs please email me at wowmotty at g mail dot com.

    Sunday, July 4, 2010

    todaysImage v1.0

    The plugin will take a group of images which have a set date range, and show an image randomly from the group depending on the current date. It is based on my original Random Image by Date script but has been significantly modified and improved! It's shiny and sparkly, but you won't be able to tell much difference on the surface.

    The frame below contains a demo of this script... you can view the page directly by clicking this link so you can more easily understand what it does and test the debuging features.



    Download: Uncompressed | Minified | Zipped Demo (2.5Mb - includes all images) | Github

    Setup

    The set up is fairly simple (I hope). The page requires three things to work:
    1. jQuery loaded (you can use Google's copy as seen in the page source).
    2. An <img> anywhere on your page.
    3. Data source consisting of a date range and image url. You can also include optional comments.
    Data Format

    To include an image in this script, you will need the following bits of information:
    • Date (required) - Use the format below
    • Image URL (required)
    • Comment (optional)
    1. Date format (do not include the year):

      Dates
      Description
      0Set image as a default (will only display if no date specific images are found).
      1/1 Dispaly image only on Jan 1st.
      1/1 - 1/5Dispaly image from Jan 1st to Jan 5th (spaces are okay).
      7/20 - 8/20Display image from June 20th to August 20th.
      1/3rdMonDisplay image only on the 3rd Monday of January.
      5/lastMonDisplay image only on the last Monday of May.
      11/3rdThur-11/4thThurDisplay image from the 3rd Thursday of Nov to the 4th Thursday of Nov.
      12/20-1/1stSunDisplay image from Dec 20th to the 1st Sunday of January.

      IMPORTANT NOTES:

      • The dates that cross months (7/20-8/20) will display along with date specific images (added to the randomization).
      • Use slashes "/" to separate the month and day and dashes "-" to set a range (e.g., using "1-1 to 1-5" will break the script)
      • Using the last weekday (lastMon) of the month in the date has one restriction at this time... it'll only works for 30 day months for now. I may fix this in future versions.
      • When using the text in the date (e.g. 1st, 2nd, 3rd, last) don't spell these fully out ( first, second, third) as the script is looking for the number and not the text.
      • The weekday in the date must have at least 3 letters - these are okay: (Mon or Monday); these are not okay (M or Mo).

    2. Image URL - Umm, yeah it's required.

    3. Comment (optional)

      • The image comment will be added to the image title (or not, as desired) or into any HTML tag using an ID or class name.

      • The script is set up so that the comment can include HTML elements to add styling, but be careful to not use quotes. The script does replace quotes with the HTML escape code " but this doesn't guarantee it will work once viewed in the comment div.
    Data Sources
    • This plugin is set up to accept data from a jQuery selector (for data contained in HTML), an array or a JSON variable that is inline or retrieved remotely.
    • There is an example how to accomplish each method below and there is also a demo of each (included in the zipped file).
    • The examples below expect an image with the ID of "todaysImage"
    • All data should be presented to the script in this order: date, url, comment; you can change this order, but it will require additional option settings, described later.
    • There is no need to maintain the exact chronological order of the data. I tried to keep them this way in the demo to make finding dates easier.
    • All script should be wrapped in a $(document).ready function.
    1. HTML

      • The data can be stored in an HTML list. You point your jQuery selector at the list and tell it which attributes have the data.
      • Here is an example list (hidden using CSS):
        <ul id="myImageList">
        <li rel="0" title="images/main1.jpg">Hello</li>
        <li rel="0" title="images/main2.jpg">Hello</li>
        <li rel="12/31-1/5" title="images/new-year.jpg">Happy New Year!</li>
        <li rel="5/1-8/5" title="images/Summer.jpg">Summer time!</li>
        </ul>
        As you see, the list is stored in an <li> tag with the date in the rel attribute, the url in the title attribute and the comment inside the tag. This is how to set the script to gather the data correctly.
        $('#todaysImage').todaysImage({
        data       : $('#myImageList li'),
        dataObject : ['rel', 'title', 'html'] // these must be in this order: [date, url, comment]
        });
        The 'rel' and 'title' parts of the dataObject are attributes of the tag while the comments needs either a 'text' or 'html' to target its data; use 'html' as in the example, if you have included any styling in your comment.

        NOTE: As stated before the order of the dataObject is important - [ date, url, comment ]

    2. ARRAY

      • An array can be set up, as I did in my original script, to contain all of the data needed for this script.
      • Once again, the order these are placed in the array are important, here is a basic template:

        images.push (["DATES","IMAGE URL", "COMMENT"]);

      • Here is an example:
        var images = [];
        images.push(["0","images/main1.jpg","Hello"]);
        images.push(["0","images/main2.jpg","Hello"]);
        images.push(["12/31-1/5","images/new-year.jpg","Happy New Year!"]);
        images.push(["5/1-8/5","images/Summer.jpg","Summer time!"]);
        the script below will access this data. Notice the dataObject option sets the order of the image array. If you already have an array with similar data, all you need to do is set the dataObject to point to the correct index so that this order is maintained [ date, image URL, comments ] (e.g. images.push([ "comment", "other data", "dates", "url' ]), would required the dataObject to be [2, 3, 0]).
        $('#todaysImage').todaysImage({
        data        : images,
        dataObject  : [0,1,2]
        });
    3. JSON - inline

      • I use this method when I have a short list and want to save myself a server call.
      • Take a standard JSON object and just add "var json =" in front of it.
      • If you already have a JSON set up but it has different names (or even a different language) then just adjust the dataObject as needed
      • Here is a basic template:
        var imageList = {"images": [
        {
        "dates"  : "0",
        "image"  : "images/main1.jpg",
        "comment": "Hello"
        },{
        "dates"  : "0",
        "image"  : "images/main2.jpg",
        "comment": "Hello"
        },{
        "dates"  : "12/31-1/5",
        "image"  : "images/new-year.jpg",
        "comment": "Happy New Year!"
        },{
        "dates"  : "5/1-8/5",
        "image"  : "images/Summer.jpg",
        "comment": "Summer time!"
        }
        ]};
        The script below will access this data. Notice that "imageList" matches the variable and "images" matches the very first name in the JSON object (the key). The dataObject by default is [ 'dates', 'image', 'comment' ] which matches the JSON above; but if you have a JSON object that has different key names like "dateRange", "imageURL" and "imageComment", then you will need to set the dataObject appropriately to [ 'dataRange', 'imageURL', 'imageComment' ].
        $('#todaysImage').todaysImage({
        data: imageList.images
        });
    4. JSON - remote

      • Use this method to load JSON from your server. It won't work cross domain (unless you have it setup to work with JSONP)
      • This method requires your JSON to be valid, or the object won't parse properly (this includes removing all comments)
      • This JSON, as stated before, is essentially the same as the JSON inline.
        {"images": [
        {
        "dates"  : "0",
        "image"  : "images/main1.jpg",
        "comment": "Hello"
        },{
        "dates"  : "0",
        "image"  : "images/main2.jpg",
        "comment": "Hello"
        },{
        "dates"  : "12/31-1/5",
        "image"  : "images/new-year.jpg",
        "comment": "Happy New Year!"
        },{
        "dates"  : "5/1-8/5",
        "image"  : "images/Summer.jpg",
        "comment": "Summer time!"
        }
        ]};
        Access this remote JSON data as follows:
        $.getJSON( 'images.json', function(imageList){
        $('#todaysImage').todaysImage({
        data: imageList.images
        })
        })
        The JSON data in the example is from the file "images.json". Replace this with the URL pointing to your data. I used "imageList" as the JSON data to show the similarities to the JSON inline method. Of course "images" is the first element (key) in the JSON object, and the dataObject doesn't need modification as the names in the JSON object match.
    Customizing
    This plugin has the following default options, so you will only need to include the line below if you want to change the default:
    $('#todaysImage').todaysImage({
    data         : '', // dataObject contains the date, image and comment names as seen in the data (names if JSON, numbers [0,1,2] in an array)
    dataObject   : ['dates','image','comment'],
    comment      : '.imageComment', // class or id where the current image comment will be added; if it doesn't exist, no comment will be shown
    noImageTitle : false,           // if true, the script will not add the comment to the image's title attribute
    
    /* language options */
    dayEndings : 'st|nd|rd|th',  // 1st, 2nd, 3rd, 4th, etc. (e.g. 1stMon & 3rdThu)
    dayLast    : 'last',         // last weekday/weekend of the month
    dayWeek    : ['sun','mon','tue','wed','thu','fri','sat'], // days of the week (case insensitive)
    
    /* debugging options */
    locked          : false,// prevent debug mode onscreen output if true (debug setting from browser URL only).
    debug           : false,// set debug mode.
    debugId         : 'imagedebug', // id of the debug output div - all info and show all images will be added here.
    debugElement    : 'body',       // Location where debug id is added (where debugId div is appended)
    defaultDate     : '1/1/2010',   // date used if setting debug mode but no default date.
    inRangeColor    : '#080',       // color highlight (green) for signifying the date is in range.
    notInRangeColor : '#f00'// color highlight (red) for dates not in range.
    })
    OptionDescription
    dataPlease refer to the Data Sources section above on how to set this data
    dataObjectPlease refer to the Data Sources section above on how to set this data
    commentThis option targets the class or Id of an HTML element where you want the current image comment to be displayed, if this target doesn't exist, no comment will be shown
    noImageTitlePrevent the script from adding the comment to the image title. Done if you want to apply a tooltip to the image to display the message
    dayEndingsAbbreviation suffixes for 1st, 2nd, 3rd, 4th, etc. The script actually only uses these to match the date string, but they are ignored otherwise. So if you mistakenly add 4rd, it will use the 4 and not the "rd"
    dayLastString used to match and causes the script to find the last weekday/weekend of the month (e.g. lastMon)
    dayWeekList of days of the week. It is used to match the weekday from the data date, so this is language agnostic, but the first day of the array must start with sunday to match the javascript date method. Limit these names to three letters and the letter case doesn't matter.
    monthFirstSet to true (default) to use standard US date formatting - mm/dd/yyyy. If set to false, the European date format can be used - dd/mm/yyyy.
    lockedLocks out using the debug mode from the browser address bar (adding "#debug" to the url will enable debug mode if the script isn't locked, like my demo)
    debugEnable debug mode through the script. This value is set to true if the script is not locked and "#debug" is added to the url. This mode will display image data to show matches found and date ranges. For more detail, see the troubleshooting section below
    debugIdThis is the Id of the element to find to output the debug data. If it doesn't exist and debug mode is initiated, a div with this Id will be added to the debugElement (see below) which by default is the document body. If using the showAll() method above, this element will need to me manually added before images will be displayed.
    debugElementBy default, the debug element is the document body. This is where the debugId div is appended, if it doesn't exist, when debug mode is initiated.
    defaultDateThis date is only used if the debug mode is initiated by the script and no other date is supplied. The default date for the debug mode when adding it to the url would be the current date unless otherwise specified - see the troubleshooting section below for more details
    inRangeColorText color applied to the debug text when an image date is in range (green by default)
    notInRangeColorText color applied to the debug text when an image date is not in range (red by default)

    Methods
    You can get, set, find current number or have the script choose another random image as follows:
    • Get current image data

      • Use the "currentImage()" method to get this data.
      • This method will return an array of the currently displayed image's date, url and comment (in that order).
      • The second line was added to show how to target the image url.
      var current = $(image).data('todaysImage').currentImage(); // returns array ['dates','image url','comment']
      alert( 'current image url = ' + current[1] );
    • Set/Get current image

      • Add a number to the "currentImage()" method to set the image. An array of the image is returned (as above).
      • Setting a number that is greater than the number of images in the date range will cause the image to wrap around back to the beginning
      // Sets displayed image to the first (zero based index) image that falls within the date range,
      // then returns array ['dates','image url','comment'] of that image
      var current = $(image).data('todaysImage').currentImage(1);
    • Get current number of images

      • Use the "currentNumber()" method to get this information.
      • This value is the number of images with a date range that covered the date (e.g. if the date is 12/24, the demo script will find 8 images from which to choose)
      // return the number of images that have date ranges that match the date
      var currentNumber = $(image).data('todaysImage').currentNumber(); // returns a number
    • Random Image

      • Use the "randomImage()" method to display another random image.
      • This method will return an array of the currently displayed image's date, url and comment (in that order).
        $(image).data('todaysImage').randomImage(); // displays a random image in the date range & returns array
    • Show All Images

      • This method is used by in edit mode when clicking on the "Show All Images" button. It is useful for checking that all the image urls are correct and all the data is valid.
      // Show all images in the data, the script targets the id found in "debugId" option
      $(image).data('todaysImage').showAll();
      • This method will not work if the element targeted by the "debugId" option doesn't exist. By default, the "debugId" is "imagedebug" which is added while the script is in debug mode. But if you want to display a list somewhere else, just make sure the target exists (Id only, no class) and change the "debugId" option to match it.
        CSS
        #allImages img { height: 100px; width: 100px; } /* make images thumbnail size */
        HTML
        <div id="allImages"></div>
        Script
        // initialization of script
        $('#todaysImage').todaysImage(
        // other options here, including data source
        debugId : 'allImages'
        });
      Troubleshooting
      • If you are noticing that one image isn't showing up or something just doesn't work right, you can try to trouble shoot the problem.
      • Initiate the debug mode in the script as follows:
        // initialization of script
        $('#todaysImage').todaysImage(
        // other options here, including data source
        debug: true,
        defaultDate: '12/24/2010' // choose any date using this format
        });
      • Additionally, you can access the debug mode from the address bar simply by adding the following (in blue) to the end:

        http://myurl.com/randomImage.htm#debug:12/31/2009

        • #debug - actives the debug mode
        • 12/31/2009 - sets the date you want to check (month/day/year)

        To prevent debug from working once you are done with your script, simply set the locked variable in the script to true:
        // initialization of script
        $('#todaysImage').todaysImage(
        // other options here, including data source
        // locks out debug mode from the URL
        locked: true
        });
      • Sample debug output:
        Date used: 11/20/2009
        (11/11), derived range: 11-11 is NOT in range; image = veterans1.jpg
        (11/11), derived range: 11-11 is NOT in range; image = veterans2.jpg
        (11/11), derived range: 11-11 is NOT in range; image = veterans3.jpg
        (11/3rdThur-11/4thThur), derived range: 19-26 is in range; image = thanksgiving1.jpg
        (11/3rdThur-11/4thThur), derived range: 19-26 is in range; image = thanksgiving2.jpg
        (11/3rdThur-11/4thThur), derived range: 19-26 is in range; image = thanksgiving3.jpg
        (11/3rdThur-11/4thThur), derived range: 19-26 is in range; image = thanksgiving4.jpg

        # of currentImages = 4
        current random image = thanksgiving4.jpg
      • Try out these links to see the debug mode in action (my example script isn't locked):

        1. #debug:1.1.2010
        2. #debug:10/31/2009
        3. #debug - This will default to todays date, but edit mode is active

    Wednesday, June 30, 2010

    ImageHighlighter v1.01

    ImageHighlighter is an updated version of my original imgHighLighter plugin with lot of improvements! Most are under the hood so you probably won't see too much of a difference on the surface.

    This plugin allows you to highlight a portion of an image when you hover over a link. In the image below, the mouse is hovering over the different links and you can see the corresponding portion of the image becomes highlighted (there is an animate gif below, but just click on the image to go to the demo page).
    I set up an demo page here.

    Download: Uncompressed | Minified | Zipped Demo | Github

    I have tested this plugin in IE8, Firefox and Chrome. Please leave me feedback if you any problems with how it works or if it doesn't work in other browsers.

    7/6/2010: Updated this post to describe v1.01 where the editor portion of the script was moved into a plugin extension. And support for jCrop was added to allow selecting the entire box instead of just getting the mouse coordinates. Check out the updated demo page!

    Setup
    • This plugin requires jQuery.
    • HoverIntent is an optional plugin, this plugin will use it's functionality if it is included.
    • Follow this basic template with a quick summary for each image you want to apply imageHighlighter functionality. For more details, go to the specific section.

      HTML
      <div>
      <ul class="imgHL">
      <li>
      <a href="#" rel="sx1,sy1,ex2,ey2">Item #1</a>
      <p>Description for item #1</p>
      </li>
      <li>
      <a href="#" rel="sx1,sy1,ex2,ey2">Item #2</a>
      <p>Description for item #2</p>
      </li>
      <li>
      <a href="#" rel="sx1,sy1,ex2,ey2">Item #3</a>
      <p>Description for item #3</p>
      </li>
      </ul>
      <br>
      <img id="imgHL" src="myimage.jpg" alt="" />
      <div class="description"></div>
      </div>
      • In the HTML above, the highlight links are all wrapped in a div with a class name "imgHL" to make them easier to target.
      • The highlight links (<a>) must contain a rel attribute with the highlight box coordinates (see the Highlights section below for more detail).
      • Each link/description pair is wrapped together (inside an <li> in this case). See the Descriptions section below for more details.
      • The image is the central element. Once the script is initialized, the image will contain all of the plugin information. It is also the target of both the imageHighlighter and imageHighlighterEditor scripts.
      • The highlight description will be placed into the div with class "description". You can target a different class/Id when you modify the script options.

      CSS (basic example)
      /* List link: currently hovered/selected */
      a.current { color: #fff; }
      
      /* Hide & Position Descriptions */
      .imgHL p { display: none; }
      .description { margin: 1em auto; clear: both; width: 450px; height: 2.4em; }
      
      /* General imageHighlighter (overlay and highlight) */
      .imageHighlighter, .imgHLDark, .imgHLLight, .imgHLOverlay { padding: 0; margin: 0; } /* overlay and highlight divs */
      .imgHLOverlay { background: #000; opacity: .5; filter: alpha(opacity=50); } /* overlay color & opacity *
      • When a link is hovered and the image reveals the highlight box, the class "current" is applied to the link. You can use this to style the link and make it stand out.
      • The css definition ".imgHL p" hides the descriptions that appear under the image (in this example). The description is moved into the ".description" element when the highlight link is hovered.
      • The description class can be placed anywhere on the page; but because of this, the class name ".description" must be unique for each imageHighlighter instance on the page. You can easily modify this class name using the plugin options.
      • The general imageHighlighter definitions apply to the div wrapping the image (.imageHighlighter), the overlay (.imgHLOverlay & .imgHLDark) and the highlighted box (.imgHLLight). As you can see, the overlay has a background color and 50% opacity to darken the image behind the highlight. This can be set to transparent here in the CSS or disabled using the script.

      Javascript
      /* window load ensures all images are loaded */
      $(window).load(function(){
      $('#imgHL').imageHighlighter({
      list : '.imgHL a'
      });
      })
      • This script uses "window.load" instead of "document.ready" to ensure that all images have been loaded. This is necessary as the script needs the image dimensions in order to initialize properly.
      • In this basic example, the highlight links are targeted using the ".imgHL" div that wraps the entire list. The default list setting is "a" which is much too general to use, but the script will ignore any link that doesn't contain a rel tag.
      • There are more options that can be set. For a full list and detailed descriptions, look under the customizing/options section!

    • Highlights: The highlight link's "rel" attribute contains all the information needed for the highlights.
      rel="sx1,sy1,ex2,ey2"
      sx1Starting X position of the highlight box } top left corner
      sy1Starting Y position of the highlight box
      ex2 Ending X position of the highlight box} bottom right corner
      ey2Ending Y position of the highlight box
      You can change the highlight properties of each image using: borderColor, borderSize & borderType described in the Customizing/Options section below.

    • Image: The image must be targeted when initializing the script. You could target the class ('.imgHL') in the example above and the script will initialize once it has found the image from that group of selections. The image contains all of the data associated with this plugin, from using the built in methods to targeting custom events.
      $("#imgHL").imageHighlighter();
    • Descriptions: Each link/description pair should be wrapped together. In the demo where the links are in a paragraph, the link/description pairs are wrapped in a span:
      <span><a rel="sx1,sy1,ex2,ey2">Item #1</a><span class="desc">Description for Item #1</span></span>
      In the other example, the pair are wrapped inside of a list (<li>). Make sure that the descriptions are hidden and targeted by the "descrip" plugin option. The script will look inside the link highlight wrapper, so you don't necessarily have to have a specific class assigned to it as long as the element is unique (e.g. don't have two <p>'s inside with the highlight link otherwise the contents of both will be displayed in the description.

      The second part of the description is set using the "descripClass". The descriptions for the highlight will appear inside an element with this class, when hovering over a link. It can be located anywhere on the page, but the class/id needs to be set in the plugin options and unique for each instance of the plugin.

    • Overlay: The overlay covers the image (darkens the background) to make the highlighted portion stand out more. You can adjust the opacity of this overlay in the CSS and you can turn off the overlay functi0nality by setting the overlay option to false.
    Customizing / Options
    This plugin has the following default options, so you will only need to include the line below if you want to change the default:
    $("#imgHL").imageHighlighter({
    borderColor : "#fff",         // highlight border color
    borderSize  : 4,              // highlight border thickness
    borderType  : "solid",        // highlight border type
    list        : "a",            // links that contain the highlight coordinates (e.g. "li.imgHL a")
    descrip     : "p",            // HTML tag sibling of the link, that contains the description text (hidden) (e.g. "p.desc")
    descripClass: ".description", // HTML tag where description text is shown (placeholder)
    overlay     : true,           // display an overlay to make the highlight stand out
    current     : "current",      // class applied to link currently used to highlight the image
    hoverTimeout: 100,            // hoverIntent timeout (only applied if hoverIntent plugin is loaded)
    zindex      : 10              // z-index of highlight box, overlay is automatically made 1 less than this number
    })
    
    Methods
    You can use the following methods to get and set the highlighted content. Note that these methods must target the image.
    • Get: In the following example, the variable current will contain the current link object that has been highlighted. If nothing is currently highlighted, the script will return null.
      var $current = $('#imgHL').data('imageHighlighter').highlight();
    • Set/Get:
    • Use a number (indexed from one: first, second, etc) - if the nth link doesn't exist, it will return null.
      var $current = $('#imgHL').data('imageHighlighter').highlight(1); // select the first link
    • Search for the case-sensitive text within the link (uses the jQuery ":contains()" selector) - if the text is not found, the script will return null.
      var $current = $('#imgHL').data('imageHighlighter').highlight("frames");
    • Search for the link with a class or ID - if the selector is not found, the script will return null.
      var $current = $('#imgHL').data('imageHighlighter').highlight(".box");
    Edit Mode
    • Updated in v1.01:
      • The edit mode script was moved into an extension for the plugin. This was done because the edit script is not required once the coordinates are obtained and the script is deployed on your site.
      • Additionally, the script was made to work with the Jcrop plugin (included with the demo file zip) allowing you to use a resizable selection box to more easily get the coordinates.
      • If you click on the coordinates, the coordinates (contained in an input tag) become selected, so you can more easily copy them.

    • Edit mode for this plugin should make it easier to obtain the coordinates of the highlight box - the coordinates added to the highlight link rel attribute.

    • As of v1.01, edit mode can be activated by:

      1. Including the imageHighlighterEditor script & the jCrop plugin script, if desired.
      2. Set up the editor by calling the script on the same image(s) as the imageHighlighter script. You can generalize the call by targeting the ".imageHighlighter" class (applied to a div that wraps the image after the imageHighlighter script is applied to it). There is only one options, seen below:
        // Enable the editor and use the Jcrop plugin, if it is available
        $('div.imageHighlighter img').imageHighlighterEditor();
        
        // Enable the editor, but don't use the Jcrop plugin (even if it has been loaded)
        $('div.imageHighlighter img').imageHighlighterEditor({ useJcrop: false });
      3. Now activate or deactivate edit mode by double clicking on the image. A green bar (styled in the CSS) will appear below the image which will show the mouse coordinates (default editor) or the box coordinates (Jcrop plugin added).

    • With the editor active:

      • Default editor - move the cursor over the image to find the coordinates. Then clicking on the image will lock the coordinate display and make copying these numbers easier.
        Mouse x,y coordinates (click to lock/unlock) : x,y
      • Jcrop plugin installed - single click anywhere on the image to make the a corner of the box, then drag your mouse any direction to create a resizeable box. The coordinates of the upper left and bottom right corners of the box will display under the image:
        Current box coordinates : x1,y1,x2,y2
      • Click on the coordinates (they are inside an input tag). The contents will automatically be selected, but not copied.
      • When you hover over a highlight link, the highlight link name and coordinates from that link is displayed above the coordinate bar.
    Bugs / Suggestions
    • When the window is repositioned, the highlights may be off until it is refreshed again when you hover over a link (especially while in edit mode), and sometimes you'll need to reload the page.
    • To make suggestions or report any bugs please email me at wowmotty at g mail dot com.