@@ -54,51 +54,46 @@ export interface ISize {
5454
5555export interface IView extends IPosition , ISize { }
5656
57- function layout ( view : ISize , around : IView , viewport : IView , anchorPosition : AnchorPosition , anchorAlignment : AnchorAlignment ) : IPosition {
57+ export enum LayoutAnchorPosition {
58+ Before ,
59+ After
60+ }
5861
59- let chooseBiased = ( a : number , aIsGood : boolean , b : number , bIsGood : boolean ) => {
60- if ( aIsGood ) {
61- return a ;
62- }
63- if ( bIsGood ) {
64- return b ;
65- }
66- return a ;
67- } ;
62+ export interface ILayoutAnchor {
63+ offset : number ;
64+ size : number ;
65+ position : LayoutAnchorPosition ;
66+ }
6867
69- let chooseOne = ( a : number , aIsGood : boolean , b : number , bIsGood : boolean , aIsPreferred : boolean ) => {
70- if ( aIsPreferred ) {
71- return chooseBiased ( a , aIsGood , b , bIsGood ) ;
72- } else {
73- return chooseBiased ( b , bIsGood , a , aIsGood ) ;
68+ /**
69+ * Lays out a one dimensional view next to an anchor in a viewport.
70+ *
71+ * @returns The view offset within the viewport.
72+ */
73+ export function layout ( viewportSize : number , viewSize : number , anchor : ILayoutAnchor ) : number {
74+ const anchorEnd = anchor . offset + anchor . size ;
75+
76+ if ( anchor . position === LayoutAnchorPosition . Before ) {
77+ if ( viewSize <= viewportSize - anchorEnd ) {
78+ return anchorEnd ; // happy case, lay it out after the anchor
7479 }
75- } ;
76-
77- let top = ( ( ) => {
78- // Compute both options (putting the segment above and below)
79- let posAbove = around . top - view . height ;
80- let posBelow = around . top + around . height ;
81-
82- // Check for both options if they are good
83- let aboveIsGood = ( posAbove >= viewport . top && posAbove + view . height <= viewport . top + viewport . height ) ;
84- let belowIsGood = ( posBelow >= viewport . top && posBelow + view . height <= viewport . top + viewport . height ) ;
8580
86- return chooseOne ( posAbove , aboveIsGood , posBelow , belowIsGood , anchorPosition === AnchorPosition . ABOVE ) ;
87- } ) ( ) ;
88-
89- let left = ( ( ) => {
90- // Compute both options (aligning left and right)
91- let posLeft = around . left ;
92- let posRight = around . left + around . width - view . width ;
81+ if ( viewSize <= anchor . offset ) {
82+ return anchor . offset - viewSize ; // ok case, lay it out before the anchor
83+ }
9384
94- // Check for both options if they are good
95- let leftIsGood = ( posLeft >= viewport . left && posLeft + view . width <= viewport . left + viewport . width ) ;
96- let rightIsGood = ( posRight >= viewport . left && posRight + view . width <= viewport . left + viewport . width ) ;
85+ return Math . max ( viewportSize - viewSize , 0 ) ; // sad case, lay it over the anchor
86+ } else {
87+ if ( viewSize <= anchor . offset ) {
88+ return anchor . offset - viewSize ; // happy case, lay it out before the anchor
89+ }
9790
98- return chooseOne ( posLeft , leftIsGood , posRight , rightIsGood , anchorAlignment === AnchorAlignment . LEFT ) ;
99- } ) ( ) ;
91+ if ( viewSize <= viewportSize - anchorEnd ) {
92+ return anchorEnd ; // ok case, lay it out after the anchor
93+ }
10094
101- return { top : top , left : left } ;
95+ return 0 ; // sad case, lay it over the anchor
96+ }
10297}
10398
10499export class ContextView {
@@ -205,30 +200,28 @@ export class ContextView {
205200 } ;
206201 }
207202
208- let viewport = {
209- top : DOM . StandardWindow . scrollY ,
210- left : DOM . StandardWindow . scrollX ,
211- height : window . innerHeight ,
212- width : window . innerWidth
213- } ;
203+ const viewSize = this . $view . getTotalSize ( ) ;
204+ const anchorPosition = this . delegate . anchorPosition || AnchorPosition . BELOW ;
205+ const anchorAlignment = this . delegate . anchorAlignment || AnchorAlignment . LEFT ;
214206
215- // Get the view's size
216- let viewSize = this . $view . getTotalSize ( ) ;
217- let view = { width : viewSize . width , height : viewSize . height } ;
207+ const verticalAnchor : ILayoutAnchor = { offset : around . top , size : around . height , position : anchorPosition === AnchorPosition . BELOW ? LayoutAnchorPosition . Before : LayoutAnchorPosition . After } ;
218208
219- let anchorPosition = this . delegate . anchorPosition || AnchorPosition . BELOW ;
220- let anchorAlignment = this . delegate . anchorAlignment || AnchorAlignment . LEFT ;
209+ let horizontalAnchor : ILayoutAnchor ;
221210
222- let result = layout ( view , around , viewport , anchorPosition , anchorAlignment ) ;
211+ if ( anchorAlignment === AnchorAlignment . LEFT ) {
212+ horizontalAnchor = { offset : around . left , size : 0 , position : LayoutAnchorPosition . Before } ;
213+ } else {
214+ horizontalAnchor = { offset : around . left + around . width , size : 0 , position : LayoutAnchorPosition . After } ;
215+ }
223216
224- let containerPosition = DOM . getDomNodePagePosition ( this . $container . getHTMLElement ( ) ) ;
225- result . top -= containerPosition . top ;
226- result . left -= containerPosition . left ;
217+ const containerPosition = DOM . getDomNodePagePosition ( this . $container . getHTMLElement ( ) ) ;
218+ const top = layout ( window . innerHeight , viewSize . height , verticalAnchor ) - containerPosition . top ;
219+ const left = layout ( window . innerWidth , viewSize . width , horizontalAnchor ) - containerPosition . left ;
227220
228221 this . $view . removeClass ( 'top' , 'bottom' , 'left' , 'right' ) ;
229222 this . $view . addClass ( anchorPosition === AnchorPosition . BELOW ? 'bottom' : 'top' ) ;
230223 this . $view . addClass ( anchorAlignment === AnchorAlignment . LEFT ? 'left' : 'right' ) ;
231- this . $view . style ( { top : result . top + 'px' , left : result . left + 'px' , width : 'initial' } ) ;
224+ this . $view . style ( { top : ` ${ top } px` , left : ` ${ left } px` , width : 'initial' } ) ;
232225 }
233226
234227 public hide ( data ?: any ) : void {
0 commit comments