/** * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ ( function() { var 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; var show = ( evt && evt.name == 'focus' ); // Show up the space on focus gain. if ( show ) { floatSpace.show(); } editor.fire( 'floatingSpaceLayout', { show: 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, offset; if ( config.floatSpacePreferRight ) { alignSide = 'right'; } else if ( editorRect.left > 0 && editorRect.right < viewRect.width && editorRect.width > spaceRect.width ) { alignSide = config.contentsLangDirection == 'rtl' ? 'right' : 'left'; } else { alignSide = mid - editorRect.left > editorRect.right - mid ? 'left' : 'right'; } // (#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 floatSpaceTpl = new CKEDITOR.template( '