Skip to content

Commit

Permalink
fix(popover): position MD popover on top of element clicked
Browse files Browse the repository at this point in the history
fixes #6683
  • Loading branch information
brandyscarney committed May 31, 2016
1 parent c897c34 commit 6bd91f0
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 23 deletions.
2 changes: 1 addition & 1 deletion demos/popover/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {App, Page, Popover, NavController, Content, NavParams} from 'ionic-angul

@Page({
template: `
<ion-list radio-group [(ngModel)]="fontFamily" (change)="changeFontFamily()">
<ion-list radio-group [(ngModel)]="fontFamily" (ionChange)="changeFontFamily()">
<ion-row>
<ion-col>
<button (click)="changeFontSize('smaller')" ion-item detail-none class="text-button text-smaller">A</button>
Expand Down
96 changes: 75 additions & 21 deletions src/components/popover/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {isPresent, isUndefined, isDefined} from '../../util/util';
import {nativeRaf, CSS} from '../../util/dom';
import {ViewController} from '../nav/view-controller';

const POPOVER_BODY_PADDING = 2;
const POPOVER_IOS_BODY_PADDING = 2;
const POPOVER_MD_BODY_PADDING = 12;

/**
* @name Popover
Expand Down Expand Up @@ -240,8 +241,7 @@ class PopoverTransition extends Transition {
super(opts);
}


positionView(nativeEle: HTMLElement, ev) {
mdPositionView(nativeEle: HTMLElement, ev) {
let originY = 'top';
let originX = 'left';

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

let targetTop = (bodyHeight / 2) - (popoverHeight / 2);
let targetLeft = bodyWidth / 2;
let targetWidth = 0;
let targetHeight = 0;

// If ev was passed, use that for target element
if (ev && ev.target) {
let targetDim = ev.target.getBoundingClientRect();
targetTop = targetDim.top;
targetLeft = targetDim.left;
targetWidth = targetDim.width;
targetHeight = targetDim.height;
let targetDim = ev && ev.target && ev.target.getBoundingClientRect();

let targetTop = targetDim && targetDim.top || (bodyHeight / 2) - (popoverHeight / 2);
let targetLeft = targetDim && targetDim.left || bodyWidth / 2 - (popoverWidth / 2);
let targetWidth = targetDim && targetDim.width || 0;
let targetHeight = targetDim && targetDim.height || 0;

let popoverCSS = {
top: targetTop,
left: targetLeft
};

// If the popover left is less than the padding it is off screen
// to the left so adjust it, else if the width of the popover
// exceeds the body width it is off screen to the right so adjust
if (popoverCSS.left < POPOVER_MD_BODY_PADDING) {
popoverCSS.left = POPOVER_MD_BODY_PADDING;
} else if (popoverWidth + POPOVER_MD_BODY_PADDING + popoverCSS.left > bodyWidth) {
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_MD_BODY_PADDING;
originX = 'right';
}

// If the popover when popped down stretches past bottom of screen,
// make it pop up if there's room above
if (targetTop + targetHeight + popoverHeight > bodyHeight && targetTop - popoverHeight > 0) {
popoverCSS.top = targetTop - popoverHeight;
nativeEle.className = nativeEle.className + ' popover-bottom';
originY = 'bottom';
// If there isn't room for it to pop up above the target cut it off
} else if (targetTop + targetHeight + popoverHeight > bodyHeight) {
popoverEle.style.bottom = POPOVER_MD_BODY_PADDING + 'px';
}

popoverEle.style.top = popoverCSS.top + 'px';
popoverEle.style.left = popoverCSS.left + 'px';

popoverEle.style[CSS.transformOrigin] = originY + ' ' + originX;

// Since the transition starts before styling is done we
// want to wait for the styles to apply before showing the wrapper
popoverWrapperEle.style.opacity = '1';
}

iosPositionView(nativeEle: HTMLElement, ev) {
let originY = 'top';
let originX = 'left';

let popoverWrapperEle = <HTMLElement>nativeEle.querySelector('.popover-wrapper');

// Popover content width and height
let popoverEle = <HTMLElement>nativeEle.querySelector('.popover-content');
let popoverDim = popoverEle.getBoundingClientRect();
let popoverWidth = popoverDim.width;
let popoverHeight = popoverDim.height;

// Window body width and height
let bodyWidth = window.innerWidth;
let bodyHeight = window.innerHeight;

// If ev was passed, use that for target element
let targetDim = ev && ev.target && ev.target.getBoundingClientRect();

let targetTop = targetDim && targetDim.top || (bodyHeight / 2) - (popoverHeight / 2);
let targetLeft = targetDim && targetDim.left || bodyWidth / 2;
let targetWidth = targetDim && targetDim.width || 0;
let targetHeight = targetDim && targetDim.height || 0;

// The arrow that shows above the popover on iOS
var arrowEle = <HTMLElement>nativeEle.querySelector('.popover-arrow');
let arrowDim = arrowEle.getBoundingClientRect();
Expand All @@ -290,10 +344,10 @@ class PopoverTransition extends Transition {
// If the popover left is less than the padding it is off screen
// to the left so adjust it, else if the width of the popover
// exceeds the body width it is off screen to the right so adjust
if (popoverCSS.left < POPOVER_BODY_PADDING) {
popoverCSS.left = POPOVER_BODY_PADDING;
} else if (popoverWidth + POPOVER_BODY_PADDING + popoverCSS.left > bodyWidth) {
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_BODY_PADDING;
if (popoverCSS.left < POPOVER_IOS_BODY_PADDING) {
popoverCSS.left = POPOVER_IOS_BODY_PADDING;
} else if (popoverWidth + POPOVER_IOS_BODY_PADDING + popoverCSS.left > bodyWidth) {
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_IOS_BODY_PADDING;
originX = 'right';
}

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

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

play() {
nativeRaf(() => {
this.positionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
this.iosPositionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
super.play();
});
}
Expand Down Expand Up @@ -394,7 +448,7 @@ class PopoverMdPopIn extends PopoverTransition {

play() {
nativeRaf(() => {
this.positionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
this.mdPositionView(this.enteringView.pageRef().nativeElement, this.opts.ev);
super.play();
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/popover/test/basic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {App, Page, Popover, NavController, Content, NavParams, ViewController} f

@Page({
template: `
<ion-list radio-group [(ngModel)]="fontFamily" (change)="changeFontFamily()">
<ion-list radio-group [(ngModel)]="fontFamily" (ionChange)="changeFontFamily()">
<ion-row>
<ion-col>
<button (click)="changeFontSize('smaller')" ion-item detail-none class="text-button text-smaller">A</button>
Expand Down
5 changes: 5 additions & 0 deletions src/components/popover/test/basic/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
</ion-navbar>

<ion-content #popoverContent padding>
<ion-list>
<button ion-item (click)="presentListPopover($event)">
Present List Popover
</button>
</ion-list>

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

0 comments on commit 6bd91f0

Please sign in to comment.