1 /*
  2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5
  6 CKEDITOR.plugins.add( 'contextmenu',
  7 {
  8 	requires : [ 'menu' ],
  9
 10 	beforeInit : function( editor )
 11 	{
 12 		editor.contextMenu = new CKEDITOR.plugins.contextMenu( editor );
 13
 14 		editor.addCommand( 'contextMenu',
 15 			{
 16 				exec : function()
 17 					{
 18 						editor.contextMenu.show();
 19 					}
 20 			});
 21 	}
 22 });
 23
 24 CKEDITOR.plugins.contextMenu = CKEDITOR.tools.createClass(
 25 {
 26 	$ : function( editor )
 27 	{
 28 		this.id = 'cke_' + CKEDITOR.tools.getNextNumber();
 29 		this.editor = editor;
 30 		this._.listeners = [];
 31 		this._.functionId = CKEDITOR.tools.addFunction( function( commandName )
 32 			{
 33 				this._.panel.hide();
 34 				editor.focus();
 35 				editor.execCommand( commandName );
 36 			},
 37 			this);
 38 	},
 39
 40 	_ :
 41 	{
 42 		onMenu : function( offsetParent, corner, offsetX, offsetY )
 43 		{
 44 			var menu = this._.menu,
 45 				editor = this.editor;
 46
 47 			if ( menu )
 48 			{
 49 				menu.hide();
 50 				menu.removeAll();
 51 			}
 52 			else
 53 			{
 54 				menu = this._.menu = new CKEDITOR.menu( editor );
 55 				menu.onClick = CKEDITOR.tools.bind( function( item )
 56 				{
 57 					var noUnlock = true;
 58 					menu.hide();
 59
 60 					if ( CKEDITOR.env.ie )
 61 						menu.onEscape();
 62
 63 					if ( item.onClick )
 64 						item.onClick();
 65 					else if ( item.command )
 66 						editor.execCommand( item.command );
 67
 68 					noUnlock = false;
 69 				}, this );
 70
 71 				menu.onEscape = function()
 72 				{
 73 					editor.focus();
 74
 75 					if ( CKEDITOR.env.ie )
 76 						editor.getSelection().unlock( true );
 77 				};
 78 			}
 79
 80 			var listeners = this._.listeners,
 81 				includedItems = [];
 82
 83 			var selection = this.editor.getSelection(),
 84 				element = selection && selection.getStartElement();
 85
 86 			// Lock the selection in IE, so it can be restored when closing the
 87 			// menu.
 88 			if ( CKEDITOR.env.ie )
 89 				selection.lock();
 90
 91 			menu.onHide = CKEDITOR.tools.bind( function()
 92 				{
 93 					menu.onHide = null;
 94
 95 					if ( CKEDITOR.env.ie )
 96 						editor.getSelection().unlock();
 97
 98 					this.onHide && this.onHide();
 99 				},
100 				this );
101
102 			// Call all listeners, filling the list of items to be displayed.
103 			for ( var i = 0 ; i < listeners.length ; i++ )
104 			{
105 				var listenerItems = listeners[ i ]( element, selection );
106
107 				if ( listenerItems )
108 				{
109 					for ( var itemName in listenerItems )
110 					{
111 						var item = this.editor.getMenuItem( itemName );
112
113 						if ( item )
114 						{
115 							item.state = listenerItems[ itemName ];
116 							menu.add( item );
117 						}
118 					}
119 				}
120 			}
121
122 			menu.show( offsetParent, corner || ( editor.lang.dir == 'rtl' ? 2 : 1 ), offsetX, offsetY );
123 		}
124 	},
125
126 	proto :
127 	{
128 		addTarget : function( element )
129 		{
130 			element.on( 'contextmenu', function( event )
131 				{
132 					var domEvent = event.data;
133
134 					// Cancel the browser context menu.
135 					domEvent.preventDefault();
136
137 					var offsetParent = domEvent.getTarget().getDocument().getDocumentElement(),
138 						offsetX = domEvent.$.clientX,
139 						offsetY = domEvent.$.clientY;
140
141 					CKEDITOR.tools.setTimeout( function()
142 						{
143 							this._.onMenu( offsetParent, null, offsetX, offsetY );
144 						},
145 						0, this );
146 				},
147 				this );
148 		},
149
150 		addListener : function( listenerFn )
151 		{
152 			this._.listeners.push( listenerFn );
153 		},
154
155 		show : function( offsetParent, corner, offsetX, offsetY )
156 		{
157 			this.editor.focus();
158 			this._.onMenu( offsetParent || CKEDITOR.document.getDocumentElement(), corner, offsetX || 0, offsetY || 0 );
159 		}
160 	}
161 });
162
163 // Fix the "contextmenu" event for DOM elements.
164 // We may do this if we identify browsers that don't support the context meny
165 // event on element directly. Leaving here for reference.
166 //if ( <specific browsers> )
167 //{
168 //	CKEDITOR.dom.element.prototype.on = CKEDITOR.tools.override( CKEDITOR.dom.element.prototype.on, function( originalOn )
169 //		{
170 //			return function( eventName )
171 //				{
172 //					if ( eventName != 'contextmenu' )
173 //						return originalOn.apply( this, arguments );
174 //
175 //					// TODO : Implement the fix.
176 //				};
177 //		});
178 //}
179