mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
43 Commits
ld/datetim
...
v3.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dc08f9c1f | ||
|
|
bc7bb21f1a | ||
|
|
016b90da47 | ||
|
|
0f5c47db15 | ||
|
|
86495e111d | ||
|
|
fba6ff0638 | ||
|
|
30f69c8a16 | ||
|
|
1beef75c80 | ||
|
|
58e1d79518 | ||
|
|
0480f73f8e | ||
|
|
f39c3811c5 | ||
|
|
6f7acdbddf | ||
|
|
bcc85d9144 | ||
|
|
00fbded168 | ||
|
|
5cad96570f | ||
|
|
e3a8d27ec1 | ||
|
|
d8b65da6ac | ||
|
|
70b5b6b5e5 | ||
|
|
5094feec89 | ||
|
|
1ca7df75ed | ||
|
|
877d8211d5 | ||
|
|
a8731dfc98 | ||
|
|
7803998542 | ||
|
|
8bd2f24d06 | ||
|
|
63f728f517 | ||
|
|
61935602a1 | ||
|
|
1a4aacf8be | ||
|
|
5a5da39a1e | ||
|
|
c7645ee59d | ||
|
|
2743c63537 | ||
|
|
7a1342caa1 | ||
|
|
3564bcfe1b | ||
|
|
f149c5ee95 | ||
|
|
2791c40c29 | ||
|
|
54ac2e393f | ||
|
|
dc958c3e2c | ||
|
|
9f86e10f46 | ||
|
|
8041eedf22 | ||
|
|
ef85ba6c1f | ||
|
|
6dee17b89b | ||
|
|
c10f72b1e2 | ||
|
|
47e3c70bf3 | ||
|
|
a91a68e198 |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -19,7 +19,7 @@
|
||||
|
||||
For Ionic V1 issues - http://plnkr.co/edit/Xo1QyAUx35ny1Xf9ODHx?p=preview
|
||||
|
||||
For Ionic issues - http://plnkr.co/edit/z0DzVL?p=preview
|
||||
For Ionic issues - http://plnkr.co/edit/cpeRJs?p=preview
|
||||
-->
|
||||
|
||||
**Related code:**
|
||||
|
||||
98
CHANGELOG.md
98
CHANGELOG.md
@@ -1,3 +1,101 @@
|
||||
<a name="3.4.2"></a>
|
||||
## [3.4.2](https://github.com/ionic-team/ionic/compare/v3.4.1...v3.4.2) (2017-06-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **rtl:** use multi direction in order to override the default ltr ([70b5b6](https://github.com/ionic-team/ionic/commit/70b5b6))
|
||||
|
||||
|
||||
|
||||
<a name="3.4.1"></a>
|
||||
## [3.4.1](https://github.com/ionic-team/ionic/compare/v3.4.0...v3.4.1) (2017-06-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **themes:** change default app-direction ([1ca7df](https://github.com/ionic-team/ionic/commit/1ca7df))
|
||||
|
||||
|
||||
|
||||
<a name="3.4.0"></a>
|
||||
# [3.4.0](https://github.com/ionic-team/ionic/compare/v3.3.0...v3.4.0) (2017-06-15)
|
||||
|
||||
### Steps to Upgrade
|
||||
|
||||
`ionic-angular` should be set to version `3.4.0` in the package.json dependency list. The latest `@angular` release `4.1.3` is also supported. Feel free to update apps by updating the `package.json` dependencies to match below.
|
||||
|
||||
```
|
||||
"dependencies": {
|
||||
"@angular/common": "4.1.3",
|
||||
"@angular/compiler": "4.1.3",
|
||||
"@angular/compiler-cli": "4.1.3",
|
||||
"@angular/core": "4.1.3",
|
||||
"@angular/forms": "4.1.3",
|
||||
"@angular/http": "4.1.3",
|
||||
"@angular/platform-browser": "4.1.3",
|
||||
"@angular/platform-browser-dynamic": "4.1.3",
|
||||
"@ionic-native/core": "3.12.1",
|
||||
"@ionic-native/splash-screen": "3.12.1",
|
||||
"@ionic-native/status-bar": "3.12.1",
|
||||
"@ionic/storage": "2.0.1",
|
||||
"ionic-angular": "3.4.2",
|
||||
"ionicons": "3.0.0",
|
||||
"rxjs": "5.4.0",
|
||||
"sw-toolbox": "3.6.0",
|
||||
"zone.js": "0.8.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/app-scripts": "1.3.7",
|
||||
"typescript": "2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** rtl fix for md ripple effect ([#11842](https://github.com/ionic-team/ionic/issues/11842)) ([bb966e5](https://github.com/ionic-team/ionic/commit/bb966e5))
|
||||
* **content:** scroll content should inherit background ([#11467](https://github.com/ionic-team/ionic/issues/11467)) ([6256b0f](https://github.com/ionic-team/ionic/commit/6256b0f))
|
||||
* **datetime:** set datetime direction the same on ltr and rtl ([#11992](https://github.com/ionic-team/ionic/issues/11992)) ([20c9dd7](https://github.com/ionic-team/ionic/commit/20c9dd7))
|
||||
* **gesture:** RTL fix for slide-gesture ([#11822](https://github.com/ionic-team/ionic/issues/11822)) ([59a1e3d](https://github.com/ionic-team/ionic/commit/59a1e3d))
|
||||
* **input:** add correct translate3d for rtl ([ef85ba6](https://github.com/ionic-team/ionic/commit/ef85ba6)), closes [#11745](https://github.com/ionic-team/ionic/issues/11745) [#11211](https://github.com/ionic-team/ionic/issues/11211)
|
||||
* **input:** better handling of attributes ([9f86e10](https://github.com/ionic-team/ionic/commit/9f86e10))
|
||||
* **input:** slightly longer delay for autofocus ([#12037](https://github.com/ionic-team/ionic/issues/12037)) ([54ac2e3](https://github.com/ionic-team/ionic/commit/54ac2e3))
|
||||
* **input:** use all supported attributes on both textareas and inputs ([#12028](https://github.com/ionic-team/ionic/issues/12028)) ([8041eed](https://github.com/ionic-team/ionic/commit/8041eed))
|
||||
* **item-sliding:** RTL fix for item sliding ([#11825](https://github.com/ionic-team/ionic/issues/11825)) ([10f4df4](https://github.com/ionic-team/ionic/commit/10f4df4))
|
||||
* **keyboard:** big keyboard/input refactor ([c10f72b](https://github.com/ionic-team/ionic/commit/c10f72b)), closes [#9699](https://github.com/ionic-team/ionic/issues/9699) [#11484](https://github.com/ionic-team/ionic/issues/11484) [#11389](https://github.com/ionic-team/ionic/issues/11389) [#11325](https://github.com/ionic-team/ionic/issues/11325) [#11291](https://github.com/ionic-team/ionic/issues/11291) [#10828](https://github.com/ionic-team/ionic/issues/10828) [#11291](https://github.com/ionic-team/ionic/issues/11291) [#10393](https://github.com/ionic-team/ionic/issues/10393) [#10257](https://github.com/ionic-team/ionic/issues/10257) [#9434](https://github.com/ionic-team/ionic/issues/9434) [#8933](https://github.com/ionic-team/ionic/issues/8933) [#7178](https://github.com/ionic-team/ionic/issues/7178) [#7047](https://github.com/ionic-team/ionic/issues/7047) [#10552](https://github.com/ionic-team/ionic/issues/10552) [#10393](https://github.com/ionic-team/ionic/issues/10393) [#10183](https://github.com/ionic-team/ionic/issues/10183) [#10187](https://github.com/ionic-team/ionic/issues/10187) [#10852](https://github.com/ionic-team/ionic/issues/10852) [#11578](https://github.com/ionic-team/ionic/issues/11578)
|
||||
* **menu:** rtl gesture for menu ([#11830](https://github.com/ionic-team/ionic/issues/11830)) ([30047f0](https://github.com/ionic-team/ionic/commit/30047f0))
|
||||
* **refresher:** border should only show when pulled ([#12015](https://github.com/ionic-team/ionic/issues/12015)) ([47e3c70](https://github.com/ionic-team/ionic/commit/47e3c70)), closes [#10994](https://github.com/ionic-team/ionic/issues/10994)
|
||||
* **rtl:** add icon-start and icon-end attributes ([#11737](https://github.com/ionic-team/ionic/issues/11737)) ([a40b872](https://github.com/ionic-team/ionic/commit/a40b872))
|
||||
* **sass:** add default flag to variables ([#11779](https://github.com/ionic-team/ionic/issues/11779)) ([f14d7d6](https://github.com/ionic-team/ionic/commit/f14d7d6))
|
||||
* **searchbar:** caret moving to the end when typing ([261bc4d](https://github.com/ionic-team/ionic/commit/261bc4d))
|
||||
* **segment:** fix border-radius logic for RTL ([#11981](https://github.com/ionic-team/ionic/issues/11981)) ([6db8c14](https://github.com/ionic-team/ionic/commit/6db8c14))
|
||||
* **select:** add cssClass for popover interface ([#11769](https://github.com/ionic-team/ionic/issues/11769)) ([1c25acb](https://github.com/ionic-team/ionic/commit/1c25acb))
|
||||
* **select:** return undefined when there are no options ([#11968](https://github.com/ionic-team/ionic/issues/11968)) ([dc6c586](https://github.com/ionic-team/ionic/commit/dc6c586)), closes [#10435](https://github.com/ionic-team/ionic/issues/10435)
|
||||
* **split-pane:** correct split-pane menu side order ([30dc247](https://github.com/ionic-team/ionic/commit/30dc247))
|
||||
* **textarea:** apply classes properly ([dc958c3](https://github.com/ionic-team/ionic/commit/dc958c3))
|
||||
* **toggle:** RTL fix for toggle ([2afb936](https://github.com/ionic-team/ionic/commit/2afb936))
|
||||
* **toolbar:** get the correct contrast color for md mode ([0f4ed1c](https://github.com/ionic-team/ionic/commit/0f4ed1c)), closes [#11848](https://github.com/ionic-team/ionic/issues/11848)
|
||||
* **toolbar:** use the correct contrast color for MD toolbar ([041689b](https://github.com/ionic-team/ionic/commit/041689b)), closes [#11848](https://github.com/ionic-team/ionic/issues/11848)
|
||||
* **transition:** RTL fix for transition on ios ([#11820](https://github.com/ionic-team/ionic/issues/11820)) ([6322134](https://github.com/ionic-team/ionic/commit/6322134))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **background-position:** add background position support for rtl ([#11946](https://github.com/ionic-team/ionic/issues/11946)) ([305c306](https://github.com/ionic-team/ionic/commit/305c306))
|
||||
* **loading:** add enableBackdropDismiss to Loading ([#11937](https://github.com/ionic-team/ionic/issues/11937)) ([d0ae810](https://github.com/ionic-team/ionic/commit/d0ae810)), closes [#7975](https://github.com/ionic-team/ionic/issues/7975)
|
||||
* **loading:** add margin start variable ([#11980](https://github.com/ionic-team/ionic/issues/11980)) ([3e0d43e](https://github.com/ionic-team/ionic/commit/3e0d43e))
|
||||
* **rtl:** add transform and transform-origin support for rtl ([#11649](https://github.com/ionic-team/ionic/issues/11649)) ([2273fb5](https://github.com/ionic-team/ionic/commit/2273fb5))
|
||||
* **rtl:** optimize the new mixins for smaller bundle, ltr separation ([#11635](https://github.com/ionic-team/ionic/issues/11635)) ([f0c6948](https://github.com/ionic-team/ionic/commit/f0c6948))
|
||||
* **rtl:** support flipped svg background images on rtl ([#11945](https://github.com/ionic-team/ionic/issues/11945)) ([f4452b5](https://github.com/ionic-team/ionic/commit/f4452b5))
|
||||
* **slides:** support centering slides and using decimal numbers ([e3c60c5](https://github.com/ionic-team/ionic/commit/e3c60c5)), closes [#10361](https://github.com/ionic-team/ionic/issues/10361)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **item-sliding:** remove duplicate class ([#11829](https://github.com/ionic-team/ionic/issues/11829)) ([c9cb9ae](https://github.com/ionic-team/ionic/commit/c9cb9ae))
|
||||
|
||||
|
||||
|
||||
<a name="3.3.0"></a>
|
||||
# [3.3.0](https://github.com/ionic-team/ionic/compare/v3.2.1...v3.3.0) (2017-05-24)
|
||||
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Hair Color</ion-label>
|
||||
<ion-select [(ngModel)]="hairColor" okText="Okay" cancelText="Dismiss" [compareWith]="compareFn">
|
||||
<ion-option *ngFor="let o of hairColorData" [value]="o">{{o.text}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Gaming</ion-label>
|
||||
<ion-select [(ngModel)]="gaming" okText="Okay" cancelText="Dismiss">
|
||||
@@ -147,6 +154,13 @@
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Skittles</ion-label>
|
||||
<ion-select [(ngModel)]="skittles" multiple="true" okText="Okay" cancelText="Dismiss" [compareWith]="compareFn">
|
||||
<ion-option *ngFor="let o of skittlesData" [value]="o">{{o.text}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Disabled</ion-label>
|
||||
<ion-select multiple disabled="true">
|
||||
|
||||
@@ -10,6 +10,10 @@ export class PageOne {
|
||||
petAlertOpts: any;
|
||||
petData: any;
|
||||
pets: Array<string>;
|
||||
hairColorData: any;
|
||||
hairColor: any;
|
||||
skittlesData: any;
|
||||
skittles: Array<any>;
|
||||
notifications: string = 'mute_1';
|
||||
rating: number = 2;
|
||||
|
||||
@@ -31,9 +35,37 @@ export class PageOne {
|
||||
{ text: 'Honey Badger', value: 'honeybadger' },
|
||||
];
|
||||
|
||||
this.hairColorData = [
|
||||
{ text: 'Brown', value: 'brown' },
|
||||
{ text: 'Blonde', value: 'blonde' },
|
||||
{ text: 'Black', value: 'black' },
|
||||
{ text: 'Red', value: 'red' }
|
||||
];
|
||||
|
||||
// Pre-selected object with different object reference
|
||||
this.hairColor = { text: 'Brown', value: 'brown' };
|
||||
|
||||
this.skittlesData = [
|
||||
{ text: 'Red', value: 'red' },
|
||||
{ text: 'Orange', value: 'orange' },
|
||||
{ text: 'Yellow', value: 'yellow' },
|
||||
{ text: 'Green', value: 'green' },
|
||||
{ text: 'Purple', value: 'purple' }
|
||||
];
|
||||
|
||||
// Pre-selected object with different object reference
|
||||
this.skittles = [
|
||||
{ text: 'Red', value: 'red' },
|
||||
{ text: 'Purple', value: 'purple' }
|
||||
];
|
||||
|
||||
this.pets = ['cat', 'dog'];
|
||||
}
|
||||
|
||||
compareFn(option1: any, option2: any) {
|
||||
return option1.value === option2.value;
|
||||
}
|
||||
|
||||
monthChange(val: any) {
|
||||
console.log('Month Change:', val);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "ionic2",
|
||||
"version": "3.3.0",
|
||||
"version": "3.4.2",
|
||||
"description": "A powerful framework for building mobile and progressive web apps with JavaScript and Angular",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -22,7 +22,8 @@
|
||||
"scripts": {
|
||||
"test": "gulp validate",
|
||||
"test:generators": "jasmine-node ./tooling/spec",
|
||||
"link": "gulp release.prepareReleasePackage && cd dist/ionic-angular && npm link"
|
||||
"link": "gulp release.prepareReleasePackage && cd dist/ionic-angular && npm link",
|
||||
"tsc": "tsc --outdir .tmp"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/common": "4.1.3",
|
||||
@@ -146,4 +147,4 @@
|
||||
"pre-push#master": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ path: ""
|
||||
category: api
|
||||
id: api
|
||||
title: Javascript
|
||||
header_sub_title: Extend Ionic even further with the power of AngularJS
|
||||
header_sub_title: Extend Ionic even further with the power of Angular
|
||||
searchable: false
|
||||
---
|
||||
|
||||
@@ -15,9 +15,6 @@ searchable: false
|
||||
|
||||
<img class="section-header" src="/img/docs/api-intro-header.png" />
|
||||
|
||||
|
||||
Ionic takes everything you know and loved about Ionic V1, and builds on top of it to provide a much more flexible framework.
|
||||
|
||||
In the API docs, you'll find two kinds of doc pages: Component and Service APIs.
|
||||
|
||||
The Component APIs include classes like `Checkbox`, `Toggle` or `Item` and show you how to use them, in addition to listing their selectors, available properties and events.
|
||||
|
||||
@@ -11,14 +11,14 @@ task('demos.watch', ['demos.prepare'], (done: Function) => {
|
||||
done(new Error(`Usage: gulp e2e.watch --folder modal`));
|
||||
}
|
||||
|
||||
serveDemo(folderInfo.componentName).then(() => {
|
||||
serveDemo(folderInfo.componentName, folderInfo.devApp).then(() => {
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
function serveDemo(folderName: any) {
|
||||
function serveDemo(folderName: any, devApp: boolean) {
|
||||
|
||||
const ionicAngularDir = join(PROJECT_ROOT, 'src');
|
||||
const srcTestRoot = join(DEMOS_ROOT, 'src', folderName);
|
||||
@@ -40,5 +40,5 @@ function serveDemo(folderName: any) {
|
||||
const appNgModulePath = join(srcTestRoot, 'app', 'app.module.ts');
|
||||
const distDir = join(distDemoRoot, 'www');
|
||||
|
||||
return runAppScriptsServe(folderName, appEntryPoint, appNgModulePath, ionicAngularDir, distDir, pathToWriteFile, ionicAngularDir, sassConfigPath, copyConfigPath, watchConfigPath);
|
||||
return runAppScriptsServe(folderName, appEntryPoint, appNgModulePath, ionicAngularDir, distDir, pathToWriteFile, ionicAngularDir, sassConfigPath, copyConfigPath, watchConfigPath, devApp);
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@ task('e2e.watch', ['e2e.prepare'], (done: Function) => {
|
||||
return;
|
||||
}
|
||||
|
||||
serveTest(folderInfo).then(() => {
|
||||
serveTest(folderInfo, folderInfo.devApp).then(() => {
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
function serveTest(folderInfo: any) {
|
||||
function serveTest(folderInfo: any, devApp: boolean) {
|
||||
|
||||
const ionicAngularDir = join(PROJECT_ROOT, 'src');
|
||||
const srcTestRoot = join(PROJECT_ROOT, 'src', 'components', folderInfo.componentName, 'test', folderInfo.componentTest);
|
||||
@@ -47,5 +47,5 @@ function serveTest(folderInfo: any) {
|
||||
const appNgModulePath = join(dirname(appEntryPoint), 'app.module.ts');
|
||||
const distDir = join(distTestRoot, 'www');
|
||||
|
||||
return runAppScriptsServe(join(folderInfo.componentName, folderInfo.componentTest), appEntryPoint, appNgModulePath, ionicAngularDir, distDir, pathToWriteFile, ionicAngularDir, sassConfigPath, copyConfigPath, null);
|
||||
return runAppScriptsServe(join(folderInfo.componentName, folderInfo.componentTest), appEntryPoint, appNgModulePath, ionicAngularDir, distDir, pathToWriteFile, ionicAngularDir, sassConfigPath, copyConfigPath, null, devApp);
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ export function runWebpack(pathToWebpackConfig: string, done: Function) {
|
||||
});
|
||||
}
|
||||
|
||||
export function runAppScriptsServe(testOrDemoName: string, appEntryPoint: string, appNgModulePath: string, srcDir: string, distDir: string, tsConfig: string, ionicAngularDir: string, sassConfigPath: string, copyConfigPath: string, watchConfigPath: string) {
|
||||
export function runAppScriptsServe(testOrDemoName: string, appEntryPoint: string, appNgModulePath: string, srcDir: string, distDir: string, tsConfig: string, ionicAngularDir: string, sassConfigPath: string, copyConfigPath: string, watchConfigPath: string, devApp: boolean) {
|
||||
console.log('Running ionic-app-scripts serve with', testOrDemoName);
|
||||
const deepLinksDir = dirname(dirname(appNgModulePath));
|
||||
let scriptArgs = [
|
||||
@@ -207,6 +207,9 @@ export function runAppScriptsServe(testOrDemoName: string, appEntryPoint: string
|
||||
'--copy', copyConfigPath,
|
||||
'--enableLint', 'false'
|
||||
];
|
||||
if (devApp) {
|
||||
scriptArgs.push('--bonjour');
|
||||
}
|
||||
|
||||
if (watchConfigPath) {
|
||||
scriptArgs.push('--watch');
|
||||
@@ -349,9 +352,11 @@ export function getFolderInfo() {
|
||||
componentName = folderSplit[0];
|
||||
componentTest = (folderSplit.length > 1 ? folderSplit[1] : 'basic');
|
||||
}
|
||||
const devApp = argv.devapp !== undefined;
|
||||
return {
|
||||
componentName: componentName,
|
||||
componentTest: componentTest
|
||||
componentTest: componentTest,
|
||||
devApp: devApp
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -117,8 +117,6 @@ export class ActionSheetCmp {
|
||||
}
|
||||
|
||||
ionViewDidEnter() {
|
||||
this._plt.focusOutActiveElement();
|
||||
|
||||
const focusableEle = this._elementRef.nativeElement.querySelector('button');
|
||||
if (focusableEle) {
|
||||
focusableEle.focus();
|
||||
|
||||
@@ -84,6 +84,7 @@ export class AlertCmp {
|
||||
msgId: string;
|
||||
subHdrId: string;
|
||||
mode: string;
|
||||
keyboardResizes: boolean;
|
||||
gestureBlocker: BlockerDelegate;
|
||||
|
||||
constructor(
|
||||
@@ -99,6 +100,7 @@ export class AlertCmp {
|
||||
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||
this.d = params.data;
|
||||
this.mode = this.d.mode || config.get('mode');
|
||||
this.keyboardResizes = config.getBoolean('keyboardResizes', false);
|
||||
_renderer.setElementClass(_elementRef.nativeElement, `alert-${this.mode}`, true);
|
||||
|
||||
if (this.d.cssClass) {
|
||||
@@ -178,7 +180,7 @@ export class AlertCmp {
|
||||
}
|
||||
|
||||
const hasTextInput = (this.d.inputs.length && this.d.inputs.some(i => !(NON_TEXT_INPUT_REGEX.test(i.type))));
|
||||
if (hasTextInput && this._plt.is('mobile')) {
|
||||
if (!this.keyboardResizes && hasTextInput && this._plt.is('mobile')) {
|
||||
// this alert has a text input and it's on a mobile device so we should align
|
||||
// the alert up high because we need to leave space for the virtual keboard
|
||||
// this also helps prevent the layout getting all messed up from
|
||||
@@ -192,18 +194,10 @@ export class AlertCmp {
|
||||
}
|
||||
|
||||
ionViewDidLeave() {
|
||||
this._plt.focusOutActiveElement();
|
||||
this.gestureBlocker.unblock();
|
||||
}
|
||||
|
||||
ionViewWillLeave() {
|
||||
this._plt.focusOutActiveElement();
|
||||
}
|
||||
|
||||
ionViewDidEnter() {
|
||||
// focus out of the active element
|
||||
this._plt.focusOutActiveElement();
|
||||
|
||||
// set focus on the first input or button in the alert
|
||||
// note that this does not always work and bring up the keyboard on
|
||||
// devices since the focus command must come from the user's touch event
|
||||
|
||||
@@ -6,9 +6,10 @@ import * as Constants from './app-constants';
|
||||
import { ClickBlock } from './click-block';
|
||||
import { runInDev, assert } from '../../util/util';
|
||||
import { Config } from '../../config/config';
|
||||
import { isNav, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util';
|
||||
import { NavOptions, DIRECTION_FORWARD, DIRECTION_BACK, isTabs } from '../../navigation/nav-util';
|
||||
import { MenuController } from './menu-controller';
|
||||
import { NavController } from '../../navigation/nav-controller';
|
||||
import { NavigationContainer } from '../../navigation/navigation-container';
|
||||
import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
import { IOSTransition } from '../../transitions/transition-ios';
|
||||
@@ -28,8 +29,9 @@ export class App {
|
||||
private _scrollTime: number = 0;
|
||||
private _title: string = '';
|
||||
private _titleSrv: Title = new Title(DOCUMENT);
|
||||
private _rootNav: NavController = null;
|
||||
private _rootNavs = new Map<string, NavigationContainer>();
|
||||
private _disableScrollAssist: boolean;
|
||||
private _didScroll = false;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
@@ -87,6 +89,11 @@ export class App {
|
||||
_plt.registerBackButtonAction(this.goBack.bind(this));
|
||||
this._disableScrollAssist = _config.getBoolean('disableScrollAssist', false);
|
||||
|
||||
const blurring = _config.getBoolean('inputBlurring', false);
|
||||
if (blurring) {
|
||||
this._enableInputBlurring();
|
||||
}
|
||||
|
||||
runInDev(() => {
|
||||
// During developement, navPop can be triggered by calling
|
||||
const win = <any>_plt.win();
|
||||
@@ -179,6 +186,7 @@ export class App {
|
||||
*/
|
||||
setScrolling() {
|
||||
this._scrollTime = Date.now() + ACTIVE_SCROLLING_TIME;
|
||||
this._didScroll = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,26 +208,59 @@ export class App {
|
||||
/**
|
||||
* @return {NavController} Returns the active NavController. Using this method is preferred when we need access to the top-level navigation controller while on the outside views and handlers like `registerBackButtonAction()`
|
||||
*/
|
||||
getActiveNav(): NavController {
|
||||
getActiveNav(navId?: string): NavControllerBase {
|
||||
const portal = this._appRoot._getPortal(Constants.PORTAL_MODAL);
|
||||
if (portal.length() > 0) {
|
||||
return findTopNav(portal);
|
||||
return <NavControllerBase> findTopNav(portal);
|
||||
}
|
||||
return findTopNav(this._rootNav || null);
|
||||
if (!this._rootNavs || !this._rootNavs.size) {
|
||||
return null;
|
||||
}
|
||||
if (this._rootNavs.size === 1) {
|
||||
return <NavControllerBase> findTopNav(this._rootNavs.values().next().value);
|
||||
}
|
||||
return <NavControllerBase> findTopNav(this.getRootNavById(navId));
|
||||
}
|
||||
|
||||
getRootNav(): any {
|
||||
console.warn('(getRootNav) is deprecated and will be removed in the next major release. Use getRootNavById instead.');
|
||||
const rootNavs = this.getRootNavs();
|
||||
if (rootNavs.length === 0) {
|
||||
return null;
|
||||
} else if (rootNavs.length > 1) {
|
||||
console.warn('(getRootNav) there are multiple root navs, use getRootNavs instead');
|
||||
}
|
||||
return rootNavs[0];
|
||||
}
|
||||
|
||||
getRootNavs(): any[] {
|
||||
const navs: NavigationContainer[] = [];
|
||||
this._rootNavs.forEach(nav => navs.push(nav));
|
||||
return navs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {NavController} Returns the root NavController
|
||||
*/
|
||||
getRootNav(): NavController {
|
||||
return this._rootNav;
|
||||
getRootNavById(navId: string): NavigationContainer {
|
||||
return this._rootNavs.get(navId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_setRootNav(nav: any) {
|
||||
this._rootNav = nav;
|
||||
registerRootNav(nav: NavigationContainer) {
|
||||
this._rootNavs.set(nav.id, nav);
|
||||
}
|
||||
|
||||
|
||||
getActiveNavContainers(): NavigationContainer[] {
|
||||
// for each root nav container, get it's active nav
|
||||
const list: NavigationContainer[] = [];
|
||||
this._rootNavs.forEach((container: NavigationContainer) => {
|
||||
list.push(findTopNav(container));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,7 +275,6 @@ export class App {
|
||||
// TODO: move _setNav() to the earlier stages of NavController. _queueTrns()
|
||||
enteringView._setNav(portal);
|
||||
|
||||
opts.keyboardClose = false;
|
||||
opts.direction = DIRECTION_FORWARD;
|
||||
|
||||
if (!opts.animation) {
|
||||
@@ -242,7 +282,7 @@ export class App {
|
||||
}
|
||||
|
||||
enteringView.setLeavingOpts({
|
||||
keyboardClose: false,
|
||||
keyboardClose: opts.keyboardClose,
|
||||
direction: DIRECTION_BACK,
|
||||
animation: enteringView.getTransitionName(DIRECTION_BACK),
|
||||
ev: opts.ev
|
||||
@@ -260,7 +300,7 @@ export class App {
|
||||
}
|
||||
|
||||
const navPromise = this.navPop();
|
||||
if (navPromise === null) {
|
||||
if (!navPromise) {
|
||||
// no views to go back to
|
||||
// let's exit the app
|
||||
if (this._config.getBoolean('navExitApp', true)) {
|
||||
@@ -275,7 +315,7 @@ export class App {
|
||||
* @hidden
|
||||
*/
|
||||
navPop(): Promise<any> {
|
||||
if (!this._rootNav || !this.isEnabled()) {
|
||||
if (!this._rootNavs || this._rootNavs.size === 0 || !this.isEnabled()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -284,43 +324,112 @@ export class App {
|
||||
if (portal.length() > 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// next get the active nav, check itself and climb up all
|
||||
// of its parent navs until it finds a nav that can pop
|
||||
return recursivePop(this.getActiveNav());
|
||||
|
||||
let navToPop: NavControllerBase = null;
|
||||
let mostRecentVC: ViewController = null;
|
||||
this._rootNavs.forEach((navContainer: NavigationContainer) => {
|
||||
const activeNav = this.getActiveNav(navContainer.id);
|
||||
const poppable = getPoppableNav(activeNav);
|
||||
if (poppable) {
|
||||
const topViewController = poppable.last();
|
||||
if (poppable._isPortal || (topViewController && poppable.length() > 1 && (!mostRecentVC || topViewController._ts >= mostRecentVC._ts))) {
|
||||
mostRecentVC = topViewController;
|
||||
navToPop = poppable;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (navToPop) {
|
||||
return navToPop.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_enableInputBlurring() {
|
||||
console.debug('App: _enableInputBlurring');
|
||||
let focused = true;
|
||||
const self = this;
|
||||
const platform = this._plt;
|
||||
|
||||
platform.registerListener(platform.doc(), 'focusin', onFocusin, { capture: true, zone: false, passive: true });
|
||||
platform.registerListener(platform.doc(), 'touchend', onTouchend, { capture: false, zone: false, passive: true });
|
||||
|
||||
function onFocusin(ev: any) {
|
||||
focused = true;
|
||||
}
|
||||
function onTouchend(ev: any) {
|
||||
// if app did scroll return early
|
||||
if (self._didScroll) {
|
||||
self._didScroll = false;
|
||||
return;
|
||||
}
|
||||
const active = <HTMLElement> self._plt.getActiveElement();
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
// only blur if the active element is a text-input or a textarea
|
||||
if (SKIP_BLURRING.indexOf(active.tagName) === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the selected target is the active element, do not blur
|
||||
const tapped = ev.target;
|
||||
if (tapped === active) {
|
||||
return;
|
||||
}
|
||||
if (SKIP_BLURRING.indexOf(tapped.tagName) >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// skip if div is a cover
|
||||
if (tapped.classList.contains('input-cover')) {
|
||||
return;
|
||||
}
|
||||
|
||||
focused = false;
|
||||
// TODO: find a better way, why 50ms?
|
||||
platform.timeout(() => {
|
||||
if (!focused) {
|
||||
active.blur();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function recursivePop(nav: any): Promise<any> {
|
||||
|
||||
function getPoppableNav(nav: NavControllerBase): NavControllerBase {
|
||||
if (!nav) {
|
||||
return null;
|
||||
}
|
||||
if (isNav(nav)) {
|
||||
var len = nav.length();
|
||||
if (len > 1 || (nav._isPortal && len > 0)) {
|
||||
// this nav controller has more than one view
|
||||
// pop the current view on this nav and we're done here
|
||||
console.debug('app, goBack pop nav');
|
||||
return nav.pop();
|
||||
}
|
||||
|
||||
if (isTabs(nav)) {
|
||||
// tabs aren't a nav, so just call this function again immediately on the parent on tabs
|
||||
return getPoppableNav(nav.parent);
|
||||
}
|
||||
const len = nav.length();
|
||||
if (len > 1 || (nav._isPortal && len > 0)) {
|
||||
// this nav controller has more than one view
|
||||
// use this nav!
|
||||
return nav;
|
||||
}
|
||||
// try again using the parent nav (if there is one)
|
||||
return recursivePop(nav.parent);
|
||||
return getPoppableNav(nav.parent);
|
||||
}
|
||||
|
||||
function findTopNav(nav: NavController) {
|
||||
var activeChildNav: any;
|
||||
|
||||
function findTopNav(nav: NavigationContainer): NavigationContainer {
|
||||
while (nav) {
|
||||
activeChildNav = nav.getActiveChildNav();
|
||||
if (!activeChildNav) {
|
||||
const childNav = nav.getActiveChildNav();
|
||||
if (!childNav) {
|
||||
break;
|
||||
}
|
||||
nav = activeChildNav;
|
||||
nav = childNav;
|
||||
}
|
||||
|
||||
return nav;
|
||||
}
|
||||
|
||||
const SKIP_BLURRING = ['INPUT', 'TEXTAREA', 'ION-INPUT', 'ION-TEXTAREA'];
|
||||
const ACTIVE_SCROLLING_TIME = 100;
|
||||
const CLICK_BLOCK_BUFFER_IN_MILLIS = 64;
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Config } from '../../config/config';
|
||||
import { DeepLinker } from '../../navigation/deep-linker';
|
||||
import { DomController } from '../../platform/dom-controller';
|
||||
import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { Keyboard } from '../../platform/keyboard';
|
||||
import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
import { NavigationContainer } from '../../navigation/navigation-container';
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { TransitionController } from '../../transitions/transition-controller';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
@@ -17,12 +17,11 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
@Directive({
|
||||
selector: '[overlay-portal]',
|
||||
})
|
||||
export class OverlayPortal extends NavControllerBase {
|
||||
export class OverlayPortal extends NavControllerBase implements NavigationContainer {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => App)) app: App,
|
||||
config: Config,
|
||||
plt: Platform,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
zone: NgZone,
|
||||
renderer: Renderer,
|
||||
@@ -34,7 +33,7 @@ export class OverlayPortal extends NavControllerBase {
|
||||
domCtrl: DomController,
|
||||
errHandler: ErrorHandler
|
||||
) {
|
||||
super(null, app, config, plt, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl, errHandler);
|
||||
super(null, app, config, plt, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl, errHandler);
|
||||
this._isPortal = true;
|
||||
this._init = true;
|
||||
this.setViewport(viewPort);
|
||||
@@ -57,4 +56,17 @@ export class OverlayPortal extends NavControllerBase {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/*
|
||||
* @private
|
||||
*/
|
||||
getType() {
|
||||
return 'portal';
|
||||
}
|
||||
|
||||
/*
|
||||
* @private
|
||||
*/
|
||||
getSecondaryIdentifier(): string {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ describe('App', () => {
|
||||
describe('goBack', () => {
|
||||
|
||||
it('should not select the previous tab', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
let tabs = mockTabs();
|
||||
let tab1 = mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
const tabs = mockTabs();
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
|
||||
tab1.root = 'Page1';
|
||||
tab2.root = 'Page2';
|
||||
@@ -44,71 +44,79 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should pop from the active tab, when tabs is nested is the root nav', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
let tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
nav.registerChildNav(tabs);
|
||||
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(tab2, 'pop');
|
||||
spyOn(tab1, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(tab2, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
let view1 = mockView();
|
||||
let view2 = mockView();
|
||||
const view1 = mockView();
|
||||
const view2 = mockView();
|
||||
tab2._views = [view1, view2];
|
||||
tab1._views = [mockView()];
|
||||
|
||||
app.goBack();
|
||||
|
||||
expect(tab1.pop).not.toHaveBeenCalled();
|
||||
expect(tab2.pop).toHaveBeenCalled();
|
||||
expect(portal.pop).not.toHaveBeenCalled();
|
||||
expect(plt.exitApp).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pop from the active tab, when tabs is the root', () => {
|
||||
let tabs = mockTabs();
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
mockTab(tabs);
|
||||
app._setRootNav(tabs);
|
||||
app.registerRootNav(tabs);
|
||||
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(tab2, 'pop');
|
||||
spyOn(tab1, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(tab2, 'pop').and.returnValue(Promise.resolve());
|
||||
|
||||
let view1 = mockView();
|
||||
let view2 = mockView();
|
||||
const view1 = mockView();
|
||||
const view2 = mockView();
|
||||
tab2._views = [view1, view2];
|
||||
|
||||
app.goBack();
|
||||
|
||||
expect(tab1.pop).not.toHaveBeenCalled();
|
||||
expect(tab2.pop).toHaveBeenCalled();
|
||||
expect(plt.exitApp).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pop the root nav when nested nav has less than 2 views', () => {
|
||||
let rootNav = mockNavController();
|
||||
let nestedNav = mockNavController();
|
||||
rootNav.registerChildNav(nestedNav);
|
||||
const rootNav = mockNavController();
|
||||
app.registerRootNav(rootNav);
|
||||
|
||||
const nestedNav = mockNavController();
|
||||
nestedNav.parent = rootNav;
|
||||
app._setRootNav(rootNav);
|
||||
rootNav.registerChildNav(nestedNav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(rootNav, 'pop');
|
||||
spyOn(nestedNav, 'pop');
|
||||
spyOn(portal, 'pop');
|
||||
spyOn(rootNav, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(nestedNav, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(portal, 'pop').and.returnValue(Promise.resolve());
|
||||
|
||||
let rootView1 = mockView();
|
||||
let rootView2 = mockView();
|
||||
const rootView1 = mockView();
|
||||
const rootView2 = mockView();
|
||||
mockViews(rootNav, [rootView1, rootView2]);
|
||||
|
||||
let nestedView1 = mockView();
|
||||
const nestedView1 = mockView();
|
||||
mockViews(nestedNav, [nestedView1]);
|
||||
|
||||
app.goBack();
|
||||
@@ -120,22 +128,22 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should pop a view from the nested nav that has more than 1 view', () => {
|
||||
let rootNav = mockNavController();
|
||||
let nestedNav = mockNavController();
|
||||
app._setRootNav(rootNav);
|
||||
const rootNav = mockNavController();
|
||||
const nestedNav = mockNavController();
|
||||
app.registerRootNav(rootNav);
|
||||
rootNav.registerChildNav(nestedNav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(rootNav, 'pop');
|
||||
spyOn(nestedNav, 'pop');
|
||||
spyOn(nestedNav, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
let rootView1 = mockView();
|
||||
let rootView2 = mockView();
|
||||
const rootView1 = mockView();
|
||||
const rootView2 = mockView();
|
||||
mockViews(rootNav, [rootView1, rootView2]);
|
||||
|
||||
let nestedView1 = mockView();
|
||||
let nestedView2 = mockView();
|
||||
const nestedView1 = mockView();
|
||||
const nestedView2 = mockView();
|
||||
mockViews(nestedNav, [nestedView1, nestedView2]);
|
||||
|
||||
app.goBack();
|
||||
@@ -147,18 +155,18 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should pop the overlay in the portal of the root nav', (done: Function) => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop');
|
||||
spyOn(portal, 'pop').and.returnValue(Promise.resolve());
|
||||
|
||||
let view1 = mockView();
|
||||
let view2 = mockView();
|
||||
const view1 = mockView();
|
||||
const view2 = mockView();
|
||||
mockViews(nav, [view1, view2]);
|
||||
|
||||
let overlay1 = mockView();
|
||||
const overlay1 = mockView();
|
||||
mockViews(portal, [overlay1]);
|
||||
|
||||
app.goBack().then(() => {
|
||||
@@ -173,15 +181,15 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should pop the second view in the root nav', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop');
|
||||
spyOn(nav, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
let view1 = mockView();
|
||||
let view2 = mockView();
|
||||
const view1 = mockView();
|
||||
const view2 = mockView();
|
||||
mockViews(nav, [view1, view2]);
|
||||
|
||||
app.goBack();
|
||||
@@ -192,17 +200,17 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should exit app when only one view in the root nav', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop');
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
let view1 = mockView();
|
||||
const view1 = mockView();
|
||||
mockViews(nav, [view1]);
|
||||
|
||||
expect(app.getActiveNav()).toBe(nav);
|
||||
expect(app.getActiveNav(nav.id)).toBe(nav);
|
||||
expect(nav.first()).toBe(view1);
|
||||
|
||||
app.goBack();
|
||||
@@ -213,8 +221,8 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should not exit app when only one view in the root nav, but navExitApp config set', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop');
|
||||
@@ -222,10 +230,10 @@ describe('App', () => {
|
||||
|
||||
config.set('navExitApp', false);
|
||||
|
||||
let view1 = mockView();
|
||||
const view1 = mockView();
|
||||
mockViews(nav, [view1]);
|
||||
|
||||
expect(app.getActiveNav()).toBe(nav);
|
||||
expect(app.getActiveNav(nav.id)).toBe(nav);
|
||||
expect(nav.first()).toBe(view1);
|
||||
|
||||
app.goBack();
|
||||
@@ -236,14 +244,14 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should not go back if app is not enabled', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop');
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
let view1 = mockView();
|
||||
const view1 = mockView();
|
||||
mockViews(nav, [view1]);
|
||||
|
||||
app.setEnabled(false, 10000);
|
||||
@@ -263,101 +271,208 @@ describe('App', () => {
|
||||
expect(plt.exitApp).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should first pop the from the nav controller with the most recent view, then pop subsequent views, and eventually exit the app when there isnt anything left to pop', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
const navTwo = mockNavController();
|
||||
app.registerRootNav(navTwo);
|
||||
|
||||
spyOn(plt, 'exitApp');
|
||||
spyOn(nav, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(navTwo, 'pop').and.returnValue(Promise.resolve());
|
||||
spyOn(portal, 'pop');
|
||||
|
||||
const view1 = mockView();
|
||||
const view2 = mockView();
|
||||
mockViews(nav, [view1, view2]);
|
||||
|
||||
const view3 = mockView();
|
||||
view3._ts = view3._ts + 1000;
|
||||
const view4 = mockView();
|
||||
view4._ts = view4._ts + 1000;
|
||||
mockViews(navTwo, [view3, view4]);
|
||||
|
||||
app.goBack();
|
||||
|
||||
mockViews(navTwo, [view3]);
|
||||
|
||||
expect(portal.pop).not.toHaveBeenCalled();
|
||||
expect(nav.pop).not.toHaveBeenCalled();
|
||||
expect(navTwo.pop).toHaveBeenCalled();
|
||||
expect(plt.exitApp).not.toHaveBeenCalled();
|
||||
|
||||
app.goBack();
|
||||
expect(nav.pop).toHaveBeenCalled();
|
||||
|
||||
mockViews(nav, [view1]);
|
||||
|
||||
app.goBack();
|
||||
expect(plt.exitApp).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActiveNav', () => {
|
||||
|
||||
it('should get active NavController when using tabs with nested nav', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
let tabs = mockTabs();
|
||||
let tab1 = mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
const tabs = mockTabs();
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
nav.registerChildNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
let nav2 = mockNavController();
|
||||
let nav3 = mockNavController();
|
||||
let nav4 = mockNavController();
|
||||
const nav2 = mockNavController();
|
||||
const nav3 = mockNavController();
|
||||
const nav4 = mockNavController();
|
||||
tab1.registerChildNav(nav4);
|
||||
tab2.registerChildNav(nav2);
|
||||
tab2.registerChildNav(nav3);
|
||||
|
||||
expect(app.getActiveNav()).toBe(nav3);
|
||||
expect(app.getActiveNav(nav.id)).toBe(nav3);
|
||||
});
|
||||
|
||||
it('should get active NavController when using tabs, nested in a root nav', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
let tabs = mockTabs();
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
let tab3 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
const tab3 = mockTab(tabs);
|
||||
nav.registerChildNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNav()).toBe(tab2);
|
||||
expect(app.getActiveNav(nav.id)).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNav()).toBe(tab3);
|
||||
expect(app.getActiveNav(nav.id)).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active tab NavController when using tabs, and tabs is the root', () => {
|
||||
let tabs = mockTabs();
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
let tab2 = mockTab(tabs);
|
||||
let tab3 = mockTab(tabs);
|
||||
app._setRootNav(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
const tab3 = mockTab(tabs);
|
||||
app.registerRootNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNav()).toBe(tab2);
|
||||
expect(app.getActiveNav(tabs.id)).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNav()).toBe(tab3);
|
||||
expect(app.getActiveNav(tabs.id)).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 3 deep', () => {
|
||||
let nav1 = mockNavController();
|
||||
let nav2 = mockNavController();
|
||||
let nav3 = mockNavController();
|
||||
app._setRootNav(nav1);
|
||||
const nav1 = mockNavController();
|
||||
const nav2 = mockNavController();
|
||||
const nav3 = mockNavController();
|
||||
app.registerRootNav(nav1);
|
||||
|
||||
nav1.registerChildNav(nav2);
|
||||
nav2.registerChildNav(nav3);
|
||||
|
||||
expect(app.getActiveNav()).toBe(nav3);
|
||||
expect(app.getActiveNav(nav1.id)).toBe(nav3);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 2 deep', () => {
|
||||
let nav1 = mockNavController();
|
||||
let nav2 = mockNavController();
|
||||
app._setRootNav(nav1);
|
||||
const nav1 = mockNavController();
|
||||
const nav2 = mockNavController();
|
||||
app.registerRootNav(nav1);
|
||||
|
||||
nav1.registerChildNav(nav2);
|
||||
expect(app.getActiveNav()).toBe(nav2);
|
||||
|
||||
const activeNav = app.getActiveNav(nav1.id);
|
||||
|
||||
expect(activeNav).toBe(nav2);
|
||||
});
|
||||
|
||||
it('should get active NavController when only one nav controller', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
expect(app.getActiveNav()).toBe(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
expect(app.getActiveNav(nav.id)).toBe(nav);
|
||||
});
|
||||
|
||||
it('should set/get the root nav controller', () => {
|
||||
let nav = mockNavController();
|
||||
app._setRootNav(nav);
|
||||
expect(app.getRootNav()).toBe(nav);
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
expect(app.getRootNavById(nav.id)).toBe(nav);
|
||||
});
|
||||
|
||||
it('should not get an active NavController if there is not root set', () => {
|
||||
expect(app.getActiveNav()).toBeNull();
|
||||
expect(app.getRootNav()).toBeNull();
|
||||
const activeNav = app.getActiveNav('');
|
||||
const rootNav = app.getRootNavById('');
|
||||
expect(activeNav).toBeFalsy();
|
||||
expect(rootNav).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should just work when there are multiple active navs', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
const rootNavTwo = mockNavController();
|
||||
|
||||
app.registerRootNav(rootNavOne);
|
||||
app.registerRootNav(rootNavTwo);
|
||||
|
||||
const childNavOne = mockNavController();
|
||||
const childNavTwo = mockNavController();
|
||||
|
||||
rootNavOne.registerChildNav(childNavOne);
|
||||
rootNavTwo.registerChildNav(childNavTwo);
|
||||
|
||||
const activeNavOne = app.getActiveNav(rootNavOne.id);
|
||||
const activeNavTwo = app.getActiveNav(rootNavTwo.id);
|
||||
|
||||
expect(activeNavOne).toBe(childNavOne);
|
||||
expect(activeNavTwo).toBe(childNavTwo);
|
||||
});
|
||||
|
||||
it('should get the active nav when no id is provided assuming there is one nav', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
|
||||
const childNavOne = mockNavController();
|
||||
rootNavOne.registerChildNav(childNavOne);
|
||||
|
||||
const result = app.getActiveNav();
|
||||
|
||||
expect(result).toEqual(childNavOne);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRootNavs', () => {
|
||||
it('should return an array of navs', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
const rootNavTwo = mockNavController();
|
||||
app.registerRootNav(rootNavTwo);
|
||||
|
||||
const results = app.getRootNavs();
|
||||
expect(results.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRootNav', () => {
|
||||
it('should return the single root nav', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
const result = app.getRootNav();
|
||||
expect(result).toEqual(rootNavOne);
|
||||
});
|
||||
|
||||
it('should return the first nav in the list for backwards compatibility', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
const rootNavTwo = mockNavController();
|
||||
app.registerRootNav(rootNavTwo);
|
||||
|
||||
const result = app.getRootNav();
|
||||
expect(result).toEqual(rootNavOne);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -381,7 +496,7 @@ describe('App', () => {
|
||||
|
||||
it('should enable click block when false is passed with duration', () => {
|
||||
// arrange
|
||||
let mockClickBlock: any = {
|
||||
const mockClickBlock: any = {
|
||||
activate: () => {}
|
||||
};
|
||||
|
||||
@@ -398,7 +513,7 @@ describe('App', () => {
|
||||
|
||||
it('should enable click block when false is passed w/o duration', () => {
|
||||
// arrange
|
||||
let mockClickBlock: any = {
|
||||
const mockClickBlock: any = {
|
||||
activate: () => {}
|
||||
};
|
||||
|
||||
@@ -416,7 +531,7 @@ describe('App', () => {
|
||||
|
||||
it('should enable click block when false is passed with a duration of 0 and with a minDuration', () => {
|
||||
// arrange
|
||||
let mockClickBlock: any = {
|
||||
const mockClickBlock: any = {
|
||||
activate: () => {}
|
||||
};
|
||||
|
||||
@@ -433,7 +548,7 @@ describe('App', () => {
|
||||
|
||||
it('should enable click block when false is passed with a null duration and a minDuration', () => {
|
||||
// arrange
|
||||
let mockClickBlock: any = {
|
||||
const mockClickBlock: any = {
|
||||
activate: () => {}
|
||||
};
|
||||
|
||||
@@ -450,7 +565,7 @@ describe('App', () => {
|
||||
|
||||
it('should enable click block when false is passed with a duration and a minDuration', () => {
|
||||
// arrange
|
||||
let mockClickBlock: any = {
|
||||
const mockClickBlock: any = {
|
||||
activate: () => {}
|
||||
};
|
||||
|
||||
@@ -466,10 +581,10 @@ describe('App', () => {
|
||||
});
|
||||
});
|
||||
|
||||
var app: App;
|
||||
var config: Config;
|
||||
var plt: MockPlatform;
|
||||
var portal: OverlayPortal;
|
||||
let app: App;
|
||||
let config: Config;
|
||||
let plt: MockPlatform;
|
||||
let portal: OverlayPortal;
|
||||
|
||||
beforeEach(() => {
|
||||
config = mockConfig();
|
||||
|
||||
@@ -492,7 +492,7 @@ $button-md-strong-font-weight: bold !default;
|
||||
}
|
||||
}
|
||||
|
||||
.md .button-effect {
|
||||
.md button .button-effect {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +118,6 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, OnDes
|
||||
super(config, elementRef, renderer, 'checkbox', false, form, item, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
initFocus() {
|
||||
this._elementRef.nativeElement.querySelector('button').focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@@ -145,8 +138,8 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, OnDes
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_inputCheckHasValue(val: boolean) {
|
||||
this._item && this._item.setElementClass('item-checkbox-checked', val);
|
||||
_inputUpdated() {
|
||||
this._item && this._item.setElementClass('item-checkbox-checked', this._value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +167,8 @@ export class EventEmitterProxy<T> extends EventEmitter<T> {
|
||||
'</div>' +
|
||||
'<ng-content select="ion-refresher"></ng-content>',
|
||||
host: {
|
||||
'[class.statusbar-padding]': 'statusbarPadding'
|
||||
'[class.statusbar-padding]': 'statusbarPadding',
|
||||
'[class.has-refresher]': '_hasRefresher'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
@@ -212,6 +213,8 @@ export class Content extends Ion implements OnDestroy, AfterViewInit, IContent {
|
||||
/** @internal */
|
||||
_fullscreen: boolean;
|
||||
/** @internal */
|
||||
_hasRefresher: boolean = false;
|
||||
/** @internal */
|
||||
_footerEle: HTMLElement;
|
||||
/** @internal */
|
||||
_dirty: boolean;
|
||||
@@ -782,6 +785,11 @@ export class Content extends Ion implements OnDestroy, AfterViewInit, IContent {
|
||||
this._cBottom += this._tabbarHeight;
|
||||
}
|
||||
|
||||
// Refresher uses a border which should be hidden unless pulled
|
||||
if (this._hasRefresher) {
|
||||
this._cTop -= 1;
|
||||
}
|
||||
|
||||
// Fixed content shouldn't include content padding
|
||||
this._fTop = this._cTop;
|
||||
this._fBottom = this._cBottom;
|
||||
|
||||
@@ -448,6 +448,7 @@ export class DateTime extends BaseInput<DateTimeData> implements AfterContentIni
|
||||
* @hidden
|
||||
*/
|
||||
_inputUpdated() {
|
||||
super._inputUpdated();
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
@@ -475,10 +476,6 @@ export class DateTime extends BaseInput<DateTimeData> implements AfterContentIni
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
_click(ev: UIEvent) {
|
||||
// do not continue if the click event came from a form submit
|
||||
if (ev.detail === 0) {
|
||||
return;
|
||||
}
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.open();
|
||||
|
||||
@@ -93,6 +93,8 @@ input.text-input:-webkit-autofill {
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.input[disabled] .input-cover {
|
||||
@@ -127,27 +129,6 @@ input.text-input:-webkit-autofill {
|
||||
}
|
||||
|
||||
|
||||
// Scroll Assist Input
|
||||
// --------------------------------------------------
|
||||
// This input is used to help the app handle
|
||||
// Next and Previous input tabbing
|
||||
|
||||
[next-input] {
|
||||
@include padding(0);
|
||||
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
|
||||
border: 0;
|
||||
background: transparent;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
// Clear Input Icon
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,242 +0,0 @@
|
||||
import { Directive, ElementRef, EventEmitter, HostListener, Output, Renderer } from '@angular/core';
|
||||
import { NgControl } from '@angular/forms';
|
||||
|
||||
import { Config } from '../../config/config';
|
||||
import { Platform } from '../../platform/platform';
|
||||
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@Directive({
|
||||
selector: '.text-input'
|
||||
})
|
||||
export class NativeInput {
|
||||
_relocated: boolean;
|
||||
_clone: boolean;
|
||||
_blurring: boolean;
|
||||
_unrefBlur: Function;
|
||||
|
||||
@Output() focusChange: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
@Output() valueChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
@Output() keydown: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
constructor(
|
||||
public _elementRef: ElementRef,
|
||||
public _renderer: Renderer,
|
||||
config: Config,
|
||||
private _plt: Platform,
|
||||
public ngControl: NgControl
|
||||
) {
|
||||
this._clone = config.getBoolean('inputCloning', false);
|
||||
this._blurring = config.getBoolean('inputBlurring', false);
|
||||
}
|
||||
|
||||
@HostListener('input', ['$event'])
|
||||
_change(ev: any) {
|
||||
this.valueChange.emit(ev.target.value);
|
||||
}
|
||||
|
||||
@HostListener('keydown', ['$event'])
|
||||
_keyDown(ev: any) {
|
||||
if (ev) {
|
||||
ev.target && this.keydown.emit(ev.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('focus')
|
||||
_focus() {
|
||||
var self = this;
|
||||
|
||||
self.focusChange.emit(true);
|
||||
|
||||
if (self._blurring) {
|
||||
// automatically blur input if:
|
||||
// 1) this input has focus
|
||||
// 2) the newly tapped document element is not an input
|
||||
console.debug(`native-input, blurring enabled`);
|
||||
|
||||
var unregTouchEnd = this._plt.registerListener(this._plt.doc(), 'touchend', (ev: TouchEvent) => {
|
||||
var tapped = <HTMLElement>ev.target;
|
||||
if (tapped && self.element()) {
|
||||
if (tapped.tagName !== 'INPUT' && tapped.tagName !== 'TEXTAREA' && !tapped.classList.contains('input-cover')) {
|
||||
self.element().blur();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
capture: true,
|
||||
zone: false
|
||||
});
|
||||
|
||||
self._unrefBlur = function() {
|
||||
console.debug(`native-input, blurring disabled`);
|
||||
unregTouchEnd();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('blur')
|
||||
_blur() {
|
||||
this.focusChange.emit(false);
|
||||
this.hideFocus(false);
|
||||
|
||||
this._unrefBlur && this._unrefBlur();
|
||||
this._unrefBlur = null;
|
||||
}
|
||||
|
||||
labelledBy(val: string) {
|
||||
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'aria-labelledby', val);
|
||||
}
|
||||
|
||||
isDisabled(val: boolean) {
|
||||
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'disabled', val ? '' : null);
|
||||
}
|
||||
|
||||
setFocus() {
|
||||
// let's set focus to the element
|
||||
// but only if it does not already have focus
|
||||
if (this._plt.getActiveElement() !== this.element()) {
|
||||
this.element().focus();
|
||||
}
|
||||
}
|
||||
|
||||
beginFocus(shouldFocus: boolean, inputRelativeY: number) {
|
||||
if (this._relocated !== shouldFocus) {
|
||||
const focusedInputEle = this.element();
|
||||
if (shouldFocus) {
|
||||
// we should focus into this element
|
||||
|
||||
if (this._clone) {
|
||||
// this platform needs the input to be cloned
|
||||
// this allows for the actual input to receive the focus from
|
||||
// the user's touch event, but before it receives focus, it
|
||||
// moves the actual input to a location that will not screw
|
||||
// up the app's layout, and does not allow the native browser
|
||||
// to attempt to scroll the input into place (messing up headers/footers)
|
||||
// the cloned input fills the area of where native input should be
|
||||
// while the native input fakes out the browser by relocating itself
|
||||
// before it receives the actual focus event
|
||||
cloneInputComponent(this._plt, focusedInputEle);
|
||||
|
||||
// move the native input to a location safe to receive focus
|
||||
// according to the browser, the native input receives focus in an
|
||||
// area which doesn't require the browser to scroll the input into place
|
||||
(<any>focusedInputEle.style)[this._plt.Css.transform] = `translate3d(-9999px,${inputRelativeY}px,0)`;
|
||||
focusedInputEle.style.opacity = '0';
|
||||
}
|
||||
|
||||
// let's now set focus to the actual native element
|
||||
// at this point it is safe to assume the browser will not attempt
|
||||
// to scroll the input into view itself (screwing up headers/footers)
|
||||
this.setFocus();
|
||||
|
||||
} else {
|
||||
// should remove the focus
|
||||
if (this._clone) {
|
||||
// should remove the cloned node
|
||||
removeClone(this._plt, focusedInputEle);
|
||||
}
|
||||
}
|
||||
|
||||
this._relocated = shouldFocus;
|
||||
}
|
||||
}
|
||||
|
||||
hideFocus(shouldHideFocus: boolean) {
|
||||
let focusedInputEle = this.element();
|
||||
|
||||
console.debug(`native-input, hideFocus, shouldHideFocus: ${shouldHideFocus}, input value: ${focusedInputEle.value}`);
|
||||
|
||||
if (shouldHideFocus) {
|
||||
cloneInputComponent(this._plt, focusedInputEle);
|
||||
(<any>focusedInputEle.style)[this._plt.Css.transform] = 'scale(0)';
|
||||
|
||||
} else {
|
||||
removeClone(this._plt, focusedInputEle);
|
||||
}
|
||||
}
|
||||
|
||||
setValue(val: any) {
|
||||
this._elementRef.nativeElement['value'] = val;
|
||||
}
|
||||
|
||||
getValue(): string {
|
||||
return this.element().value;
|
||||
}
|
||||
|
||||
setMin(val: any) {
|
||||
this._elementRef.nativeElement['min'] = val;
|
||||
}
|
||||
|
||||
setMax(val: any) {
|
||||
this._elementRef.nativeElement['max'] = val;
|
||||
}
|
||||
|
||||
setStep(val: any) {
|
||||
this._elementRef.nativeElement['step'] = val;
|
||||
}
|
||||
|
||||
setElementClass(cssClass: string, shouldAdd: boolean) {
|
||||
this._renderer.setElementClass(this._elementRef.nativeElement, cssClass, shouldAdd);
|
||||
}
|
||||
|
||||
element(): HTMLInputElement {
|
||||
return this._elementRef.nativeElement;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._unrefBlur && this._unrefBlur();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function cloneInputComponent(plt: Platform, srcNativeInputEle: HTMLInputElement) {
|
||||
// given a native <input> or <textarea> element
|
||||
// find its parent wrapping component like <ion-input> or <ion-textarea>
|
||||
// then clone the entire component
|
||||
const srcComponentEle = <HTMLElement>srcNativeInputEle.closest('ion-input,ion-textarea');
|
||||
if (srcComponentEle) {
|
||||
// DOM READ
|
||||
const srcTop = srcComponentEle.offsetTop;
|
||||
const srcLeft = srcComponentEle.offsetLeft;
|
||||
const srcWidth = srcComponentEle.offsetWidth;
|
||||
const srcHeight = srcComponentEle.offsetHeight;
|
||||
|
||||
// DOM WRITE
|
||||
// not using deep clone so we don't pull in unnecessary nodes
|
||||
const clonedComponentEle = <HTMLElement>srcComponentEle.cloneNode(false);
|
||||
clonedComponentEle.classList.add('cloned-input');
|
||||
clonedComponentEle.setAttribute('aria-hidden', 'true');
|
||||
clonedComponentEle.style.pointerEvents = 'none';
|
||||
clonedComponentEle.style.position = 'absolute';
|
||||
clonedComponentEle.style.top = srcTop + 'px';
|
||||
clonedComponentEle.style.left = srcLeft + 'px';
|
||||
clonedComponentEle.style.width = srcWidth + 'px';
|
||||
clonedComponentEle.style.height = srcHeight + 'px';
|
||||
|
||||
const clonedNativeInputEle = <HTMLInputElement>srcNativeInputEle.cloneNode(false);
|
||||
clonedNativeInputEle.value = srcNativeInputEle.value;
|
||||
clonedNativeInputEle.tabIndex = -1;
|
||||
|
||||
clonedComponentEle.appendChild(clonedNativeInputEle);
|
||||
srcComponentEle.parentNode.appendChild(clonedComponentEle);
|
||||
|
||||
srcComponentEle.style.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
(<any>srcNativeInputEle.style)[plt.Css.transform] = 'scale(0)';
|
||||
}
|
||||
|
||||
function removeClone(plt: Platform, srcNativeInputEle: HTMLElement) {
|
||||
const srcComponentEle = <HTMLElement>srcNativeInputEle.closest('ion-input,ion-textarea');
|
||||
if (srcComponentEle && srcComponentEle.parentElement) {
|
||||
const clonedInputEles = srcComponentEle.parentElement.querySelectorAll('.cloned-input');
|
||||
for (var i = 0; i < clonedInputEles.length; i++) {
|
||||
clonedInputEles[i].parentNode.removeChild(clonedInputEles[i]);
|
||||
}
|
||||
|
||||
srcComponentEle.style.pointerEvents = '';
|
||||
}
|
||||
(<any>srcNativeInputEle.style)[plt.Css.transform] = '';
|
||||
srcNativeInputEle.style.opacity = '';
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[next-input]'
|
||||
})
|
||||
export class NextInput {
|
||||
@Output() focused: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
|
||||
@HostListener('focus')
|
||||
receivedFocus() {
|
||||
console.debug('native-input, next-input received focus');
|
||||
this.focused.emit(true);
|
||||
}
|
||||
|
||||
}
|
||||
10
src/components/input/test/attributes/app/app.component.ts
Normal file
10
src/components/input/test/attributes/app/app.component.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { RootPage } from '../pages/root-page/root-page';
|
||||
|
||||
@Component({
|
||||
template: '<ion-nav [root]="root"></ion-nav>'
|
||||
})
|
||||
export class AppComponent {
|
||||
root = RootPage;
|
||||
}
|
||||
19
src/components/input/test/attributes/app/app.module.ts
Normal file
19
src/components/input/test/attributes/app/app.module.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { IonicApp, IonicModule } from '../../../../..';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { RootPageModule } from '../pages/root-page/root-page.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(AppComponent),
|
||||
RootPageModule
|
||||
],
|
||||
bootstrap: [IonicApp]
|
||||
})
|
||||
export class AppModule {}
|
||||
0
src/components/input/test/attributes/e2e.ts
Normal file
0
src/components/input/test/attributes/e2e.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
<ion-header>
|
||||
|
||||
<ion-toolbar>
|
||||
<ion-title>Input attributes</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label stacked>Stacked</ion-label>
|
||||
<ion-input #input1
|
||||
type="number"
|
||||
placeholder="Placeholder"
|
||||
value="1234"
|
||||
id="mystackinput"
|
||||
name="holaa"
|
||||
min="0"
|
||||
max="10000"
|
||||
step="2"
|
||||
autocomplete="on"
|
||||
autocorrect="on"
|
||||
autocapitalize="on"
|
||||
spellcheck="true"
|
||||
maxlength="4"
|
||||
disabled
|
||||
readonly
|
||||
></ion-input>
|
||||
</ion-item>
|
||||
|
||||
<ion-list>
|
||||
<ion-item *ngIf="input1Valid" color="secondary">Test passed</ion-item>
|
||||
<ion-item *ngIf="!input1Valid" color="danger">Test FAILED</ion-item>
|
||||
</ion-list>
|
||||
|
||||
</ion-list>
|
||||
|
||||
</ion-content>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
|
||||
import { RootPage } from './root-page';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
RootPage,
|
||||
],
|
||||
imports: [
|
||||
IonicPageModule.forChild(RootPage)
|
||||
]
|
||||
})
|
||||
export class RootPageModule {}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { TextInput } from '../../../../../../';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'root-page.html'
|
||||
})
|
||||
export class RootPage {
|
||||
|
||||
input1Valid: boolean;
|
||||
input2Valid: boolean;
|
||||
|
||||
@ViewChild('input1') input1: TextInput;
|
||||
|
||||
ionViewDidEnter() {
|
||||
this.input1Valid = this.checkInput1();
|
||||
}
|
||||
|
||||
checkInput1(): boolean {
|
||||
const nativeEle = <HTMLElement>this.input1._native.nativeElement;
|
||||
|
||||
return testAttributes(nativeEle, {
|
||||
id: null,
|
||||
type: 'number',
|
||||
placeholder: 'Placeholder',
|
||||
name: 'holaa',
|
||||
min: '0',
|
||||
max: '10000',
|
||||
step: '2',
|
||||
autocomplete: 'on',
|
||||
autocorrect: 'on',
|
||||
autocapitalize: 'on',
|
||||
spellcheck: 'true',
|
||||
maxLength: '4',
|
||||
'aria-labelledby': 'lbl-0',
|
||||
readOnly: true,
|
||||
disabled: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function testAttributes(ele: HTMLElement, attributes: any): boolean {
|
||||
for (let attr in attributes) {
|
||||
const expected = attributes[attr];
|
||||
const value = (<any>ele)[attr];
|
||||
|
||||
if (expected === null) {
|
||||
if (ele.hasAttribute(attr) || value !== '') {
|
||||
console.error(`Element should NOT have "${attr}"`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (expected !== value && expected !== ele.getAttribute(attr)) {
|
||||
console.error(`Value "${attr}" does not match: ${expected} != ${value}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -102,4 +102,16 @@
|
||||
</ion-list>
|
||||
</ion-card>
|
||||
</form>
|
||||
</ion-content>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ion-toolbar>
|
||||
<ion-input style="background: white;
|
||||
margin: 3px;
|
||||
padding: 0px 8px;
|
||||
border: 1px solid gray;
|
||||
border-radius: 5px;
|
||||
width: auto;
|
||||
transform: translateZ(0);" placeholder="chat here"></ion-input>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
@@ -1,9 +1,38 @@
|
||||
import { getScrollData } from '../input';
|
||||
import { getScrollData, TextInput } from '../input';
|
||||
import { ContentDimensions } from '../../content/content';
|
||||
import { mockConfig, mockApp, mockPlatform, mockDomController, mockElementRef, mockElementRefEle, mockRenderer, mockItem, mockForm } from '../../../util/mock-providers';
|
||||
import { commonInputTest, TEXT_CORPUS } from '../../../util/input-tester';
|
||||
|
||||
|
||||
function newInput(): TextInput {
|
||||
const platform = mockPlatform();
|
||||
const config = mockConfig();
|
||||
const app = mockApp(config, platform);
|
||||
const elementRef = mockElementRef();
|
||||
const renderer = mockRenderer();
|
||||
const item: any = mockItem();
|
||||
const form = mockForm();
|
||||
const dom = mockDomController(platform);
|
||||
const input = new TextInput(config, platform, form, app, elementRef, renderer, null, item, null, dom);
|
||||
input._native = mockElementRefEle(document.createElement('input'));
|
||||
return input;
|
||||
}
|
||||
|
||||
describe('text input', () => {
|
||||
|
||||
it('should pass common test', () => {
|
||||
const textInput = newInput();
|
||||
const ele = textInput._native.nativeElement;
|
||||
textInput._item._elementRef = mockElementRefEle(document.createElement('div'));
|
||||
commonInputTest(textInput, {
|
||||
defaultValue: '',
|
||||
corpus: TEXT_CORPUS,
|
||||
onValueChange: (value) => ele.value === value,
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('getScrollData', () => {
|
||||
|
||||
it('should scroll, top and bottom below safe area, no room to scroll', () => {
|
||||
|
||||
@@ -46,7 +46,7 @@ export class ItemReorderGesture {
|
||||
}
|
||||
this.reorderList._reorderPrepare();
|
||||
|
||||
let item = reorderMark.getReorderNode();
|
||||
const item = reorderMark.getReorderNode();
|
||||
if (!item) {
|
||||
console.error('reorder node not found');
|
||||
return false;
|
||||
@@ -71,26 +71,26 @@ export class ItemReorderGesture {
|
||||
}
|
||||
|
||||
private onDragMove(ev: any) {
|
||||
let selectedItem = this.selectedItemEle;
|
||||
const selectedItem = this.selectedItemEle;
|
||||
if (!selectedItem) {
|
||||
return;
|
||||
}
|
||||
ev.preventDefault();
|
||||
|
||||
// Get coordinate
|
||||
let coord = pointerCoord(ev);
|
||||
let posY = coord.y;
|
||||
const coord = pointerCoord(ev);
|
||||
const posY = coord.y;
|
||||
|
||||
// Scroll if we reach the scroll margins
|
||||
let scrollPosition = this.scroll(posY);
|
||||
const scrollPosition = this.scroll(posY);
|
||||
|
||||
// Only perform hit test if we moved at least 30px from previous position
|
||||
if (Math.abs(posY - this.lastYcoord) > 30) {
|
||||
let overItem = this.itemForCoord(coord);
|
||||
var overItem = this.itemForCoord(coord);
|
||||
if (overItem) {
|
||||
let toIndex = indexForItem(overItem);
|
||||
var toIndex = indexForItem(overItem);
|
||||
if (toIndex !== undefined && (toIndex !== this.lastToIndex || this.emptyZone)) {
|
||||
let fromIndex = indexForItem(selectedItem);
|
||||
var fromIndex = indexForItem(selectedItem);
|
||||
this.lastToIndex = toIndex;
|
||||
this.lastYcoord = posY;
|
||||
this.emptyZone = false;
|
||||
@@ -102,12 +102,12 @@ export class ItemReorderGesture {
|
||||
}
|
||||
|
||||
// Update selected item position
|
||||
let ydiff = Math.round(posY - this.offset.y + scrollPosition);
|
||||
const ydiff = Math.round(posY - this.offset.y + scrollPosition);
|
||||
(<any>selectedItem.style)[this.plt.Css.transform] = `translateY(${ydiff}px)`;
|
||||
}
|
||||
|
||||
private onDragEnd(ev: any) {
|
||||
let selectedItem = this.selectedItemEle;
|
||||
const selectedItem = this.selectedItemEle;
|
||||
if (!selectedItem) {
|
||||
return;
|
||||
}
|
||||
@@ -116,9 +116,9 @@ export class ItemReorderGesture {
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
let toIndex = this.lastToIndex;
|
||||
let fromIndex = indexForItem(selectedItem);
|
||||
let reorderInactive = () => {
|
||||
const toIndex = this.lastToIndex;
|
||||
const fromIndex = indexForItem(selectedItem);
|
||||
const reorderInactive = () => {
|
||||
this.selectedItemEle.style.transition = '';
|
||||
this.selectedItemEle.classList.remove(ITEM_REORDER_ACTIVE);
|
||||
this.selectedItemEle = null;
|
||||
@@ -134,7 +134,7 @@ export class ItemReorderGesture {
|
||||
}
|
||||
|
||||
private itemForCoord(coord: PointerCoordinates): HTMLElement {
|
||||
const sideOffset = this.plt.isRTL ? 100 : -100;
|
||||
const sideOffset = this.reorderList._isStart === this.plt.isRTL ? -100 : 100;
|
||||
const x = this.offset.x + sideOffset;
|
||||
const y = coord.y;
|
||||
const element = this.plt.getElementFromPoint(x, y);
|
||||
@@ -167,6 +167,7 @@ const SCROLL_JUMP = 10;
|
||||
const ITEM_REORDER_ACTIVE = 'reorder-active';
|
||||
|
||||
export interface ItemReorderGestureDelegate {
|
||||
_isStart: boolean;
|
||||
getNativeElement: () => any;
|
||||
_reorderPrepare: () => void;
|
||||
_scrollContent: (scrollPosition: number) => number;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
$reorder-initial-transform: 160% !default;
|
||||
|
||||
// Item reorder
|
||||
// --------------------------------------------------
|
||||
|
||||
ion-reorder {
|
||||
@include transform(translate3d(160%, 0, 0));
|
||||
@include transform(translate3d($reorder-initial-transform, 0, 0));
|
||||
|
||||
display: none;
|
||||
|
||||
@@ -18,13 +20,18 @@ ion-reorder {
|
||||
font-size: 1.7em;
|
||||
opacity: .25;
|
||||
|
||||
|
||||
transition: transform 140ms ease-in;
|
||||
|
||||
pointer-events: all;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.reorder-side-start ion-reorder {
|
||||
@include transform(translate3d(-$reorder-initial-transform, 0, 0));
|
||||
|
||||
order: -1;
|
||||
}
|
||||
|
||||
ion-reorder ion-icon {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -142,12 +142,14 @@ export class ReorderIndexes {
|
||||
host: {
|
||||
'[class.reorder-enabled]': '_enableReorder',
|
||||
'[class.reorder-visible]': '_visibleReorder',
|
||||
'[class.reorder-side-start]': '_isStart'
|
||||
}
|
||||
})
|
||||
export class ItemReorder implements ItemReorderGestureDelegate {
|
||||
|
||||
_enableReorder: boolean = false;
|
||||
_visibleReorder: boolean = false;
|
||||
_isStart: boolean = false;
|
||||
_reorderGesture: ItemReorderGesture;
|
||||
_lastToIndex: number = -1;
|
||||
_element: HTMLElement;
|
||||
@@ -158,6 +160,14 @@ export class ItemReorder implements ItemReorderGestureDelegate {
|
||||
*/
|
||||
@Output() ionItemReorder: EventEmitter<ReorderIndexes> = new EventEmitter<ReorderIndexes>();
|
||||
|
||||
/**
|
||||
* @input {string} Which side of the view the ion-reorder should be placed. Default `"end"`.
|
||||
*/
|
||||
@Input('side')
|
||||
set side(side: 'start' | 'end') {
|
||||
this._isStart = side === 'start';
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _plt: Platform,
|
||||
private _dom: DomController,
|
||||
|
||||
@@ -344,24 +344,24 @@ export class ItemSliding {
|
||||
|
||||
if (isFinal) {
|
||||
this.item.setElementStyle(platform.Css.transition, '');
|
||||
}
|
||||
|
||||
if (openAmount > 0) {
|
||||
var state = (openAmount >= (this._optsWidthRightSide + SWIPE_MARGIN))
|
||||
? SlidingState.Right | SlidingState.SwipeRight
|
||||
: SlidingState.Right;
|
||||
|
||||
this._setState(state);
|
||||
|
||||
} else if (openAmount < 0) {
|
||||
var state = (openAmount <= (-this._optsWidthLeftSide - SWIPE_MARGIN))
|
||||
? SlidingState.Left | SlidingState.SwipeLeft
|
||||
: SlidingState.Left;
|
||||
|
||||
this._setState(state);
|
||||
|
||||
} else {
|
||||
if (openAmount > 0) {
|
||||
var state = (openAmount >= (this._optsWidthRightSide + SWIPE_MARGIN))
|
||||
? SlidingState.Right | SlidingState.SwipeRight
|
||||
: SlidingState.Right;
|
||||
|
||||
this._setState(state);
|
||||
|
||||
} else if (openAmount < 0) {
|
||||
var state = (openAmount <= (-this._optsWidthLeftSide - SWIPE_MARGIN))
|
||||
? SlidingState.Left | SlidingState.SwipeLeft
|
||||
: SlidingState.Left;
|
||||
|
||||
this._setState(state);
|
||||
}
|
||||
}
|
||||
if (openAmount === 0) {
|
||||
assert(openAmount === 0, 'bad internal state');
|
||||
this._tmr = platform.timeout(() => {
|
||||
this._setState(SlidingState.Disabled);
|
||||
this._tmr = null;
|
||||
@@ -371,7 +371,7 @@ export class ItemSliding {
|
||||
}
|
||||
|
||||
this.item.setElementStyle(platform.Css.transform, `translate3d(${-openAmount}px,0,0)`);
|
||||
let ionDrag = this.ionDrag;
|
||||
const ionDrag = this.ionDrag;
|
||||
if (ionDrag.observers.length > 0) {
|
||||
ionDrag.emit(this);
|
||||
}
|
||||
|
||||
@@ -323,6 +323,7 @@ export class Item extends Ion {
|
||||
this._setName(elementRef);
|
||||
this._hasReorder = !!reorder;
|
||||
this.id = form.nextId().toString();
|
||||
this.labelId = 'lbl-' + this.id;
|
||||
|
||||
// auto add "tappable" attribute to ion-item components that have a click listener
|
||||
if (!(<any>renderer).orgListen) {
|
||||
@@ -391,7 +392,7 @@ export class Item extends Ion {
|
||||
set contentLabel(label: Label) {
|
||||
if (label) {
|
||||
this._label = label;
|
||||
this.labelId = label.id = ('lbl-' + this.id);
|
||||
label.id = this.labelId;
|
||||
if (label.type) {
|
||||
this.setElementClass('item-label-' + label.type, true);
|
||||
}
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
</button>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>DateTime</ion-label>
|
||||
<ion-label floating>DateTime</ion-label>
|
||||
<ion-datetime [(ngModel)]="datetime" min="1994-03-14" max="2017-12-09" displayFormat="MM/DD/YYYY" required [disabled]='disabled'></ion-datetime>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Select</ion-label>
|
||||
<ion-label floating>Select</ion-label>
|
||||
<ion-select [(ngModel)]="select" [disabled]='strDisabled()'>
|
||||
<ion-option value="">No Game Console</ion-option>
|
||||
<ion-option value="nes">NES</ion-option>
|
||||
<ion-option value="n64">Nintendo64</ion-option>
|
||||
<ion-option value="ps">PlayStation</ion-option>
|
||||
@@ -42,7 +43,7 @@
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Input (text)</ion-label>
|
||||
<ion-label floating>Input (text)</ion-label>
|
||||
<ion-input [(ngModel)]="text" [disabled]='disabled'></ion-input>
|
||||
</ion-item>
|
||||
|
||||
|
||||
@@ -13,24 +13,30 @@
|
||||
|
||||
<ion-list [reorder]="isReordering" (ionItemReorder)="reorder($event)">
|
||||
<button ion-item *ngFor="let item of items" (click)="clickedButton(item)"
|
||||
[style.background]="'rgb('+(255-item*4)+','+(255-item*4)+','+(255-item*4)+')'"
|
||||
[style.min-height]="item*2+35+'px'">
|
||||
[style.background]="'rgb('+(255-item*4)+','+(255-item*4)+','+(255-item*4)+')'"
|
||||
[style.min-height]="item*2+35+'px'">
|
||||
{{item}}
|
||||
</button>
|
||||
</ion-list>
|
||||
|
||||
<ion-list [reorder]="isReordering" (ionItemReorder)="$event.applyTo(items)">
|
||||
<ion-item-sliding *ngFor="let item of items">
|
||||
<button ion-item (click)="clickedButton(item)">
|
||||
<h2>Sliding item {{item}}</h2>
|
||||
</button>
|
||||
<ion-item-options side="right" icon-start>
|
||||
<button ion-button color='danger'>
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
Remove
|
||||
</button>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
</ion-list>
|
||||
<div *ngFor="let side of ['start', 'end']">
|
||||
<ion-list>
|
||||
<ion-list-header>{{side}}</ion-list-header>
|
||||
<ion-item-group [reorder]="isReordering" (ionItemReorder)="$event.applyTo(items)" [side]="side">
|
||||
<ion-item-sliding *ngFor="let item of items">
|
||||
<button ion-item (click)="clickedButton(item)">
|
||||
<h2>Sliding item {{item}}</h2>
|
||||
<div item-end>right</div>
|
||||
</button>
|
||||
<ion-item-options side="right" icon-start>
|
||||
<button ion-button color='danger'>
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
Remove
|
||||
</button>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
</ion-item-group>
|
||||
</ion-list>
|
||||
</div>
|
||||
|
||||
</ion-content>
|
||||
|
||||
@@ -9,7 +9,7 @@ export class RootPage {
|
||||
isReordering: boolean = false;
|
||||
|
||||
constructor() {
|
||||
let nu = 9;
|
||||
let nu = 5;
|
||||
for (let i = 0; i < nu; i++) {
|
||||
this.items.push(i);
|
||||
}
|
||||
|
||||
@@ -79,8 +79,6 @@ export class LoadingCmp {
|
||||
}
|
||||
|
||||
ionViewDidEnter() {
|
||||
this._plt.focusOutActiveElement();
|
||||
|
||||
// If there is a duration, dismiss after that amount of time
|
||||
if ( this.d && this.d.duration ) {
|
||||
this.durationTimeout = setTimeout(() => this.dismiss('backdrop'), this.d.duration);
|
||||
|
||||
@@ -25,7 +25,7 @@ import { RootNode } from '../split-pane/split-pane';
|
||||
* will be displayed differently based on the mode, however the display type can be changed
|
||||
* to any of the available [menu types](#menu-types). The menu element should be a sibling
|
||||
* to the app's content element. There can be any number of menus attached to the content.
|
||||
* These can be controlled from the templates, or programmatically using the [MenuController](../app/MenuController).
|
||||
* These can be controlled from the templates, or programmatically using the [MenuController](../../app/MenuController).
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Config } from '../../config/config';
|
||||
import { DeepLinker } from '../../navigation/deep-linker';
|
||||
import { DomController } from '../../platform/dom-controller';
|
||||
import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { Keyboard } from '../../platform/keyboard';
|
||||
import { Nav as INav } from '../../navigation/nav-interfaces';
|
||||
import { NavController } from '../../navigation/nav-controller';
|
||||
import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
@@ -66,7 +65,6 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
app: App,
|
||||
config: Config,
|
||||
plt: Platform,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
zone: NgZone,
|
||||
renderer: Renderer,
|
||||
@@ -77,7 +75,7 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
domCtrl: DomController,
|
||||
errHandler: ErrorHandler
|
||||
) {
|
||||
super(parent, app, config, plt, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl, errHandler);
|
||||
super(parent, app, config, plt, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl, errHandler);
|
||||
|
||||
if (viewCtrl) {
|
||||
// an ion-nav can also act as an ion-page within a parent ion-nav
|
||||
@@ -94,10 +92,10 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
this.parent = viewCtrl.getNav();
|
||||
this.parent.registerChildNav(this);
|
||||
|
||||
} else if (app && !app.getRootNav()) {
|
||||
} else if (app && !app.getRootNavById(this.id)) {
|
||||
// a root nav has not been registered yet with the app
|
||||
// this is the root navcontroller for the entire app
|
||||
app._setRootNav(this);
|
||||
app.registerRootNav(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,25 +110,22 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
ngAfterViewInit() {
|
||||
this._hasInit = true;
|
||||
|
||||
let navSegment = this._linker.initNav(this);
|
||||
if (navSegment && (navSegment.component || navSegment.loadChildren)) {
|
||||
// there is a segment match in the linker
|
||||
return this._linker.initViews(navSegment).then(views => {
|
||||
const segment = this._linker.getSegmentByNavId(this.id);
|
||||
|
||||
if (segment && (segment.component || segment.loadChildren)) {
|
||||
return this._linker.initViews(segment).then(views => {
|
||||
this.setPages(views, null, null);
|
||||
});
|
||||
|
||||
} else if (this._root) {
|
||||
// no segment match, so use the root property
|
||||
// no segment match, so use the root property but don't set the url I guess
|
||||
const setUrl = segment ? false : true;
|
||||
return this.push(this._root, this.rootParams, {
|
||||
isNavRoot: (<any>this._app.getRootNav() === this)
|
||||
isNavRoot: (<any>this._app.getRootNavById(this.id) === this),
|
||||
updateUrl: setUrl
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
goToRoot(opts: NavOptions) {
|
||||
return this.setRoot(this._root, this.rootParams, opts, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {Page} The Page component to load as the root page within this nav.
|
||||
*/
|
||||
@@ -169,4 +164,21 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
}
|
||||
}
|
||||
|
||||
goToRoot(opts: NavOptions) {
|
||||
return this.setRoot(this._root, this.rootParams, opts, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* @private
|
||||
*/
|
||||
getType() {
|
||||
return 'nav';
|
||||
}
|
||||
|
||||
/*
|
||||
* @private
|
||||
*/
|
||||
getSecondaryIdentifier(): string {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<ion-split-pane>
|
||||
<ion-nav [root]="rootOne"></ion-nav>
|
||||
<ion-nav [root]="rootTwo" main #content></ion-nav>
|
||||
|
||||
</ion-split-pane>
|
||||
`
|
||||
})
|
||||
export class AppComponent {
|
||||
rootOne = 'NestedNavOnePageTwo';
|
||||
rootTwo = 'NestedNavTwoPageTwo';
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { IonicApp, IonicModule } from '../../../../..';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(AppComponent, { swipeBackEnabled: true, preloadModules: true }),
|
||||
],
|
||||
bootstrap: [IonicApp]
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NestedNavOnePageOne } from './nested-nav-one-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NestedNavOnePageOne)
|
||||
],
|
||||
declarations: [
|
||||
NestedNavOnePageOne
|
||||
]
|
||||
})
|
||||
export class NestedNavOnePageOneModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-nav [root]="root"></ion-nav>
|
||||
`
|
||||
})
|
||||
export class NestedNavOnePageOne {
|
||||
|
||||
root: string = 'NestedNavOnePageTwo';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NestedNavOnePageTwo } from './nested-nav-one-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NestedNavOnePageTwo)
|
||||
],
|
||||
declarations: [
|
||||
NestedNavOnePageTwo
|
||||
]
|
||||
})
|
||||
export class NestedNavOnePageTwoModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-nav [root]="root"></ion-nav>
|
||||
`
|
||||
})
|
||||
export class NestedNavOnePageTwo {
|
||||
|
||||
root: string = 'NonTabOne';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NestedNavTwoPageOne } from './nested-nav-two-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NestedNavTwoPageOne)
|
||||
],
|
||||
declarations: [
|
||||
NestedNavTwoPageOne
|
||||
]
|
||||
})
|
||||
export class NestedNavTwoPageOneModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-nav [root]="root"></ion-nav>
|
||||
`
|
||||
})
|
||||
export class NestedNavTwoPageOne {
|
||||
|
||||
root: string = 'NestedNavTwoPageTwo';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NestedNavTwoPageTwo } from './nested-nav-two-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NestedNavTwoPageTwo)
|
||||
],
|
||||
declarations: [
|
||||
NestedNavTwoPageTwo
|
||||
]
|
||||
})
|
||||
export class NestedNavTwoPageTwoModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-nav [root]="root"></ion-nav>
|
||||
`
|
||||
})
|
||||
export class NestedNavTwoPageTwo {
|
||||
|
||||
root: string = 'NonTabTwo';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NonTabOne } from './non-tab-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NonTabOne)
|
||||
],
|
||||
declarations: [
|
||||
NonTabOne
|
||||
]
|
||||
})
|
||||
export class NonTabOneModule { }
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Nav One</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Nav 1 Page 1
|
||||
<button ion-button (click)="goToTabs()">Go to Tabs 1</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class NonTabOne {
|
||||
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
goToTabs() {
|
||||
this.nav.push('TabsOnePage');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { NonTabTwo } from './non-tab-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(NonTabTwo)
|
||||
],
|
||||
declarations: [
|
||||
NonTabTwo
|
||||
]
|
||||
})
|
||||
export class NonTabTwoModule { }
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Nav Two</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Nav 2 Page 1
|
||||
<button ion-button (click)="goToTabs()">Go to Tabs 2</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class NonTabTwo {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
goToTabs() {
|
||||
this.nav.push('TabsTwoPage');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabOnePageOne } from './tab-one-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabOnePageOne)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabOnePageOne
|
||||
]
|
||||
})
|
||||
export class TabsOneTabOnePageOneModule { }
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabOnePageOne'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 1 Page 1</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 1 Page 1
|
||||
<button ion-button (click)="nextPage()">Go to Next Page</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabOnePageOne {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
nextPage() {
|
||||
this.nav.push('TabsOneTabOnePageTwo', { userId: '123', name: 'Andy Bernard'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabOnePageThree } from './tab-one-page-three';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabOnePageThree)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabOnePageThree
|
||||
]
|
||||
})
|
||||
export class TabsOneTabOnePageThreeModule { }
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabOnePageThree/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 1 Page 3</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 1 Page 3
|
||||
<div>
|
||||
Param One: {{paramOne}}
|
||||
</div>
|
||||
<div>
|
||||
Name: {{paramTwo}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNext()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabOnePageThree {
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.paramOne = navParams.data.paramOne;
|
||||
this.paramTwo = navParams.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabOnePageTwo } from './tab-one-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabOnePageTwo)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabOnePageTwo
|
||||
]
|
||||
})
|
||||
export class TabsOneTabOnePageTwoModule { }
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabOnePageTwo/userId/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 1 Page 2</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 1 Page 2
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name: {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNext()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabOnePageTwo {
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.userId = navParams.data.userId;
|
||||
this.name = navParams.data.name;
|
||||
}
|
||||
|
||||
goToNext() {
|
||||
this.nav.push('TabsOneTabOnePageThree', { paramOne: 'Scranton', paramTwo: 'PA'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabTwoPageOne } from './tab-two-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabTwoPageOne)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabTwoPageOne
|
||||
]
|
||||
})
|
||||
export class TabsOneTabTwoPageOneModule { }
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabTwoPageOne'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 2 Page 1</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 2 Page 1
|
||||
<button ion-button (click)="nextPage()">Go to Next Page</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabTwoPageOne {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
nextPage() {
|
||||
this.nav.push('TabsOneTabTwoPageTwo', { userId: '456', name: 'Stanley Hudson'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabTwoPageThree } from './tab-two-page-three';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabTwoPageThree)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabTwoPageThree
|
||||
]
|
||||
})
|
||||
export class TabsOneTabTwoPageThreeModule { }
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabTwoPageThree/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 2 Page 3</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 2 Page 3
|
||||
<div>
|
||||
Param One: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Param Two: {{name}}
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabTwoPageThree {
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.paramOne = navParams.data.paramOne;
|
||||
this.paramTwo = navParams.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOneTabTwoPageTwo } from './tab-two-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOneTabTwoPageTwo)
|
||||
],
|
||||
declarations: [
|
||||
TabsOneTabTwoPageTwo
|
||||
]
|
||||
})
|
||||
export class TabsOneTabTwoPageTwoModule { }
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOneTabTwoPageTwo/userId/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 1 Tab 2 Page 2</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 1 Tab 2 Page 2
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name: {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNext()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsOneTabTwoPageTwo {
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.userId = navParams.data.userId;
|
||||
this.name = navParams.data.name;
|
||||
}
|
||||
|
||||
goToNext() {
|
||||
this.nav.push('TabsOneTabTwoPageThree', { paramOne: 'Nashua', paramTwo: 'NH'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsOnePage } from './tabs-one-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsOnePage)
|
||||
],
|
||||
declarations: [
|
||||
TabsOnePage
|
||||
]
|
||||
})
|
||||
export class TabsOnePageModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsOnePage'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-tabs>
|
||||
<ion-tab tabIcon="heart" [root]="tabs1Tab1" tabTitle="Heart"></ion-tab>
|
||||
<ion-tab tabIcon="star" [root]="tabs1Tab2" tabTitle="Star"></ion-tab>
|
||||
</ion-tabs>
|
||||
`
|
||||
})
|
||||
export class TabsOnePage {
|
||||
|
||||
tabs1Tab1: string = 'TabsOneTabOnePageOne';
|
||||
tabs1Tab2: string = 'TabsOneTabTwoPageOne';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabOnePageOne } from './tab-one-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabOnePageOne)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabOnePageOne
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabOnePageOneModule { }
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabOnePageOne'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 1 Page 1</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 1 Page 1
|
||||
<button ion-button (click)="nextPage()">Go to Next Page</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabOnePageOne {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
nextPage() {
|
||||
this.nav.push('TabsTwoTabOnePageTwo', { userId: '234', name: 'Phillis Vance - Vance Refridgeration'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabOnePageThree } from './tab-one-page-three';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabOnePageThree)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabOnePageThree
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabOnePageThreeModule { }
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabOnePageThree/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 1 Page 3</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 1 Page 3
|
||||
<div>
|
||||
Param One: {{paramOne}}
|
||||
</div>
|
||||
<div>
|
||||
Param Two: {{paramTwo}}
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabOnePageThree {
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.paramOne = navParams.data.paramOne;
|
||||
this.paramTwo = navParams.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabOnePageTwo } from './tab-one-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabOnePageTwo)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabOnePageTwo
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabOnePageTwoModule { }
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabOnePageTwo/userId/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 1 Page 2</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 1 Page 2
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name: {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNext()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabOnePageTwo {
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.userId = navParams.data.userId;
|
||||
this.name = navParams.data.name;
|
||||
}
|
||||
|
||||
goToNext() {
|
||||
this.nav.push('TabsTwoTabOnePageThree', { paramOne: 'Stamford', paramTwo: 'CT'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabTwoPageOne } from './tab-two-page-one';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabTwoPageOne)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabTwoPageOne
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabTwoPageOneModule { }
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabTwoPageOne'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 2 Page 1</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 2 Page 1
|
||||
<button ion-button (click)="nextPage()">Go to Next Page</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabTwoPageOne {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
nextPage() {
|
||||
this.nav.push('TabsTwoTabTwoPageTwo', { userId: '456', name: 'Michael Scarn'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabTwoPageThree } from './tab-two-page-three';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabTwoPageThree)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabTwoPageThree
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabTwoPageThreeModule { }
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabTwoPageThree/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 2 Page 3</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 2 Page 3
|
||||
<div>
|
||||
Param One: {{paramOne}}
|
||||
</div>
|
||||
<div>
|
||||
Param Two: {{paramTwo}}
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabTwoPageThree {
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.paramOne = navParams.data.paramOne;
|
||||
this.paramTwo = navParams.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoTabTwoPageTwo } from './tab-two-page-two';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoTabTwoPageTwo)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoTabTwoPageTwo
|
||||
]
|
||||
})
|
||||
export class TabsTwoTabTwoPageTwoModule { }
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoTabTwoPageTwo/userId/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Tabs 2 Tab 2 Page 2</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Tabs 2 Tab 2 Page 2
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name: {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="next()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class TabsTwoTabTwoPageTwo {
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, navParams: NavParams) {
|
||||
this.userId = navParams.data.userId;
|
||||
this.name = navParams.data.name;
|
||||
}
|
||||
|
||||
next() {
|
||||
this.nav.push('TabsTwoTabTwoPageThree', { paramOne: 'Albany', paramTwo: 'NY'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { TabsTwoPage } from './tabs-two-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(TabsTwoPage)
|
||||
],
|
||||
declarations: [
|
||||
TabsTwoPage
|
||||
]
|
||||
})
|
||||
export class TabsTwoPageModule { }
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'TabsTwoPage'
|
||||
})
|
||||
@Component({
|
||||
template: `
|
||||
<ion-tabs>
|
||||
<ion-tab tabIcon="aperture" [root]="tabs2Tab1" tabTitle="Aperture"></ion-tab>
|
||||
<ion-tab tabIcon="apps" [root]="tabs2Tab2" tabTitle="Apps"></ion-tab>
|
||||
</ion-tabs>
|
||||
`
|
||||
})
|
||||
export class TabsTwoPage {
|
||||
|
||||
tabs2Tab1: string = 'TabsTwoTabOnePageOne';
|
||||
tabs2Tab2: string = 'TabsTwoTabTwoPageOne';
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
}
|
||||
14
src/components/nav/test/advanced-nav/app/app.component.ts
Normal file
14
src/components/nav/test/advanced-nav/app/app.component.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<ion-split-pane>
|
||||
<ion-nav [root]="root"></ion-nav>
|
||||
<ion-nav [root]="root2" main #content></ion-nav>
|
||||
</ion-split-pane>
|
||||
`
|
||||
})
|
||||
export class AppComponent {
|
||||
root = 'FirstPage';
|
||||
root2 = 'FourthPage';
|
||||
}
|
||||
17
src/components/nav/test/advanced-nav/app/app.module.ts
Normal file
17
src/components/nav/test/advanced-nav/app/app.module.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { IonicApp, IonicModule } from '../../../../..';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(AppComponent, { swipeBackEnabled: true, preloadModules: true }),
|
||||
],
|
||||
bootstrap: [IonicApp]
|
||||
})
|
||||
export class AppModule {}
|
||||
5
src/components/nav/test/advanced-nav/app/main.ts
Normal file
5
src/components/nav/test/advanced-nav/app/main.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
@@ -0,0 +1,9 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page One</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h2>Page One</h2>
|
||||
<button ion-button (click)="goToPageTwo()">Go to Page Two</button>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { FirstPage } from './first-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(FirstPage)
|
||||
],
|
||||
declarations: [
|
||||
FirstPage
|
||||
]
|
||||
})
|
||||
export class FirstPageModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
templateUrl: 'first-page.html'
|
||||
})
|
||||
export class FirstPage {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
goToPageTwo() {
|
||||
this.nav.push('SecondPage', { userId: '123', name: 'Michael Scott'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page Two</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h2>Page Two</h2>
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNextPage()">Go to Next</button>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { SecondPage } from './second-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(SecondPage)
|
||||
],
|
||||
declarations: [
|
||||
SecondPage
|
||||
]
|
||||
})
|
||||
export class SecondPageModule { }
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'pageTwo/user/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
templateUrl: 'second-page.html'
|
||||
})
|
||||
export class SecondPage {
|
||||
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, public params: NavParams) {
|
||||
this.userId = this.params.data.userId;
|
||||
this.name = this.params.data.name;
|
||||
}
|
||||
|
||||
goToNextPage() {
|
||||
this.nav.push('ThirdPage', { paramOne: 'mono', paramTwo: 'stereo'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page Three</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Page Three
|
||||
<div>
|
||||
Param One: {{paramOne}}
|
||||
</div>
|
||||
<div>
|
||||
Param Two: {{paramTwo}}
|
||||
</div>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { ThirdPage } from './third-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(ThirdPage)
|
||||
],
|
||||
declarations: [
|
||||
ThirdPage
|
||||
]
|
||||
})
|
||||
export class ThirdPageModule { }
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams} from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'thirdPage/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
templateUrl: 'third-page.html'
|
||||
})
|
||||
export class ThirdPage {
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, public params: NavParams) {
|
||||
this.paramOne = params.data.paramOne;
|
||||
this.paramTwo = params.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page Five</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h2>Page Five</h2>
|
||||
<div>
|
||||
User ID: {{userId}}
|
||||
</div>
|
||||
<div>
|
||||
Name {{name}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNextPage()">Go to Next</button>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { FifthPage } from './fifth-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(FifthPage)
|
||||
],
|
||||
declarations: [
|
||||
FifthPage
|
||||
]
|
||||
})
|
||||
export class FifthPageModule { }
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'pageFive/user/:userId/name/:name'
|
||||
})
|
||||
@Component({
|
||||
templateUrl: 'fifth-page.html'
|
||||
})
|
||||
export class FifthPage {
|
||||
|
||||
userId: string;
|
||||
name: string;
|
||||
constructor(public nav: NavController, public params: NavParams) {
|
||||
this.userId = this.params.data.userId;
|
||||
this.name = this.params.data.name;
|
||||
}
|
||||
|
||||
goToNextPage() {
|
||||
this.nav.push('SixthPage', { paramOne: 'Tobey', paramTwo: 'Holly'});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user