From 5902ce032e940bced1bfb38f590afc2b56737abe Mon Sep 17 00:00:00 2001 From: luc Date: Mon, 19 Oct 2015 14:11:26 +0200 Subject: [PATCH 1/9] Corrected NullPointerException case when ImageIO reader is not found for image format. --- source/net/yacy/document/ImageParser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/net/yacy/document/ImageParser.java b/source/net/yacy/document/ImageParser.java index d10058dda..9a8d335c5 100644 --- a/source/net/yacy/document/ImageParser.java +++ b/source/net/yacy/document/ImageParser.java @@ -40,7 +40,6 @@ public class ImageParser { if (((filename.endsWith(".ico")) || (filename.endsWith(".bmp"))) && (bmpParser.isBMP(source))) { // parse image with BMP parser image = bmpParser.parse(source).getImage(); - if (image == null) return null; } else if ((filename.endsWith(".ico")) && (icoParser.isICO(source))) { // parse image with ICO parser icoParser icoparser; @@ -52,7 +51,6 @@ public class ImageParser { ConcurrentLog.fine("IMAGEPARSER", "IMAGEPARSER.parse : could not parse image " + filename, e); } } - if (image == null) return null; } else { try { image = ImageIO.read(new ByteArrayInputStream(source)); @@ -62,6 +60,9 @@ public class ImageParser { } } } + if (image == null) { + return null; + } final int handle = image.hashCode(); mediaTracker.addImage(image, handle); From 74b0283d575a55336cd8eb3b7d3065a8fe7fc665 Mon Sep 17 00:00:00 2001 From: luc Date: Tue, 20 Oct 2015 01:15:02 +0200 Subject: [PATCH 2/9] Added image preview error management. --- htroot/js/highslide/highslide.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/htroot/js/highslide/highslide.js b/htroot/js/highslide/highslide.js index 4c9399ae1..83d699b30 100644 --- a/htroot/js/highslide/highslide.js +++ b/htroot/js/highslide/highslide.js @@ -793,6 +793,12 @@ imageCreate : function() { img.onload = function () { if (hs.expanders[exp.key]) exp.contentLoaded(); }; + /* Manage loading or rendering error */ + img.onerror = function () { + if (hs.expanders[exp.key]) { + exp.contentLoaded(); + } + }; img.className = 'highslide-image'; img.style.visibility = 'hidden'; // prevent flickering in IE img.style.display = 'block'; @@ -800,6 +806,10 @@ imageCreate : function() { img.style.maxWidth = 'none'; img.style.zIndex = 3; img.title = hs.restoreTitle; + /* Ensure an alternative text and minimum dimensions in case of rendering failure */ + img.alt = 'X'; + img.style.minWidth = '3em'; + img.style.minHeight = '3em'; if (hs.safari) hs.container.appendChild(img); // uncomment this to flush img size: // if (hs.ie) img.src = null; From e2d00585e2456b3418a6d65fc8ac78f0a641f22d Mon Sep 17 00:00:00 2001 From: luc Date: Tue, 20 Oct 2015 01:17:37 +0200 Subject: [PATCH 3/9] Display full size preview using ViewImage Servlet. --- htroot/yacysearchitem.html | 6 +----- htroot/yacysearchitem.java | 8 ++++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htroot/yacysearchitem.html b/htroot/yacysearchitem.html index 21cc9b4a2..416b63044 100644 --- a/htroot/yacysearchitem.html +++ b/htroot/yacysearchitem.html @@ -40,14 +40,10 @@ :: #(item)#::#(/item)# :: #(item)#::#[name]##[hrefshort]##(/item)# diff --git a/htroot/yacysearchitem.java b/htroot/yacysearchitem.java index a38cc523c..492e4e314 100644 --- a/htroot/yacysearchitem.java +++ b/htroot/yacysearchitem.java @@ -315,8 +315,12 @@ public class yacysearchitem { final String target = sb.getConfig(imageUrlstring.matches(target_special_pattern) ? SwitchboardConstants.SEARCH_TARGET_SPECIAL : SwitchboardConstants.SEARCH_TARGET_DEFAULT, "_self"); final String license = URLLicense.aquireLicense(image.imageUrl); // this is just the license key to get the image forwarded through the YaCy thumbnail viewer, not an actual lawful license - //sb.loader.loadIfNotExistBackground(image.imageUrl, 1024 * 1024 * 10, null, ClientIdentification.yacyIntranetCrawlerAgent); - prop.putHTML("content_item_hrefCache", "ViewImage." + (!imageUrlExt.isEmpty() && "gif.png.svg".contains(imageUrlExt) ? imageUrlExt : "png") + "?maxwidth=128&maxheight=128&code="+license+"&isStatic=true&quadratic=&url=" + imageUrlstring); + /* Image format ouput for ViewImage servlet : default is png, except with gif and svg images */ + final String viewImageExt = !imageUrlExt.isEmpty() && "gif.png.svg".contains(imageUrlExt) ? imageUrlExt : "png"; + /* Thumb URL */ + prop.putHTML("content_item_hrefCache", "ViewImage." + viewImageExt + "?maxwidth=128&maxheight=128&code="+license+"&isStatic=true&quadratic=&url=" + imageUrlstring); + /* Full size preview URL */ + prop.putHTML("content_item_hrefFullPreview", "ViewImage." + viewImageExt + "?code="+license+"&isStatic=true&url=" + imageUrlstring); prop.putHTML("content_item_href", imageUrlstring); prop.putHTML("content_item_target", target); prop.put("content_item_code", license); From 37e28e0dd3788e0481e95f7ae2b4c970ac5556ae Mon Sep 17 00:00:00 2001 From: luc Date: Wed, 21 Oct 2015 02:49:51 +0200 Subject: [PATCH 4/9] - Keep aspect ratio of images rendered directly by browser such as gif and svg. - Corrected quadratic rendering of landscape images with height smaller than maxHeight --- htroot/ViewImage.java | 88 ++++++++++++++++++----------- htroot/env/base.css | 2 + htroot/yacysearchitem.html | 2 +- htroot/yacysearchitem.java | 113 ++++++++++++++++++++++++++----------- 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/htroot/ViewImage.java b/htroot/ViewImage.java index b967b720e..bccbb1642 100644 --- a/htroot/ViewImage.java +++ b/htroot/ViewImage.java @@ -106,7 +106,6 @@ public class ViewImage { return null; } - // get the image as stream if (MemoryControl.shortStatus()) { iconcache.clear(); @@ -131,7 +130,9 @@ public class ViewImage { if (resourceb == null) { if (urlString.endsWith(".ico")) { // load default favicon dfltfvcn.ico - // Should not do this here : we can be displaying search image result of '.ico' type and do not want to display a default + // Should not do this here : we can be displaying search + // image result of '.ico' type and do not want to display a + // default if (defaulticonb == null) try { resourceb = FileUtils.read(new File(sb.getAppPath(), defaulticon)); @@ -148,50 +149,70 @@ public class ViewImage { } } - // gif images are not loaded because of an animated gif bug within - // jvm which sends java into an endless loop with high CPU - if (ext.equals("gif") && "gif".equals(MultiProtocolURL.getFileExtension(url.getFileName()))) { - return new ByteArrayInputStream(resourceb); - } else if (ext.equals("svg") && "svg".equals(MultiProtocolURL.getFileExtension(url.getFileName()))) { - // svg images not supported by awt, but by most browser, deliver - // just content (without crop/scale) + String urlExt = MultiProtocolURL.getFileExtension(url.getFileName()); + if (ext != null && ext.equalsIgnoreCase(urlExt) && isBrowserRendered(urlExt)) { return new ByteArrayInputStream(resourceb); } // read image - encodedImage = parseAndScale(post, auth, urlString, ext, okToCache, resourceb); + encodedImage = parseAndScale(post, auth, urlString, ext, okToCache, resourceb); } return encodedImage; } /** - * Process resourceb byte array to try to produce an Image instance eventually scaled and cropped depending on post parameters - * @param post request post parameters. Must not be null. - * @param auth true when access rigths are OK. - * @param urlString image source URL. Must not be null. - * @param ext image file extension. May be null. - * @param okToCache true when image can be cached - * @param resourceb byte array. Must not be null. + * @param formatName + * informal file format name. For example : "png". + * @return true when image format is rendered by browser and not by + * ViewImage internals + */ + public static boolean isBrowserRendered(String formatName) { + /* + * gif images are not loaded because of an animated gif bug within jvm + * which sends java into an endless loop with high CPU + */ + /* + * svg images not supported by jdk, but by most browser, deliver just + * content (without crop/scale) + */ + return ("gif".equalsIgnoreCase(formatName) || "svg".equalsIgnoreCase(formatName)); + } + + /** + * Process resourceb byte array to try to produce an Image instance + * eventually scaled and cropped depending on post parameters + * + * @param post + * request post parameters. Must not be null. + * @param auth + * true when access rigths are OK. + * @param urlString + * image source URL. Must not be null. + * @param ext + * image file extension. May be null. + * @param okToCache + * true when image can be cached + * @param resourceb + * byte array. Must not be null. * @return an Image instance when parsing is OK, or null. */ - protected static EncodedImage parseAndScale(serverObjects post, boolean auth, String urlString, String ext, boolean okToCache, byte[] resourceb) { + protected static EncodedImage parseAndScale(serverObjects post, boolean auth, String urlString, String ext, + boolean okToCache, byte[] resourceb) { EncodedImage encodedImage = null; - + Image image = ImageParser.parse(urlString, resourceb); if (image != null) { - int width = post.getInt("width", 0); - int height = post.getInt("height", 0); int maxwidth = post.getInt("maxwidth", 0); int maxheight = post.getInt("maxheight", 0); final boolean quadratic = post.containsKey("quadratic"); boolean isStatic = post.getBoolean("isStatic"); - if (!auth || (width != 0 && height != 0) || maxwidth != 0 || maxheight != 0) { + if (!auth || maxwidth != 0 || maxheight != 0) { // find original size - final int h = image.getHeight(null); - final int w = image.getWidth(null); + int h = image.getHeight(null); + int w = image.getWidth(null); // in case of not-authorized access shrink the image to // prevent @@ -203,9 +224,11 @@ public class ViewImage { // quadratic shape if (quadratic && w != h) { image = makeSquare(image, h, w); + h = image.getHeight(null); + w = image.getWidth(null); } - Dimension finalDimensions = calculateDimensions(w, h, width, height, maxDimensions); + Dimension finalDimensions = calculateDimensions(w, h, maxDimensions); if (w != finalDimensions.width && h != finalDimensions.height) { image = scale(finalDimensions.width, finalDimensions.height, image); @@ -230,10 +253,9 @@ public class ViewImage { * * @return dimensions to render image */ - protected static Dimension calculateDimensions(final int originWidth, final int originHeight, final int targetWidth, - final int targetHeight, final Dimension max) { - int resultWidth = targetWidth; - int resultHeight = targetHeight; + protected static Dimension calculateDimensions(final int originWidth, final int originHeight, final Dimension max) { + int resultWidth; + int resultHeight; if (max.width < originWidth || max.height < originHeight) { // scale image final double hs = (originWidth <= max.width) ? 1.0 : ((double) max.width) / ((double) originWidth); @@ -321,7 +343,7 @@ public class ViewImage { } return image; } - + /** * Crop image to make a square * @@ -335,13 +357,15 @@ public class ViewImage { if (w > h) { final BufferedImage dst = new BufferedImage(h, h, BufferedImage.TYPE_INT_RGB); Graphics2D g = dst.createGraphics(); - g.drawImage(image, 0, 0, h - 1, h - 1, (w - h) / 2, 0, h + (w - h) / 2, h - 1, null); + final int offset = (w - h) / 2; + g.drawImage(image, 0, 0, h - 1, h - 1, offset, 0, h + offset, h - 1, null); g.dispose(); image = dst; } else { final BufferedImage dst = new BufferedImage(w, w, BufferedImage.TYPE_INT_RGB); Graphics2D g = dst.createGraphics(); - g.drawImage(image, 0, 0, w - 1, w - 1, 0, (h - w) / 2, w - 1, w + (h - w) / 2, null); + final int offset = (h - w) / 2; + g.drawImage(image, 0, 0, w - 1, w - 1, 0, offset, w - 1, w + offset, null); g.dispose(); image = dst; } diff --git a/htroot/env/base.css b/htroot/env/base.css index 6f908e89b..c65877797 100644 --- a/htroot/env/base.css +++ b/htroot/env/base.css @@ -260,6 +260,8 @@ tt, *.tt { width: 128px; height: 128px; /* 96px thumbnail + some lines of text */ float: left; + /* Cut non square images not rendered by YaCy ViewImage */ + overflow: hidden; } .hides .hoverShow { diff --git a/htroot/yacysearchitem.html b/htroot/yacysearchitem.html index 416b63044..6fc9c07d8 100644 --- a/htroot/yacysearchitem.html +++ b/htroot/yacysearchitem.html @@ -41,7 +41,7 @@ :: #(item)#::#(/item)# diff --git a/htroot/yacysearchitem.java b/htroot/yacysearchitem.java index 492e4e314..b6c2c41dd 100644 --- a/htroot/yacysearchitem.java +++ b/htroot/yacysearchitem.java @@ -73,6 +73,10 @@ public class yacysearchitem { private static final int SHORTEN_SUFFIX_LENGTH = SHORTEN_SUFFIX.length(); private static final int MAX_NAME_LENGTH = 60; private static final int MAX_URL_LENGTH = 120; + /** Default image item width in pixels */ + private static final int DEFAULT_IMG_WIDTH = 128; + /** Default image item height in pixels */ + private static final int DEFAULT_IMG_HEIGHT = DEFAULT_IMG_WIDTH; //private static boolean col = true; @@ -81,7 +85,7 @@ public class yacysearchitem { final serverObjects prop = new serverObjects(); final String eventID = post.get("eventID", ""); - final boolean authenticated = sb.adminAuthenticated(header) >= 2; + final boolean authenticated = sb.verifyAuthentication(header); final int item = post.getInt("item", -1); final RequestHeader.FileType fileType = header.fileType(); @@ -306,39 +310,7 @@ public class yacysearchitem { if (theSearch.query.contentdom == Classification.ContentDomain.IMAGE) { // image search; shows thumbnails - - prop.put("content", theSearch.query.contentdom.getCode() + 1); // switch on specific content - try { - SearchEvent.ImageResult image = theSearch.oneImageResult(item, timeout); - final String imageUrlstring = image.imageUrl.toNormalform(true); - final String imageUrlExt = MultiProtocolURL.getFileExtension(image.imageUrl.getFileName()); - final String target = sb.getConfig(imageUrlstring.matches(target_special_pattern) ? SwitchboardConstants.SEARCH_TARGET_SPECIAL : SwitchboardConstants.SEARCH_TARGET_DEFAULT, "_self"); - - final String license = URLLicense.aquireLicense(image.imageUrl); // this is just the license key to get the image forwarded through the YaCy thumbnail viewer, not an actual lawful license - /* Image format ouput for ViewImage servlet : default is png, except with gif and svg images */ - final String viewImageExt = !imageUrlExt.isEmpty() && "gif.png.svg".contains(imageUrlExt) ? imageUrlExt : "png"; - /* Thumb URL */ - prop.putHTML("content_item_hrefCache", "ViewImage." + viewImageExt + "?maxwidth=128&maxheight=128&code="+license+"&isStatic=true&quadratic=&url=" + imageUrlstring); - /* Full size preview URL */ - prop.putHTML("content_item_hrefFullPreview", "ViewImage." + viewImageExt + "?code="+license+"&isStatic=true&url=" + imageUrlstring); - prop.putHTML("content_item_href", imageUrlstring); - prop.putHTML("content_item_target", target); - prop.put("content_item_code", license); - prop.putHTML("content_item_name", shorten(image.imagetext, MAX_NAME_LENGTH)); - prop.put("content_item_mimetype", image.mimetype); - prop.put("content_item_fileSize", 0); - prop.put("content_item_width", image.width); - prop.put("content_item_height", image.height); - prop.put("content_item_attr", ""/*(ms.attr.equals("-1 x -1")) ? "" : "(" + ms.attr + ")"*/); // attributes, here: original size of image - prop.put("content_item_urlhash", ASCII.String(image.imageUrl.hash())); - prop.put("content_item_source", image.sourceUrl.toNormalform(true)); - prop.putXML("content_item_source-xml", image.sourceUrl.toNormalform(true)); - prop.put("content_item_sourcedom", image.sourceUrl.getHost()); - prop.put("content_item_nl", (item == theSearch.query.offset) ? 0 : 1); - prop.put("content_item", 1); - } catch (MalformedURLException e) { - prop.put("content_item", "0"); - } + processImage(sb, prop, item, theSearch, target_special_pattern, timeout); theSearch.query.transmitcount = item + 1; return prop; } @@ -370,6 +342,79 @@ public class yacysearchitem { return prop; } + + + /** + * Process search of image type and feed prop object. All parameters must not be null. + * @param sb Switchboard instance + * @param prop result + * @param item item index. + * @param theSearch search event + * @param target_special_pattern + * @param timeout result getting timeOut + */ + private static void processImage(final Switchboard sb, final serverObjects prop, final int item, + final SearchEvent theSearch, final String target_special_pattern, long timeout) { + prop.put("content", theSearch.query.contentdom.getCode() + 1); // switch on specific content + try { + SearchEvent.ImageResult image = theSearch.oneImageResult(item, timeout); + final String imageUrlstring = image.imageUrl.toNormalform(true); + final String imageUrlExt = MultiProtocolURL.getFileExtension(image.imageUrl.getFileName()); + final String target = sb.getConfig(imageUrlstring.matches(target_special_pattern) ? SwitchboardConstants.SEARCH_TARGET_SPECIAL : SwitchboardConstants.SEARCH_TARGET_DEFAULT, "_self"); + + final String license = URLLicense.aquireLicense(image.imageUrl); // this is just the license key to get the image forwarded through the YaCy thumbnail viewer, not an actual lawful license + /* Image format ouput for ViewImage servlet : default is png, except with gif and svg images */ + final String viewImageExt = !imageUrlExt.isEmpty() && ViewImage.isBrowserRendered(imageUrlExt) ? imageUrlExt : "png"; + /* Thumb URL */ + prop.putHTML("content_item_hrefCache", "ViewImage." + viewImageExt + "?maxwidth=" + DEFAULT_IMG_WIDTH + "&maxheight=" + DEFAULT_IMG_HEIGHT + "&code="+license+"&isStatic=true&quadratic=&url=" + imageUrlstring); + /* Full size preview URL */ + prop.putHTML("content_item_hrefFullPreview", "ViewImage." + viewImageExt + "?code="+license+"&isStatic=true&url=" + imageUrlstring); + prop.putHTML("content_item_href", imageUrlstring); + prop.putHTML("content_item_target", target); + prop.put("content_item_code", license); + prop.putHTML("content_item_name", shorten(image.imagetext, MAX_NAME_LENGTH)); + prop.put("content_item_mimetype", image.mimetype); + prop.put("content_item_fileSize", 0); + + String itemWidth = DEFAULT_IMG_WIDTH + "px", itemHeight = DEFAULT_IMG_HEIGHT + "px", itemStyle=""; + /* When image content is rendered by browser : + * - set smaller dimension to 100% in order to crop image on other dimension with CSS style 'overflow:hidden' on image container + * - set negative margin top behave like ViewImage which sets an offset when cutting to square */ + if (ViewImage.isBrowserRendered(imageUrlExt)) { + if (image.width > image.height) { + /* Landscape orientation */ + itemWidth = ""; + itemHeight = "100%"; + if(image.height > 0) { + double scale = ((double)DEFAULT_IMG_HEIGHT) / ((double)image.height); + int margin = (int)((image.height - image.width) * (scale / 2.0)); + itemStyle = "margin-left: " + margin + "px;"; + } + } else { + /* Portrait orientation, or square or unknown dimensions (both equals zero) */ + itemWidth = "100%"; + itemHeight = ""; + if(image.height > image.width && image.width > 0) { + double scale = ((double)DEFAULT_IMG_WIDTH) / ((double)image.width); + int margin = (int)((image.width - image.height) * (scale / 2.0)); + itemStyle = "margin-top: " + margin + "px;"; + } + } + } + prop.put("content_item_width", itemWidth); + prop.put("content_item_height", itemHeight); + prop.put("content_item_style", itemStyle); + prop.put("content_item_attr", ""/*(ms.attr.equals("-1 x -1")) ? "" : "(" + ms.attr + ")"*/); // attributes, here: original size of image + prop.put("content_item_urlhash", ASCII.String(image.imageUrl.hash())); + prop.put("content_item_source", image.sourceUrl.toNormalform(true)); + prop.putXML("content_item_source-xml", image.sourceUrl.toNormalform(true)); + prop.put("content_item_sourcedom", image.sourceUrl.getHost()); + prop.put("content_item_nl", (item == theSearch.query.offset) ? 0 : 1); + prop.put("content_item", 1); + } catch (MalformedURLException e) { + prop.put("content_item", "0"); + } + } private static String shorten(final String s, final int length) { final String ret; From a156fd65d07a3e5b1b9f17f19d8f4df91258b885 Mon Sep 17 00:00:00 2001 From: luc Date: Thu, 22 Oct 2015 00:36:34 +0200 Subject: [PATCH 5/9] Patch to manage render or load errors is still needed after highlight.js version upgrade. Updated patch for better behavior consistency between browsers. --- htroot/js/highslide/highslide.js | 2032 ++++++++++++++++++------------ 1 file changed, 1203 insertions(+), 829 deletions(-) diff --git a/htroot/js/highslide/highslide.js b/htroot/js/highslide/highslide.js index 83d699b30..45d06d867 100644 --- a/htroot/js/highslide/highslide.js +++ b/htroot/js/highslide/highslide.js @@ -1,71 +1,49 @@ - /****************************************************************************** -Name: Highslide JS -Version: 3.3.9 (February 15 2008) -Config: default -Author: Torstein H�nsi -Support: http://vikjavev.no/highslide/forum - -Licence: -Highslide JS is licensed under a Creative Commons Attribution-NonCommercial 2.5 -License (http://creativecommons.org/licenses/by-nc/2.5/). - -You are free: - * to copy, distribute, display, and perform the work - * to make derivative works - -Under the following conditions: - * Attribution. You must attribute the work in the manner specified by the - author or licensor. - * Noncommercial. You may not use this work for commercial purposes. - -* For any reuse or distribution, you must make clear to others the license - terms of this work. -* Any of these conditions can be waived if you get permission from the - copyright holder. - -Your fair use and other rights are in no way affected by the above. -******************************************************************************/ - -var hs = { - -// Apply your own settings here, or override them in the html file. +/** + * Name: Highslide JS + * Version: 4.1.13 (2011-10-06) + * Config: default + * Author: Torstein Hønsi + * Support: www.highslide.com/support + * License: www.highslide.com/#license + */ +if (!hs) { var hs = { +// Language strings +lang : { + cssDirection: 'ltr', + loadingText : 'Loading...', + loadingTitle : 'Click to cancel', + focusTitle : 'Click to bring to front', + fullExpandTitle : 'Expand to actual size (f)', + creditsText : 'Powered by Highslide JS', + creditsTitle : 'Go to the Highslide JS homepage', + restoreTitle : 'Click to close image, click and drag to move. Use arrow keys for next and previous.' +}, +// See http://highslide.com/ref for examples of settings graphicsDir : '/js/highslide/graphics/', -restoreCursor : 'zoomout.cur', // necessary for preload -expandSteps : 10, // number of steps in zoom. Each step lasts for duration/step milliseconds. +expandCursor : 'zoomin.cur', // null disables +restoreCursor : 'zoomout.cur', // null disables expandDuration : 250, // milliseconds -restoreSteps : 10, restoreDuration : 250, marginLeft : 15, marginRight : 15, marginTop : 15, marginBottom : 15, zIndexCounter : 1001, // adjust to other absolutely positioned elements - -restoreTitle : 'Click to close image, click and drag to move. Use arrow keys for next and previous.', -loadingText : 'Loading...', -loadingTitle : 'Click to cancel', loadingOpacity : 0.75, -focusTitle : 'Click to bring to front', allowMultipleInstances: true, numberOfImagesToPreload : 5, -captionSlideSpeed : 1, // set to 0 to disable slide in effect -padToMinWidth : true, // pad the popup width to make room for wide caption outlineWhileAnimating : 2, // 0 = never, 1 = always, 2 = HTML only outlineStartOffset : 3, // ends at 10 -fullExpandTitle : 'Expand to actual size', +padToMinWidth : true, // pad the popup width to make room for wide caption fullExpandPosition : 'bottom right', fullExpandOpacity : 1, showCredits : false, // you can set this to false if you want -creditsText : 'Powered by Highslide JS', -creditsHref : 'http://vikjavev.no/highslide/', -creditsTitle : 'Go to the Highslide JS homepage', +creditsHref : 'http://highslide.com/', +creditsTarget : '_self', enableKeyListener : true, +openerTagNames : ['a'], // Add more to allow slideshow indexing - -// These settings can also be overridden inline for each image -captionId : null, -spaceForCaption : 30, // leaves space below images with captions -slideshowGroup : null, // defines groups for next/previous links and keystrokes +dragByHeading: true, minWidth: 200, minHeight: 200, allowSizeReduction: true, // allow the image to reduce to fit client size. If false, this overrides minWidth and minHeight @@ -81,32 +59,58 @@ continuePreloading: true, expanders : [], overrides : [ 'allowSizeReduction', + 'useBox', 'outlineType', 'outlineWhileAnimating', - 'spaceForCaption', 'captionId', 'captionText', 'captionEval', + 'captionOverlay', + 'headingId', + 'headingText', + 'headingEval', + 'headingOverlay', + 'creditsPosition', + 'dragByHeading', + + 'width', + 'height', 'wrapperClassName', 'minWidth', 'minHeight', + 'maxWidth', + 'maxHeight', + 'pageOrigin', 'slideshowGroup', 'easing', 'easingClose', - 'fadeInOut' + 'fadeInOut', + 'src' ], overlays : [], -faders : [], +idCounter : 0, +oPos : { + x: ['leftpanel', 'left', 'center', 'right', 'rightpanel'], + y: ['above', 'top', 'middle', 'bottom', 'below'] +}, +mouse: {}, +headingOverlay: {}, +captionOverlay: {}, +timers : [], pendingOutlines : {}, clones : {}, +onReady: [], +uaVersion: /Trident\/4\.0/.test(navigator.userAgent) ? 8 : + parseFloat((navigator.userAgent.toLowerCase().match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]), ie : (document.all && !window.opera), +//ie : navigator && /MSIE [678]/.test(navigator.userAgent), // ie9 compliant? safari : /Safari/.test(navigator.userAgent), geckoMac : /Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent), $ : function (id) { - return document.getElementById(id); + if (id) return document.getElementById(id); }, push : function (arr, val) { @@ -115,50 +119,86 @@ push : function (arr, val) { createElement : function (tag, attribs, styles, parent, nopad) { var el = document.createElement(tag); - if (attribs) hs.setAttribs(el, attribs); + if (attribs) hs.extend(el, attribs); if (nopad) hs.setStyles(el, {padding: 0, border: 'none', margin: 0}); if (styles) hs.setStyles(el, styles); if (parent) parent.appendChild(el); return el; }, -setAttribs : function (el, attribs) { +extend : function (el, attribs) { for (var x in attribs) el[x] = attribs[x]; + return el; }, setStyles : function (el, styles) { for (var x in styles) { - try { - if (hs.ie && x == 'opacity') - el.style.filter = (styles[x] == 1) ? '' : 'alpha(opacity='+ (styles[x] * 100) +')'; - else el.style[x] = styles[x]; + if (hs.ieLt9 && x == 'opacity') { + if (styles[x] > 0.99) el.style.removeAttribute('filter'); + else el.style.filter = 'alpha(opacity='+ (styles[x] * 100) +')'; } - catch (e) {} + else el.style[x] = styles[x]; + } +}, +animate: function(el, prop, opt) { + var start, + end, + unit; + if (typeof opt != 'object' || opt === null) { + var args = arguments; + opt = { + duration: args[2], + easing: args[3], + complete: args[4] + }; } + if (typeof opt.duration != 'number') opt.duration = 250; + opt.easing = Math[opt.easing] || Math.easeInQuad; + opt.curAnim = hs.extend({}, prop); + for (var name in prop) { + var e = new hs.fx(el, opt , name ); + + start = parseFloat(hs.css(el, name)) || 0; + end = parseFloat(prop[name]); + unit = name != 'opacity' ? 'px' : ''; + + e.custom( start, end, unit ); + } }, +css: function(el, prop) { + if (el.style[prop]) { + return el.style[prop]; + } else if (document.defaultView) { + return document.defaultView.getComputedStyle(el, null).getPropertyValue(prop); -ieVersion : function () { - arr = navigator.appVersion.split("MSIE"); - return parseFloat(arr[1]); + } else { + if (prop == 'opacity') prop = 'filter'; + var val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b){ return b.toUpperCase(); })]; + if (prop == 'filter') + val = val.replace(/alpha\(opacity=([0-9]+)\)/, + function (a, b) { return b / 100 }); + return val === '' ? 1 : val; + } }, getPageSize : function () { - var iebody = document.compatMode && document.compatMode != "BackCompat" - ? document.documentElement : document.body; - - var width = hs.ie ? iebody.clientWidth : - (document.documentElement.clientWidth || self.innerWidth), - height = hs.ie ? iebody.clientHeight : self.innerHeight; - - return { + var d = document, w = window, iebody = d.compatMode && d.compatMode != 'BackCompat' + ? d.documentElement : d.body, + ieLt9 = hs.ie && (hs.uaVersion < 9 || typeof pageXOffset == 'undefined'); + + var width = ieLt9 ? iebody.clientWidth : + (d.documentElement.clientWidth || self.innerWidth), + height = ieLt9 ? iebody.clientHeight : self.innerHeight; + hs.page = { width: width, height: height, - scrollLeft: hs.ie ? iebody.scrollLeft : pageXOffset, - scrollTop: hs.ie ? iebody.scrollTop : pageYOffset - } + scrollLeft: ieLt9 ? iebody.scrollLeft : pageXOffset, + scrollTop: ieLt9 ? iebody.scrollTop : pageYOffset + }; + return hs.page; }, -position : function(el) { +getPosition : function(el) { var p = { x: el.offsetLeft, y: el.offsetTop }; while (el.offsetParent) { el = el.offsetParent; @@ -172,51 +212,43 @@ position : function(el) { return p; }, -expand : function(a, params, custom) { - if (a.getParams) return params; - - try { +expand : function(a, params, custom, type) { + if (!a) a = hs.createElement('a', null, { display: 'none' }, hs.container); + if (typeof a.getParams == 'function') return params; + try { new hs.Expander(a, params, custom); - return false; + return false; } catch (e) { return true; } }, + focusTopmost : function() { - var topZ = 0, topmostKey = -1; - for (var i = 0; i < hs.expanders.length; i++) { - if (hs.expanders[i]) { - if (hs.expanders[i].wrapper.style.zIndex && hs.expanders[i].wrapper.style.zIndex > topZ) { - topZ = hs.expanders[i].wrapper.style.zIndex; - + var topZ = 0, + topmostKey = -1, + expanders = hs.expanders, + exp, + zIndex; + for (var i = 0; i < expanders.length; i++) { + exp = expanders[i]; + if (exp) { + zIndex = exp.wrapper.style.zIndex; + if (zIndex && zIndex > topZ) { + topZ = zIndex; topmostKey = i; } } } if (topmostKey == -1) hs.focusKey = -1; - else hs.expanders[topmostKey].focus(); -}, - -getAdjacentAnchor : function(key, op) { - var aAr = document.getElementsByTagName('A'), hsAr = {}, activeI = -1, j = 0; - for (var i = 0; i < aAr.length; i++) { - if (hs.isHsAnchor(aAr[i]) && ((hs.expanders[key].slideshowGroup - == hs.getParam(aAr[i], 'slideshowGroup')))) { - hsAr[j] = aAr[i]; - if (hs.expanders[key] && aAr[i] == hs.expanders[key].a) { - activeI = j; - } - j++; - } - } - return hsAr[activeI + op]; + else expanders[topmostKey].focus(); }, getParam : function (a, param) { a.getParams = a.onclick; - var p = a.getParams(); + var p = a.getParams ? a.getParams() : null; a.getParams = null; - return (p && typeof p[param] != 'undefined') ? p[param] : hs[param]; + return (p && typeof p[param] != 'undefined') ? p[param] : + (typeof hs[param] != 'undefined' ? hs[param] : null); }, getSrc : function (a) { @@ -238,37 +270,34 @@ getNode : function (id) { } }, -purge : function(d) { - if (!hs.ie) return; - var a = d.attributes, i, l, n; - if (a) { - l = a.length; - for (var i = 0; i < l; i += 1) { - n = a[i].name; - if (typeof d[n] === 'function') { - d[n] = null; - } - } - } - a = d.childNodes; - if (a) { - l = a.length; - for (var i = 0; i < l; i += 1) { - hs.purge(d.childNodes[i]); - } - } +discardElement : function(d) { + if (d) hs.garbageBin.appendChild(d); + hs.garbageBin.innerHTML = ''; }, - -previousOrNext : function (el, op) { - var exp = hs.last = hs.getExpander(el); +transit : function (adj, exp) { + var last = exp || hs.getExpander(); + exp = last; + if (hs.upcoming) return false; + else hs.last = last; + hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler); try { - var adj = hs.upcoming = hs.getAdjacentAnchor(exp.key, op); + hs.upcoming = adj; adj.onclick(); - } catch (e){} - try { exp.close(); } catch (e) {} + } catch (e){ + hs.last = hs.upcoming = null; + } + try { + exp.close(); + } catch (e) {} return false; }, +previousOrNext : function (el, op) { + var exp = hs.getExpander(el); + if (exp) return hs.transit(exp.getAdjacentAnchor(op), exp); + else return false; +}, + previous : function (el) { return hs.previousOrNext(el, -1); }, @@ -280,15 +309,21 @@ next : function (el) { keyHandler : function(e) { if (!e) e = window.event; if (!e.target) e.target = e.srcElement; // ie - if (e.target.form) return; // form element has focus + if (typeof e.target.form != 'undefined') return true; // form element has focus + var exp = hs.getExpander(); var op = null; switch (e.keyCode) { + case 70: // f + if (exp) exp.doFullExpand(); + return true; + case 32: // Space case 34: // Page Down case 39: // Arrow right case 40: // Arrow down op = 1; break; + case 8: // Backspace case 33: // Page Up case 37: // Arrow left case 38: // Arrow up @@ -298,17 +333,18 @@ keyHandler : function(e) { case 13: // Enter op = 0; } - if (op !== null) { - hs.removeEventListener(document, 'keydown', hs.keyHandler); + if (op !== null) {hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler); if (!hs.enableKeyListener) return true; if (e.preventDefault) e.preventDefault(); else e.returnValue = false; - if (op == 0) { - try { hs.getExpander().close(); } catch (e) {} + if (exp) { + if (op == 0) { + exp.close(); + } else { + hs.previousOrNext(exp.key, op); + } return false; - } else { - return hs.previousOrNext(hs.focusKey, op); } } return true; @@ -316,10 +352,11 @@ keyHandler : function(e) { registerOverlay : function (overlay) { - hs.push(hs.overlays, overlay); + hs.push(hs.overlays, hs.extend(overlay, { hsId: 'hsId'+ hs.idCounter++ } )); }, -getWrapperKey : function (element) { + +getWrapperKey : function (element, expOnly) { var el, re = /^highslide-wrapper-([0-9]+)$/; // 1. look in open expanders el = element; @@ -328,32 +365,33 @@ getWrapperKey : function (element) { el = el.parentNode; } // 2. look in thumbnail - el = element; - while (el.parentNode) { - if (el.tagName && hs.isHsAnchor(el)) { - for (var key = 0; key < hs.expanders.length; key++) { - var exp = hs.expanders[key]; - if (exp && exp.a == el) return key; + if (!expOnly) { + el = element; + while (el.parentNode) { + if (el.tagName && hs.isHsAnchor(el)) { + for (var key = 0; key < hs.expanders.length; key++) { + var exp = hs.expanders[key]; + if (exp && exp.a == el) return key; + } } + el = el.parentNode; } - el = el.parentNode; } + return null; }, -getExpander : function (el) { - try { - if (!el) return hs.expanders[hs.focusKey]; - if (typeof el == 'number') return hs.expanders[el]; - if (typeof el == 'string') el = hs.$(el); - return hs.expanders[hs.getWrapperKey(el)]; - } catch (e) {} +getExpander : function (el, expOnly) { + if (typeof el == 'undefined') return hs.expanders[hs.focusKey] || null; + if (typeof el == 'number') return hs.expanders[el] || null; + if (typeof el == 'string') el = hs.$(el); + return hs.expanders[hs.getWrapperKey(el, expOnly)] || null; }, isHsAnchor : function (a) { return (a.onclick && a.onclick.toString().replace(/\s/g, ' ').match(/hs.(htmlE|e)xpand/)); }, -cleanUp : function () { +reOrder : function () { for (var i = 0; i < hs.expanders.length; i++) if (hs.expanders[i] && hs.expanders[i].isExpanded) hs.focusTopmost(); }, @@ -371,16 +409,23 @@ mouseClickHandler : function(e) el = el.parentNode; } var exp = hs.getExpander(el); - if (exp && (exp.isClosing || !exp.isExpanded)) return; + if (exp && (exp.isClosing || !exp.isExpanded)) return true; if (exp && e.type == 'mousedown') { - if (e.target.form) return; + if (e.target.form) return true; var match = el.className.match(/highslide-(image|move|resize)/); if (match) { - hs.dragArgs = { exp: exp , type: match[1], left: exp.x.min, width: exp.x.span, top: exp.y.min, - height: exp.y.span, clickX: e.clientX, clickY: e.clientY }; + hs.dragArgs = { + exp: exp , + type: match[1], + left: exp.x.pos, + width: exp.x.size, + top: exp.y.pos, + height: exp.y.size, + clickX: e.clientX, + clickY: e.clientY + }; - if (hs.dragArgs.type == 'image') exp.content.style.cursor = 'move'; hs.addEventListener(document, 'mousemove', hs.dragHandler); if (e.preventDefault) e.preventDefault(); // FF @@ -396,19 +441,16 @@ mouseClickHandler : function(e) hs.removeEventListener(document, 'mousemove', hs.dragHandler); if (hs.dragArgs) { - - if (hs.dragArgs.type == 'image') + if (hs.styleRestoreCursor && hs.dragArgs.type == 'image') hs.dragArgs.exp.content.style.cursor = hs.styleRestoreCursor; - - var hasDragged = (Math.abs(hs.dragArgs.dX) + Math.abs(hs.dragArgs.dY) > 0); + var hasDragged = hs.dragArgs.hasDragged; if (!hasDragged &&!hs.hasFocused && !/(move|resize)/.test(hs.dragArgs.type)) { exp.close(); } - else if (hasDragged || (!hasDragged && hs.hasHtmlexpanders)) { - hs.dragArgs.exp.redoShowHide(); + else if (hasDragged || (!hasDragged && hs.hasHtmlExpanders)) { + hs.dragArgs.exp.doShowHide('hidden'); } - hs.hasFocused = false; hs.dragArgs = null; @@ -416,22 +458,57 @@ mouseClickHandler : function(e) el.style.cursor = hs.styleRestoreCursor; } } + return false; }, dragHandler : function(e) { - if (!hs.dragArgs) return; + if (!hs.dragArgs) return true; if (!e) e = window.event; - var exp = hs.dragArgs.exp; + var a = hs.dragArgs, exp = a.exp; + + a.dX = e.clientX - a.clickX; + a.dY = e.clientY - a.clickY; - hs.dragArgs.dX = e.clientX - hs.dragArgs.clickX; - hs.dragArgs.dY = e.clientY - hs.dragArgs.clickY; + var distance = Math.sqrt(Math.pow(a.dX, 2) + Math.pow(a.dY, 2)); + if (!a.hasDragged) a.hasDragged = (a.type != 'image' && distance > 0) + || (distance > (hs.dragSensitivity || 5)); - exp.move(hs.dragArgs); + if (a.hasDragged && e.clientX > 5 && e.clientY > 5) { + + if (a.type == 'resize') exp.resize(a); + else { + exp.moveTo(a.left + a.dX, a.top + a.dY); + if (a.type == 'image') exp.content.style.cursor = 'move'; + } + } return false; }, +wrapperMouseHandler : function (e) { + try { + if (!e) e = window.event; + var over = /mouseover/i.test(e.type); + if (!e.target) e.target = e.srcElement; // ie + if (!e.relatedTarget) e.relatedTarget = + over ? e.fromElement : e.toElement; // ie + var exp = hs.getExpander(e.target); + if (!exp.isExpanded) return; + if (!exp || !e.relatedTarget || hs.getExpander(e.relatedTarget, true) == exp + || hs.dragArgs) return; + for (var i = 0; i < exp.overlays.length; i++) (function() { + var o = hs.$('hsId'+ exp.overlays[i]); + if (o && o.hideOnMouseOut) { + if (over) hs.setStyles(o, { visibility: 'visible', display: '' }); + hs.animate(o, { opacity: over ? o.opacity : 0 }, o.dur); + } + })(); + } catch (e) {} +}, addEventListener : function (el, event, func) { + if (el == document && event == 'ready') { + hs.push(hs.onReady, func); + } try { el.addEventListener(event, func, false); } catch (e) { @@ -459,57 +536,71 @@ removeEventListener : function (el, event, func) { preloadFullImage : function (i) { if (hs.continuePreloading && hs.preloadTheseImages[i] && hs.preloadTheseImages[i] != 'undefined') { var img = document.createElement('img'); - img.onload = function() { hs.preloadFullImage(i + 1); }; + img.onload = function() { + img = null; + hs.preloadFullImage(i + 1); + }; img.src = hs.preloadTheseImages[i]; } }, preloadImages : function (number) { if (number && typeof number != 'object') hs.numberOfImagesToPreload = number; - var a, re, j = 0; - - var aTags = document.getElementsByTagName('A'); - for (var i = 0; i < aTags.length; i++) { - a = aTags[i]; - re = hs.isHsAnchor(a); - if (re && re[0] == 'hs.expand') { - if (j < hs.numberOfImagesToPreload) { - hs.preloadTheseImages[j] = hs.getSrc(a); - j++; - } - } + + var arr = hs.getAnchors(); + for (var i = 0; i < arr.images.length && i < hs.numberOfImagesToPreload; i++) { + hs.push(hs.preloadTheseImages, hs.getSrc(arr.images[i])); } // preload outlines - new hs.Outline(hs.outlineType, function () { hs.preloadFullImage(0)} ); + if (hs.outlineType) new hs.Outline(hs.outlineType, function () { hs.preloadFullImage(0)} ); + else + hs.preloadFullImage(0); // preload cursor - var cur = hs.createElement('img', { src: hs.graphicsDir + hs.restoreCursor }); + if (hs.restoreCursor) var cur = hs.createElement('img', { src: hs.graphicsDir + hs.restoreCursor }); }, -genContainer : function () { +init : function () { if (!hs.container) { - hs.container = hs.createElement('div', - null, - { position: 'absolute', left: 0, top: 0, width: '100%', zIndex: hs.zIndexCounter }, + + hs.ieLt7 = hs.ie && hs.uaVersion < 7; + hs.ieLt9 = hs.ie && hs.uaVersion < 9; + + hs.getPageSize(); + for (var x in hs.langDefaults) { + if (typeof hs[x] != 'undefined') hs.lang[x] = hs[x]; + else if (typeof hs.lang[x] == 'undefined' && typeof hs.langDefaults[x] != 'undefined') + hs.lang[x] = hs.langDefaults[x]; + } + + hs.container = hs.createElement('div', { + className: 'highslide-container' + }, { + position: 'absolute', + left: 0, + top: 0, + width: '100%', + zIndex: hs.zIndexCounter, + direction: 'ltr' + }, document.body, true ); - hs.loading = hs.createElement('a', - { + hs.loading = hs.createElement('a', { className: 'highslide-loading', - title: hs.loadingTitle, - innerHTML: hs.loadingText, - href: 'javascript:void(0)' - }, - { + title: hs.lang.loadingTitle, + innerHTML: hs.lang.loadingText, + href: 'javascript:;' + }, { position: 'absolute', + top: '-9999px', opacity: hs.loadingOpacity, - left: '-9999px', zIndex: 1 }, hs.container ); + hs.garbageBin = hs.createElement('div', null, { display: 'none' }, hs.container); // http://www.robertpenner.com/easing/ Math.linearTween = function (t, b, c, d) { @@ -518,87 +609,187 @@ genContainer : function () { Math.easeInQuad = function (t, b, c, d) { return c*(t/=d)*t + b; }; + + hs.hideSelects = hs.ieLt7; + hs.hideIframes = ((window.opera && hs.uaVersion < 9) || navigator.vendor == 'KDE' + || (hs.ieLt7 && hs.uaVersion < 5.5)); } }, +ready : function() { + if (hs.isReady) return; + hs.isReady = true; + for (var i = 0; i < hs.onReady.length; i++) hs.onReady[i](); +}, -fade : function (el, o, oFinal, dur, i, dir) { - if (typeof i == 'undefined') { // new fader - if (dur === 0) { // instant - hs.setStyles( el, { - opacity: oFinal, - visibility: (o < oFinal ? 'visible': 'hidden') - }); - return; +updateAnchors : function() { + var el, els, all = [], images = [],groups = {}, re; + + for (var i = 0; i < hs.openerTagNames.length; i++) { + els = document.getElementsByTagName(hs.openerTagNames[i]); + for (var j = 0; j < els.length; j++) { + el = els[j]; + re = hs.isHsAnchor(el); + if (re) { + hs.push(all, el); + if (re[0] == 'hs.expand') hs.push(images, el); + var g = hs.getParam(el, 'slideshowGroup') || 'none'; + if (!groups[g]) groups[g] = []; + hs.push(groups[g], el); + } } - i = hs.faders.length; - dir = oFinal > o ? 1 : -1; - var step = (25 / (dur || 250)) * Math.abs(o - oFinal); } - o = parseFloat(o); - el.style.visibility = (o <= 0) ? 'hidden' : 'visible'; - if (o < 0 || (dir == 1 && o > oFinal)) return; - if (el.fading && el.fading.i != i) { // reverse - clearTimeout(hs.faders[el.fading.i]); - o = el.fading.o; - } - el.fading = {i: i, o: o, step: (step || el.fading.step)}; - el.style.visibility = (o <= 0) ? 'hidden' : 'visible'; - hs.setStyles(el, { opacity: o }); - hs.faders[i] = setTimeout(function() { - hs.fade(el, o + el.fading.step * dir, oFinal, null, i, dir); - }, 25); + hs.anchors = { all: all, groups: groups, images: images }; + return hs.anchors; + }, +getAnchors : function() { + return hs.anchors || hs.updateAnchors(); +}, + + close : function(el) { - try { hs.getExpander(el).close(); } catch (e) {} + var exp = hs.getExpander(el); + if (exp) exp.close(); return false; } }; // end hs object +hs.fx = function( elem, options, prop ){ + this.options = options; + this.elem = elem; + this.prop = prop; + + if (!options.orig) options.orig = {}; +}; +hs.fx.prototype = { + update: function(){ + (hs.fx.step[this.prop] || hs.fx.step._default)(this); + + if (this.options.step) + this.options.step.call(this.elem, this.now, this); + + }, + custom: function(from, to, unit){ + this.startTime = (new Date()).getTime(); + this.start = from; + this.end = to; + this.unit = unit;// || this.unit || "px"; + this.now = this.start; + this.pos = this.state = 0; + + var self = this; + function t(gotoEnd){ + return self.step(gotoEnd); + } + + t.elem = this.elem; + + if ( t() && hs.timers.push(t) == 1 ) { + hs.timerId = setInterval(function(){ + var timers = hs.timers; + + for ( var i = 0; i < timers.length; i++ ) + if ( !timers[i]() ) + timers.splice(i--, 1); + + if ( !timers.length ) { + clearInterval(hs.timerId); + } + }, 13); + } + }, + step: function(gotoEnd){ + var t = (new Date()).getTime(); + if ( gotoEnd || t >= this.options.duration + this.startTime ) { + this.now = this.end; + this.pos = this.state = 1; + this.update(); + + this.options.curAnim[ this.prop ] = true; + + var done = true; + for ( var i in this.options.curAnim ) + if ( this.options.curAnim[i] !== true ) + done = false; + + if ( done ) { + if (this.options.complete) this.options.complete.call(this.elem); + } + return false; + } else { + var n = t - this.startTime; + this.state = n / this.options.duration; + this.pos = this.options.easing(n, 0, 1, this.options.duration); + this.now = this.start + ((this.end - this.start) * this.pos); + this.update(); + } + return true; + } + +}; +hs.extend( hs.fx, { + step: { + + opacity: function(fx){ + hs.setStyles(fx.elem, { opacity: fx.now }); + }, + + _default: function(fx){ + try { + if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) + fx.elem.style[ fx.prop ] = fx.now + fx.unit; + else + fx.elem[ fx.prop ] = fx.now; + } catch (e) {} + } + } +}); -//----------------------------------------------------------------------------- hs.Outline = function (outlineType, onLoad) { this.onLoad = onLoad; this.outlineType = outlineType; - var v = hs.ieVersion(), tr; + var v = hs.uaVersion, tr; - this.hasAlphaImageLoader = hs.ie && v >= 5.5 && v < 7; + this.hasAlphaImageLoader = hs.ie && hs.uaVersion < 7; if (!outlineType) { if (onLoad) onLoad(); return; } - hs.genContainer(); + hs.init(); this.table = hs.createElement( - 'table', { cellSpacing: 0 }, - { + 'table', { + cellSpacing: 0 + }, { visibility: 'hidden', position: 'absolute', - borderCollapse: 'collapse' + borderCollapse: 'collapse', + width: 0 }, hs.container, true ); - this.tbody = hs.createElement('tbody', null, null, this.table, 1); + var tbody = hs.createElement('tbody', null, null, this.table, 1); this.td = []; for (var i = 0; i <= 8; i++) { - if (i % 3 == 0) tr = hs.createElement('tr', null, { height: 'auto' }, this.tbody, true); + if (i % 3 == 0) tr = hs.createElement('tr', null, { height: 'auto' }, tbody, true); this.td[i] = hs.createElement('td', null, null, tr, true); var style = i != 4 ? { lineHeight: 0, fontSize: 0} : { position : 'relative' }; hs.setStyles(this.td[i], style); } - this.td[4].className = outlineType; + this.td[4].className = outlineType +' highslide-outline'; this.preloadGraphic(); }; hs.Outline.prototype = { -preloadGraphic : function () { +preloadGraphic : function () { var src = hs.graphicsDir + (hs.outlinesDir || "outlines/")+ this.outlineType +".png"; - var appendTo = hs.safari ? hs.container : null; - this.graphic = hs.createElement('img', null, { position: 'absolute', left: '-9999px', + var appendTo = hs.safari && hs.uaVersion < 525 ? hs.container : null; + this.graphic = hs.createElement('img', null, { position: 'absolute', top: '-9999px' }, appendTo, true); // for onload trigger var pThis = this; @@ -611,7 +802,6 @@ onGraphicLoad : function () { var o = this.offset = this.graphic.width / 4, pos = [[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]], dim = { height: (2*o) +'px', width: (2*o) +'px' }; - for (var i = 0; i <= 8; i++) { if (pos[i]) { if (this.hasAlphaImageLoader) { @@ -637,56 +827,166 @@ onGraphicLoad : function () { hs.setStyles (this.td[i], dim); } } - + this.graphic = null; + if (hs.pendingOutlines[this.outlineType]) hs.pendingOutlines[this.outlineType].destroy(); hs.pendingOutlines[this.outlineType] = this; if (this.onLoad) this.onLoad(); }, -setPosition : function (exp, x, y, w, h, vis) { - if (vis) this.table.style.visibility = (h >= 4 * this.offset) +setPosition : function (pos, offset, vis, dur, easing) { + var exp = this.exp, + stl = exp.wrapper.style, + offset = offset || 0, + pos = pos || { + x: exp.x.pos + offset, + y: exp.y.pos + offset, + w: exp.x.get('wsize') - 2 * offset, + h: exp.y.get('wsize') - 2 * offset + }; + if (vis) this.table.style.visibility = (pos.h >= 4 * this.offset) ? 'visible' : 'hidden'; - this.table.style.left = (x - this.offset) +'px'; - this.table.style.top = (y - this.offset) +'px'; - this.table.style.width = (w + 2 * (exp.offsetBorderW + this.offset)) +'px'; - w += 2 * (exp.offsetBorderW - this.offset); - h += + 2 * (exp.offsetBorderH - this.offset); - this.td[4].style.width = w >= 0 ? w +'px' : 0; - this.td[4].style.height = h >= 0 ? h +'px' : 0; + hs.setStyles(this.table, { + left: (pos.x - this.offset) +'px', + top: (pos.y - this.offset) +'px', + width: (pos.w + 2 * this.offset) +'px' + }); + + pos.w -= 2 * this.offset; + pos.h -= 2 * this.offset; + hs.setStyles (this.td[4], { + width: pos.w >= 0 ? pos.w +'px' : 0, + height: pos.h >= 0 ? pos.h +'px' : 0 + }); if (this.hasAlphaImageLoader) this.td[3].style.height - = this.td[5].style.height = this.td[4].style.height; + = this.td[5].style.height = this.td[4].style.height; + }, destroy : function(hide) { if (hide) this.table.style.visibility = 'hidden'; - else { - hs.purge(this.table); - try { this.table.parentNode.removeChild(this.table); } catch (e) {} + else hs.discardElement(this.table); +} +}; + +hs.Dimension = function(exp, dim) { + this.exp = exp; + this.dim = dim; + this.ucwh = dim == 'x' ? 'Width' : 'Height'; + this.wh = this.ucwh.toLowerCase(); + this.uclt = dim == 'x' ? 'Left' : 'Top'; + this.lt = this.uclt.toLowerCase(); + this.ucrb = dim == 'x' ? 'Right' : 'Bottom'; + this.rb = this.ucrb.toLowerCase(); + this.p1 = this.p2 = 0; +}; +hs.Dimension.prototype = { +get : function(key) { + switch (key) { + case 'loadingPos': + return this.tpos + this.tb + (this.t - hs.loading['offset'+ this.ucwh]) / 2; + case 'wsize': + return this.size + 2 * this.cb + this.p1 + this.p2; + case 'fitsize': + return this.clientSize - this.marginMin - this.marginMax; + case 'maxsize': + return this.get('fitsize') - 2 * this.cb - this.p1 - this.p2 ; + case 'opos': + return this.pos - (this.exp.outline ? this.exp.outline.offset : 0); + case 'osize': + return this.get('wsize') + (this.exp.outline ? 2*this.exp.outline.offset : 0); + case 'imgPad': + return this.imgSize ? Math.round((this.size - this.imgSize) / 2) : 0; + } +}, +calcBorders: function() { + // correct for borders + this.cb = (this.exp.content['offset'+ this.ucwh] - this.t) / 2; + + this.marginMax = hs['margin'+ this.ucrb]; +}, +calcThumb: function() { + this.t = this.exp.el[this.wh] ? parseInt(this.exp.el[this.wh]) : + this.exp.el['offset'+ this.ucwh]; + this.tpos = this.exp.tpos[this.dim]; + this.tb = (this.exp.el['offset'+ this.ucwh] - this.t) / 2; + if (this.tpos == 0 || this.tpos == -1) { + this.tpos = (hs.page[this.wh] / 2) + hs.page['scroll'+ this.uclt]; + }; +}, +calcExpanded: function() { + var exp = this.exp; + this.justify = 'auto'; + + + // size and position + this.pos = this.tpos - this.cb + this.tb; + + if (this.maxHeight && this.dim == 'x') + exp.maxWidth = Math.min(exp.maxWidth || this.full, exp.maxHeight * this.full / exp.y.full); + + this.size = Math.min(this.full, exp['max'+ this.ucwh] || this.full); + this.minSize = exp.allowSizeReduction ? + Math.min(exp['min'+ this.ucwh], this.full) :this.full; + if (exp.isImage && exp.useBox) { + this.size = exp[this.wh]; + this.imgSize = this.full; + } + if (this.dim == 'x' && hs.padToMinWidth) this.minSize = exp.minWidth; + this.marginMin = hs['margin'+ this.uclt]; + this.scroll = hs.page['scroll'+ this.uclt]; + this.clientSize = hs.page[this.wh]; +}, +setSize: function(i) { + var exp = this.exp; + if (exp.isImage && (exp.useBox || hs.padToMinWidth)) { + this.imgSize = i; + this.size = Math.max(this.size, this.imgSize); + exp.content.style[this.lt] = this.get('imgPad')+'px'; + } else + this.size = i; + + exp.content.style[this.wh] = i +'px'; + exp.wrapper.style[this.wh] = this.get('wsize') +'px'; + if (exp.outline) exp.outline.setPosition(); + if (this.dim == 'x' && exp.overlayBox) exp.sizeOverlayBox(true); +}, +setPos: function(i) { + this.pos = i; + this.exp.wrapper.style[this.lt] = i +'px'; + + if (this.exp.outline) this.exp.outline.setPosition(); + } }; -//----------------------------------------------------------------------------- -// The expander object hs.Expander = function(a, params, custom, contentType) { + if (document.readyState && hs.ie && !hs.isReady) { + hs.addEventListener(document, 'ready', function() { + new hs.Expander(a, params, custom, contentType); + }); + return; + } this.a = a; this.custom = custom; this.contentType = contentType || 'image'; this.isImage = !this.isHtml; hs.continuePreloading = false; - hs.genContainer(); + this.overlays = []; + hs.init(); var key = this.key = hs.expanders.length; - // override inline parameters for (var i = 0; i < hs.overrides.length; i++) { var name = hs.overrides[i]; this[name] = params && typeof params[name] != 'undefined' ? params[name] : hs[name]; } + if (!this.src) this.src = a.href; // get thumb - var el = this.thumb = (params ? hs.$(params.thumbnailId) : null) - || a.getElementsByTagName('IMG')[0] || a; + var el = (params && params.thumbnailId) ? hs.$(params.thumbnailId) : a; + el = this.thumb = el.getElementsByTagName('img')[0] || el; this.thumbsUserSetId = el.id || a.id; // check if already open @@ -694,95 +994,92 @@ hs.Expander = function(a, params, custom, contentType) { if (hs.expanders[i] && hs.expanders[i].a == a) { hs.expanders[i].focus(); return false; - } + } } + // cancel other - for (var i = 0; i < hs.expanders.length; i++) { + if (!hs.allowSimultaneousLoading) for (var i = 0; i < hs.expanders.length; i++) { if (hs.expanders[i] && hs.expanders[i].thumb != el && !hs.expanders[i].onLoadStarted) { hs.expanders[i].cancelLoading(); } } - hs.expanders[this.key] = this; - if (!hs.allowMultipleInstances) { - try { hs.expanders[key - 1].close(); } catch (e){} - try { hs.expanders[hs.focusKey].close(); } catch (e){} // preserved + hs.expanders[key] = this; + if (!hs.allowMultipleInstances && !hs.upcoming) { + if (hs.expanders[key-1]) hs.expanders[key-1].close(); + if (typeof hs.focusKey != 'undefined' && hs.expanders[hs.focusKey]) + hs.expanders[hs.focusKey].close(); } - this.overlays = []; - - var pos = hs.position(el); - - // store properties of thumbnail - this.thumbWidth = el.width ? el.width : el.offsetWidth; - this.thumbHeight = el.height ? el.height : el.offsetHeight; - this.thumbLeft = pos.x; - this.thumbTop = pos.y; - this.thumbOffsetBorderW = (this.thumb.offsetWidth - this.thumbWidth) / 2; - this.thumbOffsetBorderH = (this.thumb.offsetHeight - this.thumbHeight) / 2; - // instanciate the wrapper + // initiate metrics + this.el = el; + this.tpos = this.pageOrigin || hs.getPosition(el); + hs.getPageSize(); + var x = this.x = new hs.Dimension(this, 'x'); + x.calcThumb(); + var y = this.y = new hs.Dimension(this, 'y'); + y.calcThumb(); this.wrapper = hs.createElement( - 'div', - { + 'div', { id: 'highslide-wrapper-'+ this.key, - className: this.wrapperClassName - }, - { + className: 'highslide-wrapper '+ this.wrapperClassName + }, { visibility: 'hidden', position: 'absolute', - zIndex: hs.zIndexCounter++ + zIndex: hs.zIndexCounter += 2 }, null, true ); - this.wrapper.onmouseover = function (e) { - try { hs.expanders[key].wrapperMouseHandler(e); } catch (e) {} - }; - this.wrapper.onmouseout = function (e) { - try { hs.expanders[key].wrapperMouseHandler(e); } catch (e) {} - }; + this.wrapper.onmouseover = this.wrapper.onmouseout = hs.wrapperMouseHandler; if (this.contentType == 'image' && this.outlineWhileAnimating == 2) this.outlineWhileAnimating = 0; + // get the outline - if (hs.pendingOutlines[this.outlineType]) { - this.connectOutline(); + if (!this.outlineType) { this[this.contentType +'Create'](); - } else if (!this.outlineType) { + + } else if (hs.pendingOutlines[this.outlineType]) { + this.connectOutline(); this[this.contentType +'Create'](); + } else { - this.displayLoading(); + this.showLoading(); var exp = this; new hs.Outline(this.outlineType, - function () { + function () { exp.connectOutline(); exp[exp.contentType +'Create'](); } ); } + return true; }; hs.Expander.prototype = { +error : function(e) { + if (hs.debug) alert ('Line '+ e.lineNumber +': '+ e.message); + else window.location.href = this.src; +}, -connectOutline : function(x, y) { - var w = hs.pendingOutlines[this.outlineType]; - this.objOutline = w; - w.table.style.zIndex = this.wrapper.style.zIndex; +connectOutline : function() { + var outline = this.outline = hs.pendingOutlines[this.outlineType]; + outline.exp = this; + outline.table.style.zIndex = this.wrapper.style.zIndex - 1; hs.pendingOutlines[this.outlineType] = null; }, -displayLoading : function() { +showLoading : function() { if (this.onLoadStarted || this.loading) return; - - this.originalCursor = this.a.style.cursor; - this.a.style.cursor = 'wait'; this.loading = hs.loading; var exp = this; this.loading.onclick = function() { exp.cancelLoading(); }; - this.loading.style.top = (this.thumbTop - + (this.thumbHeight - this.loading.offsetHeight) / 2) +'px'; - var exp = this, left = (this.thumbLeft + this.thumbOffsetBorderW - + (this.thumbWidth - this.loading.offsetWidth) / 2) +'px'; - setTimeout(function () { if (exp.loading) exp.loading.style.left = left }, 100); + var exp = this, + l = this.x.get('loadingPos') +'px', + t = this.y.get('loadingPos') +'px'; + setTimeout(function () { + if (exp.loading) hs.setStyles(exp.loading, { left: l, top: t, zIndex: hs.zIndexCounter++ })} + , 100); }, imageCreate : function() { @@ -793,344 +1090,293 @@ imageCreate : function() { img.onload = function () { if (hs.expanders[exp.key]) exp.contentLoaded(); }; - /* Manage loading or rendering error */ + /* Patch start : manage loading or rendering error to avoid 'loading...' stay indefinitely */ img.onerror = function () { + /* Set alternative text */ + img.alt = 'X'; + /* Set image size to ensure it can be clicked to close popup */ + if(exp.content) { + exp.content.width = 30; + exp.content.height = 30; + } if (hs.expanders[exp.key]) { exp.contentLoaded(); } }; + /* Patch end */ + if (hs.blockRightClick) img.oncontextmenu = function() { return false; }; img.className = 'highslide-image'; - img.style.visibility = 'hidden'; // prevent flickering in IE - img.style.display = 'block'; - img.style.position = 'absolute'; - img.style.maxWidth = 'none'; - img.style.zIndex = 3; - img.title = hs.restoreTitle; - /* Ensure an alternative text and minimum dimensions in case of rendering failure */ - img.alt = 'X'; - img.style.minWidth = '3em'; - img.style.minHeight = '3em'; - if (hs.safari) hs.container.appendChild(img); - // uncomment this to flush img size: - // if (hs.ie) img.src = null; - img.src = hs.getSrc(this.a); - - this.displayLoading(); + hs.setStyles(img, { + visibility: 'hidden', + display: 'block', + position: 'absolute', + maxWidth: '9999px', + zIndex: 3 + }); + img.title = hs.lang.restoreTitle; + + if (hs.safari && hs.uaVersion < 525) hs.container.appendChild(img); + if (hs.ie && hs.flushImgSize) img.src = null; + img.src = this.src; + + this.showLoading(); }, contentLoaded : function() { try { if (!this.content) return; - if (this.onLoadStarted) return; // old Gecko loop + this.content.onload = null; + if (this.onLoadStarted) return; else this.onLoadStarted = true; - + var x = this.x, y = this.y; + if (this.loading) { - this.loading.style.left = '-9999px'; + hs.setStyles(this.loading, { top: '-9999px' }); this.loading = null; - this.a.style.cursor = this.originalCursor || ''; - } - this.marginBottom = hs.marginBottom; - this.newWidth = this.content.width; - this.newHeight = this.content.height; - this.fullExpandWidth = this.newWidth; - this.fullExpandHeight = this.newHeight; + } + x.full = this.content.width; + y.full = this.content.height; - this.content.style.width = this.thumbWidth +'px'; - this.content.style.height = this.thumbHeight +'px'; - this.getCaption(); - - - this.wrapper.appendChild(this.content); - this.content.style.position = 'relative'; // Saf - if (this.caption) this.wrapper.appendChild(this.caption); - this.wrapper.style.left = this.thumbLeft +'px'; - this.wrapper.style.top = this.thumbTop +'px'; - hs.container.appendChild(this.wrapper); - - // correct for borders - this.offsetBorderW = (this.content.offsetWidth - this.thumbWidth) / 2; - this.offsetBorderH = (this.content.offsetHeight - this.thumbHeight) / 2; - var modMarginRight = hs.marginRight + 2 * this.offsetBorderW; - this.marginBottom += 2 * this.offsetBorderH; - - var ratio = this.newWidth / this.newHeight; - var minWidth = this.allowSizeReduction - ? this.minWidth : this.newWidth; - var minHeight = this.allowSizeReduction - ? this.minHeight : this.newHeight; + hs.setStyles(this.content, { + width: x.t +'px', + height: y.t +'px' + }); + this.wrapper.appendChild(this.content); + hs.container.appendChild(this.wrapper); - var justify = { x: 'auto', y: 'auto' }; + x.calcBorders(); + y.calcBorders(); - var page = hs.getPageSize(); - // justify - this.x = { - min: parseInt(this.thumbLeft) - this.offsetBorderW + this.thumbOffsetBorderW, - span: this.newWidth, - minSpan: (this.newWidth < minWidth && !hs.padToMinWidth) - ? this.newWidth : minWidth, - marginMin: hs.marginLeft, - marginMax: modMarginRight, - scroll: page.scrollLeft, - clientSpan: page.width, - thumbSpan: this.thumbWidth - }; - var oldRight = this.x.min + parseInt(this.thumbWidth); - this.x = this.justify(this.x); - this.y = { - min: parseInt(this.thumbTop) - this.offsetBorderH + this.thumbOffsetBorderH, - span: this.newHeight, - minSpan: this.newHeight < minHeight ? this.newHeight : minHeight, - marginMin: hs.marginTop, - marginMax: this.marginBottom, - scroll: page.scrollTop, - clientSpan: page.height, - thumbSpan: this.thumbHeight - }; - var oldBottom = this.y.min + parseInt(this.thumbHeight); - this.y = this.justify(this.y); + hs.setStyles (this.wrapper, { + left: (x.tpos + x.tb - x.cb) +'px', + top: (y.tpos + x.tb - y.cb) +'px' + }); + this.getOverlays(); - this.correctRatio(ratio); + var ratio = x.full / y.full; + x.calcExpanded(); + this.justify(x); + y.calcExpanded(); + this.justify(y); + if (this.overlayBox) this.sizeOverlayBox(0, 1); - var x = this.x; - var y = this.y; + if (this.allowSizeReduction) { + this.correctRatio(ratio); + if (this.isImage && this.x.full > (this.x.imgSize || this.x.size)) { + this.createFullExpand(); + if (this.overlays.length == 1) this.sizeOverlayBox(); + } + } this.show(); + } catch (e) { - window.location.href = hs.getSrc(this.a); + this.error(e); } }, -justify : function (p) { - - var tgt, dim = p == this.x ? 'x' : 'y'; - +justify : function (p, moveOnly) { + var tgtArr, tgt = p.target, dim = p == this.x ? 'x' : 'y'; var hasMovedMin = false; - var allowReduce = true; - - // calculate p.min - p.min = Math.round(p.min - ((p.span - p.thumbSpan) / 2)); // auto - - if (p.min < p.scroll + p.marginMin) { - p.min = p.scroll + p.marginMin; + var allowReduce = p.exp.allowSizeReduction; + p.pos = Math.round(p.pos - ((p.get('wsize') - p.t) / 2)); + if (p.pos < p.scroll + p.marginMin) { + p.pos = p.scroll + p.marginMin; hasMovedMin = true; } - - - if (p.span < p.minSpan) { - p.span = p.minSpan; - allowReduce = false; + if (!moveOnly && p.size < p.minSize) { + p.size = p.minSize; + allowReduce = false; } - - // calculate right/newWidth - if (p.min + p.span > p.scroll + p.clientSpan - p.marginMax) { - if (hasMovedMin && allowReduce) { - - p.span = p.clientSpan - p.marginMin - p.marginMax; // can't expand more - - } else if (p.span < p.clientSpan - p.marginMin - p.marginMax) { // move newTop up - p.min = p.scroll + p.clientSpan - p.span - p.marginMin - p.marginMax; - } else { // image larger than client - p.min = p.scroll + p.marginMin; - - if (allowReduce) p.span = p.clientSpan - p.marginMin - p.marginMax; - - } - + if (p.pos + p.get('wsize') > p.scroll + p.clientSize - p.marginMax) { + if (!moveOnly && hasMovedMin && allowReduce) { + p.size = Math.min(p.size, p.get(dim == 'y' ? 'fitsize' : 'maxsize')); + } else if (p.get('wsize') < p.get('fitsize')) { + p.pos = p.scroll + p.clientSize - p.marginMax - p.get('wsize'); + } else { // image larger than viewport + p.pos = p.scroll + p.marginMin; + if (!moveOnly && allowReduce) p.size = p.get(dim == 'y' ? 'fitsize' : 'maxsize'); + } } - if (p.span < p.minSpan) { - p.span = p.minSpan; + if (!moveOnly && p.size < p.minSize) { + p.size = p.minSize; allowReduce = false; } - if (p.min < p.marginMin) { - tmpMin = p.min; - p.min = p.marginMin; + if (p.pos < p.marginMin) { + var tmpMin = p.pos; + p.pos = p.marginMin; - if (allowReduce) p.span = p.span - (p.min - tmpMin); + if (allowReduce && !moveOnly) p.size = p.size - (p.pos - tmpMin); } - return p; }, correctRatio : function(ratio) { - var x = this.x; - var y = this.y; - var changed = false; - if (x.span / y.span > ratio) { // width greater - var tmpWidth = x.span; - x.span = y.span * ratio; - if (x.span < x.minSpan) { // below minWidth - if (hs.padToMinWidth) x.imgSpan = x.span; - x.span = x.minSpan; - if (!x.imgSpan) - y.span = x.span / ratio; + var x = this.x, + y = this.y, + changed = false, + xSize = Math.min(x.full, x.size), + ySize = Math.min(y.full, y.size), + useBox = (this.useBox || hs.padToMinWidth); + + if (xSize / ySize > ratio) { // width greater + xSize = ySize * ratio; + if (xSize < x.minSize) { // below minWidth + xSize = x.minSize; + ySize = xSize / ratio; } changed = true; - } else if (x.span / y.span < ratio) { // height greater - var tmpHeight = y.span; - y.span = x.span / ratio; + } else if (xSize / ySize < ratio) { // height greater + ySize = xSize / ratio; changed = true; } - if (changed) { - x.min = parseInt(this.thumbLeft) - this.offsetBorderW + this.thumbOffsetBorderW; - x.minSpan = x.span; - this.x = this.justify(x); - - y.min = parseInt(this.thumbTop) - this.offsetBorderH + this.thumbOffsetBorderH; - y.minSpan = y.span; - this.y = this.justify(y); + if (hs.padToMinWidth && x.full < x.minSize) { + x.imgSize = x.full; + y.size = y.imgSize = y.full; + } else if (this.useBox) { + x.imgSize = xSize; + y.imgSize = ySize; + } else { + x.size = xSize; + y.size = ySize; + } + changed = this.fitOverlayBox(this.useBox ? null : ratio, changed); + if (useBox && y.size < y.imgSize) { + y.imgSize = y.size; + x.imgSize = y.size * ratio; + } + if (changed || useBox) { + x.pos = x.tpos - x.cb + x.tb; + x.minSize = x.size; + this.justify(x, true); + + y.pos = y.tpos - y.cb + y.tb; + y.minSize = y.size; + this.justify(y, true); + if (this.overlayBox) this.sizeOverlayBox(); + } + + +}, +fitOverlayBox : function(ratio, changed) { + var x = this.x, y = this.y; + if (this.overlayBox) { + while (y.size > this.minHeight && x.size > this.minWidth + && y.get('wsize') > y.get('fitsize')) { + y.size -= 10; + if (ratio) x.size = y.size * ratio; + this.sizeOverlayBox(0, 1); + changed = true; + } } + return changed; }, show : function () { + var x = this.x, y = this.y; + this.doShowHide('hidden'); - // Selectbox bug - var imgPos = {x: this.x.min - 20, y: this.y.min - 20, w: this.x.span + 40, - h: this.y.span + 40 - + this.spaceForCaption}; - hs.hideSelects = (hs.ie && hs.ieVersion() < 7); - if (hs.hideSelects) this.showHideElements('SELECT', 'hidden', imgPos); - // Iframes bug - hs.hideIframes = ((window.opera && navigator.appVersion < 9) || navigator.vendor == 'KDE' - || (hs.ie && hs.ieVersion() < 5.5)); - if (hs.hideIframes) this.showHideElements('IFRAME', 'hidden', imgPos); - // Scrollbars bug - if (hs.geckoMac) this.showHideElements('*', 'hidden', imgPos); - - - if (this.x.imgSpan) this.content.style.margin = '0 auto'; - - // Apply size change + // Apply size change this.changeSize( - 1, - { - x: this.thumbLeft + this.thumbOffsetBorderW - this.offsetBorderW, - y: this.thumbTop + this.thumbOffsetBorderH - this.offsetBorderH, - w: this.thumbWidth, - h: this.thumbHeight, - imgW: this.thumbWidth, - o: hs.outlineStartOffset - }, - { - x: this.x.min, - y: this.y.min, - w: this.x.span, - h: this.y.span, - imgW: this.x.imgSpan, - o: this.objOutline ? this.objOutline.offset : 0 + 1, { + wrapper: { + width : x.get('wsize'), + height : y.get('wsize'), + left: x.pos, + top: y.pos + }, + content: { + left: x.p1 + x.get('imgPad'), + top: y.p1 + y.get('imgPad'), + width:x.imgSize ||x.size, + height:y.imgSize ||y.size + } }, - hs.expandDuration, - hs.expandSteps + hs.expandDuration ); }, -changeSize : function(up, from, to, dur, steps) { - - if (up && this.objOutline && !this.outlineWhileAnimating) - this.objOutline.setPosition(this, this.x.min, this.y.min, this.x.span, this.y.span); +changeSize : function(up, to, dur) { - else if (!up && this.objOutline) { - if (this.outlineWhileAnimating) this.objOutline.setPosition(this, from.x, from.y, from.w, from.h); - else this.objOutline.destroy(); - } - - if (!up) { // remove children - var n = this.wrapper.childNodes.length; - for (var i = n - 1; i >= 0 ; i--) { - var child = this.wrapper.childNodes[i]; - if (child != this.content) { - hs.purge(child); - this.wrapper.removeChild(child); - } - } - } - - if (this.fadeInOut) { - from.op = up ? 0 : 1; - to.op = up; + if (this.outline && !this.outlineWhileAnimating) { + if (up) this.outline.setPosition(); + else this.outline.destroy(); } - var dT = Math.round(dur/steps), - exp = this, - easing = Math[this.easing] || Math.easeInQuad; - if (!up) easing = Math[this.easingClose] || easing; - - for (var i = 1, t = 0; i <= steps; i++, t += dT) { - (function() { - var size = {}, pI = i; - - for (var x in from) - size[x] = easing(t + dT, from[x], to[x] - from[x], dur); - - setTimeout ( function() { - exp.setSize(size); - - if (up && pI == 1) { - exp.content.style.visibility = 'visible'; - exp.a.className += ' highslide-active-anchor'; - } + + + if (!up) this.destroyOverlays(); + + var exp = this, + x = exp.x, + y = exp.y, + easing = this.easing; + if (!up) easing = this.easingClose || easing; + var after = up ? + function() { - }, t); - })(); + if (exp.outline) exp.outline.table.style.visibility = "visible"; + setTimeout(function() { + exp.afterExpand(); + }, 50); + } : + function() { + exp.afterClose(); + }; + if (up) hs.setStyles( this.wrapper, { + width: x.t +'px', + height: y.t +'px' + }); + if (this.fadeInOut) { + hs.setStyles(this.wrapper, { opacity: up ? 0 : 1 }); + hs.extend(to.wrapper, { opacity: up }); } - - if (up) { - - setTimeout(function() { - if (exp.objOutline) exp.objOutline.table.style.visibility = "visible"; - }, t); - setTimeout(function() { - if (exp.caption) exp.writeCaption(); - exp.afterExpand(); - }, t + 50); + hs.animate( this.wrapper, to.wrapper, { + duration: dur, + easing: easing, + step: function(val, args) { + if (exp.outline && exp.outlineWhileAnimating && args.prop == 'top') { + var fac = up ? args.pos : 1 - args.pos; + var pos = { + w: x.t + (x.get('wsize') - x.t) * fac, + h: y.t + (y.get('wsize') - y.t) * fac, + x: x.tpos + (x.pos - x.tpos) * fac, + y: y.tpos + (y.pos - y.tpos) * fac + }; + exp.outline.setPosition(pos, 0, 1); + } + } + }); + hs.animate( this.content, to.content, dur, easing, after); + if (up) { + this.wrapper.style.visibility = 'visible'; + this.content.style.visibility = 'visible'; + this.a.className += ' highslide-active-anchor'; } - else setTimeout(function() { exp.afterClose(); }, t); - }, -setSize : function (to) { - try { - this.wrapper.style.width = (to.w + 2*this.offsetBorderW) +'px'; - this.content.style.width = - ((to.imgW && !isNaN(to.imgW)) ? to.imgW : to.w) +'px'; - if (hs.safari) this.content.style.maxWidth = this.content.style.width; - this.content.style.height = to.h +'px'; - - if (to.op) hs.setStyles(this.wrapper, { opacity: to.op }); - - - if (this.objOutline && this.outlineWhileAnimating) { - var o = this.objOutline.offset - to.o; - this.objOutline.setPosition(this, to.x + o, to.y + o, to.w - 2 * o, to.h - 2 * o, 1); - } - - hs.setStyles ( this.wrapper, - { - 'visibility': 'visible', - 'left': to.x +'px', - 'top': to.y +'px' - } - ); - - } catch (e) { window.location.href = hs.getSrc(this.a); } -}, + + afterExpand : function() { this.isExpanded = true; this.focus(); + if (hs.upcoming && hs.upcoming == this.a) hs.upcoming = null; + this.prepareNextOutline(); + var p = hs.page, mX = hs.mouse.x + p.scrollLeft, mY = hs.mouse.y + p.scrollTop; + this.mouseIsOver = this.x.pos < mX && mX < this.x.pos + this.x.get('wsize') + && this.y.pos < mY && mY < this.y.pos + this.y.get('wsize'); + if (this.overlayBox) this.showOverlays(); - this.createOverlays(); - if (hs.showCredits) this.writeCredits(); - if (this.fullExpandWidth > this.x.span) this.createFullExpand(); - if (!this.caption) this.prepareNextOutline(); }, @@ -1143,110 +1389,93 @@ prepareNextOutline : function() { preloadNext : function() { - var next = hs.getAdjacentAnchor(this.key, 1); - if (next.onclick.toString().match(/hs\.expand/)) + var next = this.getAdjacentAnchor(1); + if (next && next.onclick.toString().match(/hs\.expand/)) var img = hs.createElement('img', { src: hs.getSrc(next) }); }, -cancelLoading : function() { + +getAdjacentAnchor : function(op) { + var current = this.getAnchorIndex(), as = hs.anchors.groups[this.slideshowGroup || 'none']; + return (as && as[current + op]) || null; +}, + +getAnchorIndex : function() { + var arr = hs.getAnchors().groups[this.slideshowGroup || 'none']; + if (arr) for (var i = 0; i < arr.length; i++) { + if (arr[i] == this.a) return i; + } + return null; +}, + + +cancelLoading : function() { + hs.discardElement (this.wrapper); hs.expanders[this.key] = null; - this.a.style.cursor = this.originalCursor; if (this.loading) hs.loading.style.left = '-9999px'; }, writeCredits : function () { - var credits = hs.createElement('a', - { - href: hs.creditsHref, - className: 'highslide-credits', - innerHTML: hs.creditsText, - title: hs.creditsTitle - } - ); - this.createOverlay({ overlayId: credits, position: 'top left'}); + this.credits = hs.createElement('a', { + href: hs.creditsHref, + target: hs.creditsTarget, + className: 'highslide-credits', + innerHTML: hs.lang.creditsText, + title: hs.lang.creditsTitle + }); + this.createOverlay({ + overlayId: this.credits, + position: this.creditsPosition || 'top left' + }); }, -getCaption : function() { - if (!this.captionId && this.thumbsUserSetId) - this.captionId = 'caption-for-'+ this.thumbsUserSetId; - if (this.captionId) this.caption = hs.getNode(this.captionId); - if (!this.caption && !this.captionText && this.captionEval) try { - this.captionText = eval(this.captionEval); - } catch (e) {} - if (!this.caption && this.captionText) this.caption = hs.createElement('div', - { className: 'highslide-caption', innerHTML: this.captionText } ); - - if (!this.caption) { - var next = this.a.nextSibling; - while (next && !hs.isHsAnchor(next)) { - if (/highslide-caption/.test(next.className)) { - this.caption = next.cloneNode(1); - break; +getInline : function(types, addOverlay) { + for (var i = 0; i < types.length; i++) { + var type = types[i], s = null; + if (!this[type +'Id'] && this.thumbsUserSetId) + this[type +'Id'] = type +'-for-'+ this.thumbsUserSetId; + if (this[type +'Id']) this[type] = hs.getNode(this[type +'Id']); + if (!this[type] && !this[type +'Text'] && this[type +'Eval']) try { + s = eval(this[type +'Eval']); + } catch (e) {} + if (!this[type] && this[type +'Text']) { + s = this[type +'Text']; + } + if (!this[type] && !s) { + this[type] = hs.getNode(this.a['_'+ type + 'Id']); + if (!this[type]) { + var next = this.a.nextSibling; + while (next && !hs.isHsAnchor(next)) { + if ((new RegExp('highslide-'+ type)).test(next.className || null)) { + if (!next.id) this.a['_'+ type + 'Id'] = next.id = 'hsId'+ hs.idCounter++; + this[type] = hs.getNode(next.id); + break; + } + next = next.nextSibling; + } } - next = next.nextSibling; } - } - if (this.caption) { - this.marginBottom += this.spaceForCaption; - } - -}, - -writeCaption : function() { - try { - hs.setStyles(this.wrapper, { width: this.wrapper.offsetWidth +'px', - height: this.wrapper.offsetHeight +'px' } ); - hs.setStyles(this.caption, { visibility: 'hidden', marginTop: hs.safari ? 0 : '-'+ this.y.span +'px'}); - this.caption.className += ' highslide-display-block'; - var height, exp = this; - if (hs.ie && (hs.ieVersion() < 6 || document.compatMode == 'BackCompat')) { - height = this.caption.offsetHeight; - } else { - var temp = hs.createElement('div', {innerHTML: this.caption.innerHTML}, - null, null, true); // to get height - this.caption.innerHTML = ''; - this.caption.appendChild(temp); - height = this.caption.offsetHeight; - this.caption.innerHTML = this.caption.childNodes[0].innerHTML; - } - hs.setStyles(this.caption, { overflow: 'hidden', height: 0, zIndex: 2, marginTop: 0 }); - this.wrapper.style.height = 'auto'; + if (!this[type] && s) this[type] = hs.createElement('div', + { className: 'highslide-'+ type, innerHTML: s } ); - if (hs.captionSlideSpeed) { - var step = (Math.round(height/50) || 1) * hs.captionSlideSpeed; - } else { - this.placeCaption(height, 1); - return; - } - for (var h = height % step, t = 0; h <= height; h += step, t += 10) { - (function(){ - var pH = h, end = (h == height) ? 1 : 0; - setTimeout( function() { - exp.placeCaption(pH, end); - }, t); - })(); + if (addOverlay && this[type]) { + var o = { position: (type == 'heading') ? 'above' : 'below' }; + for (var x in this[type+'Overlay']) o[x] = this[type+'Overlay'][x]; + o.overlayId = this[type]; + this.createOverlay(o); } - } catch (e) {} -}, - -placeCaption : function(height, end) { - if (!this.caption) return; - this.caption.style.height = height +'px'; - this.caption.style.visibility = 'visible'; - this.y.span = this.wrapper.offsetHeight - 2 * this.offsetBorderH; - - - var o = this.objOutline; - if (o) { - o.td[4].style.height = (this.wrapper.offsetHeight - 2 * this.objOutline.offset) +'px'; - if (o.hasAlphaImageLoader) o.td[3].style.height = o.td[5].style.height = o.td[4].style.height; } - if (end) this.prepareNextOutline(); }, -showHideElements : function (tagName, visibility, imgPos) { +// on end move and resize +doShowHide : function(visibility) { + if (hs.hideSelects) this.showHideElements('SELECT', visibility); + if (hs.hideIframes) this.showHideElements('IFRAME', visibility); + if (hs.geckoMac) this.showHideElements('*', visibility); +}, +showHideElements : function (tagName, visibility) { var els = document.getElementsByTagName(tagName); var prop = tagName == '*' ? 'overflow' : 'visibility'; for (var i = 0; i < els.length; i++) { @@ -1259,26 +1488,30 @@ showHideElements : function (tagName, visibility, imgPos) { els[i].setAttribute('hidden-by', hiddenBy); if (!hiddenBy) els[i].style[prop] = els[i].origProp; } else if (visibility == 'hidden') { // hide if behind - var elPos = hs.position(els[i]); + var elPos = hs.getPosition(els[i]); elPos.w = els[i].offsetWidth; elPos.h = els[i].offsetHeight; - var clearsX = (elPos.x + elPos.w < imgPos.x || elPos.x > imgPos.x + imgPos.w); - var clearsY = (elPos.y + elPos.h < imgPos.y || elPos.y > imgPos.y + imgPos.h); + var clearsX = (elPos.x + elPos.w < this.x.get('opos') + || elPos.x > this.x.get('opos') + this.x.get('osize')); + var clearsY = (elPos.y + elPos.h < this.y.get('opos') + || elPos.y > this.y.get('opos') + this.y.get('osize')); var wrapperKey = hs.getWrapperKey(els[i]); if (!clearsX && !clearsY && wrapperKey != this.key) { // element falls behind image if (!hiddenBy) { els[i].setAttribute('hidden-by', '['+ this.key +']'); els[i].origProp = els[i].style[prop]; els[i].style[prop] = 'hidden'; - } else if (!hiddenBy.match('['+ this.key +']')) { + + } else if (hiddenBy.indexOf('['+ this.key +']') == -1) { els[i].setAttribute('hidden-by', hiddenBy + '['+ this.key +']'); } - } else if (hiddenBy == '['+ this.key +']' || hs.focusKey == wrapperKey) { // on move + } else if ((hiddenBy == '['+ this.key +']' || hs.focusKey == wrapperKey) + && wrapperKey != this.key) { // on move els[i].setAttribute('hidden-by', ''); els[i].style[prop] = els[i].origProp || ''; - } else if (hiddenBy && hiddenBy.match('['+ this.key +']')) { + } else if (hiddenBy && hiddenBy.indexOf('['+ this.key +']') > -1) { els[i].setAttribute('hidden-by', hiddenBy.replace('['+ this.key +']', '')); } @@ -1288,247 +1521,388 @@ showHideElements : function (tagName, visibility, imgPos) { }, focus : function() { - this.wrapper.style.zIndex = hs.zIndexCounter++; + this.wrapper.style.zIndex = hs.zIndexCounter += 2; // blur others for (var i = 0; i < hs.expanders.length; i++) { if (hs.expanders[i] && i == hs.focusKey) { var blurExp = hs.expanders[i]; blurExp.content.className += ' highslide-'+ blurExp.contentType +'-blur'; - - if (blurExp.caption) { - blurExp.caption.className += ' highslide-caption-blur'; - } - - blurExp.content.style.cursor = hs.ie ? 'hand' : 'pointer'; - blurExp.content.title = hs.focusTitle; + blurExp.content.style.cursor = hs.ieLt7 ? 'hand' : 'pointer'; + blurExp.content.title = hs.lang.focusTitle; } } // focus this - if (this.objOutline) this.objOutline.table.style.zIndex - = this.wrapper.style.zIndex; - + if (this.outline) this.outline.table.style.zIndex + = this.wrapper.style.zIndex - 1; this.content.className = 'highslide-'+ this.contentType; - - if (this.caption) { - this.caption.className = this.caption.className.replace(' highslide-caption-blur', ''); - } - - this.content.title = hs.restoreTitle; + this.content.title = hs.lang.restoreTitle; - hs.styleRestoreCursor = window.opera ? 'pointer' : 'url('+ hs.graphicsDir + hs.restoreCursor +'), pointer'; - if (hs.ie && hs.ieVersion() < 6) hs.styleRestoreCursor = 'hand'; - this.content.style.cursor = hs.styleRestoreCursor; + if (hs.restoreCursor) { + hs.styleRestoreCursor = window.opera ? 'pointer' : 'url('+ hs.graphicsDir + hs.restoreCursor +'), pointer'; + if (hs.ieLt7 && hs.uaVersion < 6) hs.styleRestoreCursor = 'hand'; + this.content.style.cursor = hs.styleRestoreCursor; + } hs.focusKey = this.key; - hs.addEventListener(document, 'keydown', hs.keyHandler); + hs.addEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler); }, - -move : function (e) { - this.x.min = e.left + e.dX; - this.y.min = e.top + e.dY; - - hs.setStyles(this.wrapper, { left: this.x.min +'px', top: this.y.min +'px' }); - - if (this.objOutline) - this.objOutline.setPosition(this, this.x.min, this.y.min, this.x.span, this.y.span); - +moveTo: function(x, y) { + this.x.setPos(x); + this.y.setPos(y); +}, +resize : function (e) { + var w, h, r = e.width / e.height; + w = Math.max(e.width + e.dX, Math.min(this.minWidth, this.x.full)); + if (this.isImage && Math.abs(w - this.x.full) < 12) w = this.x.full; + h = w / r; + if (h < Math.min(this.minHeight, this.y.full)) { + h = Math.min(this.minHeight, this.y.full); + if (this.isImage) w = h * r; + } + this.resizeTo(w, h); +}, +resizeTo: function(w, h) { + this.y.setSize(h); + this.x.setSize(w); + this.wrapper.style.height = this.y.get('wsize') +'px'; }, close : function() { if (this.isClosing || !this.isExpanded) return; this.isClosing = true; - hs.removeEventListener(document, 'keydown', hs.keyHandler); + hs.removeEventListener(document, window.opera ? 'keypress' : 'keydown', hs.keyHandler); try { - this.content.style.cursor = 'default'; - this.changeSize( - 0, - { - x: this.x.min, - y: this.y.min, - w: this.x.span, - h: parseInt(this.content.style.height), - imgW: this.x.imgSpan, - o: this.objOutline ? this.objOutline.offset : 0 - }, - { - x: this.thumbLeft - this.offsetBorderW + this.thumbOffsetBorderW, - y: this.thumbTop - this.offsetBorderH + this.thumbOffsetBorderH, - w: this.thumbWidth, - h: this.thumbHeight, - imgW: this.thumbWidth, - o: hs.outlineStartOffset - }, - hs.restoreDuration, - hs.restoreSteps + 0, { + wrapper: { + width : this.x.t, + height : this.y.t, + left: this.x.tpos - this.x.cb + this.x.tb, + top: this.y.tpos - this.y.cb + this.y.tb + }, + content: { + left: 0, + top: 0, + width: this.x.t, + height: this.y.t + } + }, hs.restoreDuration ); - - } catch (e) { this.afterClose(); } + } catch (e) { this.afterClose(); } }, createOverlay : function (o) { var el = o.overlayId; if (typeof el == 'string') el = hs.getNode(el); + if (o.html) el = hs.createElement('div', { innerHTML: o.html }); if (!el || typeof el == 'string') return; - - + el.style.display = 'block'; + this.genOverlayBox(); + var width = o.width && /^[0-9]+(px|%)$/.test(o.width) ? o.width : 'auto'; + if (/^(left|right)panel$/.test(o.position) && !/^[0-9]+px$/.test(o.width)) width = '200px'; var overlay = hs.createElement( - 'div', - null, - { - 'left' : 0, - 'top' : 0, - 'position' : 'absolute', - 'zIndex' : 3, - 'visibility' : 'hidden' - }, - this.wrapper, + 'div', { + id: 'hsId'+ hs.idCounter++, + hsId: o.hsId + }, { + position: 'absolute', + visibility: 'hidden', + width: width, + direction: hs.lang.cssDirection || '', + opacity: 0 + },this.overlayBox, true ); - if (o.opacity) hs.setStyles(el, { opacity: o.opacity }); - el.className += ' highslide-display-block'; - overlay.appendChild(el); - - overlay.hsPos = o.position; - this.positionOverlay(overlay); - if (o.hideOnMouseOut) overlay.setAttribute('hideOnMouseOut', true); - if (!o.opacity) o.opacity = 1; - overlay.setAttribute('opacity', o.opacity); - hs.fade(overlay, 0, o.opacity); + overlay.appendChild(el); + hs.extend(overlay, { + opacity: 1, + offsetX: 0, + offsetY: 0, + dur: (o.fade === 0 || o.fade === false || (o.fade == 2 && hs.ie)) ? 0 : 250 + }); + hs.extend(overlay, o); - hs.push(this.overlays, overlay); + + if (this.gotOverlays) { + this.positionOverlay(overlay); + if (!overlay.hideOnMouseOut || this.mouseIsOver) + hs.animate(overlay, { opacity: overlay.opacity }, overlay.dur); + } + hs.push(this.overlays, hs.idCounter - 1); }, - positionOverlay : function(overlay) { - var left = this.offsetBorderW; - var dLeft = this.x.span - overlay.offsetWidth; - var top = this.offsetBorderH; - var dTop = parseInt(this.content.style.height) - overlay.offsetHeight; - - var p = overlay.hsPos || 'center center'; - if (/^bottom/.test(p)) top += dTop; - if (/^center/.test(p)) top += dTop / 2; - if (/right$/.test(p)) left += dLeft; - if (/center$/.test(p)) left += dLeft / 2; - overlay.style.left = left +'px'; - overlay.style.top = top +'px'; + var p = overlay.position || 'middle center', + offX = overlay.offsetX, + offY = overlay.offsetY; + if (overlay.parentNode != this.overlayBox) this.overlayBox.appendChild(overlay); + if (/left$/.test(p)) overlay.style.left = offX +'px'; + + if (/center$/.test(p)) hs.setStyles (overlay, { + left: '50%', + marginLeft: (offX - Math.round(overlay.offsetWidth / 2)) +'px' + }); + + if (/right$/.test(p)) overlay.style.right = - offX +'px'; + + if (/^leftpanel$/.test(p)) { + hs.setStyles(overlay, { + right: '100%', + marginRight: this.x.cb +'px', + top: - this.y.cb +'px', + bottom: - this.y.cb +'px', + overflow: 'auto' + }); + this.x.p1 = overlay.offsetWidth; + + } else if (/^rightpanel$/.test(p)) { + hs.setStyles(overlay, { + left: '100%', + marginLeft: this.x.cb +'px', + top: - this.y.cb +'px', + bottom: - this.y.cb +'px', + overflow: 'auto' + }); + this.x.p2 = overlay.offsetWidth; + } + + if (/^top/.test(p)) overlay.style.top = offY +'px'; + if (/^middle/.test(p)) hs.setStyles (overlay, { + top: '50%', + marginTop: (offY - Math.round(overlay.offsetHeight / 2)) +'px' + }); + if (/^bottom/.test(p)) overlay.style.bottom = - offY +'px'; + if (/^above$/.test(p)) { + hs.setStyles(overlay, { + left: (- this.x.p1 - this.x.cb) +'px', + right: (- this.x.p2 - this.x.cb) +'px', + bottom: '100%', + marginBottom: this.y.cb +'px', + width: 'auto' + }); + this.y.p1 = overlay.offsetHeight; + + } else if (/^below$/.test(p)) { + hs.setStyles(overlay, { + position: 'relative', + left: (- this.x.p1 - this.x.cb) +'px', + right: (- this.x.p2 - this.x.cb) +'px', + top: '100%', + marginTop: this.y.cb +'px', + width: 'auto' + }); + this.y.p2 = overlay.offsetHeight; + overlay.style.position = 'absolute'; + } }, -createOverlays : function() { +getOverlays : function() { + this.getInline(['heading', 'caption'], true); + if (this.heading && this.dragByHeading) this.heading.className += ' highslide-move'; + if (hs.showCredits) this.writeCredits(); for (var i = 0; i < hs.overlays.length; i++) { - var o = hs.overlays[i]; - if ((!o.thumbnailId && !o.slideshowGroup) || o.thumbnailId == this.thumbsUserSetId - || o.slideshowGroup === this.slideshowGroup) { + var o = hs.overlays[i], tId = o.thumbnailId, sg = o.slideshowGroup; + if ((!tId && !sg) || (tId && tId == this.thumbsUserSetId) + || (sg && sg === this.slideshowGroup)) { this.createOverlay(o); } } + var os = []; + for (var i = 0; i < this.overlays.length; i++) { + var o = hs.$('hsId'+ this.overlays[i]); + if (/panel$/.test(o.position)) this.positionOverlay(o); + else hs.push(os, o); + } + for (var i = 0; i < os.length; i++) this.positionOverlay(os[i]); + this.gotOverlays = true; +}, +genOverlayBox : function() { + if (!this.overlayBox) this.overlayBox = hs.createElement ( + 'div', { + className: this.wrapperClassName + }, { + position : 'absolute', + width: (this.x.size || (this.useBox ? this.width : null) + || this.x.full) +'px', + height: (this.y.size || this.y.full) +'px', + visibility : 'hidden', + overflow : 'hidden', + zIndex : hs.ie ? 4 : 'auto' + }, + hs.container, + true + ); +}, +sizeOverlayBox : function(doWrapper, doPanels) { + var overlayBox = this.overlayBox, + x = this.x, + y = this.y; + hs.setStyles( overlayBox, { + width: x.size +'px', + height: y.size +'px' + }); + if (doWrapper || doPanels) { + for (var i = 0; i < this.overlays.length; i++) { + var o = hs.$('hsId'+ this.overlays[i]); + var ie6 = (hs.ieLt7 || document.compatMode == 'BackCompat'); + if (o && /^(above|below)$/.test(o.position)) { + if (ie6) { + o.style.width = (overlayBox.offsetWidth + 2 * x.cb + + x.p1 + x.p2) +'px'; + } + y[o.position == 'above' ? 'p1' : 'p2'] = o.offsetHeight; + } + if (o && ie6 && /^(left|right)panel$/.test(o.position)) { + o.style.height = (overlayBox.offsetHeight + 2* y.cb) +'px'; + } + } + } + if (doWrapper) { + hs.setStyles(this.content, { + top: y.p1 +'px' + }); + hs.setStyles(overlayBox, { + top: (y.p1 + y.cb) +'px' + }); + } +}, + +showOverlays : function() { + var b = this.overlayBox; + b.className = ''; + hs.setStyles(b, { + top: (this.y.p1 + this.y.cb) +'px', + left: (this.x.p1 + this.x.cb) +'px', + overflow : 'visible' + }); + if (hs.safari) b.style.visibility = 'visible'; + this.wrapper.appendChild (b); + for (var i = 0; i < this.overlays.length; i++) { + var o = hs.$('hsId'+ this.overlays[i]); + o.style.zIndex = o.zIndex || 4; + if (!o.hideOnMouseOut || this.mouseIsOver) { + o.style.visibility = 'visible'; + hs.setStyles(o, { visibility: 'visible', display: '' }); + hs.animate(o, { opacity: o.opacity }, o.dur); + } + } +}, + +destroyOverlays : function() { + if (!this.overlays.length) return; + hs.discardElement(this.overlayBox); }, + createFullExpand : function () { - var a = hs.createElement( - 'a', - { + this.fullExpandLabel = hs.createElement( + 'a', { href: 'javascript:hs.expanders['+ this.key +'].doFullExpand();', - title: hs.fullExpandTitle, + title: hs.lang.fullExpandTitle, className: 'highslide-full-expand' } ); - this.fullExpandLabel = a; - this.createOverlay({ overlayId: a, position: hs.fullExpandPosition, - hideOnMouseOut: true, opacity: hs.fullExpandOpacity }); + this.createOverlay({ + overlayId: this.fullExpandLabel, + position: hs.fullExpandPosition, + hideOnMouseOut: true, + opacity: hs.fullExpandOpacity + }); }, doFullExpand : function () { - try { - hs.purge(this.fullExpandLabel); - this.fullExpandLabel.parentNode.removeChild(this.fullExpandLabel); - this.focus(); - - this.x.min = parseInt(this.wrapper.style.left) - (this.fullExpandWidth - this.content.width) / 2; - if (this.x.min < hs.marginLeft) this.x.min = hs.marginLeft; - this.wrapper.style.left = this.x.min +'px'; - - hs.setStyles(this.content, { width: this.fullExpandWidth +'px', - height: this.fullExpandHeight +'px'}); - - this.x.span = this.fullExpandWidth; - this.wrapper.style.width = (this.x.span + 2*this.offsetBorderW) +'px'; - - this.y.span = this.wrapper.offsetHeight - 2 * this.offsetBorderH; - - if (this.objOutline) - this.objOutline.setPosition(this, this.x.min, this.y.min, this.x.span, this.y.span); - - for (var i = 0; i < this.overlays.length; i++) - this.positionOverlay(this.overlays[i]); - - this.redoShowHide(); - + try { + if (this.fullExpandLabel) hs.discardElement(this.fullExpandLabel); + this.focus(); + var xSize = this.x.size, + ySize = this.y.size; + this.resizeTo(this.x.full, this.y.full); + + var xpos = this.x.pos - (this.x.size - xSize) / 2; + if (xpos < hs.marginLeft) xpos = hs.marginLeft; + + var ypos = this.y.pos - (this.y.size - ySize) / 2; + if (ypos < hs.marginTop) ypos = hs.marginTop; + + this.moveTo(xpos, ypos); + this.doShowHide('hidden'); } catch (e) { - window.location.href = this.content.src; + this.error(e); } }, -// on end move and resize -redoShowHide : function() { - var imgPos = { - x: parseInt(this.wrapper.style.left) - 20, - y: parseInt(this.wrapper.style.top) - 20, - w: this.content.offsetWidth + 40, - h: this.content.offsetHeight + 40 - + this.spaceForCaption - }; - if (hs.hideSelects) this.showHideElements('SELECT', 'hidden', imgPos); - if (hs.hideIframes) this.showHideElements('IFRAME', 'hidden', imgPos); - if (hs.geckoMac) this.showHideElements('*', 'hidden', imgPos); - -}, - -wrapperMouseHandler : function (e) { - if (!e) e = window.event; - var over = /mouseover/i.test(e.type); - if (!e.target) e.target = e.srcElement; // ie - if (!e.relatedTarget) e.relatedTarget = - over ? e.fromElement : e.toElement; // ie - if (hs.getExpander(e.relatedTarget) == this || hs.dragArgs) return; - for (var i = 0; i < this.overlays.length; i++) { - var o = this.overlays[i]; - if (o.getAttribute('hideOnMouseOut')) { - var from = over ? 0 : o.getAttribute('opacity'), - to = over ? o.getAttribute('opacity') : 0; - hs.fade(o, from, to); - } - } -}, - afterClose : function () { this.a.className = this.a.className.replace('highslide-active-anchor', ''); - if (hs.hideSelects) this.showHideElements('SELECT', 'visible'); - if (hs.hideIframes) this.showHideElements('IFRAME', 'visible'); - if (hs.geckoMac) this.showHideElements('*', 'visible'); - if (this.objOutline && this.outlineWhileAnimating) this.objOutline.destroy(); - hs.purge(this.wrapper); - if (hs.ie && hs.ieVersion() < 5.5) this.wrapper.innerHTML = ''; // crash - else this.wrapper.parentNode.removeChild(this.wrapper); + this.doShowHide('visible'); + if (this.outline && this.outlineWhileAnimating) this.outline.destroy(); + + hs.discardElement(this.wrapper); + hs.expanders[this.key] = null; - hs.cleanUp(); + hs.reOrder(); } + }; +hs.langDefaults = hs.lang; // history var HsExpander = hs.Expander; +if (hs.ie && window == window.top) { + (function () { + try { + document.documentElement.doScroll('left'); + } catch (e) { + setTimeout(arguments.callee, 50); + return; + } + hs.ready(); + })(); +} +hs.addEventListener(document, 'DOMContentLoaded', hs.ready); +hs.addEventListener(window, 'load', hs.ready); // set handlers +hs.addEventListener(document, 'ready', function() { + if (hs.expandCursor) { + var style = hs.createElement('style', { type: 'text/css' }, null, + document.getElementsByTagName('HEAD')[0]), + backCompat = document.compatMode == 'BackCompat'; + + + function addRule(sel, dec) { + if (hs.ie && (hs.uaVersion < 9 || backCompat)) { + var last = document.styleSheets[document.styleSheets.length - 1]; + if (typeof(last.addRule) == "object") last.addRule(sel, dec); + } else { + style.appendChild(document.createTextNode(sel + " {" + dec + "}")); + } + } + function fix(prop) { + return 'expression( ( ( ignoreMe = document.documentElement.'+ prop + + ' ? document.documentElement.'+ prop +' : document.body.'+ prop +' ) ) + \'px\' );'; + } + if (hs.expandCursor) addRule ('.highslide img', + 'cursor: url('+ hs.graphicsDir + hs.expandCursor +'), pointer !important;'); + } +}); +hs.addEventListener(window, 'resize', function() { + hs.getPageSize(); +}); +hs.addEventListener(document, 'mousemove', function(e) { + hs.mouse = { x: e.clientX, y: e.clientY }; +}); hs.addEventListener(document, 'mousedown', hs.mouseClickHandler); hs.addEventListener(document, 'mouseup', hs.mouseClickHandler); -hs.addEventListener(window, 'load', hs.preloadImages); \ No newline at end of file + +hs.addEventListener(document, 'ready', hs.getAnchors); +hs.addEventListener(window, 'load', hs.preloadImages); +} From 70111876d2de89d11224a9d0dc75f7f39aa7f1fa Mon Sep 17 00:00:00 2001 From: luc Date: Fri, 23 Oct 2015 12:27:52 +0200 Subject: [PATCH 6/9] Filled ViewImageTest.html with all remaining IANA image file formats. Added some links to test suites and specifications. --- test/viewImageTest/ViewImageTest.html | 551 +- test/viewImageTest/test/ACAD_r2000_sample.dwg | Bin 0 -> 287651 bytes .../test/ACAD_r2000_sample_original.dxf | 50806 ++++++++++++++++ ...imated_PNG_example_bouncing_beach_ball.png | Bin 0 -> 65559 bytes ...aphy_and_natural_history_illustration.djvu | Bin 0 -> 748001 bytes test/viewImageTest/test/stone_wall.vtf | Bin 0 -> 174968 bytes test/viewImageTest/test/svflogo.svf | Bin 0 -> 12033 bytes 7 files changed, 51343 insertions(+), 14 deletions(-) create mode 100755 test/viewImageTest/test/ACAD_r2000_sample.dwg create mode 100755 test/viewImageTest/test/ACAD_r2000_sample_original.dxf create mode 100755 test/viewImageTest/test/Animated_PNG_example_bouncing_beach_ball.png create mode 100755 test/viewImageTest/test/Specimens_of_calligraphy_and_natural_history_illustration.djvu create mode 100755 test/viewImageTest/test/stone_wall.vtf create mode 100755 test/viewImageTest/test/svflogo.svf diff --git a/test/viewImageTest/ViewImageTest.html b/test/viewImageTest/ViewImageTest.html index 965b67e80..7ad0dc90b 100644 --- a/test/viewImageTest/ViewImageTest.html +++ b/test/viewImageTest/ViewImageTest.html @@ -27,10 +27,11 @@ td {

- Test page to check ViewImage rendering with different image formats - listed in IANA Media Types page, plus BMP format. + title="IANA Media Types">IANA Registered Media Types, plus BMP + format.

Prerequisites