ckeditor5-image-upload-base64
Version:
The development environment of CKEditor 5 – the best browser-based rich text editor.
927 lines (842 loc) • 26.1 kB
JavaScript
/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/
/**
* @module ui/panel/balloon/balloonpanelview
*/
import View from '../../view';
import { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';
import isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';
import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
import global from '@ckeditor/ckeditor5-utils/src/dom/global';
import { isElement } from 'lodash-es';
import '../../../theme/components/panel/balloonpanel.css';
const toPx = toUnit( 'px' );
const defaultLimiterElement = global.document.body;
/**
* The balloon panel view class.
*
* A floating container which can
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any
* {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position
* e.g. when the web page is scrolled.
*
* The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and
* the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view
* collection.
*
* There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}
* that the balloon can use, automatically switching from one to another when the viewport space becomes
* scarce to keep the balloon visible to the user as long as it is possible. The balloon will also
* accept any custom position set provided by the user compatible with the
* {@link module:utils/dom/position~Options options}.
*
* const panel = new BalloonPanelView( locale );
* const childView = new ChildView();
* const positions = BalloonPanelView.defaultPositions;
*
* panel.render();
*
* // Add a child view to the panel's content collection.
* panel.content.add( childView );
*
* // Start pinning the panel to an element with the "target" id DOM.
* // The balloon will remain pinned until unpin() is called.
* panel.pin( {
* target: document.querySelector( '#target' ),
* positions: [
* positions.northArrowSouth,
* positions.southArrowNorth
* ]
* } );
*
* @extends module:ui/view~View
*/
export default class BalloonPanelView extends View {
/**
* @inheritDoc
*/
constructor( locale ) {
super( locale );
const bind = this.bindTemplate;
/**
* The absolute top position of the balloon panel in pixels.
*
* @observable
* @default 0
* @member {Number} #top
*/
this.set( 'top', 0 );
/**
* The absolute left position of the balloon panel in pixels.
*
* @observable
* @default 0
* @member {Number} #left
*/
this.set( 'left', 0 );
/**
* The balloon panel's current position. The position name is reflected in the CSS class set
* to the balloon, i.e. `.ck-balloon-panel_arrow_nw` for the "arrow_nw" position. The class
* controls the minor aspects of the balloon's visual appearance like the placement
* of an {@link #withArrow arrow}. To support a new position, an additional CSS must be created.
*
* Default position names correspond with
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
*
* See the {@link #attachTo} and {@link #pin} methods to learn about custom balloon positions.
*
* @observable
* @default 'arrow_nw'
* @member {'arrow_nw'|'arrow_ne'|'arrow_sw'|'arrow_se'} #position
*/
this.set( 'position', 'arrow_nw' );
/**
* Controls whether the balloon panel is visible or not.
*
* @observable
* @default false
* @member {Boolean} #isVisible
*/
this.set( 'isVisible', false );
/**
* Controls whether the balloon panel has an arrow. The presence of the arrow
* is reflected in the `ck-balloon-panel_with-arrow` CSS class.
*
* @observable
* @default true
* @member {Boolean} #withArrow
*/
this.set( 'withArrow', true );
/**
* An additional CSS class added to the {@link #element}.
*
* @observable
* @member {String} #class
*/
this.set( 'class' );
/**
* A callback that starts pinning the panel when {@link #isVisible} gets
* `true`. Used by {@link #pin}.
*
* @private
* @member {Function} #_pinWhenIsVisibleCallback
*/
/**
* A collection of the child views that creates the balloon panel contents.
*
* @readonly
* @member {module:ui/viewcollection~ViewCollection}
*/
this.content = this.createCollection();
this.setTemplate( {
tag: 'div',
attributes: {
class: [
'ck',
'ck-balloon-panel',
bind.to( 'position', value => `ck-balloon-panel_${ value }` ),
bind.if( 'isVisible', 'ck-balloon-panel_visible' ),
bind.if( 'withArrow', 'ck-balloon-panel_with-arrow' ),
bind.to( 'class' )
],
style: {
top: bind.to( 'top', toPx ),
left: bind.to( 'left', toPx )
}
},
children: this.content
} );
}
/**
* Shows the panel.
*
* See {@link #isVisible}.
*/
show() {
this.isVisible = true;
}
/**
* Hides the panel.
*
* See {@link #isVisible}.
*/
hide() {
this.isVisible = false;
}
/**
* Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a
* smart positioning heuristics that chooses from available positions to make sure the panel
* is visible to the user i.e. within the limits of the viewport.
*
* This method accepts configuration {@link module:utils/dom/position~Options options}
* to set the `target`, optional `limiter` and `positions` the balloon should choose from.
*
* const panel = new BalloonPanelView( locale );
* const positions = BalloonPanelView.defaultPositions;
*
* panel.render();
*
* // Attach the panel to an element with the "target" id DOM.
* panel.attachTo( {
* target: document.querySelector( '#target' ),
* positions: [
* positions.northArrowSouth,
* positions.southArrowNorth
* ]
* } );
*
* **Note**: Attaching the panel will also automatically {@link #show} it.
*
* **Note**: An attached panel will not follow its target when the window is scrolled or resized.
* See the {@link #pin} method for a more permanent positioning strategy.
*
* @param {module:utils/dom/position~Options} options Positioning options compatible with
* {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
*/
attachTo( options ) {
this.show();
const defaultPositions = BalloonPanelView.defaultPositions;
const positionOptions = Object.assign( {}, {
element: this.element,
positions: [
defaultPositions.southArrowNorth,
defaultPositions.southArrowNorthMiddleWest,
defaultPositions.southArrowNorthMiddleEast,
defaultPositions.southArrowNorthWest,
defaultPositions.southArrowNorthEast,
defaultPositions.northArrowSouth,
defaultPositions.northArrowSouthMiddleWest,
defaultPositions.northArrowSouthMiddleEast,
defaultPositions.northArrowSouthWest,
defaultPositions.northArrowSouthEast
],
limiter: defaultLimiterElement,
fitInViewport: true
}, options );
const optimalPosition = BalloonPanelView._getOptimalPosition( positionOptions );
// Usually browsers make some problems with super accurate values like 104.345px
// so it is better to use int values.
const left = parseInt( optimalPosition.left );
const top = parseInt( optimalPosition.top );
const position = optimalPosition.name;
Object.assign( this, { top, left, position } );
}
/**
* Works the same way as the {@link #attachTo} method except that the position of the panel is
* continuously updated when:
*
* * any ancestor of the {@link module:utils/dom/position~Options#target}
* or {@link module:utils/dom/position~Options#limiter} is scrolled,
* * the browser window gets resized or scrolled.
*
* Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}
* and is immune to the changing environment.
*
* const panel = new BalloonPanelView( locale );
* const positions = BalloonPanelView.defaultPositions;
*
* panel.render();
*
* // Pin the panel to an element with the "target" id DOM.
* panel.pin( {
* target: document.querySelector( '#target' ),
* positions: [
* positions.northArrowSouth,
* positions.southArrowNorth
* ]
* } );
*
* To leave the pinned state, use the {@link #unpin} method.
*
* **Note**: Pinning the panel will also automatically {@link #show} it.
*
* @param {module:utils/dom/position~Options} options Positioning options compatible with
* {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
*/
pin( options ) {
this.unpin();
this._pinWhenIsVisibleCallback = () => {
if ( this.isVisible ) {
this._startPinning( options );
} else {
this._stopPinning();
}
};
this._startPinning( options );
// Control the state of the listeners depending on whether the panel is visible
// or not.
// TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).
this.listenTo( this, 'change:isVisible', this._pinWhenIsVisibleCallback );
}
/**
* Stops pinning the panel, as set up by {@link #pin}.
*/
unpin() {
if ( this._pinWhenIsVisibleCallback ) {
// Deactivate listeners attached by pin().
this._stopPinning();
// Deactivate the panel pin() control logic.
// TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).
this.stopListening( this, 'change:isVisible', this._pinWhenIsVisibleCallback );
this._pinWhenIsVisibleCallback = null;
this.hide();
}
}
/**
* Starts managing the pinned state of the panel. See {@link #pin}.
*
* @private
* @param {module:utils/dom/position~Options} options Positioning options compatible with
* {@link module:utils/dom/position~getOptimalPosition}.
*/
_startPinning( options ) {
this.attachTo( options );
const targetElement = getDomElement( options.target );
const limiterElement = options.limiter ? getDomElement( options.limiter ) : defaultLimiterElement;
// Then we need to listen on scroll event of eny element in the document.
this.listenTo( global.document, 'scroll', ( evt, domEvt ) => {
const scrollTarget = domEvt.target;
// The position needs to be updated if the positioning target is within the scrolled element.
const isWithinScrollTarget = targetElement && scrollTarget.contains( targetElement );
// The position needs to be updated if the positioning limiter is within the scrolled element.
const isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains( limiterElement );
// The positioning target and/or limiter can be a Rect, object etc..
// There's no way to optimize the listener then.
if ( isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement ) {
this.attachTo( options );
}
}, { useCapture: true } );
// We need to listen on window resize event and update position.
this.listenTo( global.window, 'resize', () => {
this.attachTo( options );
} );
}
/**
* Stops managing the pinned state of the panel. See {@link #pin}.
*
* @private
*/
_stopPinning() {
this.stopListening( global.document, 'scroll' );
this.stopListening( global.window, 'resize' );
}
}
// Returns the DOM element for given object or null, if there is none,
// e.g. when the passed object is a Rect instance or so.
//
// @private
// @param {*} object
// @returns {HTMLElement|null}
function getDomElement( object ) {
if ( isElement( object ) ) {
return object;
}
if ( isRange( object ) ) {
return object.commonAncestorContainer;
}
if ( typeof object == 'function' ) {
return getDomElement( object() );
}
return null;
}
/**
* A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.
*
* +-----|---------...
* | |
* | |
* | |
* | |
* +--+ | +------...
* \ | /
* \|/
* >|-----|<---------------- horizontal offset
*
* @default 30
* @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset
*/
BalloonPanelView.arrowHorizontalOffset = 25;
/**
* A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.
*
* +-------------...
* |
* |
* | /-- vertical offset
* | V
* +--+ +-----... ---------
* \ / |
* \/ |
* -------------------------------
* ^
*
* @default 15
* @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset
*/
BalloonPanelView.arrowVerticalOffset = 10;
/**
* Function used to calculate the optimal position for the balloon.
*
* @protected
* @member {Function} module:ui/panel/balloon/balloonpanelview~BalloonPanelView._getOptimalPosition
*/
BalloonPanelView._getOptimalPosition = getOptimalPosition;
/**
* A default set of positioning functions used by the balloon panel view
* when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.
*
* The available positioning functions are as follows:
*
*
*
* **North west**
*
* * `northWestArrowSouthWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northWestArrowSouthMiddleWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northWestArrowSouth`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northWestArrowSouthMiddleEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northWestArrowSouthEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
*
*
* **North**
*
* * `northArrowSouthWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northArrowSouthMiddleWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northArrowSouth`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northArrowSouthMiddleEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northArrowSouthEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* **North east**
*
* * `northEastArrowSouthWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
*
* * `northEastArrowSouthMiddleWest`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northEastArrowSouth`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northEastArrowSouthMiddleEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
* * `northEastArrowSouthEast`
*
* +-----------------+
* | Balloon |
* +-----------------+
* V
* [ Target ]
*
*
*
* **South**
*
*
* * `southArrowNorthWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southArrowNorthMiddleWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southArrowNorth`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southArrowNorthMiddleEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southArrowNorthEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
*
*
* **South west**
*
* * `southWestArrowNorthWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southWestArrowNorthMiddleWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southWestArrowNorth`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southWestArrowNorthMiddleEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southWestArrowNorthEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
*
*
* **South east**
*
* * `southEastArrowNorthWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
* * `southEastArrowNorthMiddleWest`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southEastArrowNorth`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southEastArrowNorthMiddleEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
* * `southEastArrowNorthEast`
*
* [ Target ]
* ^
* +-----------------+
* | Balloon |
* +-----------------+
*
*
* See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.
*
* Positioning functions must be compatible with {@link module:utils/dom/position~Position}.
*
* The name that the position function returns will be reflected in the balloon panel's class that
* controls the placement of the "arrow". See {@link #position} to learn more.
*
* @member {Object} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions
*/
BalloonPanelView.defaultPositions = {
// ------- North west
northWestArrowSouthWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sw'
} ),
northWestArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_smw'
} ),
northWestArrowSouth: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left - balloonRect.width / 2,
name: 'arrow_s'
} ),
northWestArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sme'
} ),
northWestArrowSouthEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_se'
} ),
// ------- North
northArrowSouthWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sw'
} ),
northArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_smw'
} ),
northArrowSouth: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,
name: 'arrow_s'
} ),
northArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sme'
} ),
northArrowSouthEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_se'
} ),
// ------- North east
northEastArrowSouthWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.right - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sw'
} ),
northEastArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_smw'
} ),
northEastArrowSouth: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.right - balloonRect.width / 2,
name: 'arrow_s'
} ),
northEastArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_sme'
} ),
northEastArrowSouthEast: ( targetRect, balloonRect ) => ( {
top: getNorthTop( targetRect, balloonRect ),
left: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_se'
} ),
// ------- South west
southWestArrowNorthWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nw'
} ),
southWestArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nmw'
} ),
southWestArrowNorth: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left - balloonRect.width / 2,
name: 'arrow_n'
} ),
southWestArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nme'
} ),
southWestArrowNorthEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_ne'
} ),
// ------- South
southArrowNorthWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nw'
} ),
southArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nmw'
} ),
southArrowNorth: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,
name: 'arrow_n'
} ),
southArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nme'
} ),
southArrowNorthEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_ne'
} ),
// ------- South east
southEastArrowNorthWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.right - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nw'
} ),
southEastArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nmw'
} ),
southEastArrowNorth: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.right - balloonRect.width / 2,
name: 'arrow_n'
} ),
southEastArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_nme'
} ),
southEastArrowNorthEast: ( targetRect, balloonRect ) => ( {
top: getSouthTop( targetRect, balloonRect ),
left: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,
name: 'arrow_ne'
} )
};
// Returns the top coordinate for positions starting with `north*`.
//
// @private
// @param {utils/dom/rect~Rect} targetRect A rect of the target.
// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.
// @returns {Number}
function getNorthTop( targetRect, balloonRect ) {
return targetRect.top - balloonRect.height - BalloonPanelView.arrowVerticalOffset;
}
// Returns the top coordinate for positions starting with `south*`.
//
// @private
// @param {utils/dom/rect~Rect} targetRect A rect of the target.
// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.
// @returns {Number}
function getSouthTop( targetRect ) {
return targetRect.bottom + BalloonPanelView.arrowVerticalOffset;
}