380 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			380 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
|  | /** | |||
|  |  * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved. | |||
|  |  * For licensing, see LICENSE.md or http://ckeditor.com/license
 | |||
|  |  */ | |||
|  | 
 | |||
|  | ( function() { | |||
|  | 	var floatSpaceTpl = CKEDITOR.addTemplate( 'floatcontainer', '<div' + | |||
|  | 			' id="cke_{name}"' + | |||
|  | 			' class="cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} ' + CKEDITOR.env.cssClass + '"' + | |||
|  | 			' dir="{langDir}"' + | |||
|  | 			' title="' + ( CKEDITOR.env.gecko ? ' ' : '' ) + '"' + | |||
|  | 			' lang="{langCode}"' + | |||
|  | 			' role="application"' + | |||
|  | 			' style="{style}"' + | |||
|  | 			' aria-labelledby="cke_{name}_arialbl"' + | |||
|  | 			'>' + | |||
|  | 				'<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' + | |||
|  | 				'<div class="cke_inner">' + | |||
|  | 					'<div id="{topId}" class="cke_top" role="presentation">{content}</div>' + | |||
|  | 				'</div>' + | |||
|  | 			'</div>' ), | |||
|  | 		win = CKEDITOR.document.getWindow(), | |||
|  | 		pixelate = CKEDITOR.tools.cssLength; | |||
|  | 
 | |||
|  | 	CKEDITOR.plugins.add( 'floatingspace', { | |||
|  | 		init: function( editor ) { | |||
|  | 			// Add listener with lower priority than that in themedui creator.
 | |||
|  | 			// Thereby floatingspace will be created only if themedui wasn't used.
 | |||
|  | 			editor.on( 'loaded', function() { | |||
|  | 				attach( this ); | |||
|  | 			}, null, null, 20 ); | |||
|  | 		} | |||
|  | 	} ); | |||
|  | 
 | |||
|  | 	function scrollOffset( side ) { | |||
|  | 		var pageOffset = side == 'left' ? 'pageXOffset' : 'pageYOffset', | |||
|  | 			docScrollOffset = side == 'left' ? 'scrollLeft' : 'scrollTop'; | |||
|  | 
 | |||
|  | 		return ( pageOffset in win.$ ) ? | |||
|  | 				win.$[ pageOffset ] | |||
|  | 			: | |||
|  | 				CKEDITOR.document.$.documentElement[ docScrollOffset ]; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	function attach( editor ) { | |||
|  | 		var config = editor.config, | |||
|  | 
 | |||
|  | 			// Get the HTML for the predefined spaces.
 | |||
|  | 			topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html, | |||
|  | 
 | |||
|  | 			// Re-positioning of the space.
 | |||
|  | 			layout = ( function() { | |||
|  | 				// Mode indicates the vertical aligning mode.
 | |||
|  | 				var mode, editable, | |||
|  | 					spaceRect, editorRect, viewRect, spaceHeight, pageScrollX, | |||
|  | 
 | |||
|  | 					// Allow minor adjustments of the float space from custom configs.
 | |||
|  | 					dockedOffsetX = config.floatSpaceDockedOffsetX || 0, | |||
|  | 					dockedOffsetY = config.floatSpaceDockedOffsetY || 0, | |||
|  | 					pinnedOffsetX = config.floatSpacePinnedOffsetX || 0, | |||
|  | 					pinnedOffsetY = config.floatSpacePinnedOffsetY || 0; | |||
|  | 
 | |||
|  | 				// Update the float space position.
 | |||
|  | 				function updatePos( pos, prop, val ) { | |||
|  | 					floatSpace.setStyle( prop, pixelate( val ) ); | |||
|  | 					floatSpace.setStyle( 'position', pos ); | |||
|  | 				} | |||
|  | 
 | |||
|  | 				// Change the current mode and update float space position accordingly.
 | |||
|  | 				function changeMode( newMode ) { | |||
|  | 					var editorPos = editable.getDocumentPosition(); | |||
|  | 
 | |||
|  | 					switch ( newMode ) { | |||
|  | 						case 'top': | |||
|  | 							updatePos( 'absolute', 'top', editorPos.y - spaceHeight - dockedOffsetY ); | |||
|  | 							break; | |||
|  | 						case 'pin': | |||
|  | 							updatePos( 'fixed', 'top', pinnedOffsetY ); | |||
|  | 							break; | |||
|  | 						case 'bottom': | |||
|  | 							updatePos( 'absolute', 'top', editorPos.y + ( editorRect.height || editorRect.bottom - editorRect.top ) + dockedOffsetY ); | |||
|  | 							break; | |||
|  | 					} | |||
|  | 
 | |||
|  | 					mode = newMode; | |||
|  | 				} | |||
|  | 
 | |||
|  | 				return function( evt ) { | |||
|  | 					// #10112 Do not fail on editable-less editor.
 | |||
|  | 					if ( !( editable = editor.editable() ) ) | |||
|  | 						return; | |||
|  | 
 | |||
|  | 					// Show up the space on focus gain.
 | |||
|  | 					evt && evt.name == 'focus' && floatSpace.show(); | |||
|  | 
 | |||
|  | 					// Reset the horizontal position for below measurement.
 | |||
|  | 					floatSpace.removeStyle( 'left' ); | |||
|  | 					floatSpace.removeStyle( 'right' ); | |||
|  | 
 | |||
|  | 					// Compute the screen position from the TextRectangle object would
 | |||
|  | 					// be very simple, even though the "width"/"height" property is not
 | |||
|  | 					// available for all, it's safe to figure that out from the rest.
 | |||
|  | 
 | |||
|  | 					// http://help.dottoro.com/ljgupwlp.php
 | |||
|  | 					spaceRect = floatSpace.getClientRect(); | |||
|  | 					editorRect = editable.getClientRect(); | |||
|  | 					viewRect = win.getViewPaneSize(); | |||
|  | 					spaceHeight = spaceRect.height; | |||
|  | 					pageScrollX = scrollOffset( 'left' ); | |||
|  | 
 | |||
|  | 					// We initialize it as pin mode.
 | |||
|  | 					if ( !mode ) { | |||
|  | 						mode = 'pin'; | |||
|  | 						changeMode( 'pin' ); | |||
|  | 						// Call for a refresh to the actual layout.
 | |||
|  | 						layout( evt ); | |||
|  | 						return; | |||
|  | 					} | |||
|  | 
 | |||
|  | 					// +------------------------ Viewport -+ \
 | |||
|  | 					// |                                   |  |-> floatSpaceDockedOffsetY
 | |||
|  | 					// | ................................. | /
 | |||
|  | 					// |                                   |
 | |||
|  | 					// |   +------ Space -+                |
 | |||
|  | 					// |   |              |                |
 | |||
|  | 					// |   +--------------+                |
 | |||
|  | 					// |   +------------------ Editor -+   |
 | |||
|  | 					// |   |                           |   |
 | |||
|  | 					//
 | |||
|  | 					if ( spaceHeight + dockedOffsetY <= editorRect.top ) | |||
|  | 						changeMode( 'top' ); | |||
|  | 
 | |||
|  | 					//     +- - - - - - - - -  Editor -+
 | |||
|  | 					//     |                           |
 | |||
|  | 					// +------------------------ Viewport -+ \
 | |||
|  | 					// |   |                           |   |  |-> floatSpacePinnedOffsetY
 | |||
|  | 					// | ................................. | /
 | |||
|  | 					// |   +------ Space -+            |   |
 | |||
|  | 					// |   |              |            |   |
 | |||
|  | 					// |   +--------------+            |   |
 | |||
|  | 					// |   |                           |   |
 | |||
|  | 					// |   +---------------------------+   |
 | |||
|  | 					// +-----------------------------------+
 | |||
|  | 					//
 | |||
|  | 					else if ( spaceHeight + dockedOffsetY > viewRect.height - editorRect.bottom ) | |||
|  | 						changeMode( 'pin' ); | |||
|  | 
 | |||
|  | 					//     +- - - - - - - - -  Editor -+
 | |||
|  | 					//     |                           |
 | |||
|  | 					// +------------------------ Viewport -+ \
 | |||
|  | 					// |   |                           |   |  |-> floatSpacePinnedOffsetY
 | |||
|  | 					// | ................................. | /
 | |||
|  | 					// |   |                           |   |
 | |||
|  | 					// |   |                           |   |
 | |||
|  | 					// |   +---------------------------+   |
 | |||
|  | 					// |   +------ Space -+                |
 | |||
|  | 					// |   |              |                |
 | |||
|  | 					// |   +--------------+                |
 | |||
|  | 					//
 | |||
|  | 					else | |||
|  | 						changeMode( 'bottom' ); | |||
|  | 
 | |||
|  | 					var mid = viewRect.width / 2, | |||
|  | 						alignSide = | |||
|  | 								( editorRect.left > 0 && editorRect.right < viewRect.width && editorRect.width > spaceRect.width ) ? | |||
|  | 										( editor.config.contentsLangDirection == 'rtl' ? 'right' : 'left' ) | |||
|  | 									: | |||
|  | 										( mid - editorRect.left > editorRect.right - mid ? 'left' : 'right' ), | |||
|  | 						offset; | |||
|  | 
 | |||
|  | 					// (#9769) If viewport width is less than space width,
 | |||
|  | 					// make sure space never cross the left boundary of the viewport.
 | |||
|  | 					// In other words: top-left corner of the space is always visible.
 | |||
|  | 					if ( spaceRect.width > viewRect.width ) { | |||
|  | 						alignSide = 'left'; | |||
|  | 						offset = 0; | |||
|  | 					} | |||
|  | 					else { | |||
|  | 						if ( alignSide == 'left' ) { | |||
|  | 							// If the space rect fits into viewport, align it
 | |||
|  | 							// to the left edge of editor:
 | |||
|  | 							//
 | |||
|  | 							// +------------------------ Viewport -+
 | |||
|  | 							// |                                   |
 | |||
|  | 							// |   +------------- Space -+         |
 | |||
|  | 							// |   |                     |         |
 | |||
|  | 							// |   +---------------------+         |
 | |||
|  | 							// |   +------------------ Editor -+   |
 | |||
|  | 							// |   |                           |   |
 | |||
|  | 							//
 | |||
|  | 							if ( editorRect.left > 0 ) | |||
|  | 								offset = editorRect.left; | |||
|  | 
 | |||
|  | 							// If the left part of the editor is cut off by the left
 | |||
|  | 							// edge of the viewport, stick the space to the viewport:
 | |||
|  | 							//
 | |||
|  | 							//       +------------------------ Viewport -+
 | |||
|  | 							//       |                                   |
 | |||
|  | 							//       +---------------- Space -+          |
 | |||
|  | 							//       |                        |          |
 | |||
|  | 							//       +------------------------+          |
 | |||
|  | 							//  +----|------------- Editor -+            |
 | |||
|  | 							//  |    |                      |            |
 | |||
|  | 							//
 | |||
|  | 							else | |||
|  | 								offset = 0; | |||
|  | 						} | |||
|  | 						else { | |||
|  | 							// If the space rect fits into viewport, align it
 | |||
|  | 							// to the right edge of editor:
 | |||
|  | 							//
 | |||
|  | 							// +------------------------ Viewport -+
 | |||
|  | 							// |                                   |
 | |||
|  | 							// |         +------------- Space -+   |
 | |||
|  | 							// |         |                     |   |
 | |||
|  | 							// |         +---------------------+   |
 | |||
|  | 							// |   +------------------ Editor -+   |
 | |||
|  | 							// |   |                           |   |
 | |||
|  | 							//
 | |||
|  | 							if ( editorRect.right < viewRect.width ) | |||
|  | 								offset = viewRect.width - editorRect.right; | |||
|  | 
 | |||
|  | 							// If the right part of the editor is cut off by the right
 | |||
|  | 							// edge of the viewport, stick the space to the viewport:
 | |||
|  | 							//
 | |||
|  | 							// +------------------------ Viewport -+
 | |||
|  | 							// |                                   |
 | |||
|  | 							// |             +------------- Space -+
 | |||
|  | 							// |             |                     |
 | |||
|  | 							// |             +---------------------+
 | |||
|  | 							// |                 +-----------------|- Editor -+
 | |||
|  | 							// |                 |                 |          |
 | |||
|  | 							//
 | |||
|  | 							else | |||
|  | 								offset = 0; | |||
|  | 						} | |||
|  | 
 | |||
|  | 						// (#9769) Finally, stick the space to the opposite side of
 | |||
|  | 						// the viewport when it's cut off horizontally on the left/right
 | |||
|  | 						// side like below.
 | |||
|  | 						//
 | |||
|  | 						// This trick reveals cut off space in some edge cases and
 | |||
|  | 						// hence it improves accessibility.
 | |||
|  | 						//
 | |||
|  | 						// +------------------------ Viewport -+
 | |||
|  | 						// |                                   |
 | |||
|  | 						// |              +--------------------|-- Space -+
 | |||
|  | 						// |              |                    |          |
 | |||
|  | 						// |              +--------------------|----------+
 | |||
|  | 						// |              +------- Editor -+   |
 | |||
|  | 						// |              |                |   |
 | |||
|  | 						//
 | |||
|  | 						//				becomes:
 | |||
|  | 						//
 | |||
|  | 						// +------------------------ Viewport -+
 | |||
|  | 						// |                                   |
 | |||
|  | 						// |   +----------------------- Space -+
 | |||
|  | 						// |   |                               |
 | |||
|  | 						// |   +-------------------------------+
 | |||
|  | 						// |              +------- Editor -+   |
 | |||
|  | 						// |              |                |   |
 | |||
|  | 						//
 | |||
|  | 						if ( offset + spaceRect.width > viewRect.width ) { | |||
|  | 							alignSide = alignSide == 'left' ? 'right' : 'left'; | |||
|  | 							offset = 0; | |||
|  | 						} | |||
|  | 					} | |||
|  | 
 | |||
|  | 					// Pin mode is fixed, so don't include scroll-x.
 | |||
|  | 					// (#9903) For mode is "top" or "bottom", add opposite scroll-x for right-aligned space.
 | |||
|  | 					var scroll = mode == 'pin' ? | |||
|  | 							0 | |||
|  | 						: | |||
|  | 							alignSide == 'left' ? pageScrollX : -pageScrollX; | |||
|  | 
 | |||
|  | 					floatSpace.setStyle( alignSide, pixelate( ( mode == 'pin' ? pinnedOffsetX : dockedOffsetX ) + offset + scroll ) ); | |||
|  | 				}; | |||
|  | 			} )(); | |||
|  | 
 | |||
|  | 		if ( topHtml ) { | |||
|  | 			var floatSpace = CKEDITOR.document.getBody().append( CKEDITOR.dom.element.createFromHtml( floatSpaceTpl.output( { | |||
|  | 					content: topHtml, | |||
|  | 					id: editor.id, | |||
|  | 					langDir: editor.lang.dir, | |||
|  | 					langCode: editor.langCode, | |||
|  | 					name: editor.name, | |||
|  | 					style: 'display:none;z-index:' + ( config.baseFloatZIndex - 1 ), | |||
|  | 					topId: editor.ui.spaceId( 'top' ), | |||
|  | 					voiceLabel: editor.lang.editorPanel + ', ' + editor.name | |||
|  | 				} ) ) ), | |||
|  | 
 | |||
|  | 				// Use event buffers to reduce CPU load when tons of events are fired.
 | |||
|  | 				changeBuffer = CKEDITOR.tools.eventsBuffer( 500, layout ), | |||
|  | 				uiBuffer = CKEDITOR.tools.eventsBuffer( 100, layout ); | |||
|  | 
 | |||
|  | 			// There's no need for the floatSpace to be selectable.
 | |||
|  | 			floatSpace.unselectable(); | |||
|  | 
 | |||
|  | 			// Prevent clicking on non-buttons area of the space from blurring editor.
 | |||
|  | 			floatSpace.on( 'mousedown', function( evt ) { | |||
|  | 				evt = evt.data; | |||
|  | 				if ( !evt.getTarget().hasAscendant( 'a', 1 ) ) | |||
|  | 					evt.preventDefault(); | |||
|  | 			} ); | |||
|  | 
 | |||
|  | 			editor.on( 'focus', function( evt ) { | |||
|  | 				layout( evt ); | |||
|  | 				editor.on( 'change', changeBuffer.input ); | |||
|  | 				win.on( 'scroll', uiBuffer.input ); | |||
|  | 				win.on( 'resize', uiBuffer.input ); | |||
|  | 			} ); | |||
|  | 
 | |||
|  | 			editor.on( 'blur', function() { | |||
|  | 				floatSpace.hide(); | |||
|  | 				editor.removeListener( 'change', changeBuffer.input ); | |||
|  | 				win.removeListener( 'scroll', uiBuffer.input ); | |||
|  | 				win.removeListener( 'resize', uiBuffer.input ); | |||
|  | 			} ); | |||
|  | 
 | |||
|  | 			editor.on( 'destroy', function() { | |||
|  | 				win.removeListener( 'scroll', uiBuffer.input ); | |||
|  | 				win.removeListener( 'resize', uiBuffer.input ); | |||
|  | 				floatSpace.clearCustomData(); | |||
|  | 				floatSpace.remove(); | |||
|  | 			} ); | |||
|  | 
 | |||
|  | 			// Handle initial focus.
 | |||
|  | 			if ( editor.focusManager.hasFocus ) | |||
|  | 				floatSpace.show(); | |||
|  | 
 | |||
|  | 			// Register this UI space to the focus manager.
 | |||
|  | 			editor.focusManager.add( floatSpace, 1 ); | |||
|  | 		} | |||
|  | 	} | |||
|  | } )(); | |||
|  | 
 | |||
|  | /** | |||
|  |  * Along with {@link #floatSpaceDockedOffsetY} it defines the | |||
|  |  * amount of offset (in pixels) between float space and the editable left/right | |||
|  |  * boundaries when space element is docked at either side of the editable. | |||
|  |  * | |||
|  |  *		config.floatSpaceDockedOffsetX = 10; | |||
|  |  * | |||
|  |  * @cfg {Number} [floatSpaceDockedOffsetX=0] | |||
|  |  * @member CKEDITOR.config | |||
|  |  */ | |||
|  | 
 | |||
|  | /** | |||
|  |  * Along with {@link #floatSpaceDockedOffsetX} it defines the | |||
|  |  * amount of offset (in pixels) between float space and the editable top/bottom | |||
|  |  * boundaries when space element is docked at either side of the editable. | |||
|  |  * | |||
|  |  *		config.floatSpaceDockedOffsetY = 10; | |||
|  |  * | |||
|  |  * @cfg {Number} [floatSpaceDockedOffsetY=0] | |||
|  |  * @member CKEDITOR.config | |||
|  |  */ | |||
|  | 
 | |||
|  | /** | |||
|  |  * Along with {@link #floatSpacePinnedOffsetY} it defines the | |||
|  |  * amount of offset (in pixels) between float space and the view port boundaries | |||
|  |  * when space element is pinned. | |||
|  |  * | |||
|  |  *		config.floatSpacePinnedOffsetX = 20; | |||
|  |  * | |||
|  |  * @cfg {Number} [floatSpacePinnedOffsetX=0] | |||
|  |  * @member CKEDITOR.config | |||
|  |  */ | |||
|  | 
 | |||
|  | /** | |||
|  |  * Along with {@link #floatSpacePinnedOffsetX} it defines the | |||
|  |  * amount of offset (in pixels) between float space and the view port boundaries | |||
|  |  * when space element is pinned. | |||
|  |  * | |||
|  |  *		config.floatSpacePinnedOffsetY = 20; | |||
|  |  * | |||
|  |  * @cfg {Number} [floatSpacePinnedOffsetY=0] | |||
|  |  * @member CKEDITOR.config | |||
|  |  */ |