Magnific-popup gallery duplicate images when i use it with Owl-carousel - asp.net

i have developed aspx page
on it i have image galley using owl-carousel
now when i added magnific-popup plugin and used gallery option
then i noticed when i click on image on carousel it get popup successfully but images get duplicated (inside popup)
Owl-Carousel gallery
First popup
Duplicated Image
my aspx code :
<div class="owl-carousel">
<asp:ListView runat="server" ID="lvDesrtProgramGallery" ItemType="SharedKernel.Core.Model.ProgramPhoto" SelectMethod="lvDesrtProgramGallery_GetData">
<ItemTemplate>
<div class="item">
<a class="desert-safari-gallery" href="<%# Item.PhotoPath %>">
<img src="<%# Item.MediumPhotoPath %>" alt="" />
<div class="overlay">
<i class="fa fa-search-plus"></i>
</div>
</a>
</div>
</ItemTemplate>
</asp:ListView>
</div>
Js code
$('.desert-safari .owl-carousel').owlCarousel({
items: 3,
dots: false,
nav: true,
loop: true,
margin: 10,
autoplay: true,
navText: ['<i class="fa fa-angle-left fa-4x"></i>', '<i class="fa fa-angle-right fa-4x"></i>'],
onInitialized: callback,
responsiveClass: true,
responsive: {
0: {
items: 1,
nav: false,
margin: 80
},
570: {
items: 1,
nav: false
},
768: {
items: 2,
nav: false
},
992: {
items: 3,
nav: false,
},
1200: {
items: 3,
nav: true,
loop: false
}
}
});
function callback(event) {
$(".desert-safari-gallery").magnificPopup({
type: "image",
removalDelay: 160,
loop: false,
preloader: false,
fixedContentPos: true,
showCloseBtn: false,
gallery: {
enabled: true
}
})
}

I just ran into this problem so I thought I'd give you my answer/solution.
The Reason:
Since your using owl carousel to loop, owl carousel is cloning items. Because your cloning the items within your carousel you're now feeding duplicates into the popup gallery. What a hassle right? There are two seemingly obvious solutions.
Solution 1: Don't use owl-carousel's loop.
This may not be the preferred solution if you want the looping feature of your carousel but this will no longer cause the popup to receive duplicate entries.
Solution 2: Create an array of objects based on the resulting elements, remove the duplicates, then use magnific's items property to set the gallery items.
Here is a working script I had to create based off a similar scenario I'm sure you can dissect what the process is:
(function( $ ) {
'use strict';
$( window ).load(function(){
var GalleryItems = [];
$('.gallery img').each(function(i){
var src = $(this).attr('href');
var theSrc = {
src: src,
type: 'image'
};
GalleryItems.push(theSrc);
});
var GalleryItems = GalleryItems.reduce(function(previous, current) {
var object = previous.filter(object => object.src === current.src);
if (object.length == 0) {
previous.push(current);
}
return previous;
}, []);
theGallery();
function theGallery(){
$('gallery').magnificPopup({
type: 'image',
gallery: {
enabled:true
},
items:GalleryItems,
});
}
});
})( jQuery );

I found that #Chris Stage's answer works perfectly, but for some n00bs who try to use the code verbatim may run into issues. I can't just leave a comment or accept the answer so I am posting my revision in hopes that it provides someone else with the correct code.
The one issue I found was that in the .each() function, that you have to target the wrapping a tag's URL to the larger image, not the image's URL itself due to the fact that the one used in the carousel may be a thumbnail or equivalent, and the larger one to the "larger image" to open in a popup may be a separate URL.
(function( $ ) {
'use strict';
$( window ).load(function(){
var GalleryItems = [];
$('.photo-gallery .item a').each(function(i){ //Target your wrapping a tag
var src = $(this).attr('href');
var theSrc = {
src: src,
type: 'image'
};
GalleryItems.push(theSrc);
});
var GalleryItems = GalleryItems.reduce(function(previous, current) {
var object = previous.filter(object => object.src === current.src);
if (object.length == 0) {
previous.push(current);
}
return previous;
}, []);
theGallery();
function theGallery(){
$('.photo-gallery').magnificPopup({ //Target parent carousel container
type: 'image',
gallery: {
enabled:true
},
items:GalleryItems,
removalDelay: 300,
mainClass: 'mfp-fade' //Adds magnific's fade effect
});
}
});
})( jQuery );
This solution worked perfectly with Owl's issue with "cloned" images and thanks to #Chris Stage for coming up with this. His answer should be the "Accepted Answer" but I'd also love an Upvote for the clarification so I can earn some Rep points :)

For future reference, here is a much simpeler solution:
$('.owl-item:not(.cloned) * .desert-safari-gallery').magnificPopup(..
Change your selector so that it will not be used for children of elements with the 'owl-item cloned' class.

You can use this little fix.
$('.owl-carousel.with-mfp').each(function () {
var $mfp = $(this);
$mfp.on('click', '.owl-item.cloned a', function (event) {
event.preventDefault();
var self = $(this);
// Dependency on image positions in owl and on unique a.href attrs
$mfp.find('.owl-item:not(.cloned) a').each(function (index) {
if ($(this).attr('href') === self.attr('href')) {
$mfp.magnificPopup('open', index);
}
});
});
$mfp.magnificPopup({
type: 'image',
delegate: '.owl-item:not(.cloned) a',
gallery: {
enabled: true
}
});

Related

Could someone check my PayPal Smart Button?

I'd be grateful if some kind person would glance over this PayPal SmartButton code?
I've put in the NO_SHIPPING and I'm not sure about all the brackets (){}[] and whether there should be double " or single ' inverted commas etc.
I'm OK with html, but this scripting mystifies me.
Thanks in anticipation, Steve
<div id="smart-button-container">
<div style="text-align: center;">
<div id="paypal-button-container"></div>
</div>
</div>
<script src="https://www.paypal.com/sdk/js?client-id=sb&e nablefunding=venmo&currency=GBP" data-sdk-integration-source="button- factory"></script>
<script>
function initPayPalButton() {
paypal.Buttons({
style: {
shape: 'pill',
color: 'gold',
layout: 'vertical',
label: 'buynow',
},
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{"description":"item for sale\nacceptM/accept43_BB1frT6.htm","amount":{"currency_code":"GBP","value":20}}],
application_context: {
shipping_preference: 'NO_SHIPPING'
}
});
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Full available details
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
// Show a success message within this page, e.g.
const element = document.getElementById('paypal-button-container');
element.innerHTML = '';
element.innerHTML = '<h3>Thank you for your payment!</h3>';
//actions.redirect('https://www.website.com/');
});
},
onError: function(err) {
console.log(err);
}
}).render('#paypal-button-container');
}
initPayPalButton();
</script>
Script SDK line is not correct, has extra spacing and a missing hyphen. You need:
<script src="https://www.paypal.com/sdk/js?client-id=sb&enable-funding=venmo&currency=GBP" data-sdk-integration-source="button-factory"></script>
That's simply the code the button factory would have generated for you, and it works.
For future reference most HTML/JS problems can be troubleshooted in a browser's Developer Tools, on the Console and Network and (for HTML) Inspect tabs, reloading the page once the Network tab is open for example.

Customize Embedded Zoom Meeting SDK with Component View in 2.2.0

When working with Embedded Zoom Component, the Zoom SDK return an element which you need to place it inside an html element
the problem is how to resize and position the returned component inside my code after rendering
const client = ZoomMtgEmbedded.createClient();
function getSignature(e) {
e.preventDefault();
// ... some code to get the signature
startMeetingZoomMtgEmbedded(response.signature);
}
function startMeetingZoomMtgEmbedded(signature) {
let meetingSDKElement = document.getElementById('meetingSDKElement');
client.init({
debug: true,
zoomAppRoot: meetingSDKElement,
language: 'en-US',
customize: {
meetingInfo: ['topic', 'host', 'mn', 'pwd', 'telPwd', 'invite', 'participant', 'dc', 'enctype'],
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'CustomButton',
onClick: () => {
console.log('custom button');
}
}
]
}
}
});
client.join({
apiKey: apiKey,
signature: signature,
meetingNumber: meetingNumber,
password: passWord,
userName: userName,
userEmail: userEmail,
tk: registrantToken,
success: (success) => {
console.log('success');
},
error: (error) => {
console.log(error);
}
});
}
return (
<div className="App">
<main>
<h1>Zoom Meeting SDK Sample React</h1>
{/* For Component View */}
<div id="meetingSDKElement"></div>
<button onClick={getSignature}>Join Meeting</button>
</main>
</div>
);
So my question is how to modify the style and the position of the component before or after the rendering of the code by the Zoom SDK.
For Resizing , You will find details in the following documentation link :
Zoom Documentation for resizing component view
For Positioning, You will find details in the following documentation link :
Zoom Documentation for positioning component view
The only way to resize camera view is editing #ZOOM_WEB_SDK_SELF_VIDEO id. So, you have to edit other classes also to make buttons, containers and etc resize like camera view does, but it is totally buggy and i don't think it is a good idea pay all this effort to a workaround, besides that, in next versions maybe they bring built in properties to do this job.
Just for example, this is the result when you change #ZOOM_WEB_SDK_SELF_VIDEO:
#ZOOM_WEB_SDK_SELF_VIDEO {
width: 720%;
height: 480%;
}
In general way, you can modify the style and position of your component by using reactive CSS styling.
In zoom way you can use (zoom web meeting SDK)
(a) "popper: {}" properties for positioning elements
(b) "viewSizes: {}" properties for default meeting canvas size
(c) for styling use "id" and "class" for reactive CSS styling
popper use:
client.init({
...
customize: {
video: {
popper: {
anchorElement: meetingSDKElement,
placement: 'top'
}
},
}
...
})
viewSizes use:
client.init({
...
customize: {
video: {
viewSizes: {
default: {
width: 1000,
height: 600,
}
}
},
}
...
})

EnjoyHint - can I have a hint without specifying an element?

I'd like to have an introductory hint in EnjoyHint that the user can move on from by simply pressing "Next". So no arrow to an element. Is this possible?
HTML
<div class="hidden"></div>
JS
var enjoyhint_script_steps = [
{
'click .hidden': '<h2>Introduction</h2><p>This is an introductory sentence, which tells you a bit about everything.</p>',
showSkip: false,
showNext: true,
margin: 0,
onBeforeStart: function () {
document.getElementsByClassName('enjoyhint_svg_wrapper')[0].style.display = 'none';
}
},
{
onBeforeStart: function () {
document.getElmentsByClassName('enjoyhint_svg_wrapper')[0].style.display = 'block';
},
...rest of step 2...
}
...rest of steps...
];
Explanation
<div class="hidden"></div> is an empty element for EnjoyHint to target.
'click .hidden': '...description...' targets the empty element and adds a description.
showSkip: false hides the skip button.
showNext: true shows the next button.
margin: 0 hides the area highlighted by EnjoyHint.
onBeforeStart: function () {...} is used to hide the arrow in the first step and show it in the second step.
var enjoyhint_script_steps = [
{
'next .hidden': '<h2>Introduction</h2><p>This is an introductory sentence, which tells you a bit about everything.</p>',
showSkip: false,
showNext: true,
onBeforeStart: function () {
$('#enjoyhint_arrpw_line').hide();
}
},
{
...rest of step 2...
}
...rest of steps...
];
Explanation
There is a better solution then target to a hidden div, when assigning the 'click' event.
The 'click' event expects the user to click on the highlithed element in order to move on to the next step and when your element is hidden you cannot click on it.
In order to have 'Next' button by default and target the user to click on it you need to use the 'next' event.
The onBeforeStart gives you the option to run any function you want just before this specific hint starts, so you can run:
function () {
$('#enjoyhint_arrpw_line').hide();
}
Inside the onBeforeStart.
When you do it like that you can highlight any element on page without an arrow and have a mandatory 'Next' button.
You can also write it that way if it's more readable:
var enjoyhint_script_steps = [
{
event: 'next',
selector: '.hidden', // or any element you want to highlight
description: '<h2>Introduction</h2><p>This is an introductory sentence, which
tells you a bit about everything.'</p>
showSkip: false,
showNext: true, // not necessary
onBeforeStart: function () {
$('#enjoyhint_arrpw_line').hide();
}
},
{
...rest of step 2...
}
...rest of steps...
];
You can make div class="hidden" and make arrow transparent
let enjoyhint_script_steps = [
{
'click .hidden': '<h2>Hello</h2>',
arrowColor:'transparent'
}
];

Change background color based on event title Fullcalendar 4

I'm trying to change the background color of an event (in Day View) of fullcalendar v4. I've spent hours trying to implement eventRender, to no avail. This has led me to find other workarounds, but now, I'm striking out!
I'm trying to figure out the solution explained here: [Fullcalendar - change event color based on value ..
But, every time the search for the word 'yes' is TRUE, I get an error in chrome console saying 'Failure parsing JSON'. If I change the search query to something that will create 'false', I do not get this error. To me, this means that the search is working, but the event render function is failing somehow.
my code:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: [ 'interaction', 'resourceDayGrid', 'resourceTimeGrid' ],
defaultView: 'resourceTimeGridDay',
defaultDate: '<?php echo $startdate?>',
validRange: {
start: '<?php echo $startdate?>',
end: '<?php echo $maxdaycal?>'
},
height: 700,
...
...
eventSources: [
{
url: 'getevents2.php?festid=<?php echo $festid?>&room=<?php echo $roomabv?>',
cache: false,
},
{
url: 'getbreaks2.php?festid=<?php echo $festid?>&room=<?php echo $roomabv?>',
cache: false,
color: 'grey',
editable: false,
}
],
eventRender: function(info) {
if(info.event.extendedProps.desc == "yes") {
element.style.css('background-color', '#000');
}
},
....
});
calendar.render();
});
My goal: Search for the word "Accomp" in the title of the element (probably in info.event.title) .. and have the background change to a different color .. like red .. or something.
I've also tried to show an Icon in this field if the word Accomp is present, but -- I had to show it in a modal, because I couldnt get eventrender to show html.
I think this is because of the differences in FC v4 .. but I'm not sure.
I've also tried: [Is it possible to assign the background colour of a FullCalendar event based on its title? .. but I couldn't get that sorted out either.
UPDATE: The search function is working, as I can see it in the console log, but whenever I try to set the css, the calendar does not render.
eventRender: function(info) {
console.log(info.event.title);
if(-1 != info.event.title.indexOf("Accomp")) {
console.log(info.event.title);
fc-title.css('background-color', '#000');
}
},
This is based on some other answers that areavailable, but it appears that there are differences in FC4... This works for me!
eventRender: function(info) {
if(-1 != info.event.title.indexOf("Accomp")) {
info.el.style.backgroundColor = "red";
}
},

Sencha Touch setActiveItem shows animation then requires click to show

When I move between views in my Sencha Touch app I see the animation (slide), then the original view(the one I started at) is shown again. At that point, if I click anywhere in the app the view will change to the correct newly active item.
I'm using Sencha Touch, XCode 4, iOS 5 SDK, and PhoneGap 1.3.0.
Thanks in advance!
here's the code for the main viewport:
plantanalyzer.views.Viewport = Ext.extend(Ext.Panel, {
fullscreen: true,
layout: 'card',
cardSwitchAnimation: 'slide',
initComponent: function() {
Ext.apply(plantanalyzer.views, {
login: new plantanalyzer.views.Login(),
plantDetail: new plantanalyzer.views.PlantDetail(),
buildingList: new plantanalyzer.views.BuildingList()
});
Ext.apply(this, {
items: [
plantanalyzer.views.login,
plantanalyzer.views.plantDetail,
plantanalyzer.views.buildingList
]
});
plantanalyzer.views.Viewport.superclass.initComponent.apply(this, arguments);
}
});
and for the viewController:
plantanalyzer.controllers.viewController = new Ext.Controller({
index: function(options) {
plantanalyzer.views.viewport.setActiveItem(plantanalyzer.views.plantDetail, options.animation);
},
show: function(options) {
plantanalyzer.views.viewport.setActiveItem(plantanalyzer.views.buildingList,
options.animation);
}
});
and this is the code for one of the views:
plantanalyzer.views.PlantDetail = Ext.extend(Ext.Panel, {
width: 320,
height: 480,
items: [
{
xtype: 'panel',
html: '<img src="images/logo.jpg"/>',
tpl: '{name}',
cls: 'plantToolbar'
},
{
xtype: 'button',
name : 'buildingSelect',
text: 'Select Building',
cls: 'standardButton',
listeners: {
'tap': function () {
'use strict';
Ext.dispatch({
controller: plantanalyzer.controllers.viewController,
action: 'show'
});
}
}
},
{
xType: 'panel',
cls: 'infoBoxes',
html: 'Efficiency (kw/ton)<br><canvas id="eff"></canvas>'
},
{
xType: 'panel',
cls: 'infoBoxes',
name: 'totalTons',
html: 'Total Plant Tons: '
},
{
xType: 'panel',
cls: 'infoBoxes',
name: 'totalCost',
html: 'Real-time Plant Cost: '
},
{
xType: 'panel',
name: 'uodateTime',
cls: 'lastUpdate',
html: 'Last Update: '
}
]
});
The code looks fine in both sections. When i had issues with phonegap and sencha touch doing this i generally found there was a javascript error occurring or extra html markup was in between the body tag of the index.html file. The first thing would be to open the console in chrome or safari and check the javascript console to determine if it is a javascript error. If you can't run it in them i would suggest the Wienre application that will give you a console and was written to debug phonegap applications (wienre will also allow you to view the html markup to make sure it is correct)
The problem must be somewhere in the view files. The code you have shown is correct.
Well, for what it's worth, after rebuilding the app I found the issue. It was some custom css that was screwing up the app. Specifically the width that was being set on some of the components.
Hopefully, this will save somebody else some time and heartache.
Thanks, Darren and Ilija for your help!

Resources