1 /* 2 Copyright (c) 2003-2012, 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 // Make sure the base class (CKEDITOR.menu) is loaded before it (#3318). 11 onLoad : function() 12 { 13 CKEDITOR.plugins.contextMenu = CKEDITOR.tools.createClass( 14 { 15 base : CKEDITOR.menu, 16 17 $ : function( editor ) 18 { 19 this.base.call( this, editor, 20 { 21 panel: 22 { 23 className : editor.skinClass + ' cke_contextmenu', 24 attributes : 25 { 26 'aria-label' : editor.lang.contextmenu.options 27 } 28 } 29 }); 30 }, 31 32 proto : 33 { 34 addTarget : function( element, nativeContextMenuOnCtrl ) 35 { 36 // Opera doesn't support 'contextmenu' event, we have duo approaches employed here: 37 // 1. Inherit the 'button override' hack we introduced in v2 (#4530), while this require the Opera browser 38 // option 'Allow script to detect context menu/right click events' to be always turned on. 39 // 2. Considering the fact that ctrl/meta key is not been occupied 40 // for multiple range selecting (like Gecko), we use this key 41 // combination as a fallback for triggering context-menu. (#4530) 42 if ( CKEDITOR.env.opera && !( 'oncontextmenu' in document.body )) 43 { 44 var contextMenuOverrideButton; 45 element.on( 'mousedown', function( evt ) 46 { 47 evt = evt.data; 48 if ( evt.$.button != 2 ) 49 { 50 if ( evt.getKeystroke() == CKEDITOR.CTRL + 1 ) 51 element.fire( 'contextmenu', evt ); 52 return; 53 } 54 55 if ( nativeContextMenuOnCtrl 56 && ( CKEDITOR.env.mac ? evt.$.metaKey : evt.$.ctrlKey ) ) 57 return; 58 59 var target = evt.getTarget(); 60 61 if ( !contextMenuOverrideButton ) 62 { 63 var ownerDoc = target.getDocument(); 64 contextMenuOverrideButton = ownerDoc.createElement( 'input' ) ; 65 contextMenuOverrideButton.$.type = 'button' ; 66 ownerDoc.getBody().append( contextMenuOverrideButton ) ; 67 } 68 69 contextMenuOverrideButton.setAttribute( 'style', 'position:absolute;top:' + ( evt.$.clientY - 2 ) + 70 'px;left:' + ( evt.$.clientX - 2 ) + 71 'px;width:5px;height:5px;opacity:0.01' ); 72 73 } ); 74 75 element.on( 'mouseup', function ( evt ) 76 { 77 if ( contextMenuOverrideButton ) 78 { 79 contextMenuOverrideButton.remove(); 80 contextMenuOverrideButton = undefined; 81 // Simulate 'contextmenu' event. 82 element.fire( 'contextmenu', evt.data ); 83 } 84 } ); 85 } 86 87 element.on( 'contextmenu', function( event ) 88 { 89 var domEvent = event.data; 90 91 if ( nativeContextMenuOnCtrl && 92 // Safari on Windows always show 'ctrlKey' as true in 'contextmenu' event, 93 // which make this property unreliable. (#4826) 94 ( CKEDITOR.env.webkit ? holdCtrlKey : ( CKEDITOR.env.mac ? domEvent.$.metaKey : domEvent.$.ctrlKey ) ) ) 95 return; 96 97 98 // Cancel the browser context menu. 99 domEvent.preventDefault(); 100 101 var offsetParent = domEvent.getTarget().getDocument().getDocumentElement(), 102 offsetX = domEvent.$.clientX, 103 offsetY = domEvent.$.clientY; 104 105 CKEDITOR.tools.setTimeout( function() 106 { 107 this.open( offsetParent, null, offsetX, offsetY ); 108 109 // IE needs a short while to allow selection change before opening menu. (#7908) 110 }, CKEDITOR.env.ie? 200 : 0, this ); 111 }, 112 this ); 113 114 if ( CKEDITOR.env.opera ) 115 { 116 // 'contextmenu' event triggered by Windows menu key is unpreventable, 117 // cancel the key event itself. (#6534) 118 element.on( 'keypress' , function ( evt ) 119 { 120 var domEvent = evt.data; 121 122 if ( domEvent.$.keyCode === 0 ) 123 domEvent.preventDefault(); 124 }); 125 } 126 127 if ( CKEDITOR.env.webkit ) 128 { 129 var holdCtrlKey, 130 onKeyDown = function( event ) 131 { 132 holdCtrlKey = CKEDITOR.env.mac ? event.data.$.metaKey : event.data.$.ctrlKey ; 133 }, 134 resetOnKeyUp = function() 135 { 136 holdCtrlKey = 0; 137 }; 138 139 element.on( 'keydown', onKeyDown ); 140 element.on( 'keyup', resetOnKeyUp ); 141 element.on( 'contextmenu', resetOnKeyUp ); 142 } 143 }, 144 145 open : function( offsetParent, corner, offsetX, offsetY ) 146 { 147 this.editor.focus(); 148 offsetParent = offsetParent || CKEDITOR.document.getDocumentElement(); 149 this.show( offsetParent, corner, offsetX, offsetY ); 150 } 151 } 152 }); 153 }, 154 155 beforeInit : function( editor ) 156 { 157 editor.contextMenu = new CKEDITOR.plugins.contextMenu( editor ); 158 159 editor.addCommand( 'contextMenu', 160 { 161 exec : function() 162 { 163 editor.contextMenu.open( editor.document.getBody() ); 164 } 165 }); 166 } 167 }); 168 169 /** 170 * Whether to show the browser native context menu when the <em>Ctrl</em> or 171 * <em>Meta</em> (Mac) key is pressed on opening the context menu with the 172 * right mouse button click or the <em>Menu</em> key. 173 * @name CKEDITOR.config.browserContextMenuOnCtrl 174 * @since 3.0.2 175 * @type Boolean 176 * @default <code>true</code> 177 * @example 178 * config.browserContextMenuOnCtrl = false; 179 */ 180