]> mj.ucw.cz Git - gallery.git/blob - gal/highslide/highslide-with-gallery.js
UCW::Gallery::Web::Highslide: Image pages do not include JS
[gallery.git] / gal / highslide / highslide-with-gallery.js
1 /** 
2  * Name:    Highslide JS
3  * Version: 4.1.13 (2011-10-06)
4  * Config:  default +slideshow +positioning +transitions +viewport +thumbstrip
5  * Author:  Torstein Hønsi
6  * Support: www.highslide.com/support
7  * License: www.highslide.com/#license
8  */
9 if (!hs) { var hs = {
10 // Language strings
11 lang : {
12         cssDirection: 'ltr',
13         loadingText : 'Loading...',
14         loadingTitle : 'Click to cancel',
15         focusTitle : 'Click to bring to front',
16         fullExpandTitle : 'Expand to actual size (f)',
17         creditsText : 'Powered by <i>Highslide JS</i>',
18         creditsTitle : 'Go to the Highslide JS homepage',
19         previousText : 'Previous',
20         nextText : 'Next', 
21         moveText : 'Move',
22         closeText : 'Close', 
23         closeTitle : 'Close (esc)', 
24         resizeTitle : 'Resize',
25         playText : 'Play',
26         playTitle : 'Play slideshow (spacebar)',
27         pauseText : 'Pause',
28         pauseTitle : 'Pause slideshow (spacebar)',
29         previousTitle : 'Previous (arrow left)',
30         nextTitle : 'Next (arrow right)',
31         moveTitle : 'Move',
32         fullExpandText : '1:1',
33         number: 'Image %1 of %2',
34         restoreTitle : 'Click to close image, click and drag to move. Use arrow keys for next and previous.'
35 },
36 // See http://highslide.com/ref for examples of settings  
37 graphicsDir : 'highslide/graphics/',
38 expandCursor : 'zoomin.cur', // null disables
39 restoreCursor : 'zoomout.cur', // null disables
40 expandDuration : 250, // milliseconds
41 restoreDuration : 250,
42 marginLeft : 15,
43 marginRight : 15,
44 marginTop : 15,
45 marginBottom : 15,
46 zIndexCounter : 1001, // adjust to other absolutely positioned elements
47 loadingOpacity : 0.75,
48 allowMultipleInstances: true,
49 numberOfImagesToPreload : 5,
50 outlineWhileAnimating : 2, // 0 = never, 1 = always, 2 = HTML only 
51 outlineStartOffset : 3, // ends at 10
52 padToMinWidth : false, // pad the popup width to make room for wide caption
53 fullExpandPosition : 'bottom right',
54 fullExpandOpacity : 1,
55 showCredits : true, // you can set this to false if you want
56 creditsHref : 'http://highslide.com/',
57 creditsTarget : '_self',
58 enableKeyListener : true,
59 openerTagNames : ['a'], // Add more to allow slideshow indexing
60 transitions : [],
61 transitionDuration: 250,
62 dimmingOpacity: 0, // Lightbox style dimming background
63 dimmingDuration: 50, // 0 for instant dimming
64
65 anchor : 'auto', // where the image expands from
66 align : 'auto', // position in the client (overrides anchor)
67 targetX: null, // the id of a target element
68 targetY: null,
69 dragByHeading: true,
70 minWidth: 200,
71 minHeight: 200,
72 allowSizeReduction: true, // allow the image to reduce to fit client size. If false, this overrides minWidth and minHeight
73 outlineType : 'drop-shadow', // set null to disable outlines
74 skin : {
75         controls:
76                 '<div class="highslide-controls"><ul>'+
77                         '<li class="highslide-previous">'+
78                                 '<a href="#" title="{hs.lang.previousTitle}">'+
79                                 '<span>{hs.lang.previousText}</span></a>'+
80                         '</li>'+
81                         '<li class="highslide-play">'+
82                                 '<a href="#" title="{hs.lang.playTitle}">'+
83                                 '<span>{hs.lang.playText}</span></a>'+
84                         '</li>'+
85                         '<li class="highslide-pause">'+
86                                 '<a href="#" title="{hs.lang.pauseTitle}">'+
87                                 '<span>{hs.lang.pauseText}</span></a>'+
88                         '</li>'+
89                         '<li class="highslide-next">'+
90                                 '<a href="#" title="{hs.lang.nextTitle}">'+
91                                 '<span>{hs.lang.nextText}</span></a>'+
92                         '</li>'+
93                         '<li class="highslide-move">'+
94                                 '<a href="#" title="{hs.lang.moveTitle}">'+
95                                 '<span>{hs.lang.moveText}</span></a>'+
96                         '</li>'+
97                         '<li class="highslide-full-expand">'+
98                                 '<a href="#" title="{hs.lang.fullExpandTitle}">'+
99                                 '<span>{hs.lang.fullExpandText}</span></a>'+
100                         '</li>'+
101                         '<li class="highslide-close">'+
102                                 '<a href="#" title="{hs.lang.closeTitle}" >'+
103                                 '<span>{hs.lang.closeText}</span></a>'+
104                         '</li>'+
105                 '</ul></div>'
106 },
107 // END OF YOUR SETTINGS
108
109
110 // declare internal properties
111 preloadTheseImages : [],
112 continuePreloading: true,
113 expanders : [],
114 overrides : [
115         'allowSizeReduction',
116         'useBox',
117         'anchor',
118         'align',
119         'targetX',
120         'targetY',
121         'outlineType',
122         'outlineWhileAnimating',
123         'captionId',
124         'captionText',
125         'captionEval',
126         'captionOverlay',
127         'headingId',
128         'headingText',
129         'headingEval',
130         'headingOverlay',
131         'creditsPosition',
132         'dragByHeading',
133         'autoplay',
134         'numberPosition',
135         'transitions',
136         'dimmingOpacity',
137         
138         'width',
139         'height',
140         
141         'wrapperClassName',
142         'minWidth',
143         'minHeight',
144         'maxWidth',
145         'maxHeight',
146         'pageOrigin',
147         'slideshowGroup',
148         'easing',
149         'easingClose',
150         'fadeInOut',
151         'src'
152 ],
153 overlays : [],
154 idCounter : 0,
155 oPos : {
156         x: ['leftpanel', 'left', 'center', 'right', 'rightpanel'],
157         y: ['above', 'top', 'middle', 'bottom', 'below']
158 },
159 mouse: {},
160 headingOverlay: {},
161 captionOverlay: {},
162 timers : [],
163
164 slideshows : [],
165
166 pendingOutlines : {},
167 clones : {},
168 onReady: [],
169 uaVersion: /Trident\/4\.0/.test(navigator.userAgent) ? 8 :
170         parseFloat((navigator.userAgent.toLowerCase().match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]),
171 ie : (document.all && !window.opera),
172 //ie : navigator && /MSIE [678]/.test(navigator.userAgent), // ie9 compliant?
173 safari : /Safari/.test(navigator.userAgent),
174 geckoMac : /Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent),
175
176 $ : function (id) {
177         if (id) return document.getElementById(id);
178 },
179
180 push : function (arr, val) {
181         arr[arr.length] = val;
182 },
183
184 createElement : function (tag, attribs, styles, parent, nopad) {
185         var el = document.createElement(tag);
186         if (attribs) hs.extend(el, attribs);
187         if (nopad) hs.setStyles(el, {padding: 0, border: 'none', margin: 0});
188         if (styles) hs.setStyles(el, styles);
189         if (parent) parent.appendChild(el);     
190         return el;
191 },
192
193 extend : function (el, attribs) {
194         for (var x in attribs) el[x] = attribs[x];
195         return el;
196 },
197
198 setStyles : function (el, styles) {
199         for (var x in styles) {
200                 if (hs.ieLt9 && x == 'opacity') {
201                         if (styles[x] > 0.99) el.style.removeAttribute('filter');
202                         else el.style.filter = 'alpha(opacity='+ (styles[x] * 100) +')';
203                 }
204                 else el.style[x] = styles[x];           
205         }
206 },
207 animate: function(el, prop, opt) {
208         var start,
209                 end,
210                 unit;
211         if (typeof opt != 'object' || opt === null) {
212                 var args = arguments;
213                 opt = {
214                         duration: args[2],
215                         easing: args[3],
216                         complete: args[4]
217                 };
218         }
219         if (typeof opt.duration != 'number') opt.duration = 250;
220         opt.easing = Math[opt.easing] || Math.easeInQuad;
221         opt.curAnim = hs.extend({}, prop);
222         for (var name in prop) {
223                 var e = new hs.fx(el, opt , name );
224                 
225                 start = parseFloat(hs.css(el, name)) || 0;
226                 end = parseFloat(prop[name]);
227                 unit = name != 'opacity' ? 'px' : '';
228                 
229                 e.custom( start, end, unit );
230         }       
231 },
232 css: function(el, prop) {
233         if (el.style[prop]) {
234                 return el.style[prop];
235         } else if (document.defaultView) {
236                 return document.defaultView.getComputedStyle(el, null).getPropertyValue(prop);
237
238         } else {
239                 if (prop == 'opacity') prop = 'filter';
240                 var val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b){ return b.toUpperCase(); })];
241                 if (prop == 'filter') 
242                         val = val.replace(/alpha\(opacity=([0-9]+)\)/, 
243                                 function (a, b) { return b / 100 });
244                 return val === '' ? 1 : val;
245         } 
246 },
247
248 getPageSize : function () {
249         var d = document, w = window, iebody = d.compatMode && d.compatMode != 'BackCompat' 
250                 ? d.documentElement : d.body,
251                 ieLt9 = hs.ie && (hs.uaVersion < 9 || typeof pageXOffset == 'undefined');
252         
253         var width = ieLt9 ? iebody.clientWidth : 
254                         (d.documentElement.clientWidth || self.innerWidth),
255                 height = ieLt9 ? iebody.clientHeight : self.innerHeight;
256         hs.page = {
257                 width: width,
258                 height: height,         
259                 scrollLeft: ieLt9 ? iebody.scrollLeft : pageXOffset,
260                 scrollTop: ieLt9 ? iebody.scrollTop : pageYOffset
261         };
262         return hs.page;
263 },
264
265 getPosition : function(el)      {
266         var p = { x: el.offsetLeft, y: el.offsetTop };
267         while (el.offsetParent) {
268                 el = el.offsetParent;
269                 p.x += el.offsetLeft;
270                 p.y += el.offsetTop;
271                 if (el != document.body && el != document.documentElement) {
272                         p.x -= el.scrollLeft;
273                         p.y -= el.scrollTop;
274                 }
275         }
276         return p;
277 },
278
279 expand : function(a, params, custom, type) {
280         if (!a) a = hs.createElement('a', null, { display: 'none' }, hs.container);
281         if (typeof a.getParams == 'function') return params;    
282         try {   
283                 new hs.Expander(a, params, custom);
284                 return false;
285         } catch (e) { return true; }
286 },
287 getElementByClass : function (el, tagName, className) {
288         var els = el.getElementsByTagName(tagName);
289         for (var i = 0; i < els.length; i++) {
290         if ((new RegExp(className)).test(els[i].className)) {
291                         return els[i];
292                 }
293         }
294         return null;
295 },
296 replaceLang : function(s) {
297         s = s.replace(/\s/g, ' ');
298         var re = /{hs\.lang\.([^}]+)\}/g,
299                 matches = s.match(re),
300                 lang;
301         if (matches) for (var i = 0; i < matches.length; i++) {
302                 lang = matches[i].replace(re, "$1");
303                 if (typeof hs.lang[lang] != 'undefined') s = s.replace(matches[i], hs.lang[lang]);
304         }
305         return s;
306 },
307
308
309 focusTopmost : function() {
310         var topZ = 0, 
311                 topmostKey = -1,
312                 expanders = hs.expanders,
313                 exp,
314                 zIndex;
315         for (var i = 0; i < expanders.length; i++) {
316                 exp = expanders[i];
317                 if (exp) {
318                         zIndex = exp.wrapper.style.zIndex;
319                         if (zIndex && zIndex > topZ) {
320                                 topZ = zIndex;                          
321                                 topmostKey = i;
322                         }
323                 }
324         }
325         if (topmostKey == -1) hs.focusKey = -1;
326         else expanders[topmostKey].focus();
327 },
328
329 getParam : function (a, param) {
330         a.getParams = a.onclick;
331         var p = a.getParams ? a.getParams() : null;
332         a.getParams = null;
333         
334         return (p && typeof p[param] != 'undefined') ? p[param] : 
335                 (typeof hs[param] != 'undefined' ? hs[param] : null);
336 },
337
338 getSrc : function (a) {
339         var src = hs.getParam(a, 'src');
340         if (src) return src;
341         return a.href;
342 },
343
344 getNode : function (id) {
345         var node = hs.$(id), clone = hs.clones[id], a = {};
346         if (!node && !clone) return null;
347         if (!clone) {
348                 clone = node.cloneNode(true);
349                 clone.id = '';
350                 hs.clones[id] = clone;
351                 return node;
352         } else {
353                 return clone.cloneNode(true);
354         }
355 },
356
357 discardElement : function(d) {
358         if (d) hs.garbageBin.appendChild(d);
359         hs.garbageBin.innerHTML = '';
360 },
361 dim : function(exp) {
362         if (!hs.dimmer) {
363                 isNew = true;
364                 hs.dimmer = hs.createElement ('div', {
365                                 className: 'highslide-dimming highslide-viewport-size',
366                                 owner: '',
367                                 onclick: function() {
368                                         
369                                                 hs.close();
370                                 }
371                         }, {
372                 visibility: 'visible',
373                                 opacity: 0
374                         }, hs.container, true);
375                         
376                 if (/(Android|iPad|iPhone|iPod)/.test(navigator.userAgent)) {
377                         var body = document.body;
378                         function pixDimmerSize() {
379                                 hs.setStyles(hs.dimmer, {
380                                         width: body.scrollWidth +'px',
381                                         height: body.scrollHeight +'px'
382                                 });
383                         }
384                         pixDimmerSize();
385                         hs.addEventListener(window, 'resize', pixDimmerSize);
386                 }
387         }
388         hs.dimmer.style.display = '';
389
390         var isNew = hs.dimmer.owner == '';
391         hs.dimmer.owner += '|'+ exp.key;
392         
393         if (isNew) {
394                 if (hs.geckoMac && hs.dimmingGeckoFix)
395                         hs.setStyles(hs.dimmer, {
396                                 background: 'url('+ hs.graphicsDir + 'geckodimmer.png)',
397                                 opacity: 1
398                         });
399                 else
400                         hs.animate(hs.dimmer, { opacity: exp.dimmingOpacity }, hs.dimmingDuration);
401         }
402 },
403 undim : function(key) {
404         if (!hs.dimmer) return;
405         if (typeof key != 'undefined') hs.dimmer.owner = hs.dimmer.owner.replace('|'+ key, '');
406
407         if (
408                 (typeof key != 'undefined' && hs.dimmer.owner != '')
409                 || (hs.upcoming && hs.getParam(hs.upcoming, 'dimmingOpacity'))
410         ) return;
411
412         if (hs.geckoMac && hs.dimmingGeckoFix) hs.dimmer.style.display = 'none';
413         else hs.animate(hs.dimmer, { opacity: 0 }, hs.dimmingDuration, null, function() {
414                 hs.dimmer.style.display = 'none';
415         });
416 },
417 transit : function (adj, exp) {
418         var last = exp || hs.getExpander();
419         exp = last;
420         if (hs.upcoming) return false;
421         else hs.last = last;
422         hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
423         try {
424                 hs.upcoming = adj;
425                 adj.onclick();          
426         } catch (e){
427                 hs.last = hs.upcoming = null;
428         }
429         try {
430                 if (!adj || exp.transitions[1] != 'crossfade')
431                 exp.close();
432         } catch (e) {}
433         return false;
434 },
435
436 previousOrNext : function (el, op) {
437         var exp = hs.getExpander(el);
438         if (exp) return hs.transit(exp.getAdjacentAnchor(op), exp);
439         else return false;
440 },
441
442 previous : function (el) {
443         return hs.previousOrNext(el, -1);
444 },
445
446 next : function (el) {
447         return hs.previousOrNext(el, 1);        
448 },
449
450 keyHandler : function(e) {
451         if (!e) e = window.event;
452         if (!e.target) e.target = e.srcElement; // ie
453         if (typeof e.target.form != 'undefined') return true; // form element has focus
454         var exp = hs.getExpander();
455         
456         var op = null;
457         switch (e.keyCode) {
458                 case 70: // f
459                         if (exp) exp.doFullExpand();
460                         return true;
461                 case 32: // Space
462                         op = 2;
463                         break;
464                 case 34: // Page Down
465                 case 39: // Arrow right
466                 case 40: // Arrow down
467                         op = 1;
468                         break;
469                 case 8:  // Backspace
470                 case 33: // Page Up
471                 case 37: // Arrow left
472                 case 38: // Arrow up
473                         op = -1;
474                         break;
475                 case 27: // Escape
476                 case 13: // Enter
477                         op = 0;
478         }
479         if (op !== null) {if (op != 2)hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
480                 if (!hs.enableKeyListener) return true;
481                 
482                 if (e.preventDefault) e.preventDefault();
483         else e.returnValue = false;
484         if (exp) {
485                         if (op == 0) {
486                                 exp.close();
487                         } else if (op == 2) {
488                                 if (exp.slideshow) exp.slideshow.hitSpace();
489                         } else {
490                                 if (exp.slideshow) exp.slideshow.pause();
491                                 hs.previousOrNext(exp.key, op);
492                         }
493                         return false;
494                 }
495         }
496         return true;
497 },
498
499
500 registerOverlay : function (overlay) {
501         hs.push(hs.overlays, hs.extend(overlay, { hsId: 'hsId'+ hs.idCounter++ } ));
502 },
503
504
505 addSlideshow : function (options) {
506         var sg = options.slideshowGroup;
507         if (typeof sg == 'object') {
508                 for (var i = 0; i < sg.length; i++) {
509                         var o = {};
510                         for (var x in options) o[x] = options[x];
511                         o.slideshowGroup = sg[i];
512                         hs.push(hs.slideshows, o);
513                 }
514         } else {
515                 hs.push(hs.slideshows, options);
516         }
517 },
518
519 getWrapperKey : function (element, expOnly) {
520         var el, re = /^highslide-wrapper-([0-9]+)$/;
521         // 1. look in open expanders
522         el = element;
523         while (el.parentNode)   {
524                 if (el.hsKey !== undefined) return el.hsKey;
525                 if (el.id && re.test(el.id)) return el.id.replace(re, "$1");
526                 el = el.parentNode;
527         }
528         // 2. look in thumbnail
529         if (!expOnly) {
530                 el = element;
531                 while (el.parentNode)   {
532                         if (el.tagName && hs.isHsAnchor(el)) {
533                                 for (var key = 0; key < hs.expanders.length; key++) {
534                                         var exp = hs.expanders[key];
535                                         if (exp && exp.a == el) return key;
536                                 }
537                         }
538                         el = el.parentNode;
539                 }
540         }
541         return null; 
542 },
543
544 getExpander : function (el, expOnly) {
545         if (typeof el == 'undefined') return hs.expanders[hs.focusKey] || null;
546         if (typeof el == 'number') return hs.expanders[el] || null;
547         if (typeof el == 'string') el = hs.$(el);
548         return hs.expanders[hs.getWrapperKey(el, expOnly)] || null;
549 },
550
551 isHsAnchor : function (a) {
552         return (a.onclick && a.onclick.toString().replace(/\s/g, ' ').match(/hs.(htmlE|e)xpand/));
553 },
554
555 reOrder : function () {
556         for (var i = 0; i < hs.expanders.length; i++)
557                 if (hs.expanders[i] && hs.expanders[i].isExpanded) hs.focusTopmost();
558 },
559
560 mouseClickHandler : function(e) 
561 {       
562         if (!e) e = window.event;
563         if (e.button > 1) return true;
564         if (!e.target) e.target = e.srcElement;
565         
566         var el = e.target;
567         while (el.parentNode
568                 && !(/highslide-(image|move|html|resize)/.test(el.className)))
569         {
570                 el = el.parentNode;
571         }
572         var exp = hs.getExpander(el);
573         if (exp && (exp.isClosing || !exp.isExpanded)) return true;
574                 
575         if (exp && e.type == 'mousedown') {
576                 if (e.target.form) return true;
577                 var match = el.className.match(/highslide-(image|move|resize)/);
578                 if (match) {
579                         hs.dragArgs = { 
580                                 exp: exp , 
581                                 type: match[1], 
582                                 left: exp.x.pos, 
583                                 width: exp.x.size, 
584                                 top: exp.y.pos, 
585                                 height: exp.y.size, 
586                                 clickX: e.clientX, 
587                                 clickY: e.clientY
588                         };
589                         
590                         
591                         hs.addEventListener(document, 'mousemove', hs.dragHandler);
592                         if (e.preventDefault) e.preventDefault(); // FF
593                         
594                         if (/highslide-(image|html)-blur/.test(exp.content.className)) {
595                                 exp.focus();
596                                 hs.hasFocused = true;
597                         }
598                         return false;
599                 }
600         } else if (e.type == 'mouseup') {
601                 
602                 hs.removeEventListener(document, 'mousemove', hs.dragHandler);
603                 
604                 if (hs.dragArgs) {
605                         if (hs.styleRestoreCursor && hs.dragArgs.type == 'image') 
606                                 hs.dragArgs.exp.content.style.cursor = hs.styleRestoreCursor;
607                         var hasDragged = hs.dragArgs.hasDragged;
608                         
609                         if (!hasDragged &&!hs.hasFocused && !/(move|resize)/.test(hs.dragArgs.type)) {
610                                 exp.close();
611                         } 
612                         else if (hasDragged || (!hasDragged && hs.hasHtmlExpanders)) {
613                                 hs.dragArgs.exp.doShowHide('hidden');
614                         }
615                         hs.hasFocused = false;
616                         hs.dragArgs = null;
617                 
618                 } else if (/highslide-image-blur/.test(el.className)) {
619                         el.style.cursor = hs.styleRestoreCursor;                
620                 }
621         }
622         return false;
623 },
624
625 dragHandler : function(e)
626 {
627         if (!hs.dragArgs) return true;
628         if (!e) e = window.event;
629         var a = hs.dragArgs, exp = a.exp;
630         
631         a.dX = e.clientX - a.clickX;
632         a.dY = e.clientY - a.clickY;    
633         
634         var distance = Math.sqrt(Math.pow(a.dX, 2) + Math.pow(a.dY, 2));
635         if (!a.hasDragged) a.hasDragged = (a.type != 'image' && distance > 0)
636                 || (distance > (hs.dragSensitivity || 5));
637         
638         if (a.hasDragged && e.clientX > 5 && e.clientY > 5) {
639                 
640                 if (a.type == 'resize') exp.resize(a);
641                 else {
642                         exp.moveTo(a.left + a.dX, a.top + a.dY);
643                         if (a.type == 'image') exp.content.style.cursor = 'move';
644                 }
645         }
646         return false;
647 },
648
649 wrapperMouseHandler : function (e) {
650         try {
651                 if (!e) e = window.event;
652                 var over = /mouseover/i.test(e.type); 
653                 if (!e.target) e.target = e.srcElement; // ie
654                 if (!e.relatedTarget) e.relatedTarget = 
655                         over ? e.fromElement : e.toElement; // ie
656                 var exp = hs.getExpander(e.target);
657                 if (!exp.isExpanded) return;
658                 if (!exp || !e.relatedTarget || hs.getExpander(e.relatedTarget, true) == exp 
659                         || hs.dragArgs) return;
660                 for (var i = 0; i < exp.overlays.length; i++) (function() {
661                         var o = hs.$('hsId'+ exp.overlays[i]);
662                         if (o && o.hideOnMouseOut) {
663                                 if (over) hs.setStyles(o, { visibility: 'visible', display: '' });
664                                 hs.animate(o, { opacity: over ? o.opacity : 0 }, o.dur);
665                         }
666                 })();   
667         } catch (e) {}
668 },
669 addEventListener : function (el, event, func) {
670         if (el == document && event == 'ready') {
671                 hs.push(hs.onReady, func);
672         }
673         try {
674                 el.addEventListener(event, func, false);
675         } catch (e) {
676                 try {
677                         el.detachEvent('on'+ event, func);
678                         el.attachEvent('on'+ event, func);
679                 } catch (e) {
680                         el['on'+ event] = func;
681                 }
682         } 
683 },
684
685 removeEventListener : function (el, event, func) {
686         try {
687                 el.removeEventListener(event, func, false);
688         } catch (e) {
689                 try {
690                         el.detachEvent('on'+ event, func);
691                 } catch (e) {
692                         el['on'+ event] = null;
693                 }
694         }
695 },
696
697 preloadFullImage : function (i) {
698         if (hs.continuePreloading && hs.preloadTheseImages[i] && hs.preloadTheseImages[i] != 'undefined') {
699                 var img = document.createElement('img');
700                 img.onload = function() { 
701                         img = null;
702                         hs.preloadFullImage(i + 1);
703                 };
704                 img.src = hs.preloadTheseImages[i];
705         }
706 },
707 preloadImages : function (number) {
708         if (number && typeof number != 'object') hs.numberOfImagesToPreload = number;
709         
710         var arr = hs.getAnchors();
711         for (var i = 0; i < arr.images.length && i < hs.numberOfImagesToPreload; i++) {
712                 hs.push(hs.preloadTheseImages, hs.getSrc(arr.images[i]));
713         }
714         
715         // preload outlines
716         if (hs.outlineType)     new hs.Outline(hs.outlineType, function () { hs.preloadFullImage(0)} );
717         else
718         
719         hs.preloadFullImage(0);
720         
721         // preload cursor
722         if (hs.restoreCursor) var cur = hs.createElement('img', { src: hs.graphicsDir + hs.restoreCursor });
723 },
724
725
726 init : function () {
727         if (!hs.container) {
728         
729                 hs.ieLt7 = hs.ie && hs.uaVersion < 7;
730                 hs.ieLt9 = hs.ie && hs.uaVersion < 9;
731                 
732                 hs.getPageSize();
733                 for (var x in hs.langDefaults) {
734                         if (typeof hs[x] != 'undefined') hs.lang[x] = hs[x];
735                         else if (typeof hs.lang[x] == 'undefined' && typeof hs.langDefaults[x] != 'undefined') 
736                                 hs.lang[x] = hs.langDefaults[x];
737                 }
738                 
739                 hs.container = hs.createElement('div', {
740                                 className: 'highslide-container'
741                         }, {
742                                 position: 'absolute',
743                                 left: 0, 
744                                 top: 0, 
745                                 width: '100%', 
746                                 zIndex: hs.zIndexCounter,
747                                 direction: 'ltr'
748                         }, 
749                         document.body,
750                         true
751                 );
752                 hs.loading = hs.createElement('a', {
753                                 className: 'highslide-loading',
754                                 title: hs.lang.loadingTitle,
755                                 innerHTML: hs.lang.loadingText,
756                                 href: 'javascript:;'
757                         }, {
758                                 position: 'absolute',
759                                 top: '-9999px',
760                                 opacity: hs.loadingOpacity,
761                                 zIndex: 1
762                         }, hs.container
763                 );
764                 hs.garbageBin = hs.createElement('div', null, { display: 'none' }, hs.container);
765                 hs.viewport = hs.createElement('div', {
766                                 className: 'highslide-viewport highslide-viewport-size'
767                         }, {
768                                 visibility: (hs.safari && hs.uaVersion < 525) ? 'visible' : 'hidden'
769                         }, hs.container, 1
770                 );
771                 
772                 // http://www.robertpenner.com/easing/ 
773                 Math.linearTween = function (t, b, c, d) {
774                         return c*t/d + b;
775                 };
776                 Math.easeInQuad = function (t, b, c, d) {
777                         return c*(t/=d)*t + b;
778                 };
779                 Math.easeOutQuad = function (t, b, c, d) {
780                         return -c *(t/=d)*(t-2) + b;
781                 };
782                 
783                 hs.hideSelects = hs.ieLt7;
784                 hs.hideIframes = ((window.opera && hs.uaVersion < 9) || navigator.vendor == 'KDE' 
785                         || (hs.ieLt7 && hs.uaVersion < 5.5));
786         }
787 },
788 ready : function() {
789         if (hs.isReady) return;
790         hs.isReady = true;
791         for (var i = 0; i < hs.onReady.length; i++) hs.onReady[i]();
792 },
793
794 updateAnchors : function() {
795         var el, els, all = [], images = [],groups = {}, re;
796                 
797         for (var i = 0; i < hs.openerTagNames.length; i++) {
798                 els = document.getElementsByTagName(hs.openerTagNames[i]);
799                 for (var j = 0; j < els.length; j++) {
800                         el = els[j];
801                         re = hs.isHsAnchor(el);
802                         if (re) {
803                                 hs.push(all, el);
804                                 if (re[0] == 'hs.expand') hs.push(images, el);
805                                 var g = hs.getParam(el, 'slideshowGroup') || 'none';
806                                 if (!groups[g]) groups[g] = [];
807                                 hs.push(groups[g], el);
808                         }
809                 }
810         }
811         hs.anchors = { all: all, groups: groups, images: images };
812         return hs.anchors;
813         
814 },
815
816 getAnchors : function() {
817         return hs.anchors || hs.updateAnchors();
818 },
819
820
821 close : function(el) {
822         var exp = hs.getExpander(el);
823         if (exp) exp.close();
824         return false;
825 }
826 }; // end hs object
827 hs.fx = function( elem, options, prop ){
828         this.options = options;
829         this.elem = elem;
830         this.prop = prop;
831
832         if (!options.orig) options.orig = {};
833 };
834 hs.fx.prototype = {
835         update: function(){
836                 (hs.fx.step[this.prop] || hs.fx.step._default)(this);
837                 
838                 if (this.options.step)
839                         this.options.step.call(this.elem, this.now, this);
840
841         },
842         custom: function(from, to, unit){
843                 this.startTime = (new Date()).getTime();
844                 this.start = from;
845                 this.end = to;
846                 this.unit = unit;// || this.unit || "px";
847                 this.now = this.start;
848                 this.pos = this.state = 0;
849
850                 var self = this;
851                 function t(gotoEnd){
852                         return self.step(gotoEnd);
853                 }
854
855                 t.elem = this.elem;
856
857                 if ( t() && hs.timers.push(t) == 1 ) {
858                         hs.timerId = setInterval(function(){
859                                 var timers = hs.timers;
860
861                                 for ( var i = 0; i < timers.length; i++ )
862                                         if ( !timers[i]() )
863                                                 timers.splice(i--, 1);
864
865                                 if ( !timers.length ) {
866                                         clearInterval(hs.timerId);
867                                 }
868                         }, 13);
869                 }
870         },
871         step: function(gotoEnd){
872                 var t = (new Date()).getTime();
873                 if ( gotoEnd || t >= this.options.duration + this.startTime ) {
874                         this.now = this.end;
875                         this.pos = this.state = 1;
876                         this.update();
877
878                         this.options.curAnim[ this.prop ] = true;
879
880                         var done = true;
881                         for ( var i in this.options.curAnim )
882                                 if ( this.options.curAnim[i] !== true )
883                                         done = false;
884
885                         if ( done ) {
886                                 if (this.options.complete) this.options.complete.call(this.elem);
887                         }
888                         return false;
889                 } else {
890                         var n = t - this.startTime;
891                         this.state = n / this.options.duration;
892                         this.pos = this.options.easing(n, 0, 1, this.options.duration);
893                         this.now = this.start + ((this.end - this.start) * this.pos);
894                         this.update();
895                 }
896                 return true;
897         }
898
899 };
900
901 hs.extend( hs.fx, {
902         step: {
903
904                 opacity: function(fx){
905                         hs.setStyles(fx.elem, { opacity: fx.now });
906                 },
907
908                 _default: function(fx){
909                         try {
910                                 if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
911                                         fx.elem.style[ fx.prop ] = fx.now + fx.unit;
912                                 else
913                                         fx.elem[ fx.prop ] = fx.now;
914                         } catch (e) {}
915                 }
916         }
917 });
918
919 hs.Outline =  function (outlineType, onLoad) {
920         this.onLoad = onLoad;
921         this.outlineType = outlineType;
922         var v = hs.uaVersion, tr;
923         
924         this.hasAlphaImageLoader = hs.ie && hs.uaVersion < 7;
925         if (!outlineType) {
926                 if (onLoad) onLoad();
927                 return;
928         }
929         
930         hs.init();
931         this.table = hs.createElement(
932                 'table', { 
933                         cellSpacing: 0 
934                 }, {
935                         visibility: 'hidden',
936                         position: 'absolute',
937                         borderCollapse: 'collapse',
938                         width: 0
939                 },
940                 hs.container,
941                 true
942         );
943         var tbody = hs.createElement('tbody', null, null, this.table, 1);
944         
945         this.td = [];
946         for (var i = 0; i <= 8; i++) {
947                 if (i % 3 == 0) tr = hs.createElement('tr', null, { height: 'auto' }, tbody, true);
948                 this.td[i] = hs.createElement('td', null, null, tr, true);
949                 var style = i != 4 ? { lineHeight: 0, fontSize: 0} : { position : 'relative' };
950                 hs.setStyles(this.td[i], style);
951         }
952         this.td[4].className = outlineType +' highslide-outline';
953         
954         this.preloadGraphic(); 
955 };
956
957 hs.Outline.prototype = {
958 preloadGraphic : function () {
959         var src = hs.graphicsDir + (hs.outlinesDir || "outlines/")+ this.outlineType +".png";
960                                 
961         var appendTo = hs.safari && hs.uaVersion < 525 ? hs.container : null;
962         this.graphic = hs.createElement('img', null, { position: 'absolute', 
963                 top: '-9999px' }, appendTo, true); // for onload trigger
964         
965         var pThis = this;
966         this.graphic.onload = function() { pThis.onGraphicLoad(); };
967         
968         this.graphic.src = src;
969 },
970
971 onGraphicLoad : function () {
972         var o = this.offset = this.graphic.width / 4,
973                 pos = [[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],
974                 dim = { height: (2*o) +'px', width: (2*o) +'px' };
975         for (var i = 0; i <= 8; i++) {
976                 if (pos[i]) {
977                         if (this.hasAlphaImageLoader) {
978                                 var w = (i == 1 || i == 7) ? '100%' : this.graphic.width +'px';
979                                 var div = hs.createElement('div', null, { width: '100%', height: '100%', position: 'relative', overflow: 'hidden'}, this.td[i], true);
980                                 hs.createElement ('div', null, { 
981                                                 filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale, src='"+ this.graphic.src + "')", 
982                                                 position: 'absolute',
983                                                 width: w, 
984                                                 height: this.graphic.height +'px',
985                                                 left: (pos[i][0]*o)+'px',
986                                                 top: (pos[i][1]*o)+'px'
987                                         }, 
988                                 div,
989                                 true);
990                         } else {
991                                 hs.setStyles(this.td[i], { background: 'url('+ this.graphic.src +') '+ (pos[i][0]*o)+'px '+(pos[i][1]*o)+'px'});
992                         }
993                         
994                         if (window.opera && (i == 3 || i ==5)) 
995                                 hs.createElement('div', null, dim, this.td[i], true);
996                         
997                         hs.setStyles (this.td[i], dim);
998                 }
999         }
1000         this.graphic = null;
1001         if (hs.pendingOutlines[this.outlineType]) hs.pendingOutlines[this.outlineType].destroy();
1002         hs.pendingOutlines[this.outlineType] = this;
1003         if (this.onLoad) this.onLoad();
1004 },
1005         
1006 setPosition : function (pos, offset, vis, dur, easing) {
1007         var exp = this.exp,
1008                 stl = exp.wrapper.style,
1009                 offset = offset || 0,
1010                 pos = pos || {
1011                         x: exp.x.pos + offset,
1012                         y: exp.y.pos + offset,
1013                         w: exp.x.get('wsize') - 2 * offset,
1014                         h: exp.y.get('wsize') - 2 * offset
1015                 };
1016         if (vis) this.table.style.visibility = (pos.h >= 4 * this.offset) 
1017                 ? 'visible' : 'hidden';
1018         hs.setStyles(this.table, {
1019                 left: (pos.x - this.offset) +'px',
1020                 top: (pos.y - this.offset) +'px',
1021                 width: (pos.w + 2 * this.offset) +'px'
1022         });
1023         
1024         pos.w -= 2 * this.offset;
1025         pos.h -= 2 * this.offset;
1026         hs.setStyles (this.td[4], {
1027                 width: pos.w >= 0 ? pos.w +'px' : 0,
1028                 height: pos.h >= 0 ? pos.h +'px' : 0
1029         });
1030         if (this.hasAlphaImageLoader) this.td[3].style.height 
1031                 = this.td[5].style.height = this.td[4].style.height;    
1032         
1033 },
1034         
1035 destroy : function(hide) {
1036         if (hide) this.table.style.visibility = 'hidden';
1037         else hs.discardElement(this.table);
1038 }
1039 };
1040
1041 hs.Dimension = function(exp, dim) {
1042         this.exp = exp;
1043         this.dim = dim;
1044         this.ucwh = dim == 'x' ? 'Width' : 'Height';
1045         this.wh = this.ucwh.toLowerCase();
1046         this.uclt = dim == 'x' ? 'Left' : 'Top';
1047         this.lt = this.uclt.toLowerCase();
1048         this.ucrb = dim == 'x' ? 'Right' : 'Bottom';
1049         this.rb = this.ucrb.toLowerCase();
1050         this.p1 = this.p2 = 0;
1051 };
1052 hs.Dimension.prototype = {
1053 get : function(key) {
1054         switch (key) {
1055                 case 'loadingPos':
1056                         return this.tpos + this.tb + (this.t - hs.loading['offset'+ this.ucwh]) / 2;
1057                 case 'loadingPosXfade':
1058                         return this.pos + this.cb+ this.p1 + (this.size - hs.loading['offset'+ this.ucwh]) / 2;
1059                 case 'wsize':
1060                         return this.size + 2 * this.cb + this.p1 + this.p2;
1061                 case 'fitsize':
1062                         return this.clientSize - this.marginMin - this.marginMax;
1063                 case 'maxsize':
1064                         return this.get('fitsize') - 2 * this.cb - this.p1 - this.p2 ;
1065                 case 'opos':
1066                         return this.pos - (this.exp.outline ? this.exp.outline.offset : 0);
1067                 case 'osize':
1068                         return this.get('wsize') + (this.exp.outline ? 2*this.exp.outline.offset : 0);
1069                 case 'imgPad':
1070                         return this.imgSize ? Math.round((this.size - this.imgSize) / 2) : 0;
1071                 
1072         }
1073 },
1074 calcBorders: function() {
1075         // correct for borders
1076         this.cb = (this.exp.content['offset'+ this.ucwh] - this.t) / 2;
1077         
1078         this.marginMax = hs['margin'+ this.ucrb];
1079 },
1080 calcThumb: function() {
1081         this.t = this.exp.el[this.wh] ? parseInt(this.exp.el[this.wh]) : 
1082                 this.exp.el['offset'+ this.ucwh];
1083         this.tpos = this.exp.tpos[this.dim];
1084         this.tb = (this.exp.el['offset'+ this.ucwh] - this.t) / 2;
1085         if (this.tpos == 0 || this.tpos == -1) {
1086                 this.tpos = (hs.page[this.wh] / 2) + hs.page['scroll'+ this.uclt];              
1087         };
1088 },
1089 calcExpanded: function() {
1090         var exp = this.exp;
1091         this.justify = 'auto';
1092         
1093         // get alignment
1094         if (exp.align == 'center') this.justify = 'center';
1095         else if (new RegExp(this.lt).test(exp.anchor)) this.justify = null;
1096         else if (new RegExp(this.rb).test(exp.anchor)) this.justify = 'max';
1097         
1098         
1099         // size and position
1100         this.pos = this.tpos - this.cb + this.tb;
1101         
1102         if (this.maxHeight && this.dim == 'x')
1103                 exp.maxWidth = Math.min(exp.maxWidth || this.full, exp.maxHeight * this.full / exp.y.full); 
1104                 
1105         this.size = Math.min(this.full, exp['max'+ this.ucwh] || this.full);
1106         this.minSize = exp.allowSizeReduction ? 
1107                 Math.min(exp['min'+ this.ucwh], this.full) :this.full;
1108         if (exp.isImage && exp.useBox)  {
1109                 this.size = exp[this.wh];
1110                 this.imgSize = this.full;
1111         }
1112         if (this.dim == 'x' && hs.padToMinWidth) this.minSize = exp.minWidth;
1113         this.target = exp['target'+ this.dim.toUpperCase()];
1114         this.marginMin = hs['margin'+ this.uclt];
1115         this.scroll = hs.page['scroll'+ this.uclt];
1116         this.clientSize = hs.page[this.wh];
1117 },
1118 setSize: function(i) {
1119         var exp = this.exp;
1120         if (exp.isImage && (exp.useBox || hs.padToMinWidth)) {
1121                 this.imgSize = i;
1122                 this.size = Math.max(this.size, this.imgSize);
1123                 exp.content.style[this.lt] = this.get('imgPad')+'px';
1124         } else
1125         this.size = i;
1126         
1127         exp.content.style[this.wh] = i +'px';
1128         exp.wrapper.style[this.wh] = this.get('wsize') +'px';
1129         if (exp.outline) exp.outline.setPosition();
1130         if (this.dim == 'x' && exp.overlayBox) exp.sizeOverlayBox(true);
1131         if (this.dim == 'x' && exp.slideshow && exp.isImage) {
1132                 if (i == this.full) exp.slideshow.disable('full-expand');
1133                 else exp.slideshow.enable('full-expand');
1134         }
1135 },
1136 setPos: function(i) {
1137         this.pos = i;
1138         this.exp.wrapper.style[this.lt] = i +'px';      
1139         
1140         if (this.exp.outline) this.exp.outline.setPosition();
1141         
1142 }
1143 };
1144
1145 hs.Expander = function(a, params, custom, contentType) {
1146         if (document.readyState && hs.ie && !hs.isReady) {
1147                 hs.addEventListener(document, 'ready', function() {
1148                         new hs.Expander(a, params, custom, contentType);
1149                 });
1150                 return;
1151         } 
1152         this.a = a;
1153         this.custom = custom;
1154         this.contentType = contentType || 'image';
1155         this.isImage = !this.isHtml;
1156         
1157         hs.continuePreloading = false;
1158         this.overlays = [];
1159         this.last = hs.last;
1160         hs.last = null;
1161         hs.init();
1162         var key = this.key = hs.expanders.length;
1163         // override inline parameters
1164         for (var i = 0; i < hs.overrides.length; i++) {
1165                 var name = hs.overrides[i];
1166                 this[name] = params && typeof params[name] != 'undefined' ?
1167                         params[name] : hs[name];
1168         }
1169         if (!this.src) this.src = a.href;
1170         
1171         // get thumb
1172         var el = (params && params.thumbnailId) ? hs.$(params.thumbnailId) : a;
1173         el = this.thumb = el.getElementsByTagName('img')[0] || el;
1174         this.thumbsUserSetId = el.id || a.id;
1175         
1176         // check if already open
1177         for (var i = 0; i < hs.expanders.length; i++) {
1178                 if (hs.expanders[i] && hs.expanders[i].a == a 
1179                         && !(this.last && this.transitions[1] == 'crossfade')) {
1180                         hs.expanders[i].focus();
1181                         return false;
1182                 }
1183         }       
1184
1185         // cancel other
1186         if (!hs.allowSimultaneousLoading) for (var i = 0; i < hs.expanders.length; i++) {
1187                 if (hs.expanders[i] && hs.expanders[i].thumb != el && !hs.expanders[i].onLoadStarted) {
1188                         hs.expanders[i].cancelLoading();
1189                 }
1190         }
1191         hs.expanders[key] = this;
1192         if (!hs.allowMultipleInstances && !hs.upcoming) {
1193                 if (hs.expanders[key-1]) hs.expanders[key-1].close();
1194                 if (typeof hs.focusKey != 'undefined' && hs.expanders[hs.focusKey])
1195                         hs.expanders[hs.focusKey].close();
1196         }
1197         
1198         // initiate metrics
1199         this.el = el;
1200         this.tpos = this.pageOrigin || hs.getPosition(el);
1201         hs.getPageSize();
1202         var x = this.x = new hs.Dimension(this, 'x');
1203         x.calcThumb();
1204         var y = this.y = new hs.Dimension(this, 'y');
1205         y.calcThumb();
1206         this.wrapper = hs.createElement(
1207                 'div', {
1208                         id: 'highslide-wrapper-'+ this.key,
1209                         className: 'highslide-wrapper '+ this.wrapperClassName
1210                 }, {
1211                         visibility: 'hidden',
1212                         position: 'absolute',
1213                         zIndex: hs.zIndexCounter += 2
1214                 }, null, true );
1215         
1216         this.wrapper.onmouseover = this.wrapper.onmouseout = hs.wrapperMouseHandler;
1217         if (this.contentType == 'image' && this.outlineWhileAnimating == 2)
1218                 this.outlineWhileAnimating = 0;
1219         
1220         // get the outline
1221         if (!this.outlineType 
1222                 || (this.last && this.isImage && this.transitions[1] == 'crossfade')) {
1223                 this[this.contentType +'Create']();
1224         
1225         } else if (hs.pendingOutlines[this.outlineType]) {
1226                 this.connectOutline();
1227                 this[this.contentType +'Create']();
1228         
1229         } else {
1230                 this.showLoading();
1231                 var exp = this;
1232                 new hs.Outline(this.outlineType, 
1233                         function () {
1234                                 exp.connectOutline();
1235                                 exp[exp.contentType +'Create']();
1236                         } 
1237                 );
1238         }
1239         return true;
1240 };
1241
1242 hs.Expander.prototype = {
1243 error : function(e) {
1244         if (hs.debug) alert ('Line '+ e.lineNumber +': '+ e.message);
1245         else window.location.href = this.src;
1246 },
1247
1248 connectOutline : function() {
1249         var outline = this.outline = hs.pendingOutlines[this.outlineType];
1250         outline.exp = this;
1251         outline.table.style.zIndex = this.wrapper.style.zIndex - 1;
1252         hs.pendingOutlines[this.outlineType] = null;
1253 },
1254
1255 showLoading : function() {
1256         if (this.onLoadStarted || this.loading) return;
1257         
1258         this.loading = hs.loading;
1259         var exp = this;
1260         this.loading.onclick = function() {
1261                 exp.cancelLoading();
1262         };
1263         var exp = this, 
1264                 l = this.x.get('loadingPos') +'px',
1265                 t = this.y.get('loadingPos') +'px';
1266         if (!tgt && this.last && this.transitions[1] == 'crossfade') 
1267                 var tgt = this.last; 
1268         if (tgt) {
1269                 l = tgt.x.get('loadingPosXfade') +'px';
1270                 t = tgt.y.get('loadingPosXfade') +'px';
1271                 this.loading.style.zIndex = hs.zIndexCounter++;
1272         }
1273         setTimeout(function () { 
1274                 if (exp.loading) hs.setStyles(exp.loading, { left: l, top: t, zIndex: hs.zIndexCounter++ })}
1275         , 100);
1276 },
1277
1278 imageCreate : function() {
1279         var exp = this;
1280         
1281         var img = document.createElement('img');
1282     this.content = img;
1283     img.onload = function () {
1284         if (hs.expanders[exp.key]) exp.contentLoaded(); 
1285         };
1286     if (hs.blockRightClick) img.oncontextmenu = function() { return false; };
1287     img.className = 'highslide-image';
1288     hs.setStyles(img, {
1289         visibility: 'hidden',
1290         display: 'block',
1291         position: 'absolute',
1292                 maxWidth: '9999px',
1293                 zIndex: 3
1294         });
1295     img.title = hs.lang.restoreTitle;
1296         if (hs.safari && hs.uaVersion < 525) hs.container.appendChild(img);
1297     if (hs.ie && hs.flushImgSize) img.src = null;
1298         img.src = this.src;
1299         
1300         this.showLoading();
1301 },
1302
1303 contentLoaded : function() {
1304         try {   
1305                 if (!this.content) return;
1306                 this.content.onload = null;
1307                 if (this.onLoadStarted) return;
1308                 else this.onLoadStarted = true;
1309                 
1310                 var x = this.x, y = this.y;
1311                 
1312                 if (this.loading) {
1313                         hs.setStyles(this.loading, { top: '-9999px' });
1314                         this.loading = null;
1315                 }       
1316                         x.full = this.content.width;
1317                         y.full = this.content.height;
1318                         
1319                         hs.setStyles(this.content, {
1320                                 width: x.t +'px',
1321                                 height: y.t +'px'
1322                         });
1323                         this.wrapper.appendChild(this.content);
1324                         hs.container.appendChild(this.wrapper);
1325                 
1326                 x.calcBorders();
1327                 y.calcBorders();
1328                 
1329                 hs.setStyles (this.wrapper, {
1330                         left: (x.tpos + x.tb - x.cb) +'px',
1331                         top: (y.tpos + x.tb - y.cb) +'px'
1332                 });
1333                 
1334                 
1335                 this.initSlideshow();
1336                 this.getOverlays();
1337                 
1338                 var ratio = x.full / y.full;
1339                 x.calcExpanded();
1340                 this.justify(x);
1341                 
1342                 y.calcExpanded();
1343                 this.justify(y);
1344                 if (this.overlayBox) this.sizeOverlayBox(0, 1);
1345
1346                 
1347                 if (this.allowSizeReduction) {
1348                                 this.correctRatio(ratio);
1349                         var ss = this.slideshow;                        
1350                         if (ss && this.last && ss.controls && ss.fixedControls) {
1351                                 var pos = ss.overlayOptions.position || '', p;
1352                                 for (var dim in hs.oPos) for (var i = 0; i < 5; i++) {
1353                                         p = this[dim];
1354                                         if (pos.match(hs.oPos[dim][i])) {
1355                                                 p.pos = this.last[dim].pos 
1356                                                         + (this.last[dim].p1 - p.p1)
1357                                                         + (this.last[dim].size - p.size) * [0, 0, .5, 1, 1][i];
1358                                                 if (ss.fixedControls == 'fit') {
1359                                                         if (p.pos + p.size + p.p1 + p.p2 > p.scroll + p.clientSize - p.marginMax)
1360                                                                 p.pos = p.scroll + p.clientSize - p.size - p.marginMin - p.marginMax - p.p1 - p.p2;
1361                                                         if (p.pos < p.scroll + p.marginMin) p.pos = p.scroll + p.marginMin; 
1362                                                 } 
1363                                         }
1364                                 }
1365                         }
1366                         if (this.isImage && this.x.full > (this.x.imgSize || this.x.size)) {
1367                                 this.createFullExpand();
1368                                 if (this.overlays.length == 1) this.sizeOverlayBox();
1369                         }
1370                 }
1371                 this.show();
1372                 
1373         } catch (e) {
1374                 this.error(e);
1375         }
1376 },
1377
1378 justify : function (p, moveOnly) {
1379         var tgtArr, tgt = p.target, dim = p == this.x ? 'x' : 'y';
1380         
1381         if (tgt && tgt.match(/ /)) {
1382                 tgtArr = tgt.split(' ');
1383                 tgt = tgtArr[0];
1384         }
1385         if (tgt && hs.$(tgt)) {
1386                 p.pos = hs.getPosition(hs.$(tgt))[dim];
1387                 if (tgtArr && tgtArr[1] && tgtArr[1].match(/^[-]?[0-9]+px$/)) 
1388                         p.pos += parseInt(tgtArr[1]);
1389                 if (p.size < p.minSize) p.size = p.minSize;
1390                 
1391         } else if (p.justify == 'auto' || p.justify == 'center') {
1392         
1393                 var hasMovedMin = false;
1394                 
1395                 var allowReduce = p.exp.allowSizeReduction;
1396                 if (p.justify == 'center')
1397                         p.pos = Math.round(p.scroll + (p.clientSize + p.marginMin - p.marginMax - p.get('wsize')) / 2);
1398                 else
1399                         p.pos = Math.round(p.pos - ((p.get('wsize') - p.t) / 2));
1400                 if (p.pos < p.scroll + p.marginMin) {
1401                         p.pos = p.scroll + p.marginMin;
1402                         hasMovedMin = true;             
1403                 }
1404                 if (!moveOnly && p.size < p.minSize) {
1405                         p.size = p.minSize;
1406                         allowReduce = false;
1407                 }
1408                 if (p.pos + p.get('wsize') > p.scroll + p.clientSize - p.marginMax) {
1409                         if (!moveOnly && hasMovedMin && allowReduce) {
1410                                 p.size = Math.min(p.size, p.get(dim == 'y' ? 'fitsize' : 'maxsize'));
1411                         } else if (p.get('wsize') < p.get('fitsize')) {
1412                                 p.pos = p.scroll + p.clientSize - p.marginMax - p.get('wsize');
1413                         } else { // image larger than viewport
1414                                 p.pos = p.scroll + p.marginMin;
1415                                 if (!moveOnly && allowReduce) p.size = p.get(dim == 'y' ? 'fitsize' : 'maxsize');
1416                         }                       
1417                 }
1418                 
1419                 if (!moveOnly && p.size < p.minSize) {
1420                         p.size = p.minSize;
1421                         allowReduce = false;
1422                 }
1423                 
1424         
1425         } else if (p.justify == 'max') {
1426                 p.pos = Math.floor(p.pos - p.size + p.t);
1427         }
1428         
1429                 
1430         if (p.pos < p.marginMin) {
1431                 var tmpMin = p.pos;
1432                 p.pos = p.marginMin; 
1433                 
1434                 if (allowReduce && !moveOnly) p.size = p.size - (p.pos - tmpMin);
1435                 
1436         }
1437 },
1438
1439 correctRatio : function(ratio) {
1440         var x = this.x, 
1441                 y = this.y,
1442                 changed = false,
1443                 xSize = Math.min(x.full, x.size),
1444                 ySize = Math.min(y.full, y.size),
1445                 useBox = (this.useBox || hs.padToMinWidth);
1446         
1447         if (xSize / ySize > ratio) { // width greater
1448                 xSize = ySize * ratio;
1449                 if (xSize < x.minSize) { // below minWidth
1450                         xSize = x.minSize;
1451                         ySize = xSize / ratio;
1452                 }
1453                 changed = true;
1454         
1455         } else if (xSize / ySize < ratio) { // height greater
1456                 ySize = xSize / ratio;
1457                 changed = true;
1458         }
1459         
1460         if (hs.padToMinWidth && x.full < x.minSize) {
1461                 x.imgSize = x.full;
1462                 y.size = y.imgSize = y.full;
1463         } else if (this.useBox) {
1464                 x.imgSize = xSize;
1465                 y.imgSize = ySize;
1466         } else {
1467                 x.size = xSize;
1468                 y.size = ySize;
1469         }
1470         changed = this.fitOverlayBox(this.useBox ? null : ratio, changed);
1471         if (useBox && y.size < y.imgSize) {
1472                 y.imgSize = y.size;
1473                 x.imgSize = y.size * ratio;
1474         }
1475         if (changed || useBox) {
1476                 x.pos = x.tpos - x.cb + x.tb;
1477                 x.minSize = x.size;
1478                 this.justify(x, true);
1479         
1480                 y.pos = y.tpos - y.cb + y.tb;
1481                 y.minSize = y.size;
1482                 this.justify(y, true);
1483                 if (this.overlayBox) this.sizeOverlayBox();
1484         }
1485         
1486         
1487 },
1488 fitOverlayBox : function(ratio, changed) {
1489         var x = this.x, y = this.y;
1490         if (this.overlayBox) {
1491                 while (y.size > this.minHeight && x.size > this.minWidth 
1492                                 &&  y.get('wsize') > y.get('fitsize')) {
1493                         y.size -= 10;
1494                         if (ratio) x.size = y.size * ratio;
1495                         this.sizeOverlayBox(0, 1);
1496                         changed = true;
1497                 }
1498         }
1499         return changed;
1500 },
1501
1502 show : function () {
1503         var x = this.x, y = this.y;
1504         this.doShowHide('hidden');
1505         if (this.slideshow && this.slideshow.thumbstrip) this.slideshow.thumbstrip.selectThumb();
1506         
1507         // Apply size change
1508         this.changeSize(
1509                 1, {
1510                         wrapper: {
1511                                 width : x.get('wsize'),
1512                                 height : y.get('wsize'),
1513                                 left: x.pos,
1514                                 top: y.pos
1515                         },
1516                         content: {
1517                                 left: x.p1 + x.get('imgPad'),
1518                                 top: y.p1 + y.get('imgPad'),
1519                                 width:x.imgSize ||x.size,
1520                                 height:y.imgSize ||y.size
1521                         }
1522                 },
1523                 hs.expandDuration
1524         );
1525 },
1526
1527 changeSize : function(up, to, dur) {
1528         // transition
1529         var trans = this.transitions,
1530         other = up ? (this.last ? this.last.a : null) : hs.upcoming,
1531         t = (trans[1] && other 
1532                         && hs.getParam(other, 'transitions')[1] == trans[1]) ?
1533                 trans[1] : trans[0];
1534                 
1535         if (this[t] && t != 'expand') {
1536                 this[t](up, to);
1537                 return;
1538         }
1539         
1540         if (this.outline && !this.outlineWhileAnimating) {
1541                 if (up) this.outline.setPosition();
1542                 else this.outline.destroy();
1543         }
1544         
1545         
1546         if (!up) this.destroyOverlays();
1547         
1548         var exp = this,
1549                 x = exp.x,
1550                 y = exp.y,
1551                 easing = this.easing;
1552         if (!up) easing = this.easingClose || easing;
1553         var after = up ?
1554                 function() {
1555                                 
1556                         if (exp.outline) exp.outline.table.style.visibility = "visible";
1557                         setTimeout(function() {
1558                                 exp.afterExpand();
1559                         }, 50);
1560                 } :
1561                 function() {
1562                         exp.afterClose();
1563                 };
1564         if (up) hs.setStyles( this.wrapper, {
1565                 width: x.t +'px',
1566                 height: y.t +'px'
1567         });
1568         if (this.fadeInOut) {
1569                 hs.setStyles(this.wrapper, { opacity: up ? 0 : 1 });
1570                 hs.extend(to.wrapper, { opacity: up });
1571         }
1572         hs.animate( this.wrapper, to.wrapper, {
1573                 duration: dur,
1574                 easing: easing,
1575                 step: function(val, args) {
1576                         if (exp.outline && exp.outlineWhileAnimating && args.prop == 'top') {
1577                                 var fac = up ? args.pos : 1 - args.pos;
1578                                 var pos = {
1579                                         w: x.t + (x.get('wsize') - x.t) * fac,
1580                                         h: y.t + (y.get('wsize') - y.t) * fac,
1581                                         x: x.tpos + (x.pos - x.tpos) * fac,
1582                                         y: y.tpos + (y.pos - y.tpos) * fac
1583                                 };
1584                                 exp.outline.setPosition(pos, 0, 1);                             
1585                         }
1586                 }
1587         });
1588         hs.animate( this.content, to.content, dur, easing, after);
1589         if (up) {
1590                 this.wrapper.style.visibility = 'visible';
1591                 this.content.style.visibility = 'visible';
1592                 this.a.className += ' highslide-active-anchor';
1593         }
1594 },
1595
1596
1597
1598 fade : function(up, to) {
1599         this.outlineWhileAnimating = false;
1600         var exp = this, t = up ? hs.expandDuration : 0;
1601         
1602         if (up) {
1603                 hs.animate(this.wrapper, to.wrapper, 0);
1604                 hs.setStyles(this.wrapper, { opacity: 0, visibility: 'visible' });
1605                 hs.animate(this.content, to.content, 0);
1606                 this.content.style.visibility = 'visible';
1607
1608                 hs.animate(this.wrapper, { opacity: 1 }, t, null, 
1609                         function() { exp.afterExpand(); });
1610         }
1611         
1612         if (this.outline) {
1613                 this.outline.table.style.zIndex = this.wrapper.style.zIndex;
1614                 var dir = up || -1, 
1615                         offset = this.outline.offset,
1616                         startOff = up ? 3 : offset,
1617                         endOff = up? offset : 3;
1618                 for (var i = startOff; dir * i <= dir * endOff; i += dir, t += 25) {
1619                         (function() {
1620                                 var o = up ? endOff - i : startOff - i;
1621                                 setTimeout(function() {
1622                                         exp.outline.setPosition(0, o, 1);
1623                                 }, t);
1624                         })();
1625                 }
1626         }
1627         
1628         
1629         if (up) {}//setTimeout(function() { exp.afterExpand(); }, t+50);
1630         else {
1631                 setTimeout( function() {
1632                         if (exp.outline) exp.outline.destroy(exp.preserveContent);
1633                         
1634                         exp.destroyOverlays();
1635         
1636                         hs.animate( exp.wrapper, { opacity: 0 }, hs.restoreDuration, null, function(){
1637                                 exp.afterClose();
1638                         });
1639                 }, t);          
1640         }
1641 },
1642 crossfade : function (up, to, from) {
1643         if (!up) return;
1644         var exp = this, 
1645                 last = this.last,
1646                 x = this.x,
1647                 y = this.y,
1648                 lastX = last.x,
1649                 lastY = last.y,
1650                 wrapper = this.wrapper,
1651                 content = this.content,
1652                 overlayBox = this.overlayBox;
1653         hs.removeEventListener(document, 'mousemove', hs.dragHandler);
1654         
1655         hs.setStyles(content, { 
1656                 width: (x.imgSize || x.size) +'px', 
1657                 height: (y.imgSize || y.size) +'px'             
1658         });
1659         if (overlayBox) overlayBox.style.overflow = 'visible';
1660         this.outline = last.outline;
1661         if (this.outline) this.outline.exp = exp;
1662         last.outline = null;
1663         var fadeBox = hs.createElement('div', {
1664                         className: 'highslide-'+ this.contentType
1665                 }, { 
1666                         position: 'absolute', 
1667                         zIndex: 4,
1668                         overflow: 'hidden',
1669                         display: 'none'
1670                 }
1671         );
1672         var names = { oldImg: last, newImg: this };
1673         for (var n in names) {  
1674                 this[n] = names[n].content.cloneNode(1);
1675                 hs.setStyles(this[n], {
1676                         position: 'absolute',
1677                         border: 0,
1678                         visibility: 'visible'
1679                 });
1680                 fadeBox.appendChild(this[n]);
1681         }
1682         wrapper.appendChild(fadeBox);
1683         if (overlayBox) {
1684                 overlayBox.className = '';
1685                 wrapper.appendChild(overlayBox);
1686         }
1687         fadeBox.style.display = '';
1688         last.content.style.display = 'none';
1689         
1690         
1691         if (hs.safari && hs.uaVersion < 525) {
1692                 this.wrapper.style.visibility = 'visible';
1693         }
1694         hs.animate(wrapper, {
1695                 width: x.size
1696         }, {
1697                 duration: hs.transitionDuration, 
1698                 step: function(val, args) {
1699                         var pos = args.pos,
1700                                 invPos = 1 - pos;
1701                         var prop,
1702                                 size = {}, 
1703                                 props = ['pos', 'size', 'p1', 'p2'];
1704                         for (var n in props) {
1705                                 prop = props[n];
1706                                 size['x'+ prop] = Math.round(invPos * lastX[prop] + pos * x[prop]);
1707                                 size['y'+ prop] = Math.round(invPos * lastY[prop] + pos * y[prop]);
1708                                 size.ximgSize = Math.round(
1709                                         invPos * (lastX.imgSize || lastX.size) + pos * (x.imgSize || x.size));
1710                                 size.ximgPad = Math.round(invPos * lastX.get('imgPad') + pos * x.get('imgPad'));
1711                                 size.yimgSize = Math.round(
1712                                         invPos * (lastY.imgSize || lastY.size) + pos * (y.imgSize || y.size));
1713                                 size.yimgPad = Math.round(invPos * lastY.get('imgPad') + pos * y.get('imgPad'));
1714                         }
1715                         if (exp.outline) exp.outline.setPosition({ 
1716                                 x: size.xpos, 
1717                                 y: size.ypos, 
1718                                 w: size.xsize + size.xp1 + size.xp2 + 2 * x.cb, 
1719                                 h: size.ysize + size.yp1 + size.yp2 + 2 * y.cb
1720                         });
1721                         last.wrapper.style.clip = 'rect('
1722                                 + (size.ypos - lastY.pos)+'px, '
1723                                 + (size.xsize + size.xp1 + size.xp2 + size.xpos + 2 * lastX.cb - lastX.pos) +'px, '
1724                                 + (size.ysize + size.yp1 + size.yp2 + size.ypos + 2 * lastY.cb - lastY.pos) +'px, '
1725                                 + (size.xpos - lastX.pos)+'px)';
1726                                 
1727                         hs.setStyles(content, {
1728                                 top: (size.yp1 + y.get('imgPad')) +'px',
1729                                 left: (size.xp1 + x.get('imgPad')) +'px',
1730                                 marginTop: (y.pos - size.ypos) +'px',
1731                                 marginLeft: (x.pos - size.xpos) +'px'
1732                         });
1733                         hs.setStyles(wrapper, {
1734                                 top: size.ypos +'px',
1735                                 left: size.xpos +'px',
1736                                 width: (size.xp1 + size.xp2 + size.xsize + 2 * x.cb)+ 'px',
1737                                 height: (size.yp1 + size.yp2 + size.ysize + 2 * y.cb) + 'px'
1738                         });
1739                         hs.setStyles(fadeBox, {
1740                                 width: (size.ximgSize || size.xsize) + 'px',
1741                                 height: (size.yimgSize || size.ysize) +'px',
1742                                 left: (size.xp1 + size.ximgPad)  +'px',
1743                                 top: (size.yp1 + size.yimgPad) +'px',
1744                                 visibility: 'visible'
1745                         });
1746                         
1747                         hs.setStyles(exp.oldImg, {
1748                                 top: (lastY.pos - size.ypos + lastY.p1 - size.yp1 + lastY.get('imgPad') - size.yimgPad)+'px',
1749                                 left: (lastX.pos - size.xpos + lastX.p1 - size.xp1 + lastX.get('imgPad') - size.ximgPad)+'px'
1750                         });             
1751                         
1752                         hs.setStyles(exp.newImg, {
1753                                 opacity: pos,
1754                                 top: (y.pos - size.ypos + y.p1 - size.yp1 + y.get('imgPad') - size.yimgPad) +'px',
1755                                 left: (x.pos - size.xpos + x.p1 - size.xp1 + x.get('imgPad') - size.ximgPad) +'px'
1756                         });
1757                         if (overlayBox) hs.setStyles(overlayBox, {
1758                                 width: size.xsize + 'px',
1759                                 height: size.ysize +'px',
1760                                 left: (size.xp1 + x.cb)  +'px',
1761                                 top: (size.yp1 + y.cb) +'px'
1762                         });
1763                 },
1764                 complete: function () {
1765                         wrapper.style.visibility = content.style.visibility = 'visible';
1766                         content.style.display = 'block';
1767                         hs.discardElement(fadeBox);
1768                         exp.afterExpand();
1769                         last.afterClose();
1770                         exp.last = null;
1771                 }
1772                 
1773         });
1774 },
1775 reuseOverlay : function(o, el) {
1776         if (!this.last) return false;
1777         for (var i = 0; i < this.last.overlays.length; i++) {
1778                 var oDiv = hs.$('hsId'+ this.last.overlays[i]);
1779                 if (oDiv && oDiv.hsId == o.hsId) {
1780                         this.genOverlayBox();
1781                         oDiv.reuse = this.key;
1782                         hs.push(this.overlays, this.last.overlays[i]);
1783                         return true;
1784                 }
1785         }
1786         return false;
1787 },
1788
1789
1790 afterExpand : function() {
1791         this.isExpanded = true; 
1792         this.focus();
1793         if (this.dimmingOpacity) hs.dim(this);
1794         if (hs.upcoming && hs.upcoming == this.a) hs.upcoming = null;
1795         this.prepareNextOutline();
1796         var p = hs.page, mX = hs.mouse.x + p.scrollLeft, mY = hs.mouse.y + p.scrollTop;
1797         this.mouseIsOver = this.x.pos < mX && mX < this.x.pos + this.x.get('wsize')
1798                 && this.y.pos < mY && mY < this.y.pos + this.y.get('wsize');    
1799         if (this.overlayBox) this.showOverlays();
1800         
1801 },
1802
1803
1804 prepareNextOutline : function() {
1805         var key = this.key;
1806         var outlineType = this.outlineType;
1807         new hs.Outline(outlineType, 
1808                 function () { try { hs.expanders[key].preloadNext(); } catch (e) {} });
1809 },
1810
1811
1812 preloadNext : function() {
1813         var next = this.getAdjacentAnchor(1);
1814         if (next && next.onclick.toString().match(/hs\.expand/)) 
1815                 var img = hs.createElement('img', { src: hs.getSrc(next) });
1816 },
1817
1818
1819 getAdjacentAnchor : function(op) {
1820         var current = this.getAnchorIndex(), as = hs.anchors.groups[this.slideshowGroup || 'none'];
1821         if (as && !as[current + op] && this.slideshow && this.slideshow.repeat) {
1822                 if (op == 1) return as[0];
1823                 else if (op == -1) return as[as.length-1];
1824         }
1825         return (as && as[current + op]) || null;
1826 },
1827
1828 getAnchorIndex : function() {
1829         var arr = hs.getAnchors().groups[this.slideshowGroup || 'none'];
1830         if (arr) for (var i = 0; i < arr.length; i++) {
1831                 if (arr[i] == this.a) return i; 
1832         }
1833         return null;
1834 },
1835
1836
1837 getNumber : function() {
1838         if (this[this.numberPosition]) {
1839                 var arr = hs.anchors.groups[this.slideshowGroup || 'none'];
1840                 if (arr) {
1841                         var s = hs.lang.number.replace('%1', this.getAnchorIndex() + 1).replace('%2', arr.length);
1842                         this[this.numberPosition].innerHTML = 
1843                                 '<div class="highslide-number">'+ s +'</div>'+ this[this.numberPosition].innerHTML;
1844                 }
1845         }
1846 },
1847 initSlideshow : function() {
1848         if (!this.last) {
1849                 for (var i = 0; i < hs.slideshows.length; i++) {
1850                         var ss = hs.slideshows[i], sg = ss.slideshowGroup;
1851                         if (typeof sg == 'undefined' || sg === null || sg === this.slideshowGroup) 
1852                                 this.slideshow = new hs.Slideshow(this.key, ss);
1853                 } 
1854         } else {
1855                 this.slideshow = this.last.slideshow;
1856         }
1857         var ss = this.slideshow;
1858         if (!ss) return;
1859         var key = ss.expKey = this.key;
1860         
1861         ss.checkFirstAndLast();
1862         ss.disable('full-expand');
1863         if (ss.controls) {
1864                 this.createOverlay(hs.extend(ss.overlayOptions || {}, {
1865                         overlayId: ss.controls,
1866                         hsId: 'controls',
1867                         zIndex: 5
1868                 }));
1869         }
1870         if (ss.thumbstrip) ss.thumbstrip.add(this);
1871         if (!this.last && this.autoplay) ss.play(true);
1872         if (ss.autoplay) {
1873                 ss.autoplay = setTimeout(function() {
1874                         hs.next(key);
1875                 }, (ss.interval || 500));
1876         }
1877 },
1878
1879 cancelLoading : function() {
1880         hs.discardElement (this.wrapper);
1881         hs.expanders[this.key] = null;
1882         if (hs.upcoming == this.a) hs.upcoming = null;
1883         hs.undim(this.key);
1884         if (this.loading) hs.loading.style.left = '-9999px';
1885 },
1886
1887 writeCredits : function () {
1888         if (this.credits) return;
1889         this.credits = hs.createElement('a', {
1890                 href: hs.creditsHref,
1891                 target: hs.creditsTarget,
1892                 className: 'highslide-credits',
1893                 innerHTML: hs.lang.creditsText,
1894                 title: hs.lang.creditsTitle
1895         });
1896         this.createOverlay({ 
1897                 overlayId: this.credits, 
1898                 position: this.creditsPosition || 'top left', 
1899                 hsId: 'credits' 
1900         });
1901 },
1902
1903 getInline : function(types, addOverlay) {
1904         for (var i = 0; i < types.length; i++) {
1905                 var type = types[i], s = null;
1906                 if (!this[type +'Id'] && this.thumbsUserSetId)  
1907                         this[type +'Id'] = type +'-for-'+ this.thumbsUserSetId;
1908                 if (this[type +'Id']) this[type] = hs.getNode(this[type +'Id']);
1909                 if (!this[type] && !this[type +'Text'] && this[type +'Eval']) try {
1910                         s = eval(this[type +'Eval']);
1911                 } catch (e) {}
1912                 if (!this[type] && this[type +'Text']) {
1913                         s = this[type +'Text'];
1914                 }
1915                 if (!this[type] && !s) {
1916                         this[type] = hs.getNode(this.a['_'+ type + 'Id']);
1917                         if (!this[type]) {
1918                                 var next = this.a.nextSibling;
1919                                 while (next && !hs.isHsAnchor(next)) {
1920                                         if ((new RegExp('highslide-'+ type)).test(next.className || null)) {
1921                                                 if (!next.id) this.a['_'+ type + 'Id'] = next.id = 'hsId'+ hs.idCounter++;
1922                                                 this[type] = hs.getNode(next.id);
1923                                                 break;
1924                                         }
1925                                         next = next.nextSibling;
1926                                 }
1927                         }
1928                 }
1929                 if (!this[type] && !s && this.numberPosition == type) s = '\n';
1930                 
1931                 if (!this[type] && s) this[type] = hs.createElement('div', 
1932                                 { className: 'highslide-'+ type, innerHTML: s } );
1933                 
1934                 if (addOverlay && this[type]) {
1935                         var o = { position: (type == 'heading') ? 'above' : 'below' };
1936                         for (var x in this[type+'Overlay']) o[x] = this[type+'Overlay'][x];
1937                         o.overlayId = this[type];
1938                         this.createOverlay(o);
1939                 }
1940         }
1941 },
1942
1943
1944 // on end move and resize
1945 doShowHide : function(visibility) {
1946         if (hs.hideSelects) this.showHideElements('SELECT', visibility);
1947         if (hs.hideIframes) this.showHideElements('IFRAME', visibility);
1948         if (hs.geckoMac) this.showHideElements('*', visibility);
1949 },
1950 showHideElements : function (tagName, visibility) {
1951         var els = document.getElementsByTagName(tagName);
1952         var prop = tagName == '*' ? 'overflow' : 'visibility';
1953         for (var i = 0; i < els.length; i++) {
1954                 if (prop == 'visibility' || (document.defaultView.getComputedStyle(
1955                                 els[i], "").getPropertyValue('overflow') == 'auto'
1956                                 || els[i].getAttribute('hidden-by') != null)) {
1957                         var hiddenBy = els[i].getAttribute('hidden-by');
1958                         if (visibility == 'visible' && hiddenBy) {
1959                                 hiddenBy = hiddenBy.replace('['+ this.key +']', '');
1960                                 els[i].setAttribute('hidden-by', hiddenBy);
1961                                 if (!hiddenBy) els[i].style[prop] = els[i].origProp;
1962                         } else if (visibility == 'hidden') { // hide if behind
1963                                 var elPos = hs.getPosition(els[i]);
1964                                 elPos.w = els[i].offsetWidth;
1965                                 elPos.h = els[i].offsetHeight;
1966                                 if (!this.dimmingOpacity) { // hide all if dimming
1967                                 
1968                                         var clearsX = (elPos.x + elPos.w < this.x.get('opos') 
1969                                                 || elPos.x > this.x.get('opos') + this.x.get('osize'));
1970                                         var clearsY = (elPos.y + elPos.h < this.y.get('opos') 
1971                                                 || elPos.y > this.y.get('opos') + this.y.get('osize'));
1972                                 }
1973                                 var wrapperKey = hs.getWrapperKey(els[i]);
1974                                 if (!clearsX && !clearsY && wrapperKey != this.key) { // element falls behind image
1975                                         if (!hiddenBy) {
1976                                                 els[i].setAttribute('hidden-by', '['+ this.key +']');
1977                                                 els[i].origProp = els[i].style[prop];
1978                                                 els[i].style[prop] = 'hidden';
1979                                                 
1980                                         } else if (hiddenBy.indexOf('['+ this.key +']') == -1) {
1981                                                 els[i].setAttribute('hidden-by', hiddenBy + '['+ this.key +']');
1982                                         }
1983                                 } else if ((hiddenBy == '['+ this.key +']' || hs.focusKey == wrapperKey)
1984                                                 && wrapperKey != this.key) { // on move
1985                                         els[i].setAttribute('hidden-by', '');
1986                                         els[i].style[prop] = els[i].origProp || '';
1987                                 } else if (hiddenBy && hiddenBy.indexOf('['+ this.key +']') > -1) {
1988                                         els[i].setAttribute('hidden-by', hiddenBy.replace('['+ this.key +']', ''));
1989                                 }
1990                                                 
1991                         }
1992                 }
1993         }
1994 },
1995
1996 focus : function() {
1997         this.wrapper.style.zIndex = hs.zIndexCounter += 2;
1998         // blur others
1999         for (var i = 0; i < hs.expanders.length; i++) {
2000                 if (hs.expanders[i] && i == hs.focusKey) {
2001                         var blurExp = hs.expanders[i];
2002                         blurExp.content.className += ' highslide-'+ blurExp.contentType +'-blur';
2003                                 blurExp.content.style.cursor = hs.ieLt7 ? 'hand' : 'pointer';
2004                                 blurExp.content.title = hs.lang.focusTitle;
2005                 }
2006         }
2007         
2008         // focus this
2009         if (this.outline) this.outline.table.style.zIndex 
2010                 = this.wrapper.style.zIndex - 1;
2011         this.content.className = 'highslide-'+ this.contentType;
2012                 this.content.title = hs.lang.restoreTitle;
2013                 
2014                 if (hs.restoreCursor) {
2015                         hs.styleRestoreCursor = window.opera ? 'pointer' : 'url('+ hs.graphicsDir + hs.restoreCursor +'), pointer';
2016                         if (hs.ieLt7 && hs.uaVersion < 6) hs.styleRestoreCursor = 'hand';
2017                         this.content.style.cursor = hs.styleRestoreCursor;
2018                 }
2019                 
2020         hs.focusKey = this.key; 
2021         hs.addEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);    
2022 },
2023 moveTo: function(x, y) {
2024         this.x.setPos(x);
2025         this.y.setPos(y);
2026 },
2027 resize : function (e) {
2028         var w, h, r = e.width / e.height;
2029         w = Math.max(e.width + e.dX, Math.min(this.minWidth, this.x.full));
2030         if (this.isImage && Math.abs(w - this.x.full) < 12) w = this.x.full;
2031         h = w / r;
2032         if (h < Math.min(this.minHeight, this.y.full)) {
2033                 h = Math.min(this.minHeight, this.y.full);
2034                 if (this.isImage) w = h * r;
2035         }
2036         this.resizeTo(w, h);
2037 },
2038 resizeTo: function(w, h) {
2039         this.y.setSize(h);
2040         this.x.setSize(w);
2041         this.wrapper.style.height = this.y.get('wsize') +'px';
2042 },
2043
2044 close : function() {
2045         if (this.isClosing || !this.isExpanded) return;
2046         if (this.transitions[1] == 'crossfade' && hs.upcoming) {
2047                 hs.getExpander(hs.upcoming).cancelLoading();
2048                 hs.upcoming = null;
2049         }
2050         this.isClosing = true;
2051         if (this.slideshow && !hs.upcoming) this.slideshow.pause();
2052         
2053         hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler);
2054         
2055         try {
2056                 this.content.style.cursor = 'default';
2057                 this.changeSize(
2058                         0, {
2059                                 wrapper: {
2060                                         width : this.x.t,
2061                                         height : this.y.t,
2062                                         left: this.x.tpos - this.x.cb + this.x.tb,
2063                                         top: this.y.tpos - this.y.cb + this.y.tb
2064                                 },
2065                                 content: {
2066                                         left: 0,
2067                                         top: 0,
2068                                         width: this.x.t,
2069                                         height: this.y.t
2070                                 }
2071                         }, hs.restoreDuration
2072                 );
2073         } catch (e) { this.afterClose(); }
2074 },
2075
2076 createOverlay : function (o) {
2077         var el = o.overlayId, 
2078                 relToVP = (o.relativeTo == 'viewport' && !/panel$/.test(o.position));
2079         if (typeof el == 'string') el = hs.getNode(el);
2080         if (o.html) el = hs.createElement('div', { innerHTML: o.html });
2081         if (!el || typeof el == 'string') return;
2082         el.style.display = 'block';
2083         o.hsId = o.hsId || o.overlayId; 
2084         if (this.transitions[1] == 'crossfade' && this.reuseOverlay(o, el)) return;
2085         this.genOverlayBox();
2086         var width = o.width && /^[0-9]+(px|%)$/.test(o.width) ? o.width : 'auto';
2087         if (/^(left|right)panel$/.test(o.position) && !/^[0-9]+px$/.test(o.width)) width = '200px';
2088         var overlay = hs.createElement(
2089                 'div', {
2090                         id: 'hsId'+ hs.idCounter++,
2091                         hsId: o.hsId
2092                 }, {
2093                         position: 'absolute',
2094                         visibility: 'hidden',
2095                         width: width,
2096                         direction: hs.lang.cssDirection || '',
2097                         opacity: 0
2098                 },
2099                 relToVP ? hs.viewport :this.overlayBox,
2100                 true
2101         );
2102         if (relToVP) overlay.hsKey = this.key;
2103         
2104         overlay.appendChild(el);
2105         hs.extend(overlay, {
2106                 opacity: 1,
2107                 offsetX: 0,
2108                 offsetY: 0,
2109                 dur: (o.fade === 0 || o.fade === false || (o.fade == 2 && hs.ie)) ? 0 : 250
2110         });
2111         hs.extend(overlay, o);
2112         
2113                 
2114         if (this.gotOverlays) {
2115                 this.positionOverlay(overlay);
2116                 if (!overlay.hideOnMouseOut || this.mouseIsOver) 
2117                         hs.animate(overlay, { opacity: overlay.opacity }, overlay.dur);
2118         }
2119         hs.push(this.overlays, hs.idCounter - 1);
2120 },
2121 positionOverlay : function(overlay) {
2122         var p = overlay.position || 'middle center',
2123                 relToVP = (overlay.relativeTo == 'viewport'),
2124                 offX = overlay.offsetX,
2125                 offY = overlay.offsetY;
2126         if (relToVP) {
2127                 hs.viewport.style.display = 'block';
2128                 overlay.hsKey = this.key;
2129                 if (overlay.offsetWidth > overlay.parentNode.offsetWidth)
2130                         overlay.style.width = '100%';
2131         } else
2132         if (overlay.parentNode != this.overlayBox) this.overlayBox.appendChild(overlay);
2133         if (/left$/.test(p)) overlay.style.left = offX +'px'; 
2134         
2135         if (/center$/.test(p))  hs.setStyles (overlay, { 
2136                 left: '50%',
2137                 marginLeft: (offX - Math.round(overlay.offsetWidth / 2)) +'px'
2138         });     
2139         
2140         if (/right$/.test(p)) overlay.style.right = - offX +'px';
2141                 
2142         if (/^leftpanel$/.test(p)) { 
2143                 hs.setStyles(overlay, {
2144                         right: '100%',
2145                         marginRight: this.x.cb +'px',
2146                         top: - this.y.cb +'px',
2147                         bottom: - this.y.cb +'px',
2148                         overflow: 'auto'
2149                 });              
2150                 this.x.p1 = overlay.offsetWidth;
2151         
2152         } else if (/^rightpanel$/.test(p)) {
2153                 hs.setStyles(overlay, {
2154                         left: '100%',
2155                         marginLeft: this.x.cb +'px',
2156                         top: - this.y.cb +'px',
2157                         bottom: - this.y.cb +'px',
2158                         overflow: 'auto'
2159                 });
2160                 this.x.p2 = overlay.offsetWidth;
2161         }
2162         var parOff = overlay.parentNode.offsetHeight;
2163         overlay.style.height = 'auto';
2164         if (relToVP && overlay.offsetHeight > parOff)
2165                 overlay.style.height = hs.ieLt7 ? parOff +'px' : '100%';
2166
2167         if (/^top/.test(p)) overlay.style.top = offY +'px'; 
2168         if (/^middle/.test(p))  hs.setStyles (overlay, { 
2169                 top: '50%', 
2170                 marginTop: (offY - Math.round(overlay.offsetHeight / 2)) +'px'
2171         });     
2172         if (/^bottom/.test(p)) overlay.style.bottom = - offY +'px';
2173         if (/^above$/.test(p)) {
2174                 hs.setStyles(overlay, {
2175                         left: (- this.x.p1 - this.x.cb) +'px',
2176                         right: (- this.x.p2 - this.x.cb) +'px',
2177                         bottom: '100%',
2178                         marginBottom: this.y.cb +'px',
2179                         width: 'auto'
2180                 });
2181                 this.y.p1 = overlay.offsetHeight;
2182         
2183         } else if (/^below$/.test(p)) {
2184                 hs.setStyles(overlay, {
2185                         position: 'relative',
2186                         left: (- this.x.p1 - this.x.cb) +'px',
2187                         right: (- this.x.p2 - this.x.cb) +'px',
2188                         top: '100%',
2189                         marginTop: this.y.cb +'px',
2190                         width: 'auto'
2191                 });
2192                 this.y.p2 = overlay.offsetHeight;
2193                 overlay.style.position = 'absolute';
2194         }
2195 },
2196
2197 getOverlays : function() {      
2198         this.getInline(['heading', 'caption'], true);
2199         this.getNumber();
2200         if (this.heading && this.dragByHeading) this.heading.className += ' highslide-move';
2201         if (hs.showCredits) this.writeCredits();
2202         for (var i = 0; i < hs.overlays.length; i++) {
2203                 var o = hs.overlays[i], tId = o.thumbnailId, sg = o.slideshowGroup;
2204                 if ((!tId && !sg) || (tId && tId == this.thumbsUserSetId)
2205                                 || (sg && sg === this.slideshowGroup)) {
2206                         this.createOverlay(o);
2207                 }
2208         }
2209         var os = [];
2210         for (var i = 0; i < this.overlays.length; i++) {
2211                 var o = hs.$('hsId'+ this.overlays[i]);
2212                 if (/panel$/.test(o.position)) this.positionOverlay(o);
2213                 else hs.push(os, o);
2214         }
2215         for (var i = 0; i < os.length; i++) this.positionOverlay(os[i]);
2216         this.gotOverlays = true;
2217 },
2218 genOverlayBox : function() {
2219         if (!this.overlayBox) this.overlayBox = hs.createElement (
2220                 'div', {
2221                         className: this.wrapperClassName
2222                 }, {
2223                         position : 'absolute',
2224                         width: (this.x.size || (this.useBox ? this.width : null) 
2225                                 || this.x.full) +'px',
2226                         height: (this.y.size || this.y.full) +'px',
2227                         visibility : 'hidden',
2228                         overflow : 'hidden',
2229                         zIndex : hs.ie ? 4 : 'auto'
2230                 },
2231                 hs.container,
2232                 true
2233         );
2234 },
2235 sizeOverlayBox : function(doWrapper, doPanels) {
2236         var overlayBox = this.overlayBox, 
2237                 x = this.x,
2238                 y = this.y;
2239         hs.setStyles( overlayBox, {
2240                 width: x.size +'px', 
2241                 height: y.size +'px'
2242         });
2243         if (doWrapper || doPanels) {
2244                 for (var i = 0; i < this.overlays.length; i++) {
2245                         var o = hs.$('hsId'+ this.overlays[i]);
2246                         var ie6 = (hs.ieLt7 || document.compatMode == 'BackCompat');
2247                         if (o && /^(above|below)$/.test(o.position)) {
2248                                 if (ie6) {
2249                                         o.style.width = (overlayBox.offsetWidth + 2 * x.cb
2250                                                 + x.p1 + x.p2) +'px';
2251                                 }
2252                                 y[o.position == 'above' ? 'p1' : 'p2'] = o.offsetHeight;
2253                         }
2254                         if (o && ie6 && /^(left|right)panel$/.test(o.position)) {
2255                                 o.style.height = (overlayBox.offsetHeight + 2* y.cb) +'px';
2256                         }
2257                 }
2258         }
2259         if (doWrapper) {
2260                 hs.setStyles(this.content, {
2261                         top: y.p1 +'px'
2262                 });
2263                 hs.setStyles(overlayBox, {
2264                         top: (y.p1 + y.cb) +'px'
2265                 });
2266         }
2267 },
2268
2269 showOverlays : function() {
2270         var b = this.overlayBox;
2271         b.className = '';
2272         hs.setStyles(b, {
2273                 top: (this.y.p1 + this.y.cb) +'px',
2274                 left: (this.x.p1 + this.x.cb) +'px',
2275                 overflow : 'visible'
2276         });
2277         if (hs.safari) b.style.visibility = 'visible';
2278         this.wrapper.appendChild (b);
2279         for (var i = 0; i < this.overlays.length; i++) {
2280                 var o = hs.$('hsId'+ this.overlays[i]);
2281                 o.style.zIndex = o.zIndex || 4;
2282                 if (!o.hideOnMouseOut || this.mouseIsOver) {
2283                         o.style.visibility = 'visible';
2284                         hs.setStyles(o, { visibility: 'visible', display: '' });
2285                         hs.animate(o, { opacity: o.opacity }, o.dur);
2286                 }
2287         }
2288 },
2289
2290 destroyOverlays : function() {
2291         if (!this.overlays.length) return;
2292         if (this.slideshow) {
2293                 var c = this.slideshow.controls;
2294                 if (c && hs.getExpander(c) == this) c.parentNode.removeChild(c);
2295         }
2296         for (var i = 0; i < this.overlays.length; i++) {
2297                 var o = hs.$('hsId'+ this.overlays[i]);
2298                 if (o && o.parentNode == hs.viewport && hs.getExpander(o) == this) hs.discardElement(o);
2299         }
2300         hs.discardElement(this.overlayBox);
2301 },
2302
2303
2304
2305 createFullExpand : function () {
2306         if (this.slideshow && this.slideshow.controls) {
2307                 this.slideshow.enable('full-expand');
2308                 return;
2309         }
2310         this.fullExpandLabel = hs.createElement(
2311                 'a', {
2312                         href: 'javascript:hs.expanders['+ this.key +'].doFullExpand();',
2313                         title: hs.lang.fullExpandTitle,
2314                         className: 'highslide-full-expand'
2315                 }
2316         );
2317         
2318         this.createOverlay({ 
2319                 overlayId: this.fullExpandLabel, 
2320                 position: hs.fullExpandPosition, 
2321                 hideOnMouseOut: true, 
2322                 opacity: hs.fullExpandOpacity
2323         });
2324 },
2325
2326 doFullExpand : function () {
2327         try {
2328                 if (this.fullExpandLabel) hs.discardElement(this.fullExpandLabel);
2329                 
2330                 this.focus();
2331                 var xSize = this.x.size,
2332                 ySize = this.y.size;
2333         this.resizeTo(this.x.full, this.y.full);
2334        
2335         var xpos = this.x.pos - (this.x.size - xSize) / 2;
2336         if (xpos < hs.marginLeft) xpos = hs.marginLeft;
2337        
2338         var ypos = this.y.pos - (this.y.size - ySize) / 2;
2339         if (ypos < hs.marginTop) ypos = hs.marginTop;
2340        
2341         this.moveTo(xpos, ypos);
2342                 this.doShowHide('hidden');
2343         
2344         } catch (e) {
2345                 this.error(e);
2346         }
2347 },
2348
2349
2350 afterClose : function () {
2351         this.a.className = this.a.className.replace('highslide-active-anchor', '');
2352         
2353         this.doShowHide('visible');
2354                 if (this.outline && this.outlineWhileAnimating) this.outline.destroy();
2355         
2356                 hs.discardElement(this.wrapper);
2357         this.destroyOverlays();
2358         if (!hs.viewport.childNodes.length) hs.viewport.style.display = 'none';
2359         
2360         if (this.dimmingOpacity) hs.undim(this.key);
2361         hs.expanders[this.key] = null;          
2362         hs.reOrder();
2363 }
2364
2365 };
2366
2367
2368 hs.Slideshow = function (expKey, options) {
2369         if (hs.dynamicallyUpdateAnchors !== false) hs.updateAnchors();
2370         this.expKey = expKey;
2371         for (var x in options) this[x] = options[x];
2372         if (this.useControls) this.getControls();
2373         if (this.thumbstrip) this.thumbstrip = hs.Thumbstrip(this);
2374 };
2375 hs.Slideshow.prototype = {
2376 getControls: function() {
2377         this.controls = hs.createElement('div', { innerHTML: hs.replaceLang(hs.skin.controls) }, 
2378                 null, hs.container);
2379         
2380         var buttons = ['play', 'pause', 'previous', 'next', 'move', 'full-expand', 'close'];
2381         this.btn = {};
2382         var pThis = this;
2383         for (var i = 0; i < buttons.length; i++) {
2384                 this.btn[buttons[i]] = hs.getElementByClass(this.controls, 'li', 'highslide-'+ buttons[i]);
2385                 this.enable(buttons[i]);
2386         }
2387         this.btn.pause.style.display = 'none';
2388         //this.disable('full-expand');
2389 },
2390 checkFirstAndLast: function() {
2391         if (this.repeat || !this.controls) return;
2392         var exp = hs.expanders[this.expKey],
2393                 cur = exp.getAnchorIndex(), 
2394                 re = /disabled$/;
2395         if (cur == 0) 
2396                 this.disable('previous');
2397         else if (re.test(this.btn.previous.getElementsByTagName('a')[0].className))
2398                 this.enable('previous');
2399         if (cur + 1 == hs.anchors.groups[exp.slideshowGroup || 'none'].length) {
2400                 this.disable('next');
2401                 this.disable('play');
2402         } else if (re.test(this.btn.next.getElementsByTagName('a')[0].className)) {
2403                 this.enable('next');
2404                 this.enable('play');
2405         }
2406 },
2407 enable: function(btn) {
2408         if (!this.btn) return;
2409         var sls = this, a = this.btn[btn].getElementsByTagName('a')[0], re = /disabled$/;
2410         a.onclick = function() {
2411                 sls[btn]();
2412                 return false;
2413         };
2414         if (re.test(a.className)) a.className = a.className.replace(re, '');
2415 },
2416 disable: function(btn) {
2417         if (!this.btn) return;
2418         var a = this.btn[btn].getElementsByTagName('a')[0];
2419         a.onclick = function() { return false; };
2420         if (!/disabled$/.test(a.className)) a.className += ' disabled';
2421 },
2422 hitSpace: function() {
2423         if (this.autoplay) this.pause();
2424         else this.play();
2425 },
2426 play: function(wait) {
2427         if (this.btn) {
2428                 this.btn.play.style.display = 'none';
2429                 this.btn.pause.style.display = '';
2430         }
2431         
2432         this.autoplay = true;   
2433         if (!wait) hs.next(this.expKey);
2434 },
2435 pause: function() {
2436         if (this.btn) {
2437                 this.btn.pause.style.display = 'none';
2438                 this.btn.play.style.display = '';
2439         }
2440         
2441         clearTimeout(this.autoplay);
2442         this.autoplay = null;
2443 },
2444 previous: function() {
2445         this.pause();
2446         hs.previous(this.btn.previous);
2447 },
2448 next: function() {
2449         this.pause();
2450         hs.next(this.btn.next);
2451 },
2452 move: function() {},
2453 'full-expand': function() {
2454         hs.getExpander().doFullExpand();
2455 },
2456 close: function() {
2457         hs.close(this.btn.close);
2458 }
2459 };
2460 hs.Thumbstrip = function(slideshow) {
2461         function add (exp) {
2462                 hs.extend(options || {}, {
2463                         overlayId: dom,
2464                         hsId: 'thumbstrip',
2465                         className: 'highslide-thumbstrip-'+ mode +'-overlay ' + (options.className || '')
2466                 });
2467                 if (hs.ieLt7) options.fade = 0;
2468                 exp.createOverlay(options);
2469                 hs.setStyles(dom.parentNode, { overflow: 'hidden' });
2470         };
2471         
2472         function scroll (delta) {       
2473                 selectThumb(undefined, Math.round(delta * dom[isX ? 'offsetWidth' : 'offsetHeight'] * 0.7));
2474         };
2475         
2476         function selectThumb (i, scrollBy) {
2477                 if (i === undefined) for (var j = 0; j < group.length; j++) {
2478                         if (group[j] == hs.expanders[slideshow.expKey].a) {
2479                                 i = j;
2480                                 break;
2481                         }
2482                 }
2483                 if (i === undefined) return;
2484                 var as = dom.getElementsByTagName('a'),
2485                         active = as[i],
2486                         cell = active.parentNode,
2487                         left = isX ? 'Left' : 'Top',
2488                         right = isX ? 'Right' : 'Bottom',
2489                         width = isX ? 'Width' : 'Height',
2490                         offsetLeft = 'offset' + left,
2491                         offsetWidth = 'offset' + width,
2492                         overlayWidth = div.parentNode.parentNode[offsetWidth],
2493                         minTblPos = overlayWidth - table[offsetWidth],
2494                         curTblPos = parseInt(table.style[isX ? 'left' : 'top']) || 0,
2495                         tblPos = curTblPos,
2496                         mgnRight = 20;
2497                 if (scrollBy !== undefined) {
2498                         tblPos = curTblPos - scrollBy;
2499                         
2500                         if (minTblPos > 0) minTblPos = 0;
2501                         if (tblPos > 0) tblPos = 0;
2502                         if (tblPos < minTblPos) tblPos = minTblPos;
2503                         
2504         
2505                 } else {
2506                         for (var j = 0; j < as.length; j++) as[j].className = '';
2507                         active.className = 'highslide-active-anchor';
2508                         var activeLeft = i > 0 ? as[i - 1].parentNode[offsetLeft] : cell[offsetLeft],
2509                                 activeRight = cell[offsetLeft] + cell[offsetWidth] + 
2510                                         (as[i + 1] ? as[i + 1].parentNode[offsetWidth] : 0);
2511                         if (activeRight > overlayWidth - curTblPos) tblPos = overlayWidth - activeRight;
2512                         else if (activeLeft < -curTblPos) tblPos = -activeLeft;
2513                 }
2514                 var markerPos = cell[offsetLeft] + (cell[offsetWidth] - marker[offsetWidth]) / 2 + tblPos;
2515                 hs.animate(table, isX ? { left: tblPos } : { top: tblPos }, null, 'easeOutQuad');
2516                 hs.animate(marker, isX ? { left: markerPos } : { top: markerPos }, null, 'easeOutQuad');
2517                 scrollUp.style.display = tblPos < 0 ? 'block' : 'none';
2518                 scrollDown.style.display = (tblPos > minTblPos)  ? 'block' : 'none';
2519                 
2520         };
2521         
2522
2523         // initialize
2524         var group = hs.anchors.groups[hs.expanders[slideshow.expKey].slideshowGroup || 'none'],
2525                 options = slideshow.thumbstrip,
2526                 mode = options.mode || 'horizontal',
2527                 floatMode = (mode == 'float'),
2528                 tree = floatMode ? ['div', 'ul', 'li', 'span'] : ['table', 'tbody', 'tr', 'td'],
2529                 isX = (mode == 'horizontal'),
2530                 dom = hs.createElement('div', {
2531                                 className: 'highslide-thumbstrip highslide-thumbstrip-'+ mode,
2532                                 innerHTML:
2533                                         '<div class="highslide-thumbstrip-inner">'+
2534                                         '<'+ tree[0] +'><'+ tree[1] +'></'+ tree[1] +'></'+ tree[0] +'></div>'+
2535                                         '<div class="highslide-scroll-up"><div></div></div>'+
2536                                         '<div class="highslide-scroll-down"><div></div></div>'+
2537                                         '<div class="highslide-marker"><div></div></div>'
2538                         }, {
2539                                 display: 'none'
2540                         }, hs.container),
2541                 domCh = dom.childNodes,
2542                 div = domCh[0],
2543                 scrollUp = domCh[1],
2544                 scrollDown = domCh[2],
2545                 marker = domCh[3],
2546                 table = div.firstChild,
2547                 tbody = dom.getElementsByTagName(tree[1])[0],
2548                 tr;
2549         for (var i = 0; i < group.length; i++) {
2550                 if (i == 0 || !isX) tr = hs.createElement(tree[2], null, null, tbody);
2551                 (function(){
2552                         var a = group[i],
2553                                 cell = hs.createElement(tree[3], null, null, tr),
2554                                 pI = i;
2555                         hs.createElement('a', {
2556                                 href: a.href,
2557                                 title: a.title,
2558                                 onclick: function() {
2559                                         if (/highslide-active-anchor/.test(this.className)) return false;
2560                                         hs.getExpander(this).focus();
2561                                         return hs.transit(a);
2562                                 },
2563                                 innerHTML: hs.stripItemFormatter ? hs.stripItemFormatter(a) : a.innerHTML
2564                         }, null, cell);
2565                 })();
2566         }
2567         if (!floatMode) {
2568                 scrollUp.onclick = function () { scroll(-1); };
2569                 scrollDown.onclick = function() { scroll(1); };
2570                 hs.addEventListener(tbody, document.onmousewheel !== undefined ? 
2571                                 'mousewheel' : 'DOMMouseScroll', function(e) {        
2572                         var delta = 0;
2573                 e = e || window.event;
2574                 if (e.wheelDelta) {
2575                                 delta = e.wheelDelta/120;
2576                                 if (hs.opera) delta = -delta;
2577                 } else if (e.detail) {
2578                                 delta = -e.detail/3;
2579                 }
2580                 if (delta) scroll(-delta * 0.2);
2581                         if (e.preventDefault) e.preventDefault();
2582                         e.returnValue = false;
2583                 });
2584         }
2585         
2586         return {
2587                 add: add,
2588                 selectThumb: selectThumb
2589         }
2590 };
2591 hs.langDefaults = hs.lang;
2592 // history
2593 var HsExpander = hs.Expander;
2594 if (hs.ie && window == window.top) {
2595         (function () {
2596                 try {
2597                         document.documentElement.doScroll('left');
2598                 } catch (e) {
2599                         setTimeout(arguments.callee, 50);
2600                         return;
2601                 }
2602                 hs.ready();
2603         })();
2604 }
2605 hs.addEventListener(document, 'DOMContentLoaded', hs.ready);
2606 hs.addEventListener(window, 'load', hs.ready);
2607
2608 // set handlers
2609 hs.addEventListener(document, 'ready', function() {
2610         if (hs.expandCursor || hs.dimmingOpacity) {
2611                 var style = hs.createElement('style', { type: 'text/css' }, null, 
2612                         document.getElementsByTagName('HEAD')[0]), 
2613                         backCompat = document.compatMode == 'BackCompat';
2614                         
2615                 
2616                 function addRule(sel, dec) {
2617                         if (hs.ie && (hs.uaVersion < 9 || backCompat)) {
2618                                 var last = document.styleSheets[document.styleSheets.length - 1];
2619                                 if (typeof(last.addRule) == "object") last.addRule(sel, dec);
2620                         } else {
2621                                 style.appendChild(document.createTextNode(sel + " {" + dec + "}"));
2622                         }
2623                 }
2624                 function fix(prop) {
2625                         return 'expression( ( ( ignoreMe = document.documentElement.'+ prop +
2626                                 ' ? document.documentElement.'+ prop +' : document.body.'+ prop +' ) ) + \'px\' );';
2627                 }
2628                 if (hs.expandCursor) addRule ('.highslide img', 
2629                         'cursor: url('+ hs.graphicsDir + hs.expandCursor +'), pointer !important;');
2630                 addRule ('.highslide-viewport-size',
2631                         hs.ie && (hs.uaVersion < 7 || backCompat) ?
2632                                 'position: absolute; '+
2633                                 'left:'+ fix('scrollLeft') +
2634                                 'top:'+ fix('scrollTop') +
2635                                 'width:'+ fix('clientWidth') +
2636                                 'height:'+ fix('clientHeight') :
2637                                 'position: fixed; width: 100%; height: 100%; left: 0; top: 0');
2638         }
2639 });
2640 hs.addEventListener(window, 'resize', function() {
2641         hs.getPageSize();
2642         if (hs.viewport) for (var i = 0; i < hs.viewport.childNodes.length; i++) {
2643                 var node = hs.viewport.childNodes[i],
2644                         exp = hs.getExpander(node);
2645                 exp.positionOverlay(node);
2646                 if (node.hsId == 'thumbstrip') exp.slideshow.thumbstrip.selectThumb();
2647         }
2648 });
2649 hs.addEventListener(document, 'mousemove', function(e) {
2650         hs.mouse = { x: e.clientX, y: e.clientY };
2651 });
2652 hs.addEventListener(document, 'mousedown', hs.mouseClickHandler);
2653 hs.addEventListener(document, 'mouseup', hs.mouseClickHandler);
2654
2655 hs.addEventListener(document, 'ready', hs.getAnchors);
2656 hs.addEventListener(window, 'load', hs.preloadImages);
2657 }