Site > Home > Example Code > Tooltips on iPad  
Displaying a Tooltip on an iPad

If you're reading this page, you're doubtless aware that touch-based browsers don't have a mouse cursor. Having a mouse cursor is a necessary precondition of detecting mouse events, such as "hover". This page presents a workaround that makes tooltips accessible from touch-based browsers.

Touch-based browsers haven't been that common until recently. Even where they existed, they weren't much used, due to the small sizes of most multi-touch screens. The iPad is changing all that. Soon there will be large multi-touch browsers besides Safari for the iPad, but for now, what we're REALLY talking about here is the iPad.

Nevertheless, I'm going to try to remain ecumenical about this and keep saying "touch-based browser".


Detecting Touch-Based Browsers on the Server

In general, you don't want to send this code to a browser unless it's touch-based. The easy way to do this is to search for the strings "iPad", "iPhone" or "iPod" in the HTTP header HTTP_USER_AGENT. Because ColdFusion's "regular expression find" command ("REFind") accepts the pipe character ("|") to mean "or", ColdFusion can do this in only one line:

        <cfset Variables.TouchBasedBrowser = (REFind("iPad|iPhone|iPod", CGI.HTTP_USER_AGENT) GT 0)>

REFind is case-sensitive, which is okay, because iPads, iPhones and iPod Touches declare themselves with those exact same upper and lower case characteristics. It returns 0 if the regular expression is not found, or the 1-based offset of the first occurrence if it is found. CGI.HTTP_USER_AGENT retrieves the value of the HTTP header HTTP_USER_AGENT in the request (typically a GET). The expression "something GT 0" returns "Yes" or "No" (ColdFusion's English-friendly boolean values), according to whether or not the expression is true or false. And the parentheses around that expression guarantee that it will be evaluated ahead of the assignment operator ("=").

Interestingly, this same REFind works with Opera and the Atomic WebBrowser for iPad too. However, the Atomic WebBrowser allows setting the user agent string to those of other browsers, if you do that for a non-iPad browser, it won't work, obviously.

Other server-side scripting languages would have their own syntax for the same thing, but ColdFusion's pretty easy, and this provides the gist of how to do it.

On the browser you're currently using to read this, Variables.TouchBasedBrowser got set to NO.

As time goes by, there are bound to be more touch-based browsers. Please send an e-mail to info (at) webmanwalking (dot) org if you want me to add your favorite touch-based browser to this list. (Please include the substring of HTTP_USER_AGENT that uniquely identifies the touch-based version of that browser.)


Getting a Context-Sensitive Help Menu ("ContextMenu")

The trick is to define an event handler for an event you CAN detect, namely oncontextmenu. The context menu is typically revealed by right-click if you have a two-button mouse, or by clicking with a modifier key down if you have a one-button mouse, or by pressing and holding on a touch-based browser. To do this, you have to use <a>, not <div> or <input> or <span>, because with plain-old background text, Safari for iPad defaults to selecting text.

If you don't give an <a> tag the href attribute, it isn't hot, so what should you give as the href? Some like "#", but that scrolls to top-of-page. Some like "#nonexistentname", but that's pretty kludgey (pronounced "clue-jee"). Some like "javascript:void();" or "javascript:void(0);", but that can throw an error. And here's an href that literally means "do nothing":

        <a href="javascript:(function(){})();">Hotlink that does nothing.</a>

(Define an anonymous JavaScript function that does nothing, and then call it.) Unfortunately, javascript URLs don't trigger the contextmenu event.

So we're going to need to have an href of an actual page that doesn't potentially throw away form data. I came up with a ColdFusion page that looks for and displays a Query_String containing Tooltip=((text)), and to give the hotlink target="_blank" (pop up a new window).


Showing the Tooltip without jQuery

That said, here's a self-contained example of how to do display a tooltip just prior to the context menu:

        <a href="javascript:(function(){})();" class="emphasize_max" title="This is my tooltip."<cfif Variables.TouchBasedBrowser>
        oncontextmenu="return confirm(this.title + '\n\n'
        + 'The message above is a tooltip. \n'
        + 'If you want to see the context-sensitive help menu too, click OK. \n'
        + 'If all you wanted to see was the tooltip, press Cancel.');"</cfif>
        >This text has a tooltip. (Press and hold if you're on an iPad, or just hover over it if not.)</a>

This text has a tooltip. (Press and hold if you're on an iPad, or just hover over it if not.)

Returning false prevents the default action, which would be to display the context-sensitive help menu.


Showing the Tooltip with jQuery

You can't do <cfif> in a cacheable JavaScript file. The ".js" suffix prevents ColdFusion from getting control. You could <cfinclude> it, but that keeps it from being cacheable, slowing down page load times. But you CAN write a standard routine that you can include on every touch-based browser page.

TouchBasedBrowser.js (hotlink opens new window to my TouchBasedBrowser.js file):

                .not("[oncontextmenu]")     // Don't bind this handler if the HTML already defined something.
                    .bind("contextmenu", function()
                        return confirm(this.title + '\n\n'
                        + 'The message above is a tooltip (displayed by jQuery for this example). \n'
                        + 'If you want to see the context-sensitive help menu too, click OK. \n'
                        + 'If all you wanted to see was the tooltip, press Cancel.')

Calling page (something.cfm, for the <cfif>):

        <script src="/library/javascripts/jquery/jquery.js"></script>
        <cfif Variables.TouchBasedBrowser>
            <script src="TouchBasedBrowser.js"></script>


        <a target="_blank" href="/library/callbacks/dsp_tooltip.cfm?Tooltip=This%20is%20my%20jQuery%2Ddisplayed%20tooltip%2E" class="emphasize_max" title="This is my jQuery-displayed tooltip.">Much simpler.</a>

Much simpler.

So, the next time someone tells you that it can't be done, you can counter their lack of imagination with a demonstration that it can.