Skip to content

Commit a96e36a

Browse files
committed
feat(popover): change template in popover to a page similar to modal
add ability to pass event in the transition, so on present of the popover, clean up the positioning references #5420
1 parent 53fd3c3 commit a96e36a

File tree

9 files changed

+133
-114
lines changed

9 files changed

+133
-114
lines changed

src/components/nav/nav-controller.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,8 @@ export class NavController extends Ion {
11571157
duration: opts.duration,
11581158
easing: opts.easing,
11591159
renderDelay: opts.transitionDelay || this._trnsDelay,
1160-
isRTL: this.config.platform.isRTL()
1160+
isRTL: this.config.platform.isRTL(),
1161+
ev: opts.ev,
11611162
};
11621163

11631164
let transAnimation = Transition.createTransition(enteringView,
@@ -1779,6 +1780,7 @@ export interface NavOptions {
17791780
postLoad?: Function;
17801781
progressAnimation?: boolean;
17811782
climbNav?: boolean;
1783+
ev?: any;
17821784
}
17831785

17841786
const STATE_ACTIVE = 'active';

src/components/popover/popover.ios.scss

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// iOS Popover
55
// --------------------------------------------------
66

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

1514

1615
.popover-wrapper {
17-
padding: $popover-ios-padding;
18-
1916
min-width: $popover-ios-min-width;
2017
max-width: $popover-ios-max-width;
2118

@@ -34,23 +31,24 @@ $popover-ios-background: #f3f3f3 !default;
3431
position: absolute;
3532
display: block;
3633
top: -20px;
37-
width: 30px;
38-
height: 19px;
34+
width: 20px;
35+
height: 10px;
3936
overflow: hidden;
4037

4138
&:after {
4239
position: absolute;
4340

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

46-
top: 12px;
47-
left: 5px;
48-
width: 20px;
49-
height: 20px;
43+
top: 3px;
44+
left: 3px;
45+
width: 14px;
46+
height: 14px;
47+
5048
background-color: $popover-ios-background;
5149
border-radius: 3px;
5250
content: '';
53-
transform: rotate(-45deg);
51+
transform: rotate(45deg);
5452
}
5553
}
5654

src/components/popover/popover.md.scss

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// Material Design Popover
55
// --------------------------------------------------
66

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

1514

1615
.popover-wrapper {
17-
padding: $popover-md-padding;
18-
1916
min-width: $popover-md-min-width;
2017
max-width: $popover-md-max-width;
2118

@@ -25,11 +22,3 @@ $popover-md-background: #fafafa !default;
2522
color: $popover-md-text-color;
2623
background: $popover-md-background;
2724
}
28-
29-
30-
// Material Design Popover Template
31-
// -----------------------------------------
32-
33-
.popover-template {
34-
35-
}

src/components/popover/popover.scss

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// Popover
44
// --------------------------------------------------
55

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

99

1010
ion-popover {
@@ -29,10 +29,20 @@ ion-popover {
2929

3030
flex-direction: column;
3131

32-
min-width: $popover-min-width;
33-
max-height: $popover-max-height;
32+
width: $popover-width;
33+
height: $popover-height;
34+
35+
min-width: $popover-width;
36+
max-height: $popover-height;
37+
38+
overflow: hidden;
3439

3540
opacity: 0;
41+
42+
ion-page {
43+
display: flex;
44+
overflow: auto;
45+
}
3646
}
3747

3848

src/components/popover/popover.ts

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import {Component, Renderer, ElementRef, HostListener, ViewEncapsulation} from '@angular/core';
1+
import {Component, ViewChild, ViewContainerRef, DynamicComponentLoader} from '@angular/core';
2+
import {Renderer, ElementRef} from '@angular/core';
23

34
import {Animation} from '../../animations/animation';
45
import {Transition, TransitionOptions} from '../../transitions/transition';
56
import {Config} from '../../config/config';
67
import {NavParams} from '../nav/nav-params';
8+
import {Platform} from '../../platform/platform'
79
import {isPresent, isUndefined, isDefined} from '../../util/util';
810
import {ViewController} from '../nav/view-controller';
911

10-
const POPOVER_BODY_PADDING = 6;
12+
const POPOVER_BODY_PADDING = 2;
1113

1214
/**
1315
* @name Popover
@@ -16,14 +18,15 @@ const POPOVER_BODY_PADDING = 6;
1618
*/
1719
export class Popover extends ViewController {
1820

19-
constructor(opts: PopoverOptions = {}) {
21+
constructor(componentType, data: any = {}, opts: PopoverOptions = {}) {
2022
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
2123
opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? !!opts.enableBackdropDismiss : true;
2224

23-
super(PopoverCmp, opts);
25+
data.componentType = componentType;
26+
data.opts = opts;
27+
super(PopoverCmp, data);
2428
this.viewType = 'popover';
2529
this.isOverlay = true;
26-
this.usePortal = false;
2730

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

5962
}
@@ -64,30 +67,29 @@ export class Popover extends ViewController {
6467
@Component({
6568
selector: 'ion-popover',
6669
template:
67-
'<div disable-activated class="backdrop" (click)="bdClick()" [class.hide-backdrop]="!d.showBackdrop" role="presentation"></div>' +
70+
'<div disable-activated class="backdrop" (click)="bdClick()" [class.hide-backdrop]="!d.showBackdrop"></div>' +
6871
'<div class="popover-arrow"></div>' +
6972
'<div class="popover-wrapper">' +
70-
'<div *ngIf="d.template" [innerHTML]="d.template" class="popover-template"></div>' +
71-
'</div>',
72-
host: {
73-
'role': 'dialog'
74-
},
75-
encapsulation: ViewEncapsulation.None,
73+
'<div #viewport></div>' +
74+
'</div>'
7675
})
7776
class PopoverCmp {
77+
@ViewChild('viewport', {read: ViewContainerRef}) viewport: ViewContainerRef;
78+
7879
private d: any;
7980
private id: number;
8081
private created: number;
8182
private showSpinner: boolean;
8283

83-
constructor(
84-
private _viewCtrl: ViewController,
85-
private _config: Config,
84+
constructor(private _loader: DynamicComponentLoader,
8685
private _elementRef: ElementRef,
8786
private _renderer: Renderer,
88-
params: NavParams
87+
private _config: Config,
88+
private _navParams: NavParams,
89+
private _viewCtrl: ViewController,
90+
private _platform: Platform
8991
) {
90-
this.d = params.data;
92+
this.d = _navParams.data.opts;
9193
this.created = Date.now();
9294

9395
if (this.d.cssClass) {
@@ -97,9 +99,18 @@ class PopoverCmp {
9799
this.id = (++popoverIds);
98100
}
99101

102+
onPageWillEnter() {
103+
this._loader.loadNextToLocation(this._navParams.data.componentType, this.viewport).then(componentRef => {
104+
this._viewCtrl.setInstance(componentRef.instance);
105+
106+
// manually fire onPageWillEnter() since ModalCmp's onPageWillEnter already happened
107+
this._viewCtrl.willEnter();
108+
});
109+
}
110+
100111
ngOnInit() {
101-
if (this.d.element && this.d.event) {
102-
this.positionView(this.d.element, this.d.event);
112+
if (this.d.event) {
113+
this.positionView(this.d.event);
103114
}
104115
}
105116

@@ -110,71 +121,64 @@ class PopoverCmp {
110121
}
111122
}
112123

113-
positionView(targetEle, ev) {
114-
let popoverEle = this._elementRef.nativeElement;
115-
let popoverWrapperEle = popoverEle.querySelector('.popover-wrapper');
124+
positionView(ev) {
125+
let nativeEle = this._elementRef.nativeElement;
116126

117-
// Popover width and height
118-
let popoverWidth = popoverWrapperEle.offsetWidth;
119-
let popoverHeight = popoverWrapperEle.offsetHeight;
127+
// Popover wrapper width and height
128+
let popoverEle = nativeEle.querySelector('.popover-wrapper');
129+
let popoverDim = popoverEle.getBoundingClientRect();
130+
let popoverWidth = popoverDim.width;
131+
let popoverHeight = popoverDim.height;
120132

121133
// Window body width and height
122-
let bodyWidth = window.innerWidth;
123-
let bodyHeight = window.innerHeight;
124-
125-
// Clicked element width and height
126-
targetEle = targetEle._elementRef.nativeElement;
127-
let targetWidth = targetEle.offsetWidth;
128-
let targetHeight = targetEle.offsetHeight;
134+
let bodyWidth = this._platform.width();
135+
let bodyHeight = this._platform.height();
129136

130-
// console.log("Popover Wrapper Element", popoverWrapperEle);
131-
// console.log("Popover Wrapper Width & Height", popoverWidth, popoverHeight);
132-
// console.log("Body Width & Height", bodyWidth, bodyHeight);
133-
// console.log("Target", targetEle);
134-
// console.log("Target Width & Height", targetWidth, targetHeight);
135-
136-
let popoverCSS = {
137-
top: ev.clientY + targetHeight - (popoverHeight / 2),
138-
left: ev.clientX - popoverWidth / 2
139-
};
137+
// Target element width and height
138+
let targetDim = ev.target.getBoundingClientRect();
139+
let targetTop = targetDim.top;
140+
let targetLeft = targetDim.left;
141+
let targetWidth = targetDim.width;
142+
let targetHeight = targetDim.height;
140143

141144
// The arrow that shows above the popover on iOS
142-
var arrowEle = popoverEle.querySelector('.popover-arrow');
143-
var arrowWidth = arrowEle.offsetWidth;
144-
var arrowHeight = arrowEle.offsetHeight;
145-
146-
let arrowLeft = targetWidth + targetWidth / 2 -
147-
arrowEle.offsetWidth / 2 - popoverCSS.left;
145+
var arrowEle = nativeEle.querySelector('.popover-arrow');
146+
let arrowDim = arrowEle.getBoundingClientRect();
147+
var arrowWidth = arrowDim.width;
148+
var arrowHeight = arrowDim.height;
148149

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

155+
let popoverCSS = {
156+
top: targetTop + targetHeight + (arrowHeight - 1),
157+
left: targetLeft + (targetWidth / 2) - (popoverWidth / 2)
158+
};
159+
154160
// If the popover left is less than the padding it is off screen
155161
// to the left so adjust it, else if the width of the popover
156162
// exceeds the body width it is off screen to the right so adjust
157163
if (popoverCSS.left < POPOVER_BODY_PADDING) {
158164
popoverCSS.left = POPOVER_BODY_PADDING;
159-
arrowCSS.left = (POPOVER_BODY_PADDING * 2);
160165
} else if (popoverWidth + POPOVER_BODY_PADDING + popoverCSS.left > bodyWidth) {
161166
popoverCSS.left = bodyWidth - popoverWidth - POPOVER_BODY_PADDING;
162-
arrowCSS.left = bodyWidth - (POPOVER_BODY_PADDING * 2) - arrowWidth;
163167
}
164168

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

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

176-
this._renderer.setElementStyle(popoverWrapperEle, 'top', popoverCSS.top + 'px');
177-
this._renderer.setElementStyle(popoverWrapperEle, 'left', popoverCSS.left + 'px');
180+
this._renderer.setElementStyle(popoverEle, 'top', popoverCSS.top + 'px');
181+
this._renderer.setElementStyle(popoverEle, 'left', popoverCSS.left + 'px');
178182
}
179183

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

196200
export interface PopoverOptions {
197-
template?: string;
198-
element?: any;
199201
event?: any;
200202
cssClass?: string;
201203
showBackdrop?: boolean;
@@ -209,6 +211,8 @@ class PopoverPopIn extends Transition {
209211
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
210212
super(opts);
211213

214+
console.log(opts);
215+
212216
let ele = enteringView.pageRef().nativeElement;
213217
let backdrop = new Animation(ele.querySelector('.backdrop'));
214218
let wrapper = new Animation(ele.querySelector('.popover-wrapper'));

0 commit comments

Comments
 (0)