chore(build): rename ionic directory to src and update all references in the build process.

This commit is contained in:
Josh Thomas
2016-05-19 13:20:59 -05:00
parent 8470ae04ac
commit c8f760f080
595 changed files with 73 additions and 87 deletions

View File

@ -0,0 +1,46 @@
import {Component, Input, ViewEncapsulation} from '@angular/core';
import {Config} from '../../config/config';
import {InfiniteScroll} from './infinite-scroll';
/**
* @private
*/
@Component({
selector: 'ion-infinite-scroll-content',
template:
'<div class="infinite-loading">' +
'<div class="infinite-loading-spinner" *ngIf="loadingSpinner">' +
'<ion-spinner [name]="loadingSpinner"></ion-spinner>' +
'</div>' +
'<div class="infinite-loading-text" [innerHTML]="loadingText" *ngIf="loadingText"></div>' +
'</div>',
host: {
'[attr.state]': 'inf.state'
},
encapsulation: ViewEncapsulation.None,
})
export class InfiniteScrollContent {
/**
* @input {string} An animated SVG spinner that shows while loading.
*/
@Input() loadingSpinner: string;
/**
* @input {string} Optional text to display while loading.
*/
@Input() loadingText: string;
constructor(private inf: InfiniteScroll, private _config: Config) {}
/**
* @private
*/
ngOnInit() {
if (!this.loadingSpinner) {
this.loadingSpinner = this._config.get('infiniteLoadingSpinner', this._config.get('spinner', 'ios'));
}
}
}

View File

@ -0,0 +1,57 @@
@import "../../globals.core";
// Infinite Scroll
// --------------------------------------------------
$infinite-scroll-loading-margin: 0 0 32px 0 !default;
$infinite-scroll-loading-color: #666 !default;
$infinite-scroll-loading-text-margin: 4px 32px 0 32px !default;
ion-infinite-scroll {
display: block;
width: 100%;
}
// Infinite Scroll Content
// --------------------------------------------------
ion-infinite-scroll-content {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
min-height: 84px;
text-align: center;
}
.infinite-loading {
display: none;
margin: $infinite-scroll-loading-margin;
width: 100%;
}
.infinite-loading-text {
margin: $infinite-scroll-loading-text-margin;
color: $infinite-scroll-loading-color;
}
// Infinite Scroll Content States
// --------------------------------------------------
ion-infinite-scroll-content[state=loading] .infinite-loading {
display: block;
}
ion-infinite-scroll-content[state=disabled] {
display: none;
}

View File

@ -0,0 +1,252 @@
import {Directive, Input, Output, EventEmitter, Host, NgZone, ElementRef} from '@angular/core';
import {Content} from '../content/content';
/**
* @name InfiniteScroll
* @description
* The Infinite Scroll allows you to perform an action when the user
* scrolls a specified distance from the bottom of the page.
*
* The expression assigned to the `infinite` event is called when
* the user scrolls to the specified distance. When this expression
* has finished its tasks, it should call the `complete()` method
* on the infinite scroll instance.
*
* @usage
* ```html
* <ion-content>
*
* <ion-list>
* <ion-item *ngFor="let i of items">{{i}}</ion-item>
* </ion-list>
*
* <ion-infinite-scroll (infinite)="doInfinite($event)">
* <ion-infinite-scroll-content></ion-infinite-scroll-content>
* </ion-infinite-scroll>
*
* </ion-content>
* ```
*
* ```ts
* @Page({...})
* export class NewsFeedPage {
*
* constructor() {
* this.items = [];
* for (var i = 0; i < 30; i++) {
* this.items.push( this.items.length );
* }
* }
*
* doInfinite(infiniteScroll) {
* console.log('Begin async operation');
*
* setTimeout(() => {
* for (var i = 0; i < 30; i++) {
* this.items.push( this.items.length );
* }
*
* console.log('Async operation has ended');
* infiniteScroll.complete();
* }, 500);
* }
*
* }
* ```
*
*
* ## Infinite Scroll Content
*
* By default, Ionic uses the infinite scroll spinner that looks
* best for the platform the user is on. However, you can change the
* default spinner or add text by adding properties to the
* `ion-infinite-scroll-content` component.
*
* ```html
* <ion-content>
*
* <ion-infinite-scroll (infinite)="doInfinite($event)">
* <ion-infinite-scroll-content
* loadingSpinner="bubbles"
* loadingText="Loading more data...">
* </ion-infinite-scroll-content>
* </ion-infinite-scroll>
*
* </ion-content>
* ```
*
*
* ## Further Customizing Infinite Scroll Content
*
* The `ion-infinite-scroll` component holds the infinite scroll logic.
* It requires a child component in order to display the content.
* Ionic uses `ion-infinite-scroll-content` by default. This component
* displays the infinite scroll and changes the look depending
* on the infinite scroll's state. Separating these components allows
* developers to create their own infinite scroll content components.
* You could replace our default content with custom SVG or CSS animations.
*
* @demo /docs/v2/demos/infinite-scroll/
*
*/
@Directive({
selector: 'ion-infinite-scroll'
})
export class InfiniteScroll {
private _lastCheck: number = 0;
private _highestY: number = 0;
private _scLsn: Function;
private _thr: string = '15%';
private _thrPx: number = 0;
private _thrPc: number = 0.15;
private _init: boolean = false;
state: string = STATE_ENABLED;
/**
* @input {string} The threshold distance from the bottom
* of the content to call the `infinite` output event when scrolled.
* The threshold value can be either a percent, or
* in pixels. For example, use the value of `10%` for the `infinite`
* output event to get called when the user has scrolled 10%
* from the bottom of the page. Use the value `100px` when the
* scroll is within 100 pixels from the bottom of the page.
* Default is `15%`.
*/
@Input()
get threshold(): string {
return this._thr;
}
set threshold(val: string) {
this._thr = val;
if (val.indexOf('%') > -1) {
this._thrPx = 0;
this._thrPc = (parseFloat(val) / 100);
} else {
this._thrPx = parseFloat(val);
this._thrPc = 0;
}
}
/**
* @output {event} The expression to call when the scroll reaches
* the threshold distance. From within your infinite handler,
* you must call the infinite scroll's `complete()` method when
* your async operation has completed.
*/
@Output() infinite: EventEmitter<InfiniteScroll> = new EventEmitter();
constructor(
@Host() private _content: Content,
private _zone: NgZone,
private _elementRef: ElementRef
) {
_content.addCssClass('has-infinite-scroll');
}
private _onScroll(ev) {
if (this.state === STATE_LOADING || this.state === STATE_DISABLED) {
return 1;
}
let now = Date.now();
if (this._lastCheck + 32 > now) {
// no need to check less than every XXms
return 2;
}
this._lastCheck = now;
let infiniteHeight = this._elementRef.nativeElement.scrollHeight;
if (!infiniteHeight) {
// if there is no height of this element then do nothing
return 3;
}
let d = this._content.getContentDimensions();
let reloadY = d.contentHeight;
if (this._thrPc) {
reloadY += (reloadY * this._thrPc);
} else {
reloadY += this._thrPx;
}
let distanceFromInfinite = ((d.scrollHeight - infiniteHeight) - d.scrollTop) - reloadY;
if (distanceFromInfinite < 0) {
this._zone.run(() => {
this.state = STATE_LOADING;
this.infinite.emit(this);
});
return 5;
}
return 6;
}
/**
* Call `complete()` within the `infinite` output event handler when
* your async operation has completed. For example, the `loading`
* state is while the app is performing an asynchronous operation,
* such as receiving more data from an AJAX request to add more items
* to a data list. Once the data has been received and UI updated, you
* then call this method to signify that the loading has completed.
* This method will change the infinite scroll's state from `loading`
* to `enabled`.
*/
complete() {
this.state = STATE_ENABLED;
}
/**
* Call `enable(false)` to disable the infinite scroll from actively
* trying to receive new data while scrolling. This method is useful
* when it is known that there is no more data that can be added, and
* the infinite scroll is no longer needed.
* @param {boolean} shouldEnable If the infinite scroll should be
* enabled or not. Setting to `false` will remove scroll event listeners
* and hide the display.
*/
enable(shouldEnable: boolean) {
this.state = (shouldEnable ? STATE_ENABLED : STATE_DISABLED);
this._setListeners(shouldEnable);
}
private _setListeners(shouldListen: boolean) {
if (this._init) {
if (shouldListen) {
if (!this._scLsn) {
this._zone.runOutsideAngular(() => {
this._scLsn = this._content.addScrollListener( this._onScroll.bind(this) );
});
}
} else {
this._scLsn && this._scLsn();
this._scLsn = null;
}
}
}
/**
* @private
*/
ngAfterContentInit() {
this._init = true;
this._setListeners(this.state !== STATE_DISABLED);
}
/**
* @private
*/
ngOnDestroy() {
this._setListeners(false);
}
}
const STATE_ENABLED = 'enabled';
const STATE_DISABLED = 'disabled';
const STATE_LOADING = 'loading';

View File

@ -0,0 +1,82 @@
import {ViewChild} from '@angular/core';
import {App, Page, InfiniteScroll, NavController} from '../../../../../ionic';
@Page({
templateUrl: 'main.html'
})
class E2EPage1 {
@ViewChild(InfiniteScroll) infiniteScroll: InfiniteScroll;
items = [];
enabled: boolean = true;
constructor(private nav: NavController) {
for (var i = 0; i < 30; i++) {
this.items.push( this.items.length );
}
}
doInfinite(infiniteScroll: InfiniteScroll) {
console.log('Begin async operation');
getAsyncData().then(newData => {
for (var i = 0; i < newData.length; i++) {
this.items.push( this.items.length );
}
console.log('Finished receiving data, async operation complete');
infiniteScroll.complete();
if (this.items.length > 90) {
this.enabled = false;
infiniteScroll.enable(this.enabled);
}
});
}
goToPage2() {
this.nav.push(E2EPage2);
}
toggleInfiniteScroll() {
this.enabled = !this.enabled;
this.infiniteScroll.enable(this.enabled);
}
}
@Page({
template: '<ion-content><button (click)="nav.pop()">Pop</button></ion-content>'
})
class E2EPage2 {
constructor(private nav: NavController) {}
}
@App({
template: '<ion-nav [root]="root"></ion-nav>'
})
class E2EApp {
root;
constructor() {
this.root = E2EPage1;
}
}
function getAsyncData(): Promise<any[]> {
// async return mock data
return new Promise(resolve => {
setTimeout(() => {
let data = [];
for (var i = 0; i < 30; i++) {
data.push(i);
}
resolve(data);
}, 500);
});
}

View File

@ -0,0 +1,26 @@
<ion-toolbar><ion-title>Infinite Scroll</ion-title></ion-toolbar>
<ion-content>
<p>
InfiniteScroll is enabled: {{enabled}}
</p>
<button (click)="toggleInfiniteScroll()" block>
Toggle InfiniteScroll Enabled
</button>
<ion-list>
<button ion-item (click)="goToPage2()" *ngFor="let item of items">
{{ item }}
</button>
</ion-list>
<ion-infinite-scroll (infinite)="doInfinite($event)" threshold="100px">
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more data...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>

View File

@ -0,0 +1,138 @@
import {InfiniteScroll, Content, Config} from '../../../../ionic';
export function run() {
describe('Infinite Scroll', () => {
describe('_onScroll', () => {
it('should not set loading state when does not meet threshold', () => {
setInfiniteScrollHeight(25);
content.getContentDimensions = function() {
return { scrollHeight: 1000, scrollTop: 350, contentHeight: 500 };
};
inf.threshold = '100px';
setInfiniteScrollTop(300);
var result = inf._onScroll(scrollEv());
expect(result).toEqual(6);
});
it('should set loading state when meets threshold', () => {
setInfiniteScrollHeight(25);
content.getContentDimensions = function() {
return { scrollHeight: 1000, scrollTop: 500, contentHeight: 500 };
};
inf.threshold = '100px';
setInfiniteScrollTop(300);
var result = inf._onScroll(scrollEv());
expect(result).toEqual(5);
});
it('should not run if there is not infinite element height', () => {
setInfiniteScrollTop(0);
var result = inf._onScroll(scrollEv());
expect(result).toEqual(3);
});
it('should not run again if ran less than 32ms ago', () => {
inf._lastCheck = Date.now();
var result = inf._onScroll(scrollEv());
expect(result).toEqual(2);
});
it('should not run if state is disabled', () => {
inf.state = 'disabled';
var result = inf._onScroll(scrollEv());
expect(result).toEqual(1);
});
it('should not run if state is loading', () => {
inf.state = 'loading';
var result = inf._onScroll(scrollEv());
expect(result).toEqual(1);
});
it('should not run if not enabled', () => {
inf.state = 'disabled';
var result = inf._onScroll(scrollEv());
expect(result).toEqual(1);
});
});
describe('threshold', () => {
it('should set by percent', () => {
inf.threshold = '10%';
expect(inf._thr).toEqual('10%');
expect(inf._thrPx).toEqual(0);
expect(inf._thrPc).toEqual(0.1);
});
it('should set by pixels', () => {
inf.threshold = '10';
expect(inf._thr).toEqual('10');
expect(inf._thrPx).toEqual(10);
expect(inf._thrPc).toEqual(0);
inf.threshold = '10px';
expect(inf._thr).toEqual('10px');
expect(inf._thrPx).toEqual(10);
expect(inf._thrPc).toEqual(0);
});
});
let config = new Config();
let inf: InfiniteScroll;
let content: Content;
let contentElementRef;
let infiniteElementRef;
let zone = {
run: function(cb) {cb()},
runOutsideAngular: function(cb) {cb()}
};
beforeEach(() => {
contentElementRef = mockElementRef();
content = new Content(contentElementRef, config, null, null, null);
content.scrollElement = document.createElement('scroll-content');
infiniteElementRef = mockElementRef();
inf = new InfiniteScroll(content, zone, infiniteElementRef);
});
function scrollEv() {
return {}
}
function mockElementRef() {
return {
nativeElement: {
classList: { add: function(){}, remove: function(){} },
scrollTop: 0,
hasAttribute: function(){}
}
}
}
function setInfiniteScrollTop(scrollTop) {
infiniteElementRef.nativeElement.scrollTop = scrollTop;
}
function setInfiniteScrollHeight(scrollHeight) {
infiniteElementRef.nativeElement.scrollHeight = scrollHeight;
}
function getScrollElementStyles() {
return content.scrollElement.style;
}
});
}

View File

@ -0,0 +1,49 @@
import {App, InfiniteScroll} from '../../../../../ionic';
@App({
templateUrl: 'main.html'
})
class E2EApp {
items = [];
constructor() {
for (var i = 0; i < 5; i++) {
this.items.push( this.items.length );
}
}
doInfinite(infiniteScroll: InfiniteScroll) {
console.log('Begin async operation');
getAsyncData().then(newData => {
for (var i = 0; i < newData.length; i++) {
this.items.push( this.items.length );
}
console.log('Finished receiving data, async operation complete');
infiniteScroll.complete();
if (this.items.length > 90) {
infiniteScroll.enable(false);
}
});
}
}
function getAsyncData(): Promise<number[]> {
// async return mock data
return new Promise(resolve => {
setTimeout(() => {
let data = [];
for (var i = 0; i < 30; i++) {
data.push(i);
}
resolve(data);
}, 500);
});
}

View File

@ -0,0 +1,18 @@
<ion-toolbar><ion-title>Infinite Scroll</ion-title></ion-toolbar>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of items">
{{ item }}
</ion-item>
</ion-list>
<ion-infinite-scroll (infinite)="doInfinite($event)" threshold="100px">
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more data...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>