text: /**
   * Floating-Tools
   * Author: Philipp Stracker (2013)
   * Project page: http://stracker-phil.github.com/Floating-Tools/
   */
  (function() {
  
  	var floatingtools = function() {
  		this.dom = null;  // the main toolbar-object
  		this.toolbars = [];
  		this.is_visible = false;
  
  		this.hide_on_blur = true; //!TODO: Make this an configuration option
  
  		this.toolbarsize = false;
  		this.editoroffset = false;
  		this.mousepos = {x:0, y:0};
  	};
  
  
  
  
  	CKEDITOR.plugins.add( 'floating-tools', {
  		requires: 'toolbar',
  
  
  		init: function( editor ) {
  
  
  			/**
  			 * Create the UI elements required by this plugin
  			 * UI is the floating toolbar
  			 * Many parts of this function are taken from the toolbar plugin
  			 */
  			editor.on( 'uiSpace', function( event ) {
  				// Create toolbar only once...
  				event.removeListener();
  
  				editor.floatingtools = new floatingtools();
  
  				var labelId = CKEDITOR.tools.getNextId();
  
  				var output = [
  					// Did not find a nicer way to include the CSS required for the toolbar...
  					'<style>',
  					'.pos-relative {position:relative}',
  					'.cke_floatingtools{',
  						'position:absolute;',
  						'left:0;',
  						'top:-500px;',
  						'padding: 5px 0 0 6px;',
  						'border:1px solid #b1b1b1;',
  						'border-radius:3px;',
  						'box-shadow: 0 1px 10px rgba(0,0,0,0.3);',
  						'transition:opacity .1s;-o-transition:opacity .1s;-moz-transition:opacity .1s;-webkit-transition:opacity .1s;',
  					'}',
  					'</style>',
  					'<span id="', labelId, '" class="cke_voice_label">', editor.lang.toolbar.toolbars, '</span>',
  					'<span id="' + editor.ui.spaceId( 'floatingtools' ) + '" class="cke_floatingtools cke_top" role="group" aria-labelledby="', labelId, '" onmousedown="return false;">' ];
  
  				var groupStarted, pendingSeparator;
  				var toolbars = editor.floatingtools.toolbars,
  					toolbar = getFloatingToolbarConfig( editor );
  
  
  				// Build the toolbar
  				for ( var r = 0; r < toolbar.length; r++ ) {
  					var toolbarId,
  						toolbarObj = 0,
  						toolbarName,
  						row = toolbar[ r ],
  						items;
  
  					// It's better to check if the row object is really
  					// available because it's a common mistake to leave
  					// an extra comma in the toolbar definition
  					// settings, which leads on the editor not loading
  					// at all in IE. (#3983)
  					if ( !row )
  						continue;
  
  					if ( groupStarted ) {
  						output.push( '</span>' );
  						groupStarted = 0;
  						pendingSeparator = 0;
  					}
  
  					if ( row === '/' ) {
  						output.push( '<span class="cke_toolbar_break"></span>' );
  						continue;
  					}
  
  					items = row.items || row;
  
  					// Create all items defined for this toolbar.
  					for ( var i = 0; i < items.length; i++ ) {
  						var item = items[ i ],
  							canGroup;
  
  						if ( item ) {
  							if ( item.type == CKEDITOR.UI_SEPARATOR ) {
  								// Do not add the separator immediately. Just save
  								// it be included if we already have something in
  								// the toolbar and if a new item is to be added (later).
  								pendingSeparator = groupStarted && item;
  								continue;
  							}
  
  							canGroup = item.canGroup !== false;
  
  							// Initialize the toolbar first, if needed.
  							if ( !toolbarObj ) {
  								// Create the basic toolbar object.
  								toolbarId = CKEDITOR.tools.getNextId();
  								toolbarObj = { id: toolbarId, items: [] };
  								toolbarName = row.name && ( editor.lang.toolbar.toolbarGroups[ row.name ] || row.name );
  
  								// Output the toolbar opener.
  								output.push( '<span id="', toolbarId, '" class="cke_toolbar"', ( toolbarName ? ' aria-labelledby="' + toolbarId + '_label"' : '' ), ' role="toolbar">' );
  
  								// If a toolbar name is available, send the voice label.
  								toolbarName && output.push( '<span id="', toolbarId, '_label" class="cke_voice_label">', toolbarName, '</span>' );
  
  								output.push( '<span class="cke_toolbar_start"></span>' );
  
  								// Add the toolbar to the "editor.toolbox.toolbars"
  								// array.
  								var index = toolbars.push( toolbarObj ) - 1;
  
  								// Create the next/previous reference.
  								if ( index > 0 ) {
  									toolbarObj.previous = toolbars[ index - 1 ];
  									toolbarObj.previous.next = toolbarObj;
  								}
  							}
  
  							if ( canGroup ) {
  								if ( !groupStarted ) {
  									output.push( '<span class="cke_toolgroup" role="presentation">' );
  									groupStarted = 1;
  								}
  							} else if ( groupStarted ) {
  								output.push( '</span>' );
  								groupStarted = 0;
  							}
  
  							function addItem( item ) {
  								var itemObj = item.render( editor, output );
  								index = toolbarObj.items.push( itemObj ) - 1;
  
  								if ( index > 0 ) {
  									itemObj.previous = toolbarObj.items[ index - 1 ];
  									itemObj.previous.next = itemObj;
  								}
  
  								itemObj.toolbar = toolbarObj;
  
  								// No need for keyboard handlers, the toolbar is only accessibly by mouse
  								/*
  								itemObj.onkey = itemKeystroke;
  
  								// Fix for #3052:
  								// Prevent JAWS from focusing the toolbar after document load.
  								itemObj.onfocus = function() {
  									if ( !editor.toolbox.focusCommandExecuted )
  										editor.focus();
  								};
  								*/
  							}
  
  							if ( pendingSeparator ) {
  								addItem( pendingSeparator );
  								pendingSeparator = 0;
  							}
  
  							addItem( item );
  
  						}
  					}
  
  					if ( groupStarted ) {
  						output.push( '</span>' );
  						groupStarted = 0;
  						pendingSeparator = 0;
  					}
  
  					if ( toolbarObj )
  						output.push( '<span class="cke_toolbar_end"></span></span>' );
  
  				}
  
  
  				output.push( '</span>' );
  				event.data.html += output.join( '' );
  			});
  
  
  
  			/**
  			 * Do the magic: Attach eventhandlers to see if text is selected
  			 * When text is selected then show the floating toolbar, else hide it
  			 */
  			editor.on('contentDom', function( event ) {
  
  				unfocus_toolbar();
  
  				/**
  				 * Attach an eventhandler to the mouse-up event
  				 */
  				editor.document.on('mouseup', function( mouse_event ) {
  					// When user right-clicks, ctrl-clicks, etc. then do not show the toolbar
  					data = mouse_event.data.$;
  					if (data.button !== 0 || data.ctrlKey || data.altKey || data.shiftKey) return true;
  
  					// When the user clears the selection by single-clicking in the editor then this event is fired before the selection is removed
  					// So we add a short delay to give the browser a chance to remove the selection before we do anything
  					setTimeout( function() {
  						if (is_text_selected()) {
  							// Save the current mouse-position
  							set_mousepos (mouse_event.data.$);
  							// when there is text selected after mouse-up: show the toolbar
  							editor.execCommand('showFloatingTools');
  						} else {
  							// when no text is selected then hide the toolbar
  							editor.execCommand('hideFloatingTools');
  						}
  					}, 100);
  				});
  
  
  				/**
  				 * On keypress we will always hide the toolbar
  				 * The toolbar is only accessible via mouse
  				 */
  				editor.document.on('keyup', function( key_event ) {
  					editor.execCommand('hideFloatingTools');
  				});
  
  
  				/**
  				 * On blur hide the toolbar (editor looses focus)
  				 */
  				editor.on('blur', function( e ) {
  					if (editor.floatingtools.hide_on_blur) {
  						hide_toolbar();
  					}
  				});
  
  
  				/**
  				 * Attach the mouse-over event to the toolbar.
  				 * When cursor is above the toolbar then set opacity to 1
  				 */
  				toolbar = get_element();
  				toolbar.on('mouseover', function( mouse_event ) {
  					focus_toolbar();
  				});
  
  
  				/**
  				 * When the mouse moves out of the toolbar then make it transparent again
  				 */
  				toolbar.on('mouseout', function( mouse_event ) {
  					unfocus_toolbar();
  				})
  
  				editor.container.addClass('pos-relative');
  				console.log(editor.container);
  			});
  
  
  
  			/**
  			 * Display the floating toolbar
  			 */
  			editor.addCommand( 'showFloatingTools', {
  				exec : function( editor ) {
  					if (is_text_selected()) {
  						toolbar = get_element();
  						unfocus_toolbar();
  						toolbar.show();
  
  						// Get the size of the toolbar
  						size = get_toolbar_size()
  						// Get the offset of the editor
  						offset = get_editor_offset();
  						// Get the mouse position
  						pos = get_mousepos();
  
  						// Calculate the position for the toolbar
  						toolpos = calculate_position(pos, size, offset);
  
  						toolbar.setStyles({
  							'left' : toolpos.x + 'px',
  							'top' : toolpos.y + 'px'
  						});
  						editor.floatingtools.is_visible = true;
  					}
  				}
  			});
  
  
  			/**
  			 * Hide the floating toolbar
  			 */
  			editor.addCommand( 'hideFloatingTools', {
  				exec : function( editor ) {
  					hide_toolbar();
  				}
  			});
  
  
  			/**
  			 * ===== Behind the scenes. Getters, setters, calculation, etc.
  			 */
  
  
  			hide_toolbar = function() {
  				if (false != editor.floatingtools.is_visible) {
  					toolbar = get_element();
  					toolbar.hide();
  					editor.floatingtools.is_visible = false;
  				}
  			}
  
  
  			/**
  			 * Store the current mouse-position, so we can position the toolbar near the cursor
  			 */
  			set_mousepos = function(data) {
  				editor.floatingtools.mousepos = {
  					left: data.clientX,
  					top: data.clientY
  				};
  			}
  
  
  
  			/**
  			 * Store the current mouse-position, so we can position the toolbar near the cursor
  			 */
  			get_mousepos = function() {
  				return editor.floatingtools.mousepos;
  			}
  
  
  			/**
  			 * Returns the main toolbar-object (the parent of all items in the floating-toolbar)
  			 */
  			get_element = function() {
  				if (! editor.floatingtools.dom) {
  					var dom_id = editor.ui.spaceId( 'floatingtools' );
  					editor.floatingtools.dom = CKEDITOR.document.getById( dom_id );
  				}
  				return editor.floatingtools.dom;
  			}
  
  
  
  			/**
  			 * Returns the offset of the editor area (effectively the height of the top-toolbar)
  			 */
  			get_editor_offset = function() {
  				if (! editor.floatingtools.editoroffset) {
  					var editor_id = editor.ui.spaceId( 'contents' );
  					var obj = CKEDITOR.document.getById( editor_id );
  					editor.floatingtools.editoroffset = {
  						left:   obj.$.offsetLeft,
  						top:    obj.$.offsetTop,
  						width:  obj.$.offsetWidth,
  						height: obj.$.offsetHeight
  					};
  				}
  				return editor.floatingtools.editoroffset;
  			}
  
  
  			/**
  			 * Calculates the position for the toolbar
  			 */
  			calculate_position = function(pos, toolbar_size, offset) {
  				toolpos = {
  					x: pos.left + offset.left - (toolbar_size.width/2),
  					y: pos.top + offset.top - (toolbar_size.height + 20)
  				}
  
  				// make sure toolbar does not extend out of the left CKEditor border
  				if (toolpos.x < offset.left + 2) toolpos.x = offset.left + 2;
  
  				// make sure toolbar does not extend out of the right CKEditor border
  				if (pos.left + (toolbar_size.width/2) >= offset.left + offset.width-2 )
  					toolpos.x = offset.left + offset.width - toolbar_size.width - 2;
  
  				// Make sure toolbar does no go into the top toolbar area
  				if (toolpos.y < offset.top) toolpos.y = offset.top;
  
  				// make sure toolbar does not cover the mouse-cursor when text in the top line is selected
  				if (offset.top+pos.top > toolpos.y
  				&& offset.top+pos.top < toolpos.y+toolbar_size.height)
  					toolpos.y = offset.top + pos.top + 24; // display toolbar below the cursor
  
  				return toolpos;
  			}
  
  
  			/**
  			 * Returns the size of the floating toolbar
  			 */
  			get_toolbar_size = function() {
  				if (! editor.floatingtools.toolbarsize) {
  					var obj = get_element();
  					editor.floatingtools.toolbarsize = {
  						width: obj.$.offsetWidth,
  						height: obj.$.offsetHeight
  					};
  				}
  				return editor.floatingtools.toolbarsize;
  			}
  
  
  			/**
  			 * Check if text is selected.
  			 * Retrns true when there is at least 1 character selected in the editor
  			 */
  			is_text_selected = function () {
  				var text = editor.getSelection().getSelectedText();
  				return text != '';
  			}
  
  
  			/**
  			 * Make the toolbar opaque
  			 */
  			focus_toolbar = function() {
  				obj = get_element();
  				obj.setOpacity(1);
  			}
  
  
  			/**
  			 * Make the toolbar transparent
  			 */
  			unfocus_toolbar = function() {
  				obj = get_element();
  				obj.setOpacity(0.25);
  			},
  
  
  			/**
  			 * Get the plugin configuration.
  			 * Kidnapped from the toolbar-plugin...
  			 */
  			getFloatingToolbarConfig = function( editor ) {
  				var removeButtons = editor.config.removeButtons;
  
  				removeButtons = removeButtons && removeButtons.split( ',' );
  
  				function buildToolbarConfig() {
  					// Take the base for the new toolbar, which is basically a toolbar
  					// definition without items.
  					var toolbar = getPrivateFloatingToolbarGroups( editor );
  					return populateToolbarConfig( toolbar );
  
  				}
  
  				// Returns an object containing all toolbar groups used by ui items.
  				function getItemDefinedGroups() {
  					var groups = {},
  						itemName, item, itemToolbar, group, order;
  
  					for ( itemName in editor.ui.items ) {
  						item = editor.ui.items[ itemName ];
  						itemToolbar = item.toolbar || 'others';
  						if ( itemToolbar ) {
  							// Break the toolbar property into its parts: "group_name[,order]".
  							itemToolbar = itemToolbar.split( ',' );
  							group = itemToolbar[ 0 ];
  							order = parseInt( itemToolbar[ 1 ] || -1, 10 );
  
  							// Initialize the group, if necessary.
  							groups[ group ] || ( groups[ group ] = [] );
  
  							// Push the data used to build the toolbar later.
  							groups[ group ].push( { name: itemName, order: order} );
  						}
  					}
  
  					// Put the items in the right order.
  					for ( group in groups ) {
  						groups[ group ] = groups[ group ].sort( function( a, b ) {
  							return a.order == b.order ? 0 :
  								b.order < 0 ? -1 :
  								a.order < 0 ? 1 :
  								a.order < b.order ? -1 :
  								1;
  						});
  					}
  
  					return groups;
  				}
  
  				function fillGroup( toolbarGroup, uiItems ) {
  					if ( uiItems.length ) {
  						if ( toolbarGroup.items )
  							toolbarGroup.items.push( editor.ui.create( '-' ) );
  						else
  							toolbarGroup.items = [];
  
  						var item, name;
  						while ( ( item = uiItems.shift() ) ) {
  							name = typeof item == 'string' ? item : item.name;
  
  							// Ignore items that are configured to be removed.
  							if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) {
  								item = editor.ui.create( name );
  
  								if ( !item )
  									continue;
  
  								if ( !editor.addFeature( item ) )
  									continue;
  
  								toolbarGroup.items.push( item );
  							}
  						}
  					}
  				}
  
  				function populateToolbarConfig( config ) {
  					var toolbar = [],
  						i, group, newGroup;
  
  					for ( i = 0; i < config.length; ++i ) {
  						group = config[ i ];
  						newGroup = {};
  
  						if ( group == '/' )
  							toolbar.push( group );
  						else if ( CKEDITOR.tools.isArray( group) ) {
  							fillGroup( newGroup, CKEDITOR.tools.clone( group ) );
  							toolbar.push( newGroup );
  						}
  						else if ( group.items ) {
  							fillGroup( newGroup, CKEDITOR.tools.clone( group.items ) );
  							newGroup.name = group.name;
  							toolbar.push( newGroup);
  						}
  					}
  
  					return toolbar;
  				}
  
  				var toolbar = editor.config.floatingtools;
  
  				// If it is a string, return the relative "toolbar_name" config.
  				if ( typeof toolbar == 'string' )
  					toolbar = editor.config[ 'floatingtools_' + toolbar ];
  
  				return ( editor.toolbar = toolbar ? populateToolbarConfig( toolbar ) : buildToolbarConfig() );
  			},
  
  
  			/**
  			 * Return the default toolbar configuration.
  			 */
  			getPrivateFloatingToolbarGroups = function( editor ) {
  				return editor._.floatingToolsGroups || ( editor._.floatingToolsGroups = [
  					{ name: 'styles',    items: [ 'Font','FontSize' ]},
  					{ name: 'format',    items: [ 'Bold','Italic' ]},
  					{ name: 'paragraph', items: [ 'JustifyCenter','Outdent','Indent','NumberedList','BulletedList' ]}
  				]);
  			}
  
  		}
  
  	} );
  
  
  })();
  
  
  
  