Create Fancybox gallery when integrated with PikaChoose [duplicate] - javascript

I'm using the Fancybox integration with Pikachoose as explained here:
http://www.pikachoose.com/how-to-fancybox/
I'm trying to get the lightbox to display next and previous arrows but not on the pikachoose stage and I'm having a bit of trouble. I tried to add the options of showNavArrows: true in the fancybox section of the script but it wouldn't work. So then I tried the nav options on pikachoose to display using this: {text: {previous: "Previous", next: "Next" }}
but I keep getting an error, possibly my syntax isn't going in the right place?
Can someone help please?
this is the code I'm using :
$(document).ready(function () {
var a = function (self) {
self.anchor.fancybox({
transitionIn: elastic,
transitionOut: elastic,
speedIn: 600,
speedOut: 200,
overlayShow: false
});
};
$("#pikame").PikaChoose({
showCaption: false,
buildFinished: a,
autoPlay: false,
transition: [0],
speed: 500,
showCaption: false
});
});

The problem with the method explained in http://www.pikachoose.com/how-to-fancybox/ is that you bind fancybox to the current pikachoose element self.anchor.
With that approach, there is no way to know what group of images will belong to a fancybox gallery (you would need more than one element sharing the same rel attribute) because there is just a single pikachoose image : every image is displayed toggling dynamically its href and src attributes (<a> and <img> tags respectively) inside the .pika-stage container.
As a workaround, you would need to built the fancybox group of elements BEFORE binding your html structure to pikachoose (pikachoose will modify the DOM structure)
1). So having this html structure :
<div class="pikachoose">
<ul id="pikame">
<li>
<a title="one" href="image01.jpg" id="single_1"><img alt="" src="thumb01.jpg" /></a>
</li>
<li>
<a title="two" href="image02.jpg" id="single_2"><img alt="" src="thumb02.jpg" /></a>
</li>
<li>
<a title="three" href="image03.jpg" id="single_3"><img alt="" src="thumb03.jpg" /></a>
</li>
</ul>
</div>
2). Create the fancybox group of elements iterating through each anchor with this script :
var fancyGallery = []; // fancybox gallery group
$(document).ready(function () {
$("#pikame").find("a").each(function(i){
// buidl fancybox gallery group
fancyGallery[i] = {"href" : this.href, "title" : this.title};
});
}); // ready
3). Then bind pikachoose to the same selector #pikame. You can use the .end() method to do it over the first decelerated selector without duplicating it ;)
var fancyGallery = []; // fancybox gallery group
$(document).ready(function () {
// build fancybox group
$("#pikame").find("a").each(function(i){
// buidl fancybox gallery
fancyGallery[i] = {"href" : this.href, "title" : this.title};
}).end().PikaChoose({
autoPlay : false, // optional
// bind fancybox to big images element after pikachoose is built
buildFinished: fancy
}); // PikaChoose
}); // ready
Notice that we used the pikachoose option buildFinished: fancy, which actually will fire the fancybox gallery when we click on the big image.
4). Here is the function :
var fancy = function (self) {
// bind click event to big image
self.anchor.on("click", function(e){
// find index of corresponding thumbnail
var pikaindex = $("#pikame").find("li.active").index();
// open fancybox gallery starting from corresponding index
$.fancybox(fancyGallery,{
// fancybox options
"cyclic": true, // optional for fancybox v1.3.4 ONLY, use "loop" for v2.x
"index": pikaindex // start with the corresponding thumb index
});
return false; // prevent default and stop propagation
}); // on click
}
Notice that we bound a click event using .on() (requires jQuery v1.7+) to the pikachoose element self.anchor to fire fancybox gallery using the manual method $.fancybox([group]).
This workaround works equally fine for fancybox v1.3.4 or v2.x. See DEMO using v1.3.4 that seems to work fine even with IE7 ;)

JFK response is great, but there is something to correct :
if carousel is enabled in Pikachoose, the computed index using this method will give you an invalid one, beacause pikachoose will manipulate DOM by appending existing li in ul:
var pikaindex = $("#pikame").find("li.active").index();
Solution :
function getCurrentIndex(fancyGallery) {
var activeLi = $(""#pikame").find("li.active");
if (activeLi.length != 1) {
console.error('(getCurrentIndex) - only one image must have an active class set by Pikachoose');
return -1;
}
var activeLiHtml0 = activeLi[0];
var activeHref = $(activeLiHtml0).find('img').attr('src'); // do not look for <a> tags, PikaChoose will remove them
if (activeHref === null || activeHref.length == 0) {
console.error('(getCurrentIndex) - can not get href attribute from selected image');
return -1;
}
for (var i=0 ; i<fancyGallery.length ;i++) {
var obj = fancyGallery[i];
if (obj.href.indexOf(activeHref) >= 0){
console.debug('(getCurrentIndex) - found index: ' + i);
return i;
}
}
console.error('(getCurrentIndex) - this href: <' + activeHref + '> was not found in configured table');
return -1;
};

Related

How to load Photoswipe with Ajax to get server side pictures?

I'm searching for a gallery library and I see PhotoSwipe. Actually I just made the tutorial in the documentation.
I don't see any tutorial to load my server side pictures dynamically.
I need to load them with Ajax because I have a datatables, and inside each row I set an icon. The user can click on this icon and it will appears a bootstrap modal. In this modal I have to show the thumbnails related with the clicked row. And when the user click on the thumbnails I need to show the gallery.
It's possible to load dynamically server side pictures ?
I think you can achieve this by initiating the gallery from the click event. If you make this a delegated event, it will also get triggered on newly created images. Then you only need to create the image array upon triggering the click event and fire up the gallery.
Your images should be added like this:
<img class="myAjaxLoadedImage" src="myAjaxLoadedImage1_thumbnail.jpg" alt=""
data-img-title="My title 1" data-img-src="myAjaxLoadedImage1.jpg"
data-img-width="800" data-img-height="600">
<img class="myAjaxLoadedImage" src="myAjaxLoadedImage2_thumbnail.jpg" alt=""
data-img-title="My title 2" data-img-src="myAjaxLoadedImage2.jpg"
data-img-width="400" data-img-height="700">
...
And the JS would then be:
(function($) {
var pswp;
$(function() {
pswp = $('.pswp')[0];
setGalleryClickEvents();
});
function setGalleryClickEvents() {
$(document).on('click','.myAjaxLoadedImage',function(e) {
if (pswp) {
var options = {
index: $(this).index()
// + other PhotoSwipe options here...
}
var images = [];
$('.myAjaxLoadedImage').each(function() {
var $img = $(this);
images.push({
src: $img.data('imgSrc'),
w: $img.data('imgWidth'),
h: $img.data('imgHeight'),
title: $img.data('imgTitle')
});
});
var gallery = new PhotoSwipe(pswp, PhotoSwipeUI_Default, images, options);
gallery.init();
}
});
}
})(jQuery);

jQuery Lightbox gallery only working once

I am trying to build my own simple jQuery lightbox gallery. My logic behind it is as follows: Only thumbnails will be shown & created at first. These link to the full size images.
<section class="gallery-set">
<a href="img/about/gallery/a1.1.jpg">
<img src="img/about/gallery/thumb1.1.jpg" alt=""
height="192" width="383">
</a>
<a href="img/about/gallery/a1.jpg">
<img src="img/about/gallery/thumb1.jpg" alt=""
height="192" width="383">
</a>
<a href="img/about/gallery/a2.1.jpg">
<img src="img/about/gallery/thumb2.1.jpg" alt=""
height="192" width="383">
</a>
</section>
Therefore, when you click on any of these thumbnails, I dynamically create an overlay-lightbox and all full size images, showing only the one that links to the thumbnail you clicked. Although the rest of the images has been created too, these are hidden for now.
function lightBox() {
var gallery = $('.gallery-set'),
overlay = $('<div/>', {id: 'overlay'});
overlay.appendTo('body').hide();
gallery.on('click', 'a', function(event) {
event.preventDefault();
var clickedThumb = $(this),
clickedThumbPath = $(this).attr('href'),
clickedImg = $('<img>', {src: clickedThumbPath, alt: 'fullSizeImage', class: 'current'}),
prevThumbs = clickedThumb.prevAll(),
nextThumbs = clickedThumb.nextAll();
prevThumbs.each(function() {
var prevImg = $('<img>', {src: $(this).attr('href'), class: 'prev non-current'});
prevImg.appendTo(overlay);
});
clickedImg.appendTo(overlay);
nextThumbs.each(function() {
var nextImg = $('<img>', {src: $(this).attr('href'), class: 'next non-current'});
nextImg.appendTo(overlay);
});
overlay.show();
})
.....
.....
}
Now, when you click the second thumbnail, jQuery dynamically creates all the fullsize images and this is how HTML structure looks like:
Now that I have this structure, I can easily traverse the full sized images by left and right arrows. The current image gets hidden and the next one gets shown. For this logic I am using two classes, current and non-current where the first one has set display to block and the second one to none. This piece of code is within the lightbox() function:
$(document).on('keyup', function(event) {
var pressed = event.keyCode || event.which,
arrow = {left: 37, right: 39};
switch(pressed) {
case arrow.left:
var curr = overlay.find('.current'),
prev = curr.prev();
if(curr.hasClass('current')) {
curr.removeClass('current').addClass('non-current');
} else {
curr.addClass('non-current');
}
if(prev.hasClass('non-current')) {
prev.removeClass('non-current').addClass('current');
} else {
prev.addClass('current');
}
break;
case arrow.right:
var curr = overlay.find('.current'),
next = curr.next();
curr.removeClass('current').addClass('non-current');
next.removeClass('non-current').addClass('current');
break;
}
});
overlay.on('click', function() {
overlay.hide();
overlay.find('img').remove();
});
});
Everything works fine the first time. However, once I close the lightbox and try to open it again, the correct image opens but the arrows functionality is gone. I do not understand why - since I am dynamically creating the full sized images everytime user clicks on the gallery and putting event listeners (arrows) only once these have been created.
Just for the record, I am calling this lightbox() function from the HTML file right before the closing tag.
Any ideas much appreciated. Also, if there's a simpler / better way of doing this, please do let me know! I don't want to use any plugin as I think this is pretty simple and straightforward. Or, I thought it WOULD BE SIMPLE I should rather say.

jQuery slideDown not working on element with dynamically assigned id

EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.

Photoswipe pswp class Not Clearing After Closing Image

I have a Photoswipe (http://photoswipe.com) image gallery on my site, and the css class is not resetting/clearing to remove the view after I close a gallery for the second time.
ex.
User opens item 1, AJAX populates the figure(s) into the picture div.
User clicks an image from item 1 and Photoswipe opens the image properly (setting the following class):
class="pswp pswp--supports-fs pswp--open pswp--animate_opacity pswp--notouch pswp--css_animation pswp--svg pswp--animated-in pswp--visible"
User closes the image from item 1, class resets as normal:
class="pswp"
User closes item 1 and JS/JQuery clears all html in picture div. User opens item 2, AJAX populates the figure into the picture div. User clicks an image from item 2 and Photoswipe opens the image properly setting the same class as before.
class="pswp pswp--supports-fs pswp--open pswp--animate_opacity pswp--notouch pswp--css_animation pswp--svg pswp--animated-in pswp--visible"
This is where the problem occurs. User closes the image from item 2 and the only thing that changes is:
aria-hidden="true"
but the class does not clear, it remains:
class="pswp pswp--supports-fs pswp--open pswp--animate_opacity pswp--notouch pswp--css_animation pswp--svg pswp--animated-in pswp--visible"
when it should change to:
class="pswp"
This disables all interaction on the website since there is an invisible div/class on top of everything. The class needs to be changed back to pswp somehow.
AJAX/JS To Populate picture div (I added an id to the div):
if (i == 0) {
$('#listing_photos_container').append('<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject"><img src="' + json[i].image_url + '" height="400" width="600" itemprop="thumbnail" alt="listingPhoto" class="listing-photo"></figure>');
} else {
$('#listing_photos_container').append('<figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject" class="listing-photo-holder"><img src="' + json[i].image_url + '" height="400" width="600" itemprop="thumbnail" alt="listingPhoto" class="listing-photo-holder"></figure>');
}
JS/JQuery to clear photo div:
$('#listing_photos_container').html('');
EDIT: The click listener function is running twice when a users clicks the photo to bring full screen. This is the code for the listener:
$.ajax({
type: "POST",
url: 'http://example.com/action?action=photos',
data: {id: id},
success: function (data) {
console.log('API Call - Photos');
json = JSON.parse(data);
$('#listing_photos_container').html('');
for (var i = 0; i < json.length; i++) {
// Styling code here
}
$('#list_header').html(
(function($) {
$('.picture').each( function() {
var $pic = $(this),
getItems = function() {
var items = [];
$pic.find('a').each(function() {
var $href = $(this).attr('href'),
$size = $(this).data('size').split('x'),
$width = $size[0],$height = $size[1];
var item = {
src : $href,
w : $width,
h : $height
}
items.push(item);
});
return items;
}
var items = getItems();
console.log('Items for PSWP' + items);
alert('Alert Point 1'); // This is called once, (as it should).
var $pswp = $('.pswp')[0];
$pic.on('click', 'figure', function(event) {
// This block is called twice..
alert('Click Funct');
event.preventDefault();
var $index = $(this).index();
var options = {
index: $index,
bgOpacity: 0.7,
showHideOpacity: true
}
// Initialize PhotoSwipe
alert('Setting new PhotoSwipe');
var lightBox = new PhotoSwipe($pswp, PhotoSwipeUI_Default, items, options);
lightBox.init();
}); // End $pic.on
});// End .picture each
})(jQuery)
); // End list_header.html
} // End AJAX Success
}); // End AJAX
You may have already fixed this, but in case someone else falls upon this.
This can happen if you trigger opening the gallery more than once without closing it. It may be that you have registered multiple click handlers to open the gallery or for some reason the event is being fired twice.
It happens because in the init function the current class name of the pswp element is retrieved and cached, then on destroy the class name is restored. When the second open occurs without destroy being called _initialClassName will be set to class="pswp pswp--supports-fs pswp--open pswp--animate_opacity pswp--notouch pswp--css_animation pswp--svg pswp--animated-in pswp--visible" as your are seeing
Line 776 of photoswipe.js where initialclass is set
_initalClassName = template.className;
Breakpoint this in your browser to see if it is called multiple times when opening
Line 942 onwards destroy function
destroy: function() {
_shout('destroy');
Breakpoint this in your browser to ensure it is being called for every time open is called
Final Solution
The problem is that when opening the popup and loading the images you are filling #listing_photos_container with your photos, then adding a click handler to open photoswipe. This click handler is added to the top element, so will remain when the popup is closed, then the next time it is opened a new click handler will be added.
To fix this you just need to unbind the click handler when closing the popup, you can do this with $(".picture").off('click'); somewhere inside your closeListing() function
It's quite simple, before every .click(...) you need to write .unbind('click').
Example:
$('a#open-photoswipe').unbind('click').click(function() {
// open photoswipe here
});
Was having similar problem - just define lightBox as global variable. And on destroy define it as null. And in beginning of function where You initialize lightBox just check if lighBox is already defined, then do return.

Jquery hover event stuck on clone elements

I am creating an plugin with wordpress for the portfolio items. Everything works fine . But the issue is when i apply the filter the hover effect stopped working on the cloned items
also available JS FIDDLE
the jquery code is given below i tried
/* Scroll to Top Button */
jQuery(document).ready(function() {
// Animate Box Shadow on some elements
// Add the overlay. We don't need it in HTML so we create it here
// Clone portfolio items to get a second collection for Quicksand plugin
var $portfolioClone = jQuery(".rudra-portfolio").clone(true);
// Attempt to call Quicksand on every click event handler
jQuery(".rudra-portfolio-filter a").click(function(e) {
jQuery(".rudra-portfolio-filter li").removeClass("current");
// Get the class attribute value of the clicked link
var $filterClass = jQuery(this).parent().attr("class");
if ($filterClass == "all") {
var $filteredPortfolio = $portfolioClone.find("li");
} else {
var $filteredPortfolio = $portfolioClone.find("li[data-type~=" + $filterClass + "]");
}
// Call quicksand
jQuery("ul.rudra-portfolio").quicksand($filteredPortfolio, {
duration: 500,
easing: 'easeInOutQuad'
});
jQuery(this).parent().addClass("current");
// Prevent the browser jump to the link anchor
e.preventDefault();
})
jQuery(".port-li").click(function() {
jQuery(this).find('.content-wrapper').slideDown();
});
jQuery(".overeffect").mouseover(function() {
jQuery(this).find('.content-wrapper').slideDown();
});
jQuery("#portfolio-grid li").mouseleave(function() {
jQuery('.content-wrapper').slideUp(500);
});
});
hour effect is working fine for first and second time , but after that it stopped working .
Update
I also tried this Jquery clone
solved by me ..
i just need to use this
jQuery(document).on('hover',".overeffect",function(){
jQuery(this).find('.content-wrapper').slideDown();
});

Categories

Resources