Yesterday a reader asked me about building context menu support for images within a jQuery Mobile operation. Turns out it's pretty easy. Obviously there is no such thing as a right-click menu on a touch device. That being said - the convention that most mobile applications use is a "taphold" listener. You touch the item with your finger and wait. In a second or two, the context menu pops up. The taphold event is trivial to use in jQuery Mobile (with a caveat I'll get to in a second), but what isn't as trivial is deciding what UI to use. jQuery Mobile will - soon - have a popup UI item. For now though I decided on the excellent SimpleDialog2 plugin by JTSage. Let's look at an example.
I've taken a few simple images and embedded them into the page. Note that each employs a class, touchableImage.
In the code block at the bottom, I register an event listener for the taphold event and fire off a call to the SimpleDialog2 control. I won't go into a lot of detail over the options, use the link above for details, but I basically wanted a non-modal window with a set of options for the image. (For now those links don't actually do anything, but you get the idea.) You can demo this yourself below. Remember that if you are not on a touch device, you're screwed, unless you use Chrome which allows you to emulate touch events now.
Here's a quick screen shot so you can see it in action.
Ok, if you want to stop reading now, you can. What follows is an interesting issue I discovered with iOS and tap events and how I debugged it using Adobe Shadow. Still here? Ok, I warned you.
One of the nice features of the SimpleDialog2 control is that you can auto-dismiss it if you click anywhere else in the DOM. The attribute, forceInput, when set to false, allows for easy dismissal of the control. I wanted to use that feature, and it worked great in Android, but on iOS, it did not. As soon as the dialog showed up it went away.
Here's where Shadow comes in. I was using Shadow to load the page and I remembered that I could use the console there too. I added a quick event listener for tap, went back to the iPad, and tested again. I saw my first tap event, I saw the taphold, and when I lifted my finger, I saw another tap event! Apparently this is (I believe) normal for iOS. You can see some discussion of this here.
So for now, I switched forceInput to true which requires the user to forcibly close the dialog, which isn't horrible I guess. I could - possibly - sniff for iOS/Android and toggle the field depending on the platform, but for now, I'm satisfied with it.
And once again - Shadow helps save the day. I know I sound like a broken record, and I know I work for Adobe, but damn, this is probably one of the best development tools I've used in a long time.
Archived Comments
Hi
First of all thanks for the quick and nice sample!! It is exactly what I need in the lag of the next version Popup's.
One question which might be trivial but how do you reference to the object so you know what Image to "Send to Facebook"/"Send to Twitter" ...
Again thanks for our support
Kim
Basic idea would be:
The taphold event is passed the item you clicked on as this. Store a copy of that in a global variable.
Use event listeners for the 3 links. When clicked, fetch the global variable.
Does that make sense?
Ray,
When i ran the demo on my S2 i first got the 'copy image' android dialogue open. Your context menu opened below that?
Bit unusual not sure if this just on my phone
Tlv
Peter
HI Ray,
Yes it makes sense, I did see the global variable afterwards.. not a big fan of global variables for events, but easy enough to handle..
Thanks again
Kim
@Ray,
Is there a stopPropgation in Phonegap? So capture the event then stop the next ("tap") event firing after the taphold? This is the way I handle adding buttons to lists in Flex to stop the list "indexChanged" event firing when I've added a button on top of a list item.
+Peter Doyle: Shoot, I see that too on my One X. Let me investigate.
+Kim_ras: I hear ya - I think in this case it is ok though.
+Gareth: Remember - this isn't a PG issue but a web issue. PG is using webkit to render the content. So it isn't "Does PG support it", but can we do it in JS anyway. I'll try it on iOS and let you know. (As it stands, this isn't using PG anyway - just normal web pages.)
Peter/Gareth: stopProp worked great for the Android phone. I'm updating the Gist now (give it a few seconds). Thanks.
It did not - however - allow me to switch back the forceInput thing.
how can we pass parameters to taphold event
You don't. Parameters (involving the event) are passed already. Provide more detail on what you are trying to do and maybe I can help.
It doesn't work on Windows Phone device!
It doesn't work how? Saying it doesn't work isn't helpful. Is it not rendering the menu in the right place? Did you add a console.log(...) to the taphold event to ensure it was firing at least? I need more details on -where- it fails.
On windows phone's IE browser, when taphold on a link/img/a etc. the default action is show a context menu, like "open in new tab"/"copy the link address". it won't show our simpdialog.
If you have a windows phone mobile, you can run your demo page and you will see this problem soon.
Thanks!
Hmpth, you got me there. Best I can recommend is posting to the jQuery Mobile forum and letting us know. I don't have access to a Windows Phone right now.
Pavan @(<a href="http://www.pavanh.com/">pavanh</a>)
Very nice tutorial with efficent and detailed explaination, you can also check
this one <a href="http://www.pavanh.com/2013/...">context menu</a>
@pavan: To be clear, that is for native development. This blog post is about how to do it for mobile web or hybrid apps.
I do jquery only for a couple of month.
I refer to http://raymondcamden.com/de...
I ran this on firefox (no touchscreen) and emulated taphold by mousedown and liked it very much.
Then i ran it on my android cellphone. But the context dialog (right click) showed up first and then the simple dialog. Can happen the sd is completely hidden behind context dialog. how to supress firing context dialog just for this single event?
Hmm. You may want to try this: http://stackoverflow.com/qu...
Mr. Raymond Camden, please helpe me, do you can telle why it does not work this code?
$ (document). ready (function () {
$ (". various".) on ("taphold", "img", function () {
$ (this) fancybox ().;
});
});
No, I can't, because you didn't say how it wasn't working.
Is there any way to get the location of the taphold so that popup menu can be displayed relative to the touch location?
Not sure actually - try dumping the event object. It may contain the position.
First result via Google: http://stackoverflow.com/qu...
I'd tried examining the event object and experimented with different attributes but found nothing useful.
After posting this question, I found the post you mentioned and implemented that approach.
Was hoping for something a little less convoluted as I would have expected this information to be available on the event. It appears to be available in the original "touchstart" event as something like touches[0].clientX and clientY but doesn't make it through to the "taphold" event.
Thanks very much for your response (and the other articles of yours I've been learning from).
REGARDS
Peter
In theory - you could raise this as an issue with the jQM team as they added the taphold support for their framework. In theory. ;)