First selection in Photoswipe gallery does not work - jquery-mobile

I am using Photoswipe gallery with jQuery Mobile. The first selection, when clicked/tapped shows just the image with full URL and does not work the gallery way. When I go back and select again, it works fine.
Can any one please tell me how can I sort this out?
Cheers!

When user comes to photoswipe gallery page directly using link photoswipe is not initialized. For example even going to official demo using direct link renders this problem. Link: http://www.photoswipe.com/latest/examples/04-jquery-mobile.html#Gallery1
Try putting script in which photoswipe attaches handlers for pageshow and pagehide events before jquery-mobile.js. If handlers are attached after they wont be triggered first time user visits page.
<script type="text/javascript" src="code.photoswipe-3.0.5.min.js"></script>
<script type="text/javascript">
(function(window, $, PhotoSwipe){
$(document).ready(function(){
$('div.gallery-page')
.live('pageshow', function(e){
if( $('ul.gallery', e.target).length > 0 ){
var
currentPage = $(e.target),
options = {},
photoSwipeInstance = $("ul.gallery a", e.target).photoSwipe(options, currentPage.attr('id'));
return true;
}
})
.live('pagehide', function(e){
if( $('ul.gallery', e.target).length > 0 ){
var
currentPage = $(e.target),
photoSwipeInstance = PhotoSwipe.getInstance(currentPage.attr('id'));
if (typeof photoSwipeInstance != "undefined" && photoSwipeInstance != null) {
PhotoSwipe.detatch(photoSwipeInstance);
}
return true;
}
});
});
}(window, window.jQuery, window.Code.PhotoSwipe));
</script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>

Related

migrate from jquerymobile 1.2.1 to 1.4.5

I am migrating up from jquerymobile 1.2 to 1.4.5
the content for each of my pages on my app commences with the following syntax,
$("#DemoAccountRegistrationPage").live("pageshow", function() {
I have been able to figure out i need to transition the .live to .on so the above becomes each page reference
$("#DemoAccountRegistrationPage").on("pagecontainershow", function() {
however i realise that the above format is still not compliant for 1.4.5 hence why the content is not loading
can someone please provide me the correct syntax to be able to change
$("#DemoAccountRegistrationPage").on("pagecontainershow", function() {
to the correct syntax for compliance with 1.4.5
I have read over the jquery docs but cannot fully understand what the correct syntax needs to be (very new to jquery mobile)
The jQuery docs are not at all very clear on this, but in a nutshell, pageshow was deprecated in JQM 1.4.0 in favour of using pagecontainershow on the pagecontainer widget.
I was able to get something working by adding the pagecontainershow listener to the document, then inspecting the arguments to figure out if it matched the page I wanted; something like this:
$(document).on('pagecontainershow', function(event, ui) {
if(ui.toPage[0].id == "my_page_id"){
// do some stuff for my_page
}
});
I tried to make it a bit more reusable, like this:
function on_pagecontainershow(page_id, fn){
$(document).on('pagecontainershow', function(event, ui) {
if(ui.toPage[0].id == page_id){
fn();
}
});
}
on_pagecontainershow('test_page', function(){
alert('pagecontainershow triggered');
});
Syntaxes I tried and failed to get working:
$(document).on('pagecontainershow', '#test_page', function(event, ui) {
alert("I don't get called (1)");
});
$(document).delegate("#test_page", "pagecontainershow", function() {
alert("I don't get called (2)");
});
$("#test_page").on("pagecontainershow", function() {
alert("I don't get called (3)");
});
You can try it out in this fiddle.
This works for me, as i'm using it in one of my projects:
$(document).on("pagecontainershow", function(e, ui) {
var pageId = $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
if (typeof ui.toPage == "object") {
/* manipulate page navigating to */
switch(pageId) {
case "page-one":
//do stuff
break;
case "page-two":
// do other stuff
break;
}
}
});

How can I trigger a YouTube video to play in browser on iOS by clicking on a play button instead of the embed?

On my site, I want to have users watch an embedded YouTube video without leaving the page, but I don't want to have the not so stylistic YouTube embed visible prior to clicking.
This is entirely doable on desktop, as you can use the YouTube JavaScript API to trigger the embed to play, but on iOS, programmatic triggering of the player to play is blocked. So how can I do this on iOS?
When thinking about this problem, I thought that one alternative route would be to have a layer that's opaque and styled, but you could click through it. This would mean the user thinks they're clicking a pretty button, when actually they're just clicking the embed to play.
Turns out there's a way of doing this, using the fancy (unofficial) CSS pointer-events property! Setting this to none means that clicks don't register, and instead punch straight through the element to whatever is behind it. In this case, the YouTube embed iframe. Support is iOS 6+.
Here's a JSFiddle of it working.
Note this is for iOS (and maybe Android) - it utilises the behaviour in which the video will automatically go full screen when it starts playing. If you watch this on desktop, the overlay remains.. overlaid.
There's some more polishing to be done with this to get it schmick:
Handling the initial click and altering the UI so they know immediately the video is kicking off. Perhaps hide the overlay, fade it, or change it to simply signify "Loading... "
On finish, resetting the video by recreating the iframe
You could do some tricky stuff with this technique, e.g. having a small player iframe overlaid by a small button. Still going to go fullscreen, so it'll work fine.
But regardless, there you go - proof of concept of playing a YouTube video on iOS without the user knowing they clicked on an embed.
iOS allows to call HTMLMediaElement.play function only from dispatched (triggered) by an user event (for example, from a "click" event handler).
Thus the code like this will work in iOS (because the player.playVideo is called from the dispatched by an user "click" event):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
var player;
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
player = e.target
}
}
})
}
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
player.playVideo()
})
})()
</script>
<script src="https://www.youtube.com/iframe_api"></script>
And the code like this will work in iOS too (because the initial call (the playMyVideo()) is still in the "click" event):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
var playMyVideo;
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
playMyVideo = function() {
var player = e.target
player.playVideo()
}
}
}
})
}
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
playMyVideo()
})
})()
</script>
<script src="https://www.youtube.com/iframe_api"></script>
But the code like this will not work in iOS (because the player.playVideo is called from the https://www.youtube.com/iframe_api script and not from the "click" event; i.e. only the window.onYouTubeIframeAPIReady function declaration is presented in the "click" event and window.onYouTubeIframeAPIReady is called from the https://www.youtube.com/iframe_api script):
<div class="video">
Play
<iframe width="560" height="315" src="https://www.youtube.com/embed/pqLVAeoRavo?enablejsapi=1" frameborder="0" allowfullscreen allow="autoplay"></iframe>
</div>
<script>
(function() {
document.querySelector('.video .play').addEventListener('click', function(e) {
e.preventDefault()
window.onYouTubeIframeAPIReady = function() {
new YT.Player(document.querySelector('.video iframe'), {
events: {
onReady: function(e) {
var player = e.target
player.playVideo()
}
}
})
}
var tag = document.createElement('script')
tag.src = 'https://www.youtube.com/iframe_api'
var firstScriptTag = document.getElementsByTagName('script')[0]
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
})
})()
</script>

Why tap event is suppressed by touchstart event?

I have this code:
$('.selector').on({
touchstart: function (e) {
e.preventDefault();
alert(3);
e.stopPropagation();
},
tap: function (e) {
e.preventDefault();
alert(4);
e.stopPropagation();
}
});
Only touchstart is triggered. Can anybody explain why?
P.S. : This is how I include the script for jQuery mobile :
<script src="http://code.jquery.com/mobile/1.4.4/jquery.mobile-1.4.4.min.js"></script>
EDIT:
I want to introduce a hover functionality on one of my div and I thought that with tap event it will be like clicking and with touchstart like hover.
$('.selector').on('tap swipe', function (e) {
e.preventDefault();
if(e.type == 'swipe') {
alert(1);
}
if(e.type == 'tap') {
alert(2);
}
e.stopPropagation();
});
$('.selector .sel1').on('tap swipe', function (e) {
e.preventDefault();
if(e.type == 'swipe') {
alert(3);
}
if(e.type == 'tap') {
alert(4);
}
e.stopPropagation();
});
With this code the swipe event on my div works fine, but for inside element I can't reproduce the swipe event, only tap gets triggered. I really can't figure out why.
Use syntax like this:
$('.selector').on("touchstart tap", function(e){
e.preventDefault();
if(e.type == "touchstart"){
alert(3);
}
if(e.type == "tap"){
alert(4);
}
e.stopPropagation();
});
Touchstart seems to no longer be offered as a native event within jQuery Mobile ver. 1.4.5 Perhaps you can use "tap" and "swipe" (or "swipeleft" / "swiperight") to achieve your goals? Its not entirely clear on what you are creating.
Note: one thing that you can do is easily customize the native jQuery Mobile functions for swipe. See details at http://api.jquerymobile.com/swipe/
Before you make the .on("swipe"...) binding you can change the test values used by jQuery swipe. Its as easy as
$.event.special.swipe.horizontalDistanceThreshold = 100; // in lieu of 30px
You can verify that data setup via alerts or console.log(). Perhaps this will work for you? hmmm.. by working on vertical distance threshold, you could in essence temporarily define "swipe" to function as a "swipe-up", then you'd have swipeleft, swiperight and swipeup to play with.

Stop the back history, juste close panel [duplicate]

I have a jQuery mobile panel which slides in from the side, it works great.
But lets say you have a login page, that redirects to a main page with a panel. Now if the user opens the panel, and then clicks the back button, he expects the panel to close. But instead the browser navigates back to the login page.
I´ve tried adding something to the url:
window.location.hash = "panelOpen";
But that just messes up the jQuery mobile history state pattern. I´ve also tried to listen to the navigate event, and prevent it if a panel is open:
$(window).on('navigate', function (e, hans) {
var panels = $('[data-role="panel"].ui-panel-open');
if (panels&&panels.length>0) {
e.preventDefault();
e.stopPropagation();
$('#' + panels[0].id).panel('close');
return false;
}
});
This kind of works, except that the url is changed, and I cannot grab the event that changes the url. Furthermore, it also messes up the jQuery mobile history pattern.
So how does people achieve this expected 'app-like' behaviour with a jQuery mobile panel; open panel > history back > close panel. And thats it.
Thanks alot!
Updated
Instead of retrieving current URL from jQuery Mobile's history, It is safer to retrieve it from hashchange event event.originalEvent.newURL and then pass it to popstate event to be replaceState() with that URL.
Instead of listening to navigate, listen to popstate which fires before. The trick here is manipulate both browser's history and jQuery Mobile's history by replaceState() and reload same page without transition.
var newUrl;
$(window).on("hashchange", function (e) {
/* retrieve URL */
newUrl = e.originalEvent.newURL;
}).on("popstate", function (e) {
var direction = e.historyState.direction == "back" ? true : false,
activePanel = $(".ui-panel-open").length > 0 ? true : false,
url = newUrl,
title = document.title;
if (direction && activePanel) {
$(".ui-panel-open").panel("close");
$(".ui-header .ui-btn-active").removeClass("ui-btn-active");
/* reload same page to maintain jQM's history */
$.mobile.pageContainer.pagecontainer("change", url, {
allowSamePageTransition: true
});
/* replace state to maintain browsers history */
window.history.replaceState({}, title, url);
/* prevent navigating into history */
return false;
}
});
This part is meant to maintain same transition used previously as transition is set to none when reloading same page.
$(document).on("pagebeforechange", function (e, data) {
if (data.options && data.options.allowSamePageTransition) {
data.options.transition = "none";
} else {
data.options.transition = $.mobile.defaultPageTransition;
}
});
Demo - Code
I am a little bit late on the party, but i had recently the same requirements and i would like to share how i did it. So, i extended the requirement in the original question to Panels, Popups and Pages:
...an expected 'app-like' behaviour, history back > close
whaterver is open. And thats it.
In .on("panelopen"), .on("popupafteropen") and .on("pagecontainershow") i simply add another entry to the window history, by using the HTML5 API (https://developer.mozilla.org/en-US/docs/Web/API/History_API) (I believe there is no need to use the JQM navigate browser quirks for that):
window.history.pushState({}, window.document.title, window.location.href);
After that, i'm using more or less Omar's function to intercept the popstate event:
$(window).on("popstate", function (e) {
var pageId = $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
var pageOpen = (pageId != "page-home");
var panelOpen = $(".ui-panel-open").length > 0;
var popupOpen = $(".ui-popup-active").length > 0;
if(pageOpen) {
$.mobile.pageContainer.pagecontainer("change", "#page-home", {reverse: true});
return false;
}
if(panelOpen) {
$(".ui-panel-open").panel("close");
return false;
}
if(popupOpen) {
$(".ui-popup-active .ui-popup").popup("close")
return false;
}
});
As you see, the is just only one level to the home-page, but this can be easily extended by using JQM history implementation to get the previous page:
var activeId = $.mobile.navigate.history.activeIndex;
var jqmHistory = $.mobile.navigate.history.stack; // array of pages
and use pagecontainer to change to the active entry - 1.
As last note, this works well also by completely disabling the built-in JQM Ajax navigation system:
/* Completely disable navigation for mobile app */
$.mobile.ajaxEnabled = false;
$.mobile.loadingMessage = false;
$.mobile.pushStateEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
$.mobile.popup.prototype.options.history = false;
(Tested in Browser, on real Android and iOS devices)

jquery mobile, programmatically change page and open panel once landed

I am using Jquery Mobile 1.4 and I would like to create a button that sends the user to another page, and opens the panel on this new page once landed :
I am trying this :
$(document).on('pagecreate','#faq-page', function(){
$('#faqcontactus').on("tap", function() {
$( "body" ).pagecontainer( "change", "#welcome-page", { transition: "fade" });
$( "body" ).pagecontainer( "getActivePage" ).find('#mypanel').panel("open");
});
});
which goes to the page, opens the panel, but closes it instantly.
Can you help ?
Thanks
You can't do it after you initiate page change process. That process is asynchronous and pane open will not wait for this function to end. What you need to do is wait for next page to became visible, then you should trigger panel.
Something like this:
$(document).on('pagecontainershow', function (e, ui) {
var activePage = $(':mobile-pagecontainer').pagecontainer('getActivePage');
var activePageId = activePage .attr('id')
if(activePageId === 'welcome-page') {
activePage.find('#mypanel').panel("open");
}
});
You should wait until page is fully loaded before you open the panel, i.e. use pagecontainershow.
$(document).on("pagecontainershow", function () {
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage");
if(activePage[0].id == "welcome-page") {
$(".ui-panel", activePage).panel("open");
}
});

Resources