2

This code works well for a gallery where all images are indexed as thumbnails, but when just one index picture is shown on the site, and all other pictures are hidden, photoswipe hangs itself upon trying to return from a picture which is hidden.

When I simply comment it in the options, the transition effects will look bad as a side effect.

var initPhotoSwipeFromDOM = function(gallerySelector) {

// parse slide data (url, title, size ...) from DOM elements 
// (children of gallerySelector)
var parseThumbnailElements = function(el) {
    var thumbElements = el.childNodes,
        numNodes = thumbElements.length,
        items = [],
        figureEl,
        linkEl,
        size,
        item;

    for(var i = 0; i < numNodes; i++) {

        figureEl = thumbElements[i]; // <figure> element

        // include only element nodes 
        if(figureEl.nodeType !== 1) {
            continue;
        }

        linkEl = figureEl.children[0]; // <a> element

        size = linkEl.getAttribute('data-size').split('x');

        // create slide object
        item = {
            src: linkEl.getAttribute('href'),
            w: parseInt(size[0], 10),
            h: parseInt(size[1], 10)
        };



        if(figureEl.children.length > 1) {
            // <figcaption> content
            item.title = figureEl.children[1].innerHTML; 
        }

        if(linkEl.children.length > 0) {
            // <img> thumbnail element, retrieving thumbnail url
            item.msrc = linkEl.children[0].getAttribute('src');
        } 

        item.el = figureEl; // save link to element for getThumbBoundsFn
        items.push(item);
    }

    return items;
};

// find nearest parent element
var closest = function closest(el, fn) {
    return el && ( fn(el) ? el : closest(el.parentNode, fn) );
};

// triggers when user clicks on thumbnail
var onThumbnailsClick = function(e) {
    e = e || window.event;
    e.preventDefault ? e.preventDefault() : e.returnValue = false;

    var eTarget = e.target || e.srcElement;

    // find root element of slide
    var clickedListItem = closest(eTarget, function(el) {
        return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
    });

    if(!clickedListItem) {
        return;
    }

    // find index of clicked item by looping through all child nodes
    // alternatively, you may define index via data- attribute
    var clickedGallery = clickedListItem.parentNode,
        childNodes = clickedListItem.parentNode.childNodes,
        numChildNodes = childNodes.length,
        nodeIndex = 0,
        index;

    for (var i = 0; i < numChildNodes; i++) {
        if(childNodes[i].nodeType !== 1) { 
            continue; 
        }

        if(childNodes[i] === clickedListItem) {
            index = nodeIndex;
            break;
        }
        nodeIndex++;
    }



    if(index >= 0) {
        // open PhotoSwipe if valid index found
        openPhotoSwipe( index, clickedGallery );
    }
    return false;
};

// parse picture index and gallery index from URL (#&pid=1&gid=2)
var photoswipeParseHash = function() {
    var hash = window.location.hash.substring(1),
    params = {};

    if(hash.length < 5) {
        return params;
    }

    var vars = hash.split('&');
    for (var i = 0; i < vars.length; i++) {
        if(!vars[i]) {
            continue;
        }
        var pair = vars[i].split('=');  
        if(pair.length < 2) {
            continue;
        }           
        params[pair[0]] = pair[1];
    }

    if(params.gid) {
        params.gid = parseInt(params.gid, 10);
    }

    if(!params.hasOwnProperty('pid')) {
        return params;
    }
    params.pid = parseInt(params.pid, 10);
    return params;
};

var openPhotoSwipe = function(index, galleryElement, disableAnimation) {
    var pswpElement = document.querySelectorAll('.pswp')[0],
        gallery,
        options,
        items;

    items = parseThumbnailElements(galleryElement);

    // define options (if needed)
    options = {
        index: index,

        // define gallery index (for URL)
        galleryUID: galleryElement.getAttribute('data-pswp-uid'),

        getThumbBoundsFn: function(index) {
            // See Options -> getThumbBoundsFn section of documentation for more info
            var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
                pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
                rect = thumbnail.getBoundingClientRect(); 

            return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
        }

    };

    if(disableAnimation) {
        options.showAnimationDuration = 0;
    }

    // Pass data to PhotoSwipe and initialize it
    gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
    gallery.init();
};

// loop through all gallery elements and bind events
var galleryElements = document.querySelectorAll( gallerySelector );

for(var i = 0, l = galleryElements.length; i < l; i++) {
    galleryElements[i].setAttribute('data-pswp-uid', i+1);
    galleryElements[i].onclick = onThumbnailsClick;
}

// Parse URL and open gallery if it contains #&pid=3&gid=1
var hashData = photoswipeParseHash();
if(hashData.pid > 0 && hashData.gid > 0) {
    openPhotoSwipe( hashData.pid - 1 ,  galleryElements[ hashData.gid - 1 ], true );
}
};

// execute above function
initPhotoSwipeFromDOM('.my-gallery');

The code I used on the dom: (Pictures are hidden as of the 2nd figure)

<div itemscope itemtype="http://schema.org/ImageGallery">

    <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
        <a href="large-image-1.jpg" itemprop="contentUrl">
           <img src="small-image.jpg" itemprop="thumbnail" alt="Image description" />
            <figcaption itemprop="caption description">Long image description 1</figcaption>
        </a>
    </figure>

    <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
        <a href="large-image-2.jpg" itemprop="contentUrl">
            <figcaption itemprop="caption description">Long image description 2</figcaption>
        </a>
    </figure>

    ...

</div>

2 Answers2

2

Just return empty object if element is not found, or return coordinates of the main image.

getThumbBoundsFn: function(index) {

    if(!items[index].el || !items[index].el.getElementsByTagName('img')[0]) {
        return {};
    }

    var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
        pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
        rect = thumbnail.getBoundingClientRect(); 

    return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
}
Dmitry Semenov
  • 4,566
  • 2
  • 36
  • 39
  • Thank you Dmitry, that helps. But when I exit photoswipe from an image which is not the index image the transition effect is not the same. Can you experience the same? – user3497785 Mar 28 '15 at 08:36
  • 1
    Ok, I now stronlgy assume when I return the coordinates of the main image it'll work properly with the transition. Unfortunately I am not experienced enough to figure this out on my own even after reading the code over and over again and reading documetation and [this snippet](http://javascript.info/tutorial/coordinates). Can this code be modified to return the coordinates of the main image instead of nothing? – user3497785 Mar 29 '15 at 19:22
1

Try this in your HTML code for the hidden images:

<figure class="hidden" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
    <a href="full size image url" itemprop="contentUrl" data-size="imagesize ej 620x340">
    <img src="" itemprop="thumbnail"></a>
    <figcaption itemprop="caption description">Caption</figcaption>
</figure>

Just pass an empty value for your thumbnail and the Photoswipe plugin works perfect. It is an easy workaround if you are not an expert in javascript, for me works like a charm.

Cheers!

EDIT: For the second, third, etc images you need to add an empty value for the thumbnail: <img src="" itemprop="thumbnail"> Using your code:

<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
    <a href="large-image-2.jpg" itemprop="contentUrl">
        <!--ADD HERE--><img src="" itemprop="thumbnail"><!--END OF ADDED CODE-->
        <figcaption itemprop="caption description">Long image description 2</figcaption>
    </a>
</figure>
Jason Sturges
  • 15,855
  • 14
  • 59
  • 80
Visual RTV
  • 23
  • 5
  • I'm not sure if I get you right, but how can the images be hidden that way? – user3497785 Apr 10 '15 at 15:39
  • Sorry for the delay in the answer, I have edited my previous answer to answer you. Photoswipe get stuck if you don't have a value for the thumbnail, even without have any value, so just adding for images that doesn't have any thumbnail just works. – Visual RTV May 20 '15 at 14:13
  • I'm sorry, I just figured that `` is very bad practice and will not work in Firefox i.e. [Reference](http://stackoverflow.com/questions/5775469/whats-the-valid-way-to-include-an-image-with-no-src) – user3497785 Jun 03 '15 at 07:53
  • Yes, you are right, use this code instead sorry: `` this will generate a 1x1 transparent pixel that doesn't send any extra request to the server. You can see that solution from here: http://stackoverflow.com/questions/5775469/whats-the-valid-way-to-include-an-image-with-no-src/28077004#28077004 – Visual RTV Jun 10 '15 at 15:48