
// -------------------------------------------------------------------
// Image Thumbnail Viewer II- By Dynamic Drive
// Last updated: Oct 14th, 2008 - this Notice Must Remain for Legal Use
// update ©2008 John Davenport Scheuer - as first seen in http://www.dynamicdrive.com/forums/
// username: jscheuer1 - source code (for some version) avaiable at: http://www.dynamicdrive.com/
// -------------------------------------------------------------------

var thumbnailviewer2 = {

 enableTitle : true, //Should "title" attribute of link and any paired image's 3rd parameter to be used as caption?
 hideImgMouseOut : false, //Hide enlarged image when mouse moves out of anchor link? (if enlarged image is hyperlinked, always set to false!)
 disableOnClick : true, //Disable default onclick for mouseover triggers?
 populateWithFirst : true, //Fire first link in load area group(s)?
 enablePaging : false, //Allow for "Next", "Previous", "Start", and/or "End" links and/or other elements for each primary load area id?
 enableTransition : false, //Enable GradientWipe transition in IE 6+? (if true & not IE, a fade transition will be attempted)

// For All Six options, use global true/false or an object containing individual primary load area id(s) (from rev attributes)
// Examples of using objects:
/*

 hideImgMouseOut : {loadarea2 : true}, // which would hide onmouseout only for loadarea2

 or:

 hideImgMouseOut : {loadare : true, loadarea2 : true}, // which would hide onmouseout only for loadarea and loadarea2

*/

// objects may be used for all six configuration items, when using objects, any loadarea not mentioned defaults to false for that option

       ///////////// Stop Editing /////////////

 pagingTitles : ['Next', 'Previous', 'Start', 'End'], //array of allowed titles for paging elements
 iefiltercapable : false, //property to hold result of tests for IE proprietary filter support
 fadecapable : false, //property to hold result of test for generic style opacity (fade) support
 preloadedimages : [], //array to hold preloaded enlarged images
 paginate : {}, //object to hold pagination class/id names
 boolObj : function (v, p){return v === true || typeof v == 'object' && typeof v[p] != 'undefined' && v[p];}, //returns true if fed a precise boolean true or an object with a 'truthy' property p

 testforfilters : function(){
  /*@cc_on @*/
  /*@if(@_jscript_version >= 5)
  if(this.enableTransition && navigator.appVersion.replace(/^.*MSIE (\d).*$/, '$1') >= 6)
   try {
    this.iefiltercapable = document.documentElement.filters;
    this.iefilterstring = 'progid:DXImageTransform.Microsoft.GradientWipe(GradientSize=1.0 Duration=0.7)'; //IE 6+ specific multimedia filter string
   } catch(e){this.iefiltercapable = null};
  else this.iefiltercapable = null;
  @end @*/
  if(this.enableTransition && this.iefiltercapable === false && typeof document.documentElement.style.opacity == 'string')
  this.fadecapable = true;
 },

 populate : function(t, ext){ //parse the attribute values of a trigger for populating its load area(s)
  var s = t.rel.split('::'), p = t.rev.split('::')[0], tbn = thumbnailviewer2;
  ext? (s.splice? s.splice(0, 2) : (function(){s.reverse(); s.length -= 2; s.reverse();})()) : s = t.rev.split('::');
  var l = document.getElementById(s[0]), a = null, n = ext? 3 : 1, f,
  tran = tbn.boolObj(tbn.enableTransition, p), hide = tbn.boolObj(tbn.hideImgMouseOut, p),
  trancapable = tbn.fadecapable || tbn.iefiltercapable, i = document.createElement('img'),
  emptyLoadArea = function(){
   while (l.lastChild) l.removeChild(l.lastChild);
   if(trancapable && hide && tran)
    l.style.background = '';
  };
  i.style.border = 'none';
  i.style.visibility = 'hidden';

  if (!ext && /mouseover/.test(t.rel) && tbn.boolObj(tbn.disableOnClick, p)) //kill onclick event for mouseover triggers if so confgured
   if (!t.onclick || !t.onclick.killed$for$thumbnailviewer2) {
    t.onclick = function(){return false;};
    t.onclick.killed$for$thumbnailviewer2 = true;
  };

  tbn.boolAdd(hide, t, 'mouseout', emptyLoadArea, ext);

  if (trancapable && tran){ //Is this an IE browser that supports filters or a browser that fades & is this feature enabled?
   if (document.getElementById('ie_w$u234' + s[0]))
    l.style.background = 'url(' + document.getElementById('ie_w$u234' + s[0]).src + ') no-repeat 0 0';
   i.id = 'ie_w$u234' + s[0];
   tbn.iefiltercapable? i.style.filter = tbn.iefilterstring : i.style.opacity = 0;
  };
  
  tbn.boolAdd(true , i, 'load', function(){ //When enlarged image has completely loaded
   i.style.visibility = '';
   if(tran && tbn.iefiltercapable) i.filters[0].Play();
   else if (tran && trancapable) tbn.fadein(i);
   //if title enabled as caption & a caption (as title attribute, or if this is a 2nd paired image, as a value) is available
   if(tbn.boolObj(tbn.enableTitle, p) && ((ext && s[2] && s[2] != '') || (!ext && t.title && t.title != ''))){
    var br = document.createElement('br');
    l.appendChild(br);
    l.appendChild(document.createTextNode(ext? s[2] : t.title));
   };
  }, false, true);

  tbn.boolAdd(true , i, 'error', function(){ //If an error has occurred while loading the image to show
   i.style.visibility = '';
   if(tran && tbn.iefiltercapable) i.filters[0].Stop();
   else if(tran && trancapable) i.style.opacity = 1;
  }, false, true);

  emptyLoadArea();

  if (s[n]){ //if there is a link for the larger image
   a = document.createElement('a');
   a.href = s[n];
   if (s[n + 1] || s[n + 2]){ //if link is targeted and/or perhaps has other specifications
    f = function(e){
     var win = window.open(s[n], s[n + 1], s[n + 2] || '');
     if(s[n + 3])
      win.focus();
     if(e && e.preventDefault)
      e.preventDefault();
     return false;
    };
    tbn.boolAdd(true, a, 'click', f, false, true);
   };
   l.appendChild(a);
   };

  (a || l).appendChild(i);
   if (tran && tbn.iefiltercapable) i.filters[0].Apply();
   i.src = ext? s[1] : t.href;

  if(!ext && t.rel.split('::').length > 3) //if this is a trigger with paired load areas & larger images,
   tbn.populate(t, 1) //and it's second one hasn't been processed yet, go again with the second one
 },

 fadein : function(i){ //generic opacity fade in
  if(i.style.opacity < 0.99){
   var tbn = thumbnailviewer2;
   i.style.opacity = parseFloat(i.style.opacity) + 0.03;
   setTimeout(function(){tbn.fadein(i);}, 30);
  } else i.style.opacity = 0.9999;
 },

 clickOver : function(e){ //front end to determine what to do with onmouseover & onclick events
  e = e || window.event; thumbnailviewer2.preload(e); //preload any larger images added since page load or last event
  var t = e.target || e.srcElement || null, re = null, k = e.type || null, tbn = thumbnailviewer2;

  if(t && k){ //if we have an event target and an event type
   if(tbn.boolObj(tbn.enablePaging, t.className) && k == 'click' && //if this is a click on an allowed paging link
   (tbn.paginate[t.className] || (t.parentNode && tbn.paginate[t.parentNode.className])))
    return tbn.page(e, t);
   re = new RegExp('^enlargeimage::' + k) //otherwise, set regExp to help define it as a trigger
   t = t.rel && re.test(t.rel)? t : t.parentNode? t.parentNode : null;
  };

  if(!t || !k || !t.rel || !re || !re.test(t.rel)) //if true, we have no trigger or a trigger unrelated to this script
   return undefined;

  tbn.populate(t); //if we've gotten this far, get to work displaying the larger image

  if(k == 'click'){ //if a valid click trigger was clicked, don't execute the href of the trigger
   if(e.preventDefault)
    e.preventDefault();
   return false;
  }; return undefined; //otherwise let other code or default behavior decide what to do about a click
 },

 page : function(e, t){ //parse paging ("Next", "Previous", "Start", or "End") elements
  var tbn = thumbnailviewer2, pt = tbn.pagingTitles;
  t = tbn.paginate[t.className]? t : t.parentNode;
  if(!new RegExp('^(' + pt.join(')|(') + ')$').test(t.title)){ //error alert for erroneously classed elements conflicting with paging
   alert('"' + t.className + '" classed elements are reserved for Thumbnail II Viewer pagination\n' +
   'and require a title attribute of "' + pt[0] + '", "' + pt[1] + '", "' + pt[2] + '", or "' + pt[3] + '".');
   return undefined;
  };
  t = [t.className, t.title]; //break element into its relevant attributes as an array
  for(var c = 0, el = document.getElementById(t[0]), a = document.getElementsByTagName('a'), imt = [], i = 0; i < a.length; ++i)
   if(a[i].rev.split('::')[0] == t[0]){ //if element is classed as a paging link for a load area
    if(el.getElementsByTagName('img')[0] && el.getElementsByTagName('img')[0].src == a[i].href)
     c = imt.length; //with above line gets current image trigger number from this group or remains 0 if none
    imt[imt.length] = a[i]; //collecting an array of triggers for this load area
   };
  c = t[1] == pt[3]? imt.length - 1 : !el.getElementsByTagName('img')[0]? 0 : t[1] == pt[0]? c + 1 : t[1] == pt[1]? c - 1 : 0;
  c = c < 0? c + imt.length : c >= imt.length? c - imt.length : c; //with above line determine which trigger for this load area is wanted
  tbn.populate(imt[c]); //and fire it
  if(e && e.preventDefault) //with below two lines, since all paging is done onclick, stop the default click behavior (if any) of the element
   e.preventDefault();
  return false;
 },

 attachfocus : function (el, f){ //helper function for attachEvent onfocus in IE which require 'this' keyword to refer to focused link
  var t = function(){return f.apply(el)};
  el.attachEvent('onfocus', t);
 },

 boolAdd : function (b, el, k, f, ext, i){ //thumbnailviewer2's addEventListener/attachEvent engine
  if(b){
   if(!i && !el['on' + k]) el['on' + k] = function(){return;};
   if(i || !el['on' + k]['altered$for$thumbnailviewer2' + (ext? 'ext' : '')]){
    if(el.addEventListener)
     el.addEventListener(k, f, false);
    else if(el.attachEvent)
     k == 'focus'? this.attachfocus(el, f) : el.attachEvent('on' + k, f);
    if(!i) el['on' + k]['altered$for$thumbnailviewer2' + (ext? 'ext' : '')] = true;
   };
  };
 },

 preload : function(e){ //runs onload and on all other significant events for this script to set/upgrade preloads and element event observation
  e = e || window.event; var k = e.type;
  if(k == 'keydown' && (window.opera? !/^9|(16)$/.test(e.keyCode) : e.keyCode != 9)) return; //if keydown & not a relevant key
  var a = document.getElementsByTagName('a'), tbn = thumbnailviewer2, load = k == 'load';
  if(load){ //set initial values that either need not change, or that need not change unless event is not onload
   tbn.testforfilters();
   var loadit = true, eloadit = true;
  };
  for (var rel, f, c = tbn.preloadedimages.length, i = a.length - 1; i > -1; --i)
   if(/^enlargeimage/.test(a[i].rel)){
    tbn.paginate[a[i].rev.split('::')[0]] = true; //populate paginate object should it be needed for paging or other uses
    tbn.boolAdd(/^enlargeimage::mouseover/.test(a[i].rel), a[i], 'focus', function(){tbn.populate(this);}); //add onfocus to mouseover triggers
    if(!load) //if not onload, before adding a preload, make sure it hasn't already been preloaded
     for(var loadit = true, eloadit = true, j = 0; j < c; ++j){
      if(a[i].href == tbn.preloadedimages[j].src)
       loadit = false;
      if(a[i].rel.split('::').length > 3 && a[i].rel.split('::')[3] == tbn.preloadedimages[j].src)
       eloadit = false;
     };
    if(loadit){ //if onload, or this image hasn't been preloaded
     tbn.preloadedimages[c] = new Image();
     tbn.preloadedimages[c++].src = a[i].href;
    };
    if(a[i].rel.split('::').length > 3 && eloadit){ //if there is a paired image & the event is onload, or it hasn't been preloaded
     rel = a[i].rel.split('::');
     tbn.preloadedimages[c] = new Image();
     tbn.preloadedimages[c].src = rel[3];
     rel[3] = tbn.preloadedimages[c++].src;
     a[i].rel = rel.join('::'); //with above line, set actual image URI back to the rel attribute for possible future testing
    };
   };
  if(tbn.populateWithFirst && load) //if any or all load areas are configured to populate onload
   for(var p in tbn.paginate)
    if(tbn.boolObj(tbn.populateWithFirst, p)) //if all or this load area so configured
     for(var i = 0; i < a.length; ++i) //find its first trigger & execute it
      if(p == a[i].rev.split('::')[0]){
       tbn.populate(a[i]);
       break; //and stop looking
      };
 },
 
 init : function(){ //attach/add all relevant event observations only if they haven't already been attached/added
  var e = [['load', 'preload'], ['keydown', 'preload'], ['mouseover', 'clickOver'], ['click', 'clickOver']];
  for (var i = e.length - 1; i > -1; --i)
   this.boolAdd(!this.init.run, (i? document : window), e[i][0], this[e[i][1]], false, true);
  this.init.run = true;
 }
};

thumbnailviewer2.init();