Skip to content

Commit

Permalink
feat(popover): change template in popover to a page similar to modal
Browse files Browse the repository at this point in the history
add ability to pass event in the transition, so on present of the
popover, clean up the positioning

references #5420
  • Loading branch information
brandyscarney committed May 23, 2016
1 parent 53fd3c3 commit a96e36a
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 114 deletions.
4 changes: 3 additions & 1 deletion src/components/nav/nav-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,8 @@ export class NavController extends Ion {
duration: opts.duration,
easing: opts.easing,
renderDelay: opts.transitionDelay || this._trnsDelay,
isRTL: this.config.platform.isRTL()
isRTL: this.config.platform.isRTL(),
ev: opts.ev,
};

let transAnimation = Transition.createTransition(enteringView,
Expand Down Expand Up @@ -1779,6 +1780,7 @@ export interface NavOptions {
postLoad?: Function;
progressAnimation?: boolean;
climbNav?: boolean;
ev?: any;
}

const STATE_ACTIVE = 'active';
Expand Down
18 changes: 8 additions & 10 deletions src/components/popover/popover.ios.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// iOS Popover
// --------------------------------------------------

$popover-ios-padding: 24px 34px !default;
$popover-ios-min-width: 150px !default;
$popover-ios-max-width: 270px !default;
$popover-ios-max-height: 90% !default;
Expand All @@ -14,8 +13,6 @@ $popover-ios-background: #f3f3f3 !default;


.popover-wrapper {
padding: $popover-ios-padding;

min-width: $popover-ios-min-width;
max-width: $popover-ios-max-width;

Expand All @@ -34,23 +31,24 @@ $popover-ios-background: #f3f3f3 !default;
position: absolute;
display: block;
top: -20px;
width: 30px;
height: 19px;
width: 20px;
height: 10px;
overflow: hidden;

&:after {
position: absolute;

z-index: $z-index-overlay-wrapper;

top: 12px;
left: 5px;
width: 20px;
height: 20px;
top: 3px;
left: 3px;
width: 14px;
height: 14px;

background-color: $popover-ios-background;
border-radius: 3px;
content: '';
transform: rotate(-45deg);
transform: rotate(45deg);
}
}

Expand Down
11 changes: 0 additions & 11 deletions src/components/popover/popover.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// Material Design Popover
// --------------------------------------------------

$popover-md-padding: 24px 34px !default;
$popover-md-min-width: 150px !default;
$popover-md-max-width: 270px !default;
$popover-md-max-height: 90% !default;
Expand All @@ -14,8 +13,6 @@ $popover-md-background: #fafafa !default;


.popover-wrapper {
padding: $popover-md-padding;

min-width: $popover-md-min-width;
max-width: $popover-md-max-width;

Expand All @@ -25,11 +22,3 @@ $popover-md-background: #fafafa !default;
color: $popover-md-text-color;
background: $popover-md-background;
}


// Material Design Popover Template
// -----------------------------------------

.popover-template {

}
18 changes: 14 additions & 4 deletions src/components/popover/popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// Popover
// --------------------------------------------------

$popover-min-width: 150px !default;
$popover-max-height: 90% !default;
$popover-width: 200px !default;
$popover-height: 250px !default;


ion-popover {
Expand All @@ -29,10 +29,20 @@ ion-popover {

flex-direction: column;

min-width: $popover-min-width;
max-height: $popover-max-height;
width: $popover-width;
height: $popover-height;

min-width: $popover-width;
max-height: $popover-height;

overflow: hidden;

opacity: 0;

ion-page {
display: flex;
overflow: auto;
}
}


Expand Down
130 changes: 67 additions & 63 deletions src/components/popover/popover.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {Component, Renderer, ElementRef, HostListener, ViewEncapsulation} from '@angular/core';
import {Component, ViewChild, ViewContainerRef, DynamicComponentLoader} from '@angular/core';
import {Renderer, ElementRef} from '@angular/core';

import {Animation} from '../../animations/animation';
import {Transition, TransitionOptions} from '../../transitions/transition';
import {Config} from '../../config/config';
import {NavParams} from '../nav/nav-params';
import {Platform} from '../../platform/platform'
import {isPresent, isUndefined, isDefined} from '../../util/util';
import {ViewController} from '../nav/view-controller';

const POPOVER_BODY_PADDING = 6;
const POPOVER_BODY_PADDING = 2;

/**
* @name Popover
Expand All @@ -16,14 +18,15 @@ const POPOVER_BODY_PADDING = 6;
*/
export class Popover extends ViewController {

constructor(opts: PopoverOptions = {}) {
constructor(componentType, data: any = {}, opts: PopoverOptions = {}) {
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? !!opts.enableBackdropDismiss : true;

super(PopoverCmp, opts);
data.componentType = componentType;
data.opts = opts;
super(PopoverCmp, data);
this.viewType = 'popover';
this.isOverlay = true;
this.usePortal = false;

// by default, popovers should not fire lifecycle events of other views
// for example, when a popover enters, the current active view should
Expand All @@ -44,16 +47,16 @@ export class Popover extends ViewController {
*
* | Option | Type | Description |
* |-----------------------|------------|------------------------------------------------------------------------------------------------------------------|
* | template |`string` | The html content for the popover. |
* | cssClass |`string` | An additional class for custom styles. |
* | showBackdrop |`boolean` | Whether to show the backdrop. Default true. |
* | enableBackdropDismiss |`boolean` | Wheather the popover should be dismissed by tapping the backdrop. Default true. |
*
*
* @param {object} data Any data to pass to the popover view
* @param {object} opts Popover options
*/
static create(opts: PopoverOptions = {}) {
return new Popover(opts);
static create(componentType, data = {}, opts: PopoverOptions = {}) {
return new Popover(componentType, data, opts);
}

}
Expand All @@ -64,30 +67,29 @@ export class Popover extends ViewController {
@Component({
selector: 'ion-popover',
template:
'<div disable-activated class="backdrop" (click)="bdClick()" [class.hide-backdrop]="!d.showBackdrop" role="presentation"></div>' +
'<div disable-activated class="backdrop" (click)="bdClick()" [class.hide-backdrop]="!d.showBackdrop"></div>' +
'<div class="popover-arrow"></div>' +
'<div class="popover-wrapper">' +
'<div *ngIf="d.template" [innerHTML]="d.template" class="popover-template"></div>' +
'</div>',
host: {
'role': 'dialog'
},
encapsulation: ViewEncapsulation.None,
'<div #viewport></div>' +
'</div>'
})
class PopoverCmp {
@ViewChild('viewport', {read: ViewContainerRef}) viewport: ViewContainerRef;

private d: any;
private id: number;
private created: number;
private showSpinner: boolean;

constructor(
private _viewCtrl: ViewController,
private _config: Config,
constructor(private _loader: DynamicComponentLoader,
private _elementRef: ElementRef,
private _renderer: Renderer,
params: NavParams
private _config: Config,
private _navParams: NavParams,
private _viewCtrl: ViewController,
private _platform: Platform
) {
this.d = params.data;
this.d = _navParams.data.opts;
this.created = Date.now();

if (this.d.cssClass) {
Expand All @@ -97,9 +99,18 @@ class PopoverCmp {
this.id = (++popoverIds);
}

onPageWillEnter() {
this._loader.loadNextToLocation(this._navParams.data.componentType, this.viewport).then(componentRef => {
this._viewCtrl.setInstance(componentRef.instance);

// manually fire onPageWillEnter() since ModalCmp's onPageWillEnter already happened
this._viewCtrl.willEnter();
});
}

ngOnInit() {
if (this.d.element && this.d.event) {
this.positionView(this.d.element, this.d.event);
if (this.d.event) {
this.positionView(this.d.event);
}
}

Expand All @@ -110,71 +121,64 @@ class PopoverCmp {
}
}

positionView(targetEle, ev) {
let popoverEle = this._elementRef.nativeElement;
let popoverWrapperEle = popoverEle.querySelector('.popover-wrapper');
positionView(ev) {
let nativeEle = this._elementRef.nativeElement;

// Popover width and height
let popoverWidth = popoverWrapperEle.offsetWidth;
let popoverHeight = popoverWrapperEle.offsetHeight;
// Popover wrapper width and height
let popoverEle = nativeEle.querySelector('.popover-wrapper');
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;

// Clicked element width and height
targetEle = targetEle._elementRef.nativeElement;
let targetWidth = targetEle.offsetWidth;
let targetHeight = targetEle.offsetHeight;
let bodyWidth = this._platform.width();
let bodyHeight = this._platform.height();

// console.log("Popover Wrapper Element", popoverWrapperEle);
// console.log("Popover Wrapper Width & Height", popoverWidth, popoverHeight);
// console.log("Body Width & Height", bodyWidth, bodyHeight);
// console.log("Target", targetEle);
// console.log("Target Width & Height", targetWidth, targetHeight);

let popoverCSS = {
top: ev.clientY + targetHeight - (popoverHeight / 2),
left: ev.clientX - popoverWidth / 2
};
// Target element width and height
let targetDim = ev.target.getBoundingClientRect();
let targetTop = targetDim.top;
let targetLeft = targetDim.left;
let targetWidth = targetDim.width;
let targetHeight = targetDim.height;

// The arrow that shows above the popover on iOS
var arrowEle = popoverEle.querySelector('.popover-arrow');
var arrowWidth = arrowEle.offsetWidth;
var arrowHeight = arrowEle.offsetHeight;

let arrowLeft = targetWidth + targetWidth / 2 -
arrowEle.offsetWidth / 2 - popoverCSS.left;
var arrowEle = nativeEle.querySelector('.popover-arrow');
let arrowDim = arrowEle.getBoundingClientRect();
var arrowWidth = arrowDim.width;
var arrowHeight = arrowDim.height;

let arrowCSS = {
top: ev.clientY + targetHeight - (popoverHeight / 2) - arrowHeight,
left: ev.clientX - (arrowWidth / 2)
top: targetTop + targetHeight,
left: targetLeft + (targetWidth / 2) - (arrowWidth / 2)
}

let popoverCSS = {
top: targetTop + targetHeight + (arrowHeight - 1),
left: targetLeft + (targetWidth / 2) - (popoverWidth / 2)
};

// 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;
arrowCSS.left = (POPOVER_BODY_PADDING * 2);
} else if (popoverWidth + POPOVER_BODY_PADDING + popoverCSS.left > bodyWidth) {
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_BODY_PADDING;
arrowCSS.left = bodyWidth - (POPOVER_BODY_PADDING * 2) - arrowWidth;
}

// If the popover when popped down stretches past bottom of screen,
// make it pop up if there's room above
if (popoverCSS.top + POPOVER_BODY_PADDING + popoverHeight > bodyHeight &&
popoverCSS.top - popoverHeight > 0) {
popoverCSS.top = popoverCSS.top - targetHeight - popoverHeight;
this._renderer.setElementClass(this._elementRef.nativeElement, 'popover-bottom', true);
if (popoverCSS.top + POPOVER_BODY_PADDING + popoverHeight > bodyHeight && popoverCSS.top - popoverHeight > 0) {
arrowCSS.top = targetTop - (arrowHeight + 1);
popoverCSS.top = targetTop - popoverHeight - (arrowHeight - 1);
this._renderer.setElementClass(this._elementRef.nativeElement, 'popover-bottom', true);
}

this._renderer.setElementStyle(arrowEle, 'top', arrowCSS.top + 'px');
this._renderer.setElementStyle(arrowEle, 'left', arrowCSS.left + 'px');

this._renderer.setElementStyle(popoverWrapperEle, 'top', popoverCSS.top + 'px');
this._renderer.setElementStyle(popoverWrapperEle, 'left', popoverCSS.left + 'px');
this._renderer.setElementStyle(popoverEle, 'top', popoverCSS.top + 'px');
this._renderer.setElementStyle(popoverEle, 'left', popoverCSS.left + 'px');
}

dismiss(role): Promise<any> {
Expand All @@ -194,8 +198,6 @@ class PopoverCmp {
}

export interface PopoverOptions {
template?: string;
element?: any;
event?: any;
cssClass?: string;
showBackdrop?: boolean;
Expand All @@ -209,6 +211,8 @@ class PopoverPopIn extends Transition {
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(opts);

console.log(opts);

let ele = enteringView.pageRef().nativeElement;
let backdrop = new Animation(ele.querySelector('.backdrop'));
let wrapper = new Animation(ele.querySelector('.popover-wrapper'));
Expand Down
Loading

0 comments on commit a96e36a

Please sign in to comment.