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

10 comments:

  1. Excellent script. I had to re-read everything several times to understand it correctly. :)

    A quick question; we have in Holland several holidays which aren't on fixed dates. For example Eastern and some other national holidays. I figured out the correct dates for each year, but is there a way to implent them by year?

    For example:

    pasen:
    8 april 2012
    31 maart 2013
    20 april 2014
    5 april 2015
    27 maart 2016
    16 april 2017


    pinksteren:
    27 mei 2012
    19 mei 2013
    8 juni 2014
    24 mei 2015
    15 mei 2016
    4 juni 2017

    goede vrijdag:
    6 april 2012
    29 maart 2013
    18 april 2014
    3 april 2015
    25 maart 2016
    14 april 2017

    hemelvaartsdag:
    17 mei 2012
    9 mei 2013
    29 mei 2014
    14 mei 2015
    5 mei 2016
    25 mei 2017

    Is it possible to add those by the appropiate year?

    Let me know, thanks. And keep up the good work!

    Regards

    ReplyDelete
  2. Hi De Elektrische Auto!

    Hmm, wow interesting, I never knew! Sadly, the current version doesn't allow you to enter a year, but I'll put it on my to do list and hopefully get an update out there before the new year

    Thanks for sharing!
    Rob

    ReplyDelete
  3. Thanks for the quick answer. Just thought you might wanted to know. Would be a great option. I am using it for my browser startpage. So if I could add years (as an option) for certain dates, it would only needed to be set once and don't look back. :)

    Thanks though.

    ReplyDelete
  4. Hi De Elektrische Auto!

    The plugin has been updated to allow specific dates. Get the latest version from github. Merry Christmas!

    ReplyDelete
  5. Wow! Great man. Highly appreciated. Didn't expect it this fast, but a very welcome Christmas gift! :)

    And you also Merry Christmas!

    ReplyDelete
  6. First the best wishes for 2012!

    Finally got the time to restart using your script, however I have replaced the .js files with the new ones and now images don't show up anymore.

    If I understand correctly; if you don't set a date, an image will appear every year on that particular date, correct?

    If I set images for a specific date on 2012, it will only appear on that specific date AND year, right?

    Maybe I am doing it wrong; but replacing the .js files, was the only thing I needed to do right?

    ReplyDelete
  7. Nevermind, I think I understand now. You now have always to set the year. Even it specific events (like Christmas) are always on the same date.

    So instead of:

    {"dates" : "28/12-4/1", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},

    You know do:

    {"dates" : "28/12/2011-4/1/2012", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},
    {"dates" : "28/12/2012-4/1/2013", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},
    {"dates" : "28/12/2013-4/1/2014", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},
    {"dates" : "28/12/2014-4/1/2015", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},
    {"dates" : "28/12/2015-4/1/2016", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},
    {"dates" : "28/12/2016-4/1/2017", "image" : "afbeeldingen/startpagina-oudennieuw.png", "comment": ""},

    Right?

    ReplyDelete
  8. Hiya!

    No you shouldn't have to set the year for repeated events, unless I messed something up =/.

    Including a year will make the event only occur that one time. Are you sure the "monthFirst" option is set to false for the date format you are using?

    ReplyDelete
  9. Oh okay... So it should work. :S

    monthFirst : false // This "EU" version uses the European date format: dd/mm/yyyy

    Yes it's set to false.

    ReplyDelete
  10. Nevermind you are right, it is broken... could we continue this discussion via email instead of in comments? Email me on my gmail account with user name wowmotty. Thanks!

    ReplyDelete

Note: Only a member of this blog may post a comment.