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