Skip to content

Commit

Permalink
refactor(refresher): allow refresher content customization
Browse files Browse the repository at this point in the history
Breaking Change:

## Refresher:

- `<ion-refresher>` now takes a child `<ion-refresher-content>`
component.
- Custom refresh content components can now be replaced for Ionic's
default refresher content.
- Properties `pullingIcon`, `pullingText` and `refreshingText` have
been moved to the `<ion-refresher-content>` component.
- `spinner` property has been renamed to `refreshingSpinner` and now
goes on the `<ion-refresher-content>` component.
- `refreshingIcon` property is no longer an input, but instead
`refreshingSpinner` should be used.

Was:

```
<ion-refresher (refresh)="doRefresh($event)"
pullingIcon="arrow-dropdown">
</ion-refresher>
```

Now:

```
<ion-refresher (refresh)="doRefresh($event)">
  <ion-refresher-content
pullingIcon="arrow-dropdown"></ion-refresher-content>
</ion-refresher>
```
  • Loading branch information
adamdbradley committed Feb 27, 2016
1 parent d5ebf3f commit 91df5f9
Show file tree
Hide file tree
Showing 21 changed files with 1,296 additions and 811 deletions.
31 changes: 20 additions & 11 deletions demos/refresher/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import {App, Page, IonicApp} from 'ionic-angular';
import {App, Page, Refresher} from 'ionic-angular';
import {MockProvider} from './mock-provider';


@App({
templateUrl: 'main.html'
templateUrl: 'main.html',
providers: [MockProvider]
})
class ApiDemoApp {
doRefresh(refresher) {
console.log('DOREFRESH', refresher)
items: string[];

setTimeout(() => {
refresher.complete();
})
constructor(private mockProvider: MockProvider) {
this.items = mockProvider.getData();
}

doStarting() {
console.log('DOSTARTING');
doRefresh(refresher: Refresher) {
console.log('DOREFRESH', refresher);

this.mockProvider.getAsyncData().then((newData) => {
for (var i = 0; i < newData.length; i++) {
this.items.unshift( newData[i] );
}

refresher.endRefreshing();
});
}

doPulling(amt) {
console.log('DOPULLING', amt);
doPulling(refresher: Refresher) {
console.log('DOPULLING', refresher.progress);
}
}
31 changes: 9 additions & 22 deletions demos/refresher/main.html
Original file line number Diff line number Diff line change
@@ -1,33 +1,20 @@
<ion-toolbar>
<ion-title>Refresher</ion-title>
<ion-title>Pull To Refresh</ion-title>
</ion-toolbar>


<ion-content>
<ion-refresher (starting)="doStarting()" (refresh)="doRefresh($event, refresher)" (pulling)="doPulling($event, amt)">
<ion-refresher (refresh)="doRefresh($event)" (pulling)="doPulling($event)">
<ion-refresher-content
pullingText="Pull to refresh..."
refreshingText="Refreshing...">
</ion-refresher-content>
</ion-refresher>

<ion-list>
<ion-item>Item 1</ion-item>
<ion-item>Item 2</ion-item>
<ion-item>Item 3</ion-item>
<ion-item>Item 4</ion-item>
<ion-item>Item 5</ion-item>
<ion-item>Item 6</ion-item>
<ion-item>Item 7</ion-item>
<ion-item>Item 8</ion-item>
<ion-item>Item 9</ion-item>
<ion-item>Item 10</ion-item>
<ion-item>Item 11</ion-item>
<ion-item>Item 12</ion-item>
<ion-item>Item 13</ion-item>
<ion-item>Item 14</ion-item>
<ion-item>Item 15</ion-item>
<ion-item>Item 16</ion-item>
<ion-item>Item 17</ion-item>
<ion-item>Item 18</ion-item>
<ion-item>Item 19</ion-item>
<ion-item>Item 20</ion-item>
<ion-item *ngFor="#item of items">
{{ item }}
</ion-item>
</ion-list>

</ion-content>
61 changes: 61 additions & 0 deletions demos/refresher/mock-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {Injectable} from 'angular2/core';

/**
* Mock Data Access Object
**/
@Injectable()
export class MockProvider {

getData() {
// return mock data synchronously
let data = [];
for (var i = 0; i < 3; i++) {
data.push( this._getRandomData() );
}
return data;
}

getAsyncData() {
// async receive mock data
return new Promise(resolve => {

setTimeout(() => {
resolve(this.getData());
}, 1000);

});
}

private _getRandomData() {
let i = Math.floor( Math.random() * this._data.length );
return this._data[i];
}

private _data = [
'Fast Times at Ridgemont High',
'Peggy Sue Got Married',
'Raising Arizona',
'Moonstruck',
'Fire Birds',
'Honeymoon in Vegas',
'Amos & Andrew',
'It Could Happen to You',
'Trapped in Paradise',
'Leaving Las Vegas',
'The Rock',
'Con Air',
'Face/Off',
'City of Angels',
'Gone in Sixty Seconds',
'The Family Man',
'Windtalkers',
'Matchstick Men',
'National Treasure',
'Ghost Rider',
'Grindhouse',
'Next',
'Kick-Ass',
'Drive Angry',
];

}
2 changes: 1 addition & 1 deletion ionic/components.core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"components/icon/icon",
"components/menu/menu",
"components/modal/modal",
"components/refresher/refresher",
"components/scroll/scroll",
"components/scroll/pull-to-refresh",
"components/slides/slides",
"components/spinner/spinner";

Expand Down
3 changes: 2 additions & 1 deletion ionic/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ export * from './components/overlay/overlay'
export * from './components/slides/slides'
export * from './components/radio/radio-button'
export * from './components/radio/radio-group'
export * from './components/refresher/refresher'
export * from './components/refresher/refresher-content'
export * from './components/scroll/scroll'
export * from './components/scroll/pull-to-refresh'
export * from './components/searchbar/searchbar'
export * from './components/segment/segment'
export * from './components/select/select'
Expand Down
4 changes: 4 additions & 0 deletions ionic/components/app/structure.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ $z-index-menu-backdrop: 79;
$z-index-overlay: 1000;
$z-index-click-block: 9999;

$z-index-scroll-content: 1;
$z-index-refresher: 0;

$z-index-navbar-section: 10;

$z-index-toolbar: 10;
Expand Down Expand Up @@ -129,6 +132,7 @@ ion-content {

scroll-content {
position: absolute;
z-index: $z-index-scroll-content;
top: 0;
right: 0;
bottom: 0;
Expand Down
141 changes: 81 additions & 60 deletions ionic/components/content/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ import {Component, ElementRef, Optional, NgZone} from 'angular2/core';
import {Ion} from '../ion';
import {IonicApp} from '../app/app';
import {Config} from '../../config/config';
import {raf} from '../../util/dom';
import {raf, transitionEnd} from '../../util/dom';
import {ViewController} from '../nav/view-controller';
import {Animation} from '../../animations/animation';
import {ScrollTo} from '../../animations/scroll-to';

/**
* @name Content
* @description
* The Content component provides an easy to use content area that can be configured to use Ionic's custom Scroll View, or the built in overflow scrolling of the browser.
* The Content component provides an easy to use content area with some useful
* methods to control the scrollable area.
*
* While we recommend using the custom Scroll features in Ionic in most cases, sometimes (for performance reasons) only the browser's native overflow scrolling will suffice, and so we've made it easy to toggle between the Ionic scroll implementation and overflow scrolling.
*
* You can implement pull-to-refresh with the [Refresher](../../scroll/Refresher) component.
* The content area can also implement pull-to-refresh with the
* [Refresher](../../scroll/Refresher) component.
*
* @usage
* ```html
* <ion-content id="myContent">
* <ion-content>
* Add your content here!
* </ion-content>
* ```
Expand All @@ -30,7 +30,8 @@ import {ScrollTo} from '../../animations/scroll-to';
template:
'<scroll-content>' +
'<ng-content></ng-content>' +
'</scroll-content>'
'</scroll-content>' +
'<ng-content select="ion-refresher"></ng-content>'
})
export class Content extends Ion {
private _padding: number = 0;
Expand All @@ -42,10 +43,6 @@ export class Content extends Ion {
*/
scrollElement: HTMLElement;

/**
* @param {elementRef} elementRef A reference to the component's DOM element.
* @param {config} config The config object to change content's default settings.
*/
constructor(
private _elementRef: ElementRef,
private _config: Config,
Expand Down Expand Up @@ -83,7 +80,8 @@ export class Content extends Ion {
* @private
*/
ngOnDestroy() {
this.scrollElement.removeEventListener('scroll', this._onScroll);
this.scrollElement.removeEventListener('scroll', this._onScroll.bind(this));
this.scrollElement = null;
}

/**
Expand Down Expand Up @@ -112,28 +110,70 @@ export class Content extends Ion {
* @param {Function} handler The method you want perform when scrolling
* @returns {Function} A function that removes the scroll handler.
*/
addScrollEventListener(handler) {
if (!this.scrollElement) {
return;
}
addScrollListener(handler) {
return this._addListener('scroll', handler);
}

// ensure we're not creating duplicates
this.scrollElement.removeEventListener('scroll', handler);
/**
* @private
*/
addTouchStartListener(handler) {
return this._addListener('touchstart', handler);
}

this.scrollElement.addEventListener('scroll', handler);
/**
* @private
*/
addTouchMoveListener(handler) {
return this._addListener('touchmove', handler);
}

/**
* @private
*/
addTouchEndListener(handler) {
return this._addListener('touchend', handler);
}

/**
* @private
*/
addMouseDownListener(handler) {
return this._addListener('mousedown', handler);
}

/**
* @private
*/
addMouseUpListener(handler) {
return this._addListener('mouseup', handler);
}

/**
* @private
*/
addMouseMoveListener(handler) {
return this._addListener('mousemove', handler);
}

private _addListener(type: string, handler: any): Function {
if (!this.scrollElement) { return; }

// ensure we're not creating duplicates
this.scrollElement.removeEventListener(type, handler);
this.scrollElement.addEventListener(type, handler);

return () => {
this.scrollElement.removeEventListener('scroll', handler);
this.scrollElement.removeEventListener(type, handler);
}
}


/**
* @private
* Call a method when scrolling has stopped
*
* @param {Function} callback The method you want perform when scrolling has ended
*/
onScrollEnd(callback) {
onScrollEnd(callback: Function) {
let lastScrollTop = null;
let framesUnchanged = 0;
let _scrollEle = this.scrollElement;
Expand Down Expand Up @@ -163,43 +203,8 @@ export class Content extends Ion {
setTimeout(next, 100);
}

/**
* @private
* Adds the specified touchmove handler to the content's scroll element.
*
* ```ts
* @Page({
* template: `<ion-content id="my-content"></ion-content>`
* )}
* export class MyPage{
* constructor(app: IonicApp){
* this.app = app;
* }
* // Need to wait until the component has been initialized
* ngAfterViewInit() {
* // Here 'my-content' is the ID of my ion-content
* this.content = this.app.getComponent('my-content');
* this.content.addTouchMoveListener(this.touchHandler);
* }
* touchHandler() {
* console.log("I'm touching all the magazines!!");
* }
* }
* ```
* @param {Function} handler The method you want to perform when touchmove is firing
* @returns {Function} A function that removes the touchmove handler.
*/
addTouchMoveListener(handler) {
if (!this.scrollElement) { return; }

// ensure we're not creating duplicates
this.scrollElement.removeEventListener('touchmove', handler);

this.scrollElement.addEventListener('touchmove', handler);

return () => {
this.scrollElement.removeEventListener('touchmove', handler);
}
onScrollElementTransitionEnd(callback: Function) {
transitionEnd(this.scrollElement, callback);
}

/**
Expand Down Expand Up @@ -276,6 +281,22 @@ export class Content extends Ion {
return this._scrollTo.start(0, 0, 300, 0);
}

getScrollTop(): number {
return this.getNativeElement().scrollTop;
}

addCssClass(className: string) {
this.getNativeElement().classList.add(className);
}

removeCssClass(className: string) {
this.getNativeElement().classList.remove(className);
}

setScrollElementStyle(prop: string, val: any) {
this.scrollElement.style[prop] = val;
}

/**
* @private
* Returns the content and scroll elements' dimensions.
Expand Down
Loading

0 comments on commit 91df5f9

Please sign in to comment.