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( 'floatpanel',
  7 {
  8 	requires : [ 'panel' ]
  9 });
 10
 11 (function()
 12 {
 13 	var panels = {};
 14
 15 	function getPanel( editor, doc, parentElement, definition, level )
 16 	{
 17 		// Generates the panel key: docId-eleId-CSSs
 18 		var key =
 19 			doc.getUniqueId() +
 20 			'-' + parentElement.getUniqueId() +
 21 			'-' + editor.skinName +
 22 			( ( definition.css && ( '-' + definition.css ) ) || '' ) +
 23 			( ( level && ( '-' + level ) ) || '' );
 24
 25 		var panel = panels[ key ];
 26
 27 		if ( !panel )
 28 		{
 29 			panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition );
 30 			panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.renderHtml( editor ), doc ) );
 31
 32 			panel.element.setStyles(
 33 				{
 34 					display : 'none',
 35 					position : 'absolute'
 36 				});
 37 		}
 38
 39 		return panel;
 40 	}
 41
 42 	CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass(
 43 	{
 44 		$ : function( editor, parentElement, definition, level )
 45 		{
 46 			definition.forceIFrame = true;
 47
 48 			var doc = parentElement.getDocument(),
 49 				panel = getPanel( editor, doc, parentElement, definition, level || 0 ),
 50 				element = panel.element,
 51 				iframe = element.getFirst().getFirst();
 52
 53 			this.element = element;
 54
 55 			this._ =
 56 			{
 57 				// The panel that will be floating.
 58 				panel : panel,
 59 				parentElement : parentElement,
 60 				definition : definition,
 61 				document : doc,
 62 				iframe : iframe,
 63 				children : []
 64 			}
 65 		},
 66
 67 		proto :
 68 		{
 69 			addBlock : function( name, block )
 70 			{
 71 				return this._.panel.addBlock( name, block );
 72 			},
 73
 74 			addListBlock : function( name, multiSelect )
 75 			{
 76 				return this._.panel.addListBlock( name, multiSelect );
 77 			},
 78
 79 			getBlock : function( name )
 80 			{
 81 				return this._.panel.getBlock( name );
 82 			},
 83
 84 			showBlock : function( name, offsetParent, corner, offsetX, offsetY )
 85 			{
 86 				var panel = this._.panel,
 87 					block = panel.showBlock( name );
 88
 89 				var element = this.element,
 90 					iframe = this._.iframe,
 91 					position = offsetParent.getDocumentPosition( element.getDocument() );
 92
 93 				var left	= position.x + ( offsetX || 0 ),
 94 					top		= position.y + ( offsetY || 0 );
 95
 96 				if ( corner == 2 || corner == 3 )
 97 					left += offsetParent.$.offsetWidth - 1;
 98
 99 				if ( corner == 3 || corner == 4 )
100 					top += offsetParent.$.offsetHeight - 1;
101
102 				element.setStyles(
103 					{
104 						left	: left + 'px',
105 						top		: top + 'px',
106 						display	: ''
107 					});
108
109 				if ( block.autoSize )
110 				{
111 					function setHeight()
112 					{
113 						element.getFirst().setStyle( 'height', block.element.$.scrollHeight + 'px' );
114 					}
115
116 					if ( !CKEDITOR.env.gecko || panel.isLoaded )
117 						setHeight();
118 					else
119 						panel.onLoad = setHeight;
120 				}
121 				else
122 					element.getFirst().removeStyle( 'height' );
123
124 				// Configure the IFrame blur event. Do that only once.
125 				if ( !this._.blurSet )
126 				{
127 					// Non IE prefer the event into a window object.
128 					var focused = CKEDITOR.env.ie ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow );
129
130 					focused.on( 'blur', function()
131 						{
132 							if ( !this._.activeChild )
133 								this.hide();
134 						},
135 						this );
136
137 					focused.on( 'focus', function()
138 						{
139 							this._.focused = true;
140 							this.hideChild();
141 						},
142 						this );
143
144 					this._.blurSet = 1;
145 				}
146
147 				// Set the IFrame focus, so the blur event gets fired.
148 				setTimeout( function()
149 					{
150 						iframe.$.contentWindow.focus();
151 					}, 0);
152
153 				panel.onEscape = CKEDITOR.tools.bind( function()
154 					{
155 						this.onEscape && this.onEscape();
156 					},
157 					this );
158
159 				if ( this.onShow )
160 					this.onShow.call( this );
161 			},
162
163 			hide : function()
164 			{
165 				if ( !this.onHide || this.onHide.call( this ) !== true )
166 				{
167 					this.hideChild();
168 					this.element.setStyle( 'display', 'none' );
169 				}
170 			},
171
172 			showAsChild : function( panel, blockName, offsetParent, corner, offsetX, offsetY )
173 			{
174 				this.hideChild();
175
176 				panel.onHide = CKEDITOR.tools.bind( function()
177 					{
178 						// Use a timeout, so we give time for this menu to get
179 						// potentially focused.
180 						CKEDITOR.tools.setTimeout( function()
181 							{
182 								if ( !this._.focused )
183 									this.hide();
184 							},
185 							0, this );
186 					},
187 					this );
188
189 				this._.activeChild = panel;
190 				this._.focused = false;
191
192 				panel.showBlock( blockName, offsetParent, corner, offsetX, offsetY );
193 			},
194
195 			hideChild : function()
196 			{
197 				var activeChild = this._.activeChild;
198
199 				if ( activeChild )
200 				{
201 					delete activeChild.onHide;
202 					delete this._.activeChild;
203 					activeChild.hide();
204 				}
205 			}
206 		}
207 	});
208 })();
209