Context Sensitive menu on hyperlinks of Adobe AIR HTML control
Posted on 24 October 2010
Adobe AIR includes a rich HTML control based on the open-source WebKit engine. This allows AIR applications to display rich HTML control and provide custom functionality around those web pages. Thus, an application can allow a user to display an HTML control and add functionalities like spell-check, dictionary support etc. One of the most required functionalities when making rich Web Application is the use of custom context-sensitive menus. Context-sensitive menus is a list of menu options, that open when you right click on an element of a user-interface (subject that the element supports one).
In this post we will try and look on how to add a custom context-sensitive menu on hyperlinks present in an HTML page loaded inside an AIR HTML control. We would two menu options called, ‘Open link in Browser’ and ‘Copy Link’ to the context-sensitive menu. To achieve the same adopt the following procedure,
-
Create an AIR application consisting of an HTML control
-
Capture the Event.COMPLETE event handler so as to figure out when an HTML page has completely loaded inside the HTML control
-
Wire a context-sensitive menu event listener that is invoked when a user right-clicks inside the HTML control
-
In the event handler for the same, generate a context sensitive menu and display it at the right location.
Done. A snapshot of how the application looks like is,
Below is the code that makes use of the above approach in a simple application. When executing the example, wait for the page to load completely. Once, all Javascript’s on the page have loaded, try clicking on the hyperlinks in the page displayed.
The code for the application is also available in my Google Code repository.
The main MXML code is as,
<s:windowedapplication height="600" initialize="onInit()" width="800" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<br>
<br>
<fx:script>
<br>
<br>
</fx:script>
<br>
<br>
<mx:html height="100%" id="html" width="100%">
<br>
<br>
</mx:html>
</s:windowedapplication>
The SCRIPT block should contain the following code,
import mx.controls.Menu;
import mx.events.MenuEvent;
/**
* Instance of the menu being rendered.
*/
private var myMenu:Menu = null;
/**
* Initialize the application
*/
private function onInit():void {
this.html.addEventListener(Event.COMPLETE, htmlLoadCompleteHandler);
this.html.addEventListener(MouseEvent.MOUSE_DOWN, htmlMouseDownHandler);
// shameless publicity
this.html.location = "http://blog.sangupta.com";
}
private function htmlLoadCompleteHandler(event:Event):void {
const document:Object = this.html.htmlLoader.window.document;
document.body.oncontextmenu = contextMenuHandler;
document.body.onclick = clickHandler;
}
/**
* Remove menu when you click on Flex surface than document body
*/
private function htmlMouseDownHandler(event:MouseEvent):void {
hideContextMenu();
}
/**
* Remove menu when you click on document body
*/
private function clickHandler(event:Object = null):void {
hideContextMenu();
}
/**
* Hide the context menu
*/
private function hideContextMenu():void {
if(myMenu != null) {
myMenu.hide();
}
}
/**
* Function that builds the context menu
*/
private function contextMenuHandler(event:Object = null):* {
var target:Object = event.srcElement;
if(target.nodeType == '1' && String(target.nodeName).toLowerCase() == 'a') {
// the URL of the anchor element
var url:String = target.href as String;
var x:Number = event.x;
var y:Number = event.y;
var p:Point = new Point(x,y);
p = this.localToGlobal(p);
if(myMenu != null) {
hideContextMenu();
myMenu = null;
}
var items:Array = new Array();
var object:Object = null;
// open link in browser
object = new Object();
object.label = 'Open In Browser';
object.eventName = 'browser';
items.push(object);
// separator
object = new Object();
object.type = 'separator';
items.push(object);
// copy link
object = new Object();
object.label = 'Copy';
object.eventName = 'copy';
items.push(object);
// create the menu object
myMenu = Menu.createMenu(parent, items, false);
// add menu item click handler
myMenu.addEventListener(MenuEvent.ITEM_CLICK, menuItemClickHandler);
// show the menu
myMenu.show(p.x, p.y);
// disable default context sensitive menu handler
return false;
}
}
private function menuItemClickHandler(event:MenuEvent):void {
// handle the menu item click event here
}
Hope this helps.