ContextMenuManager

I dont like the way we create and modify items with ContextMenu class in ActionScript 3.0, first we have to create item, then add event listener, then push our item to ContextMenu.customItems, I think this is quite alot of code for simple task. And there is one more disadvanage, we cannot subclass ContextMenu items, this means we cannot create subclass which would add some items by default.

All this inspired me to create my own class which would manage ContextMenu instance. Then I’ve added methods like remove, insert, getItem.

Take a look on the code below, this code creates new item in new ContextMenu instance.

var myContextMenu:ContextMenu = new ContextMenu();
    myContextMenu.hideBuiltInItems();
var item:ContextMenuItem = new ContextMenuItem("My Caption");
    item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,myHandler);
myContextMenu.customItems.push(item);
myInteractiveObject.contextMenu = myContextMenu;

If we want to add second item, get read for 3 more lines of code, and what about 5, 10 items?. I want to do this task like this:

var cmm:CMManager = new CMManager(myInteractiveObject);
    cmm.add("My Caption",myHandler);

That’s all folks, now lets think about something more complex, what if we want to create different type of controls, with different ContextMenu’s, but we also want all ContextMenu’s to have “About My Application” item. This is simple, just subclass CMManager:

package
{
	import eu.orangeflash.managers.CMManager;
	import flash.display.InteractiveObject;
	import flash.ui.ContextMenu;
	import flash.events.ContextMenuEvent;

	public class MyCMM extends CMManager
	{
		public function MyCMM(target:InteractiveObject)
		{
			super(target);
			add("About My Super Application",traceAbout);
		}

		private function traceAbout(event:ContextMenuEvent):void
		{
			trace("My Supper App");
		}
	}
}

Easy, isn’t it?, here is CMManager source code:

package eu.orangeflash.managers
{
	import flash.display.InteractiveObject;
	import flash.events.*;
	import flash.errors.IllegalOperationError;
	import flash.ui.*;
	import flash.utils.getQualifiedClassName;

	/**
	 * Class manages ContextMenu item, has methods such as add, remove, insert.
	 *
	 * @author		Nirth
	 * @url			http://orangeflash.eu
	 * @see			ContextMenu, ContextMenuItem, ContextMenuEvent, EventDispatcher, InteractiveObject
	 */
	public class CMManager
	extends EventDispatcher
	{
		protected var menu:ContextMenu;
		protected var target:InteractiveObject;
		/**
		 * Constructor, creates new CMManager isntance
		 *
		 * @param	target		Reference to InteractiveObject which menu will be managed
		 */
		public function CMManager(target:InteractiveObject, hideBuiltInItems:Boolean = true)
		{
			this.target = target;

			menu = new ContextMenu();

			if(hideBuiltInItems)
			{
				menu.hideBuiltInItems();
			}

			this.target.contextMenu = menu;

			menu.addEventListener(ContextMenuEvent.MENU_SELECT,passEvent);
		}
		/**
		 * Method, adds new ContextMenuItem.
		 *
		 * @param	caption				Specifies the menu item caption (text) displayed in the context menu.
		 * @param	handler				Event handler for menu item.
		 * @param	separatorBefore		Indicates whether a separator bar should appear above the specified menu item.
		 * @param	enabled				Indicates whether the specified menu item is enabled or disabled.
		 * @param	visible				Indicates whether the specified menu item is visible when the Flash Player context menu is displayed.
		 *
		 * @return						Reference to newly created ContextMenuItem
		 */
		public function add(caption:String,
							handler:Function,
							separatorBefore:Boolean = false,
							enabled:Boolean = true,
							visible:Boolean = true):ContextMenuItem
		{
			var result:ContextMenuItem = createItem(caption, handler, separatorBefore, enabled, visible);

			menu.customItems.push(result);

			return result;
		}
		/**
		 * Method, inserts new ContextMenuItem.
		 *
		 * @param	id					String or Number(int,uint). If id is string, ContextMenuManager will add before ContextMenuItem with captions which matches id, otherwise will be added item with index.
		 * @param	caption				Specifies the menu item caption (text) displayed in the context menu.
		 * @param	handler				Event handler for menu item.
		 * @param	separatorBefore		Indicates whether a separator bar should appear above the specified menu item.
		 * @param	enabled				Indicates whether the specified menu item is enabled or disabled.
		 * @param	visible				Indicates whether the specified menu item is visible when the Flash Player context menu is displayed.
		 *
		 * @return						Reference to newly created ContextMenuItem
		 */
		public function insert(	id:*,
								caption:String,
								handler:Function,
								separatorBefore:Boolean = false,
								enabled:Boolean = true,
								visible:Boolean = true):ContextMenuItem
		{
			var result:ContextMenuItem 	= createItem(caption, handler, separatorBefore, enabled, visible);
			var index:int 				= id is String ? getIndexByCaption(id) : id as int;

			(menu.customItems as Array).splice(index,0,result);

			return result;
		}
		/**
		 * Method, removes item from customItems array
		 *
		 * @param	id		String or Number(int,uint). If id is string, ContextMenuManager will remove ContextMenuItem with captions which matches id, otherwise will remove item with index.
		 */
		public function remove(id:*):void
		{
			if(id is String)
			{
				id = getIndexByCaption(id);
			}
			customItems.splice(id as Number,1);
		}

		/**
		 * Method. Hides all built-in menu items (except Settings) in the specified ContextMenu object. If the debugger version of Flash Player is running, the Debugging menu item appears, although it is dimmed for SWF files that do not have remote debugging enabled.
		 *
		 */
		public function hideBuiltInItems():void
		{
			menu.hideBuiltInItems();
		}
		/**
		 * Method, returns reference to ContextMenuItem by it's id.
		 *
		 * @param	id		String or Number(int,uint). If id is string, ContextMenuManager will return ContextMenuItem with captions which matches id, otherwise will return item with index.
		 *
		 * @return			reference to the ContextMenuItem instance.
		 */
		public function getItem(id:*):ContextMenuItem
		{
			if(id is String)
			{
				id = getIndexByCaption(id);
			}
			return menu.customItems[id];
		}

		/**
		 * Property[read-only] An array of ContextMenuItem objects.
		 *
		 * @return			An array of ContextMenuItem objects.
		 */
		public function get customItems():Array
		{
			return menu.customItems;
		}

		/**
		 * Property[read-only] An object that has the following properties of the ContextMenuBuiltInItems class: forwardAndBack, loop, play, print, quality, rewind, save, and zoom.
		 *
		 * @return			An object that has the following properties of the ContextMenuBuiltInItems class.
		 */
		public function get builtInItems():ContextMenuBuiltInItems
		{
			return menu.builtInItems;
		}

		/**
		 *	Property[read-only], returns reference to context menu.
		 *
		 * @return		ContextMenu
		 */
		public function get contextMenu():ContextMenu
		{
			return menu;
		}

		/**
		 *@private
		 */
		protected function createItem(caption:String, handler:Function, separatorBefore:Boolean = false, enabled:Boolean = true, visible:Boolean = true):ContextMenuItem
		{
			var result:ContextMenuItem = new ContextMenuItem(caption,separatorBefore,enabled,visible);
				result.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,handler);
				result.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT,passEvent);

			return result;
		}
		/**
		 *@private
		 */
		protected function getIndexByCaption(caption:String):int
		{
			for ( var i:uint = 0 ; i < menu.customItems.length ; i ++ )
			{
				if(menu.customItems[i].caption == caption)
				{
					return i;
				}
			}
			return -1;
		}
		/**
		 * @private
		 */
		protected function passEvent(event:ContextMenuEvent):void
		{
			dispatchEvent(new ContextMenuEvent(	event.type,
												event.bubbles,
												event.cancelable,
												event.mouseTarget,
												event.contextMenuOwner));
		}
	}
}

5 Responses to “ContextMenuManager”

  1. Actionscript Classes » ContextMenuManager Says:

    […] http://orangeflash.eu/?p=12 […]

  2. Cristi Says:

    hello!

    i’m clueless … i’ve tried to import this class (made the folders for class etc. put this on 1st frame and nothing happenned)

    do you have a working exmple with this ? a zip package maybe will be very appreciated, keep up the good work and thank you …

  3. Hilary Bridel Says:

    Very nice job.
    Do you know if there is a way to make the contextmenu appear via Actionscript rather than right clicking the mouse?

  4. Nik Says:

    This is great - Thanks!
    Also helpful are the javadoc comments for those of us wanting to learn about documenting custom classes…

  5. Nirth Says:

    2Hilary
    I don’t think there is any.
    2Nik
    Thanks
    2 Cristi
    Oh, sorry i was not checking comments on this blog for a long time=(