Skip to content

Commit 6bd91f0

Browse files
committed
fix(popover): position MD popover on top of element clicked
fixes #6683
1 parent c897c34 commit 6bd91f0

File tree

4 files changed

+82
-23
lines changed

4 files changed

+82
-23
lines changed

demos/popover/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {App, Page, Popover, NavController, Content, NavParams} from 'ionic-angul
44

55
@Page({
66
template: `
7-
<ion-list radio-group [(ngModel)]="fontFamily" (change)="changeFontFamily()">
7+
<ion-list radio-group [(ngModel)]="fontFamily" (ionChange)="changeFontFamily()">
88
<ion-row>
99
<ion-col>
1010
<button (click)="changeFontSize('smaller')" ion-item detail-none class="text-button text-smaller">A</button>

src/components/popover/popover.ts

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {isPresent, isUndefined, isDefined} from '../../util/util';
1010
import {nativeRaf, CSS} from '../../util/dom';
1111
import {ViewController} from '../nav/view-controller';
1212

13-
const POPOVER_BODY_PADDING = 2;
13+
const POPOVER_IOS_BODY_PADDING = 2;
14+
const POPOVER_MD_BODY_PADDING = 12;
1415

1516
/**
1617
* @name Popover
@@ -240,8 +241,7 @@ class PopoverTransition extends Transition {
240241
super(opts);
241242
}
242243

243-
244-
positionView(nativeEle: HTMLElement, ev) {
244+
mdPositionView(nativeEle: HTMLElement, ev) {
245245
let originY = 'top';
246246
let originX = 'left';
247247

@@ -257,20 +257,74 @@ class PopoverTransition extends Transition {
257257
let bodyWidth = window.innerWidth;
258258
let bodyHeight = window.innerHeight;
259259

260-
let targetTop = (bodyHeight / 2) - (popoverHeight / 2);
261-
let targetLeft = bodyWidth / 2;
262-
let targetWidth = 0;
263-
let targetHeight = 0;
264-
265260
// If ev was passed, use that for target element
266-
if (ev && ev.target) {
267-
let targetDim = ev.target.getBoundingClientRect();
268-
targetTop = targetDim.top;
269-
targetLeft = targetDim.left;
270-
targetWidth = targetDim.width;
271-
targetHeight = targetDim.height;
261+
let targetDim = ev && ev.target && ev.target.getBoundingClientRect();
262+
263+
let targetTop = targetDim && targetDim.top || (bodyHeight / 2) - (popoverHeight / 2);
264+
let targetLeft = targetDim && targetDim.left || bodyWidth / 2 - (popoverWidth / 2);
265+
let targetWidth = targetDim && targetDim.width || 0;
266+
let targetHeight = targetDim && targetDim.height || 0;
267+
268+
let popoverCSS = {
269+
top: targetTop,
270+
left: targetLeft
271+
};
272+
273+
// If the popover left is less than the padding it is off screen
274+
// to the left so adjust it, else if the width of the popover
275+
// exceeds the body width it is off screen to the right so adjust
276+
if (popoverCSS.left < POPOVER_MD_BODY_PADDING) {
277+
popoverCSS.left = POPOVER_MD_BODY_PADDING;
278+
} else if (popoverWidth + POPOVER_MD_BODY_PADDING + popoverCSS.left > bodyWidth) {
279+
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_MD_BODY_PADDING;
280+
originX = 'right';
281+
}
282+
283+
// If the popover when popped down stretches past bottom of screen,
284+
// make it pop up if there's room above
285+
if (targetTop + targetHeight + popoverHeight > bodyHeight && targetTop - popoverHeight > 0) {
286+
popoverCSS.top = targetTop - popoverHeight;
287+
nativeEle.className = nativeEle.className + ' popover-bottom';
288+
originY = 'bottom';
289+
// If there isn't room for it to pop up above the target cut it off
290+
} else if (targetTop + targetHeight + popoverHeight > bodyHeight) {
291+
popoverEle.style.bottom = POPOVER_MD_BODY_PADDING + 'px';
272292
}
273293

294+
popoverEle.style.top = popoverCSS.top + 'px';
295+
popoverEle.style.left = popoverCSS.left + 'px';
296+
297+
popoverEle.style[CSS.transformOrigin] = originY + ' ' + originX;
298+
299+
// Since the transition starts before styling is done we
300+
// want to wait for the styles to apply before showing the wrapper
301+
popoverWrapperEle.style.opacity = '1';
302+
}
303+
304+
iosPositionView(nativeEle: HTMLElement, ev) {
305+
let originY = 'top';
306+
let originX = 'left';
307+
308+
let popoverWrapperEle = <HTMLElement>nativeEle.querySelector('.popover-wrapper');
309+
310+
// Popover content width and height
311+
let popoverEle = <HTMLElement>nativeEle.querySelector('.popover-content');
312+
let popoverDim = popoverEle.getBoundingClientRect();
313+
let popoverWidth = popoverDim.width;
314+
let popoverHeight = popoverDim.height;
315+
316+
// Window body width and height
317+
let bodyWidth = window.innerWidth;
318+
let bodyHeight = window.innerHeight;
319+
320+
// If ev was passed, use that for target element
321+
let targetDim = ev && ev.target && ev.target.getBoundingClientRect();
322+
323+
let targetTop = targetDim && targetDim.top || (bodyHeight / 2) - (popoverHeight / 2);
324+
let targetLeft = targetDim && targetDim.left || bodyWidth / 2;
325+
let targetWidth = targetDim && targetDim.width || 0;
326+
let targetHeight = targetDim && targetDim.height || 0;
327+
274328
// The arrow that shows above the popover on iOS
275329
var arrowEle = <HTMLElement>nativeEle.querySelector('.popover-arrow');
276330
let arrowDim = arrowEle.getBoundingClientRect();
@@ -290,10 +344,10 @@ class PopoverTransition extends Transition {
290344
// If the popover left is less than the padding it is off screen
291345
// to the left so adjust it, else if the width of the popover
292346
// exceeds the body width it is off screen to the right so adjust
293-
if (popoverCSS.left < POPOVER_BODY_PADDING) {
294-
popoverCSS.left = POPOVER_BODY_PADDING;
295-
} else if (popoverWidth + POPOVER_BODY_PADDING + popoverCSS.left > bodyWidth) {
296-
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_BODY_PADDING;
347+
if (popoverCSS.left < POPOVER_IOS_BODY_PADDING) {
348+
popoverCSS.left = POPOVER_IOS_BODY_PADDING;
349+
} else if (popoverWidth + POPOVER_IOS_BODY_PADDING + popoverCSS.left > bodyWidth) {
350+
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_IOS_BODY_PADDING;
297351
originX = 'right';
298352
}
299353

@@ -306,7 +360,7 @@ class PopoverTransition extends Transition {
306360
originY = 'bottom';
307361
// If there isn't room for it to pop up above the target cut it off
308362
} else if (targetTop + targetHeight + popoverHeight > bodyHeight) {
309-
popoverEle.style.bottom = POPOVER_BODY_PADDING + '%';
363+
popoverEle.style.bottom = POPOVER_IOS_BODY_PADDING + '%';
310364
}
311365

312366
arrowEle.style.top = arrowCSS.top + 'px';
@@ -344,7 +398,7 @@ class PopoverPopIn extends PopoverTransition {
344398

345399
play() {
346400
nativeRaf(() => {
347-
this.positionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
401+
this.iosPositionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
348402
super.play();
349403
});
350404
}
@@ -394,7 +448,7 @@ class PopoverMdPopIn extends PopoverTransition {
394448

395449
play() {
396450
nativeRaf(() => {
397-
this.positionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
451+
this.mdPositionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
398452
super.play();
399453
});
400454
}

src/components/popover/test/basic/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {App, Page, Popover, NavController, Content, NavParams, ViewController} f
44

55
@Page({
66
template: `
7-
<ion-list radio-group [(ngModel)]="fontFamily" (change)="changeFontFamily()">
7+
<ion-list radio-group [(ngModel)]="fontFamily" (ionChange)="changeFontFamily()">
88
<ion-row>
99
<ion-col>
1010
<button (click)="changeFontSize('smaller')" ion-item detail-none class="text-button text-smaller">A</button>

src/components/popover/test/basic/main.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
</ion-navbar>
2020

2121
<ion-content #popoverContent padding>
22+
<ion-list>
23+
<button ion-item (click)="presentListPopover($event)">
24+
Present List Popover
25+
</button>
26+
</ion-list>
2227

2328
<button block (click)="presentListPopover($event)" class="e2eOpenListPopover">
2429
Present List Popover

0 commit comments

Comments
 (0)