The other day I was doing some mobile app development using Appcelerator’s Titanium Studio, when I ran into an issue of wanting to have links from a WebView
open up in a new window. I needed an Appcelerator WebView link click event listener, but there is currently no such thing. I did some googling, but the solutions seemed excessive. Many required loading jQuery, or looping through the DOM after the page had loaded.
In my specific scenario, I have HTML content which is a small part of an object, not part of a full-blown HTML page. I didn’t need to worry about needing access to the page after the document had loaded. I also know the rules for the HTML content in question. I could work with the existing object’s HTML before giving it to the WebView
.
Faking an Appcelerator WebView Link Click Event Listener
Since there is no event listener just for link clicks, we need to fake one. Given that my requirements are self-contained HTML, it’s a pretty simple search and replace task. If you’re doing this with HTML from an unknown source, your results may not be as useful. I’ll explain more later. First, to the code!
Below is an app.js
file you can dump into a new Titanium project to see the approach in action. The bulk of it is setup. We create some usable HTML, a WebView
, and a Window
. The guts start on line 17.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | var html = 'Lorem ipsum <a href="http://bitsandbabble.com/">dolor</a> sit amet, consectetur <a href="http://studio27indy.com/">adipisicing</a> elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; var web1 = Ti.UI.createWebView( { backgroundColor: '#fff', top: '20dp', bottom: '20dp', left: '20dp', right: '20dp', } ); var win = Ti.UI.createWindow( { backgroundColor: '#eee' } ); win.add( web1 ); Ti.App.addEventListener( 'webViewClick', function( e ) { var web2 = Ti.UI.createWebView( { backgroundColor: '#000', top: '20dp', bottom: 0, left: 0, right: 0, url: e.URL } ); win.add( web2 ); } ); html = html.replace( /<a /gi, '<a onClick="Ti.App.fireEvent( \'webViewClick\', { URL: this.href } ); return false;" ' ); html = '<html><body>' + html + '</body></html>'; web1.html = html; win.open(); |
The idea is to fire an application level event any time a link is clicked. We accomplish this by the replace done on line 32. We’re just doing a regex match on any links, and using some JavaScript to fire a Titanium event. The important parts of this are passing along the href of the link, and returning false to prevent the current WebView from loading the new page. I did run into a slight snag when testing this approach. When setting the WebView.html
property, you have to give it a complete document for any JavaScript to be executed. I simply wrapped the HTML content in minimal tags (see line 34).
We setup our event listener on line 17. In the example, it simply loads a new WebView in the current window. Since you have the URL from the fired event, you can do virtually anything you want here. In my app, the initial HTML content is contained in a small area of the UI. So when the user clicks a link, I save the current window state, and open up a new window with a full screen WebView.
This approach is by no meals a foolproof solution. It works for limited cases where you know the type of content of the incoming HTML. If you’re unsure of the type of content, it would be best to try another approach, adding exceptions for links to other parts of the current page, etc.
If you’re in control of the HTML content, this is by far the easiest method I’ve seen to capture Appcelerator WebView
link click events.
Brilliant Spencer, thanks for this. I’d previously use JQuery to loop through and add click events, which means loading JQuery and is messy. This is a lot neater!
Nice post. Thank you !!!