mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
921ccbb79e | ||
|
|
c08de08d5f | ||
|
|
4199accdc2 | ||
|
|
70ab2a4e74 | ||
|
|
eacc5d4f23 | ||
|
|
112d4f5490 | ||
|
|
f42e81b02b | ||
|
|
9b5c0e035b | ||
|
|
4e56458b5c | ||
|
|
b5bfda2c42 | ||
|
|
200fa935b8 | ||
|
|
66faa1d959 | ||
|
|
b248eb7508 | ||
|
|
c7b2b186ec | ||
|
|
86210750d5 | ||
|
|
794d88d455 | ||
|
|
a48d02a966 | ||
|
|
d028a29d0e | ||
|
|
288c00a641 | ||
|
|
3b5c34c801 | ||
|
|
f2dc8b24b1 | ||
|
|
547ab8d8ef | ||
|
|
e2b3d753a7 | ||
|
|
3fb0371927 | ||
|
|
59f97e780d | ||
|
|
468dcd32fa | ||
|
|
cfd9e3b3a9 | ||
|
|
86e2742d58 | ||
|
|
8c207e827e | ||
|
|
fdacbbf1d0 | ||
|
|
ac04710b8a | ||
|
|
d0cad6b31e | ||
|
|
f5ef1ca552 | ||
|
|
830f885a06 | ||
|
|
318737535f | ||
|
|
04fe92cd58 | ||
|
|
b809665944 | ||
|
|
4d786b30ba | ||
|
|
4f49f27824 | ||
|
|
7e8bd5a8fe | ||
|
|
f4539aacc9 | ||
|
|
4911d9f01a | ||
|
|
6e64b8d915 | ||
|
|
e3216da03e | ||
|
|
bd0c265978 | ||
|
|
846eb09991 | ||
|
|
ac4a043314 | ||
|
|
106950533c | ||
|
|
295fe783b0 | ||
|
|
0a6bb3bb21 | ||
|
|
1b9c3daef1 | ||
|
|
26b09f1d49 | ||
|
|
1e9539b9df | ||
|
|
17b3a39f0d | ||
|
|
475b722c7d | ||
|
|
50beafae6a | ||
|
|
f605f0a74c | ||
|
|
e401997a42 | ||
|
|
16f2ebe241 | ||
|
|
584afd040f | ||
|
|
de0f9d5f28 | ||
|
|
4596dbe5c0 | ||
|
|
400aa549d4 | ||
|
|
add0c4ecfe | ||
|
|
519d657e6e | ||
|
|
a8ceee467b | ||
|
|
97f9522110 | ||
|
|
961bfc3ebb | ||
|
|
5b9fe5e81a | ||
|
|
c4e7552b56 | ||
|
|
cec718c6c7 | ||
|
|
ab511c4744 | ||
|
|
2d49e10da4 | ||
|
|
ce46c24413 | ||
|
|
f7fce5fa16 | ||
|
|
d23b9f7d49 | ||
|
|
4c13535416 | ||
|
|
889b49f372 | ||
|
|
acb6facc7b | ||
|
|
2153940de8 |
30
.github/ISSUE_TEMPLATE.md
vendored
30
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,12 +1,19 @@
|
||||
**Resources:**
|
||||
Before submitting an issue, please consult our troubleshooting guide (http://ionicframework.com/docs/troubleshooting/) and developer resources (http://ionicframework.com/docs/developer-resources/)
|
||||
|
||||
Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Pro services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Pro support portal (http://support.ionicjs.com)
|
||||
|
||||
**Ionic version:** (check one with "x")
|
||||
[ ] **1.x** (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
|
||||
(For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
|
||||
[ ] **2.x**
|
||||
[ ] **3.x**
|
||||
[ ] **4.x**
|
||||
|
||||
**I'm submitting a ...** (check one with "x")
|
||||
[ ] bug report
|
||||
[ ] feature request
|
||||
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
|
||||
|
||||
Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
|
||||
|
||||
**Current behavior:**
|
||||
<!-- Describe how the bug manifests. -->
|
||||
@@ -15,17 +22,22 @@
|
||||
<!-- Describe what the behavior would be without the bug. -->
|
||||
|
||||
**Steps to reproduce:**
|
||||
<!-- If you are able to illustrate the bug or feature request with an example, please provide steps to reproduce and if possible a demo using one of the following templates:
|
||||
|
||||
For Ionic V1 issues - http://plnkr.co/edit/Xo1QyAUx35ny1Xf9ODHx?p=preview
|
||||
|
||||
For Ionic issues - http://plnkr.co/edit/cpeRJs?p=preview
|
||||
-->
|
||||
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
|
||||
|
||||
**Related code:**
|
||||
|
||||
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
|
||||
|
||||
A sample application via GitHub
|
||||
|
||||
StackBlitz (https://stackblitz.com)
|
||||
|
||||
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
|
||||
|
||||
-->
|
||||
|
||||
```
|
||||
insert any relevant code here
|
||||
insert short code snippets here
|
||||
```
|
||||
|
||||
**Other information:**
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@ log.txt
|
||||
*.sublime-workspace
|
||||
|
||||
.idea/
|
||||
.sourcemaps/
|
||||
.vscode/
|
||||
.sass-cache/
|
||||
.versions/
|
||||
|
||||
172
CHANGELOG.md
172
CHANGELOG.md
@@ -1,3 +1,175 @@
|
||||
<a name="3.6.1"></a>
|
||||
## [3.6.1](https://github.com/ionic-team/ionic/compare/v3.6.0...v3.6.1) (2017-09-07)
|
||||
|
||||
### Upgrade Instructions
|
||||
|
||||
`ionic-angular@3.6.1` is a drop-in replacement for 3.6.0. To install it, please run:
|
||||
|
||||
```
|
||||
npm install -g ionic@latest
|
||||
npm install @ionic/app-scripts@2.1.4 --save-dev
|
||||
npm install ionic-angular@3.6.1 --save
|
||||
```
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **generators:** Update documentation URLs for templates ([475b722](https://github.com/ionic-team/ionic/commit/475b722))
|
||||
* **navigation:** check existence of done transition callback ([#12640](https://github.com/ionic-team/ionic/issues/12640)) ([0a6bb3b](https://github.com/ionic-team/ionic/commit/0a6bb3b))
|
||||
* **navigation:** ensure secondaryId always has a string value ([#12641](https://github.com/ionic-team/ionic/issues/12641)) ([1069505](https://github.com/ionic-team/ionic/commit/1069505))
|
||||
* **navigation:** fix popTo signature and make usage uniform ([3187375](https://github.com/ionic-team/ionic/commit/3187375))
|
||||
* **slider:** guard the processing of _slides ([b809665](https://github.com/ionic-team/ionic/commit/b809665)), closes [#12791](https://github.com/ionic-team/ionic/issues/12791)
|
||||
|
||||
|
||||
|
||||
<a name="3.6.0"></a>
|
||||
# [3.6.0](https://github.com/ionic-team/ionic/compare/v3.5.3...v3.6.0) (2017-07-27)
|
||||
|
||||
|
||||
### Upgrade Instructions
|
||||
|
||||
`ionic-angular` 3.6.0 requires developer's to update to the latest version of the `Ionic CLI` and `@ionic/app-scripts`.
|
||||
|
||||
To upgrade, please run
|
||||
|
||||
```
|
||||
npm install -g ionic@latest
|
||||
npm install @ionic/app-scripts@latest --save-dev
|
||||
npm install ionic-angular@latest --save
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
The URL when using deep linking is shortened and improved in this release. Due to a limitation in our nav system, if you're using `ion-tabs` and have a tab name that matches a segment, meaning you have a tab name of `schedule` and a segment of `schedule`, there could potentially be issues. To mitigate these issues, make sure you set the `tabUrlPath` property on the `ion-tab` and give it a unique name. This limitation will require an API change to fix so it will be resolved in `ionic-angular` 4.x.
|
||||
|
||||
|
||||
The upgrades include necessary changes to generators that add back lazy loading functionality, as well as an improved way of generating component/directives/and pipes.
|
||||
|
||||
### New Generators
|
||||
|
||||
The release adds back the functionality to generate lazy loaded pages.
|
||||
To generate a lazy loaded page, run:
|
||||
|
||||
```bash
|
||||
ionic g page <Page-Name>
|
||||
```
|
||||
|
||||
This will include a `.module.ts` file in the page directory created. If you do not want to generate a lazy loaded page, you can run:
|
||||
|
||||
```bash
|
||||
ionic g page <Page-Name> --no-module
|
||||
```
|
||||
|
||||
This will also generate lazy loaded tabs as well, accepting the `--no-module` flag as well to disable it.
|
||||
|
||||
|
||||
For pipes/components/components, we now generate a shared common module for each of these.
|
||||
|
||||
So running:
|
||||
|
||||
```bash
|
||||
ionic g component music-card
|
||||
```
|
||||
|
||||
Will create a `components/components.module.ts` file that declares and exports the `music-card` component.
|
||||
We think that this will allow developers to get up and running with custom components much faster and will less overhead.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **list:** remove margin of MD buttons in ion-item-options ([#12263](https://github.com/ionic-team/ionic/issues/12263)) ([97f9522](https://github.com/ionic-team/ionic/commit/97f9522))
|
||||
* **nav:** make call to setPages return the promise so if it rejects it doesn't get lost ([de0f9d5](https://github.com/ionic-team/ionic/commit/de0f9d5))
|
||||
* **navigation:** account for race conditions in developer's code ([4596dbe](https://github.com/ionic-team/ionic/commit/4596dbe))
|
||||
* **navigation:** fix bug where that occurred when tab identifier and segment had the exact same string ([add0c4e](https://github.com/ionic-team/ionic/commit/add0c4e))
|
||||
* **navigation:** fix null pointer exceptions that would occur when destroying a nav controller while its transitioning ([584afd0](https://github.com/ionic-team/ionic/commit/584afd0))
|
||||
* **navigation:** reduce urls to minimum set of fields ([a8ceee4](https://github.com/ionic-team/ionic/commit/a8ceee4))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **generators:** refactor generators ([400aa54](https://github.com/ionic-team/ionic/commit/400aa54))
|
||||
|
||||
|
||||
|
||||
<a name="3.5.3"></a>
|
||||
## [3.5.3](https://github.com/ionic-team/ionic/compare/v3.5.2...v3.5.3) (2017-07-14)
|
||||
|
||||
## Upgrade Instructions
|
||||
`ionic-angular@3.5.3` is a drop-in replacement for `3.5.2`. To install it, simply run `npm install ionic-angular@3.5.3 --save --save-exact`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **app:** restore getActiveNav api ([2d49e10](https://github.com/ionic-team/ionic/commit/2d49e10))
|
||||
|
||||
|
||||
|
||||
<a name="3.5.2"></a>
|
||||
## [3.5.2](https://github.com/ionic-team/ionic/compare/v3.5.1...v3.5.2) (2017-07-13)
|
||||
|
||||
## Upgrade Instructions
|
||||
`ionic-angular@3.5.2` is a drop-in replacement for `3.5.1`. To install it, simply run `npm install ionic-angular@3.5.2 --save --save-exact`.
|
||||
|
||||
We have released a new version of our build process for `ionic-angular` apps, `@ionic/app-scripts` in conjunction with this release of `ionic-angular`. While it's not a required update, we recommend it because we have greatly improved the developer experience. Incremental, or update builds while developing are much faster now. We've also added `scope hoisting` for better start-up performance on production builds.
|
||||
|
||||
To upgrade to `@ionic/app-scripts`, run the following command:
|
||||
|
||||
```
|
||||
rm -rf node_modules
|
||||
npm install @ionic/app-scripts@2.0.2 --save-dev --save-exact
|
||||
```
|
||||
|
||||
After installing the update, you'll need to make a minor change to the `src/index.html` file to include a new `<script>` tag for `build/vendor.js`. The reason for this breaking change in `@ionic/app-scripts` is for faster builds. By separating out the `node_modules` dependencies into a `vendor.js` file, the incremental build is faster.
|
||||
|
||||
```
|
||||
...
|
||||
<body>
|
||||
|
||||
<!-- Ionic's root component and where the app will load -->
|
||||
<ion-app></ion-app>
|
||||
|
||||
<!-- cordova.js required for cordova apps -->
|
||||
<script src="cordova.js"></script>
|
||||
|
||||
<!-- The polyfills js is generated during the build process -->
|
||||
<script src="build/polyfills.js"></script>
|
||||
|
||||
<!-- The vendor js is generated during the build process
|
||||
and includes all files in the node_modules directory -->
|
||||
<script src="build/vendor.js"></script>
|
||||
|
||||
<!-- The bundle js is generated during the build process -->
|
||||
<script src="build/main.js"></script>
|
||||
|
||||
</body>
|
||||
...
|
||||
```
|
||||
|
||||
If you're customizing `@ionic/app-scripts`, we recommend you review the [changelog](https://github.com/ionic-team/ionic-app-scripts/blob/master/CHANGELOG.md), and update any of your configs accordingly.
|
||||
|
||||
## Notes
|
||||
`3.5.2` is the same as `3.5.1`. We had a small publishing error.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **navigation:** fix swipe-to-go-back ([04e78d8](https://github.com/ionic-team/ionic/commit/04e78d8))
|
||||
* **navigation:** mark as not transitioning on success in addition to '_transitionFinish', provide no ([48b3243](https://github.com/ionic-team/ionic/commit/48b3243))
|
||||
* **navigation:** navs can have n child navs instead of just one ([fce4422](https://github.com/ionic-team/ionic/commit/fce4422))
|
||||
* **navigation:** restore getActiveChildNav method to maintain old API, add deprecation notice ([d22d77b](https://github.com/ionic-team/ionic/commit/d22d77b))
|
||||
* **navigation:** ts2.4 compatibility ([08be9dc](https://github.com/ionic-team/ionic/commit/08be9dc)), closes [#12233](https://github.com/ionic-team/ionic/issues/12233) [#12235](https://github.com/ionic-team/ionic/issues/12235)
|
||||
* **select:** not activated on enter in input field ([ad25cd1](https://github.com/ionic-team/ionic/commit/ad25cd1)), closes [#12202](https://github.com/ionic-team/ionic/issues/12202)
|
||||
* **sliding-item:** ionSwipe event is fired ([#12157](https://github.com/ionic-team/ionic/issues/12157)) ([b5aa304](https://github.com/ionic-team/ionic/commit/b5aa304)), closes [#12146](https://github.com/ionic-team/ionic/issues/12146)
|
||||
* **tabs:** have tabs behavior match nav when navigating back/forth via the url ([3f39e14](https://github.com/ionic-team/ionic/commit/3f39e14))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **navigation:** support for named ion-nav/ion-tabs to improve url in the short term ([486bff0](https://github.com/ionic-team/ionic/commit/486bff0))
|
||||
|
||||
|
||||
<a name="3.5.1"></a>
|
||||
## [3.5.1](https://github.com/ionic-team/ionic/compare/v3.5.0...v3.5.1) (2017-07-13)
|
||||
|
||||
See the [3.5.2](https://github.com/ionic-team/ionic/blob/master/CHANGELOG.md#352-2017-07-13) changelog. We had a publishing error here.
|
||||
|
||||
<a name="3.5.0"></a>
|
||||
# [3.5.0](https://github.com/ionic-team/ionic/compare/v3.4.2...v3.5.0) (2017-06-28)
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -20,4 +20,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -4,6 +4,9 @@ jobs:
|
||||
working_directory: ~/ionic/
|
||||
docker:
|
||||
- image: node:7
|
||||
branches:
|
||||
ignore:
|
||||
- mono-refactor
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
|
||||
@@ -16,7 +16,7 @@ export class PageOne {
|
||||
|
||||
filterItems(ev: any) {
|
||||
this.setItems();
|
||||
let val = ev.value;
|
||||
let val = ev.target.value;
|
||||
|
||||
if (val && val.trim() !== '') {
|
||||
this.items = this.items.filter(function(item) {
|
||||
|
||||
3286
package-lock.json
generated
3286
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "ionic2",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.1",
|
||||
"description": "A powerful framework for building mobile and progressive web apps with JavaScript and Angular",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -26,20 +26,20 @@
|
||||
"tsc": "tsc --outdir .tmp"
|
||||
},
|
||||
"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",
|
||||
"@angular/common": "4.4.3",
|
||||
"@angular/compiler": "4.4.3",
|
||||
"@angular/compiler-cli": "4.4.3",
|
||||
"@angular/core": "4.4.3",
|
||||
"@angular/forms": "4.4.3",
|
||||
"@angular/http": "4.4.3",
|
||||
"@angular/platform-browser": "4.4.3",
|
||||
"@angular/platform-browser-dynamic": "4.4.3",
|
||||
"ionicons": "~3.0.0",
|
||||
"rxjs": "5.4.0",
|
||||
"zone.js": "0.8.12"
|
||||
"rxjs": "5.4.3",
|
||||
"zone.js": "0.8.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/app-scripts": "^1.3.11",
|
||||
"@ionic/app-scripts": "2.1.4-201709271749",
|
||||
"@ionic/commit-hooks": "1.0.3",
|
||||
"@types/connect": "3.4.30",
|
||||
"@types/del": "2.2.31",
|
||||
@@ -52,7 +52,7 @@
|
||||
"@types/lodash": "4.14.35",
|
||||
"@types/merge2": "0.3.29",
|
||||
"@types/mkdirp": "0.3.29",
|
||||
"@types/node": "^6.0.34",
|
||||
"@types/node": "^6.0.88",
|
||||
"@types/protractor": "^4.0.0",
|
||||
"@types/run-sequence": "0.0.28",
|
||||
"@types/semver": "5.3.30",
|
||||
@@ -131,12 +131,11 @@
|
||||
"sw-toolbox": "3.4.0",
|
||||
"systemjs": "0.19.38",
|
||||
"through2": "2.0.1",
|
||||
"ts-node": "1.3.0",
|
||||
"ts-node": "3.3.0",
|
||||
"tslint": "^5.4.3",
|
||||
"tslint-ionic-rules": "0.0.11",
|
||||
"typescript": "~2.3.3",
|
||||
"typescript": "~2.3.2",
|
||||
"vinyl": "1.2.0",
|
||||
"webpack": "^2.1.0-beta.27",
|
||||
"yargs": "5.0.0"
|
||||
},
|
||||
"config": {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<ion-app></ion-app>
|
||||
|
||||
<script src="./build/polyfills.js"></script>
|
||||
<script src="./build/vendor.js"></script>
|
||||
<script src="./build/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -29,6 +29,14 @@ module.exports = function jekyll(renderDocsProcessor) {
|
||||
if (docs[i].href) {
|
||||
docs[i].href = doc.href.replace('content/', '');
|
||||
}
|
||||
if (docs[i].description) {
|
||||
docs[i].description = docs[i].description.replace(/(\#\#\#).+/g, (section) => {
|
||||
const title = section.replace(/^(\#+\s?)/, '');
|
||||
const segment = title.replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase();
|
||||
|
||||
return `\n<h3><a class="anchor" name="${segment}" href="#${segment}">${title}</a></h3>\n`;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
docs.push({
|
||||
|
||||
23
scripts/docs/templates/common.template.html
vendored
23
scripts/docs/templates/common.template.html
vendored
@@ -242,7 +242,7 @@ Improve this doc
|
||||
|
||||
<!-- @usage tag -->
|
||||
<@ if doc.usage @>
|
||||
<h2><a class="anchor" name="usage" href="#usage"></a>Usage</h2>
|
||||
<h2><a class="anchor" name="usage" href="#usage">Usage</a></h2>
|
||||
<@ block usage @>
|
||||
<$ doc.usage | marked $>
|
||||
<@ endblock @>
|
||||
@@ -250,7 +250,7 @@ Improve this doc
|
||||
|
||||
<!-- @property tags -->
|
||||
<@ if doc.properties @>
|
||||
<h2><a class="anchor" name="attributes" href="#attributes"></a>Attributes:</h2>
|
||||
<h2><a class="anchor" name="attributes" href="#attributes">Attributes</a></h2>
|
||||
<table class="table" style="margin:0;">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -293,10 +293,10 @@ Improve this doc
|
||||
|
||||
|
||||
<@- if doc.statics.length -@>
|
||||
<h2><a class="anchor" name="static-members" href="#static-members"></a>Static Members</h2>
|
||||
<h2><a class="anchor" name="static-members" href="#static-members">Static Members</a></h2>
|
||||
<@- for method in doc.statics @><@ if not method.internal @>
|
||||
<div id="<$ method.name $>"></div>
|
||||
<h3><a class="anchor" name="<$ method.name $>" href="#<$ method.name $>"></a><$ functionSyntax(method) $></h3>
|
||||
<h3><a class="anchor" name="<$ method.name $>" href="#<$ method.name $>"><$ functionSyntax(method) $></a></h3>
|
||||
|
||||
<$ method.description $>
|
||||
|
||||
@@ -327,14 +327,15 @@ Improve this doc
|
||||
<!-- instance methods on the class -->
|
||||
<@- if doc.members and doc.members.length @>
|
||||
|
||||
<h2><a class="anchor" name="instance-members" href="#instance-members"></a>Instance Members</h2>
|
||||
<h2><a class="anchor" name="instance-members" href="#instance-members">Instance Members</a></h2>
|
||||
<@- for method in doc.members @>
|
||||
|
||||
<div id="<$ method.name $>"></div>
|
||||
|
||||
<h3>
|
||||
<a class="anchor" name="<$ method.name $>" href="#<$ method.name $>"></a>
|
||||
<a class="anchor" name="<$ method.name $>" href="#<$ method.name $>">
|
||||
<$ functionSyntax(method) $>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<$ method.description $>
|
||||
@@ -366,26 +367,26 @@ Improve this doc
|
||||
|
||||
<@- if doc.inputs and doc.inputs.length @>
|
||||
<!-- input methods on the class -->
|
||||
<h2><a class="anchor" name="input-properties" href="#input-properties"></a>Input Properties</h2>
|
||||
<h2><a class="anchor" name="input-properties" href="#input-properties">Input Properties</a></h2>
|
||||
<$ inputTable(doc.inputs) $>
|
||||
<@- endif -@>
|
||||
|
||||
<@- if doc.outputs and doc.outputs.length @>
|
||||
<!-- output events on the class -->
|
||||
<h2><a class="anchor" name="output-events" href="#output-events"></a>Output Events</h2>
|
||||
<h2><a class="anchor" name="output-events" href="#output-events">Output Events</a></h2>
|
||||
<$ outputTable(doc.outputs) $>
|
||||
<@- endif -@>
|
||||
|
||||
|
||||
<@ block advanced @>
|
||||
<@- if doc.advanced -@>
|
||||
<h2><a class="anchor" name="advanced" href="#advanced"></a>Advanced</h2>
|
||||
<h2><a class="anchor" name="advanced" href="#advanced">Advanced</a></h2>
|
||||
<$ doc.advanced | marked $>
|
||||
<@- endif -@>
|
||||
<@ endblock @>
|
||||
|
||||
<@ if doc.sassVariables @>
|
||||
<h2 id="sass-variable-header"><a class="anchor" name="sass-variables" href="#sass-variables"></a>Sass Variables</h2>
|
||||
<h2 id="sass-variable-header"><a class="anchor" name="sass-variables" href="#sass-variables">Sass Variables</a></h2>
|
||||
<$ sassTable(doc.sassVariables) $>
|
||||
<@ endif @>
|
||||
|
||||
@@ -393,7 +394,7 @@ Improve this doc
|
||||
<!-- related link -->
|
||||
<@- if doc.see @>
|
||||
|
||||
<h2><a class="anchor" name="related" href="#related"></a>Related</h2>
|
||||
<h2><a class="anchor" name="related" href="#related">Related</a></h2>
|
||||
<@ for s in doc.see @>
|
||||
<$ s | safe $> <@- if not loop.last @>,<@- endif -@>
|
||||
<@- endfor -@>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
}
|
||||
</script>
|
||||
<script src="./build/polyfills.ng.js"></script>
|
||||
<script src="./build/vendor.js"></script>
|
||||
<script src="./build/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -59,9 +59,9 @@ function getDemosEntryPoints() {
|
||||
|
||||
|
||||
function buildDemos(filePaths: string[]) {
|
||||
var batches = chunkArrayInGroups(filePaths, argv.batches || 1);
|
||||
var batch = argv.batch || 0;
|
||||
if(batch >= batches.length) {
|
||||
const batches = chunkArrayInGroups(filePaths, argv.batches || 1);
|
||||
const batch = argv.batch || 0;
|
||||
if (batch >= batches.length) {
|
||||
throw new Error(`Batch number higher than total number of batches.`);
|
||||
}
|
||||
|
||||
@@ -100,13 +100,13 @@ function buildDemo(filePath: string) {
|
||||
const distDir = join(distTestRoot, 'www');
|
||||
|
||||
return runAppScriptsBuild(
|
||||
appEntryPoint,
|
||||
appNgModulePath,
|
||||
ionicAngularDir,
|
||||
distDir,
|
||||
pathToWriteFile,
|
||||
ionicAngularDir,
|
||||
sassConfigPath,
|
||||
appEntryPoint,
|
||||
appNgModulePath,
|
||||
ionicAngularDir,
|
||||
distDir,
|
||||
pathToWriteFile,
|
||||
ionicAngularDir,
|
||||
sassConfigPath,
|
||||
copyConfigPath
|
||||
).then(() => {
|
||||
const end = Date.now();
|
||||
@@ -116,8 +116,8 @@ function buildDemo(filePath: string) {
|
||||
}
|
||||
|
||||
function chunkArrayInGroups(arr, size) {
|
||||
var result = [];
|
||||
for(var i = 0; i < arr.length; i++) {
|
||||
const result = [];
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (!Array.isArray(result[i % size])) {
|
||||
result[i % size] = [];
|
||||
}
|
||||
@@ -129,7 +129,7 @@ function chunkArrayInGroups(arr, size) {
|
||||
function uploadToS3(path) {
|
||||
// fail silently if envars not present
|
||||
if (!process.env.AWS_KEY || !process.env.AWS_SECRET) {
|
||||
return new Promise((resolve) => {resolve();});
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let client = s3.createClient({
|
||||
@@ -143,23 +143,23 @@ function uploadToS3(path) {
|
||||
let demo = path.split('/')[path.split('/').length - 2];
|
||||
|
||||
let params = {
|
||||
localDir: path.replace('tsconfig.json',''),
|
||||
deleteRemoved: true,
|
||||
localDir: path.replace('tsconfig.json', ''),
|
||||
deleteRemoved: true,
|
||||
s3Params: {
|
||||
Bucket: "ionic-demos",
|
||||
Bucket: 'ionic-demos',
|
||||
Prefix: demo,
|
||||
},
|
||||
};
|
||||
|
||||
var uploader = client.uploadDir(params);
|
||||
const uploader = client.uploadDir(params);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uploader.on('error', function(err) {
|
||||
console.error("s3 Upload Error:", err.stack);
|
||||
console.error('s3 Upload Error:', err.stack);
|
||||
reject();
|
||||
});
|
||||
uploader.on('end', function() {
|
||||
console.log(demo, " demo uploaded to s3");
|
||||
console.log(demo, ' demo uploaded to s3');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
@@ -167,7 +167,7 @@ function uploadToS3(path) {
|
||||
|
||||
task('demos.download', (done: Function) => {
|
||||
if (!process.env.AWS_KEY || !process.env.AWS_SECRET) {
|
||||
return new Promise((resolve) => {resolve();});
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let client = s3.createClient({
|
||||
@@ -180,23 +180,23 @@ task('demos.download', (done: Function) => {
|
||||
let params = {
|
||||
localDir: join(process.cwd(), 'dist', 'demos', 'src'),
|
||||
s3Params: {
|
||||
Bucket: "ionic-demos",
|
||||
Bucket: 'ionic-demos',
|
||||
},
|
||||
};
|
||||
|
||||
let uploader = client.downloadDir(params);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uploader.on('error', function(err) {
|
||||
console.error("s3 Download Error:", err.stack);
|
||||
console.error('s3 Download Error:', err.stack);
|
||||
reject();
|
||||
});
|
||||
uploader.on('end', function() {
|
||||
console.log("Demos downloaded from s3");
|
||||
console.log('Demos downloaded from s3');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
task('demos.clean', (done: Function) => {
|
||||
// this is a super hack, but it works for now
|
||||
|
||||
@@ -22,34 +22,10 @@ task('demos.polyfill', (done: Function) => {
|
||||
});
|
||||
});
|
||||
|
||||
task('demos.copyAndCompile', (done: (err: any) => void) => {
|
||||
runSequence(
|
||||
'demos.copySource',
|
||||
'demos.compileTests',
|
||||
'demos.bundle',
|
||||
done);
|
||||
});
|
||||
|
||||
task('demos.copyExternalDependencies', () => {
|
||||
src([`${SCRIPTS_ROOT}/${DEMOS_NAME}/*.css`]).pipe(dest(`${DIST_DEMOS_ROOT}/css`));
|
||||
});
|
||||
|
||||
task('demos.sass', () => {
|
||||
// ensure there is a version.scss file
|
||||
setSassIonicVersion(`E2E-${createTimestamp()}`);
|
||||
return compileSass(`${DIST_DEMOS_ROOT}/css`);
|
||||
});
|
||||
|
||||
task('demos.fonts', () => {
|
||||
return copyFonts(`${DIST_DEMOS_ROOT}/fonts`);
|
||||
});
|
||||
|
||||
task('demos.serve', function() {
|
||||
connect.server({
|
||||
root: './',
|
||||
port: LOCAL_SERVER_PORT,
|
||||
livereload: {
|
||||
port: 35700
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { task, src, dest } from 'gulp';
|
||||
import { writePolyfills } from '../util';
|
||||
import { dest, src, task } from 'gulp';
|
||||
import { readFileAsync, writeFileAsync, writePolyfills } from '../util';
|
||||
import { join } from 'path';
|
||||
|
||||
task('polyfill', ['polyfill.copy-readme', 'polyfill.write']);
|
||||
@@ -13,6 +13,9 @@ task('polyfill.write', (done: Function) => {
|
||||
});
|
||||
|
||||
task('polyfill.copy-readme', (done: Function) => {
|
||||
return src(join('scripts', 'polyfill', 'readme.md'))
|
||||
.pipe(dest(join('dist', 'ionic-angular', 'polyfills')), done);
|
||||
return readFileAsync(join('scripts', 'polyfill', 'readme.md')).then((fileContent: string) => {
|
||||
return writeFileAsync(join('dist', 'ionic-angular', 'polyfills', 'readme.md'), fileContent);
|
||||
}).then(() => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -325,7 +325,7 @@ export function writePolyfills(outputDirectory: string) {
|
||||
promises.push(bundlePolyfill(NG_ENTRIES, join(outputDirectory, 'polyfills.ng.js')));
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
||||
}
|
||||
|
||||
function bundlePolyfill(pathsToIncludeInPolyfill: string[], outputPath: string) {
|
||||
return rollup({
|
||||
|
||||
@@ -46,7 +46,7 @@ export function config(config) {
|
||||
'dist/ionic-angular/umd/**/!(*spec).js': ['coverage'],
|
||||
'dist/ionic-angular/**/*.js': ['sourcemap']
|
||||
},
|
||||
reporters: ['dots', 'coverage', 'spec'],
|
||||
reporters: ['coverage', 'spec'],
|
||||
specReporter: {
|
||||
maxLogLines: 5, // limit number of lines logged per test
|
||||
suppressErrorSummary: true, // do not print error summary
|
||||
|
||||
@@ -3,8 +3,8 @@ import { Component } from '@angular/core';
|
||||
/**
|
||||
* Generated class for the $CLASSNAME component.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
|
||||
* for more info on Angular Components.
|
||||
* See https://angular.io/api/core/Component for more info on Angular
|
||||
* Components.
|
||||
*/
|
||||
@Component({
|
||||
selector: '$FILENAME',
|
||||
|
||||
@@ -3,8 +3,8 @@ import { Directive } from '@angular/core';
|
||||
/**
|
||||
* Generated class for the $CLASSNAME directive.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/api/core/index/DirectiveMetadata-class.html
|
||||
* for more info on Angular Directives.
|
||||
* See https://angular.io/api/core/Directive for more info on Angular
|
||||
* Directives.
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[$FILENAME]' // Attribute selector
|
||||
|
||||
@@ -9,8 +9,5 @@ import { $CLASSNAME } from './$FILENAME';
|
||||
imports: [
|
||||
IonicPageModule.forChild($CLASSNAME),
|
||||
],
|
||||
exports: [
|
||||
$CLASSNAME
|
||||
]
|
||||
})
|
||||
export class $CLASSNAMEModule {}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NavController, NavParams } from 'ionic-angular';
|
||||
$IMPORTSTATEMENT
|
||||
|
||||
/**
|
||||
* Generated class for the $CLASSNAME page.
|
||||
*
|
||||
* See http://ionicframework.com/docs/components/#navigation for more info
|
||||
* on Ionic pages and navigation.
|
||||
* See https://ionicframework.com/docs/components/#navigation for more info on
|
||||
* Ionic pages and navigation.
|
||||
*/
|
||||
|
||||
$IONICPAGE
|
||||
@Component({
|
||||
selector: 'page-$FILENAME',
|
||||
templateUrl: '$FILENAME.html',
|
||||
|
||||
@@ -3,11 +3,10 @@ import { Pipe, PipeTransform } from '@angular/core';
|
||||
/**
|
||||
* Generated class for the $CLASSNAME pipe.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/guide/pipes.html for more info on
|
||||
* Angular Pipes.
|
||||
* See https://angular.io/api/core/Pipe for more info on Angular Pipes.
|
||||
*/
|
||||
@Pipe({
|
||||
name: '$FILENAME',
|
||||
name: '$PIPENAME',
|
||||
})
|
||||
export class $CLASSNAME implements PipeTransform {
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,8 @@ import 'rxjs/add/operator/map';
|
||||
/*
|
||||
Generated class for the $CLASSNAME provider.
|
||||
|
||||
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
|
||||
for more info on providers and Angular DI.
|
||||
See https://angular.io/guide/dependency-injection for more info on providers
|
||||
and Angular DI.
|
||||
*/
|
||||
@Injectable()
|
||||
export class $CLASSNAME {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NavController } from 'ionic-angular';
|
||||
$TABS_IMPORTSTATEMENT
|
||||
|
||||
/**
|
||||
* Generated class for the $CLASSNAME tabs.
|
||||
*
|
||||
* See https://angular.io/docs/ts/latest/guide/dependency-injection.html for
|
||||
* more info on providers and Angular DI.
|
||||
* See https://ionicframework.com/docs/components/#navigation for more info on
|
||||
* Ionic pages and navigation.
|
||||
*/
|
||||
$IONICPAGE
|
||||
@Component({
|
||||
selector: 'page-$FILENAME',
|
||||
templateUrl: '$FILENAME.html'
|
||||
|
||||
@@ -39,10 +39,10 @@ import { Config } from '../../config/config';
|
||||
*
|
||||
* export class MyClass{
|
||||
*
|
||||
* constructor(public actionSheetCtrl: ActionSheetController) {}
|
||||
* constructor(public actionSheetCtrl: ActionSheetController) { }
|
||||
*
|
||||
* presentActionSheet() {
|
||||
* let actionSheet = this.actionSheetCtrl.create({
|
||||
* const actionSheet = this.actionSheetCtrl.create({
|
||||
* title: 'Modify your album',
|
||||
* buttons: [
|
||||
* {
|
||||
@@ -115,7 +115,7 @@ import { Config } from '../../config/config';
|
||||
* out first, *then* start the next transition.
|
||||
*
|
||||
* ```ts
|
||||
* let actionSheet = this.actionSheetCtrl.create({
|
||||
* const actionSheet = this.actionSheetCtrl.create({
|
||||
* title: 'Hello',
|
||||
* buttons: [{
|
||||
* text: 'Ok',
|
||||
|
||||
@@ -89,6 +89,10 @@ $action-sheet-ios-button-cancel-font-weight: 600 !default;
|
||||
@include text-align($action-sheet-ios-text-align);
|
||||
}
|
||||
|
||||
.action-sheet-ios .action-sheet-wrapper {
|
||||
@include margin(auto, auto, constant(safe-area-inset-bottom), auto);
|
||||
}
|
||||
|
||||
.action-sheet-ios .action-sheet-container {
|
||||
@include deprecated-variable(padding, $action-sheet-ios-padding) {
|
||||
@include padding($action-sheet-ios-padding-top, $action-sheet-ios-padding-end, $action-sheet-ios-padding-bottom, $action-sheet-ios-padding-start);
|
||||
|
||||
@@ -51,12 +51,10 @@ import { Config } from '../../config/config';
|
||||
* ```ts
|
||||
* import { AlertController } from 'ionic-angular';
|
||||
*
|
||||
* constructor(private alertCtrl: AlertController) {
|
||||
*
|
||||
* }
|
||||
* constructor(public alertCtrl: AlertController) { }
|
||||
*
|
||||
* presentAlert() {
|
||||
* let alert = this.alertCtrl.create({
|
||||
* const alert = this.alertCtrl.create({
|
||||
* title: 'Low battery',
|
||||
* subTitle: '10% of battery remaining',
|
||||
* buttons: ['Dismiss']
|
||||
@@ -65,7 +63,7 @@ import { Config } from '../../config/config';
|
||||
* }
|
||||
*
|
||||
* presentConfirm() {
|
||||
* let alert = this.alertCtrl.create({
|
||||
* const alert = this.alertCtrl.create({
|
||||
* title: 'Confirm purchase',
|
||||
* message: 'Do you want to buy this book?',
|
||||
* buttons: [
|
||||
@@ -88,7 +86,7 @@ import { Config } from '../../config/config';
|
||||
* }
|
||||
*
|
||||
* presentPrompt() {
|
||||
* let alert = this.alertCtrl.create({
|
||||
* const alert = this.alertCtrl.create({
|
||||
* title: 'Login',
|
||||
* inputs: [
|
||||
* {
|
||||
@@ -181,14 +179,14 @@ import { Config } from '../../config/config';
|
||||
* out first, *then* start the next transition.
|
||||
*
|
||||
* ```ts
|
||||
* let alert = this.alertCtrl.create({
|
||||
* const alert = this.alertCtrl.create({
|
||||
* title: 'Hello',
|
||||
* buttons: [{
|
||||
* text: 'Ok',
|
||||
* handler: () => {
|
||||
* // user has clicked the alert button
|
||||
* // begin the alert's dismiss transition
|
||||
* let navTransition = alert.dismiss();
|
||||
* const navTransition = alert.dismiss();
|
||||
*
|
||||
* // start some async method
|
||||
* someAsyncOperation().then(() => {
|
||||
|
||||
@@ -206,9 +206,21 @@ 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()`
|
||||
* @return {NavController} Returns the first Active Nav Controller from the list. This method is deprecated
|
||||
*/
|
||||
getActiveNavs(navId?: string): NavControllerBase[] {
|
||||
getActiveNav(): NavControllerBase {
|
||||
console.warn('(getActiveNav) is deprecated and will be removed in the next major release. Use getActiveNavs instead.');
|
||||
const navs = this.getActiveNavs();
|
||||
if (navs && navs.length) {
|
||||
return navs[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {NavController[]} Returns the active NavControllers. Using this method is preferred when we need access to the top-level navigation controller while on the outside views and handlers like `registerBackButtonAction()`
|
||||
*/
|
||||
getActiveNavs(rootNavId?: string): NavControllerBase[] {
|
||||
const portal = this._appRoot._getPortal(Constants.PORTAL_MODAL);
|
||||
if (portal.length() > 0) {
|
||||
return <NavControllerBase[]> findTopNavs(portal);
|
||||
@@ -219,7 +231,16 @@ export class App {
|
||||
if (this._rootNavs.size === 1) {
|
||||
return <NavControllerBase[]> findTopNavs(this._rootNavs.values().next().value);
|
||||
}
|
||||
return <NavControllerBase[]> findTopNavs(this.getRootNavById(navId));
|
||||
if (rootNavId) {
|
||||
return <NavControllerBase[]> findTopNavs(this._rootNavs.get(rootNavId));
|
||||
}
|
||||
// fallback to just using all root names
|
||||
let activeNavs: NavigationContainer[] = [];
|
||||
this._rootNavs.forEach(nav => {
|
||||
const topNavs = findTopNavs(nav);
|
||||
activeNavs = activeNavs.concat(topNavs);
|
||||
});
|
||||
return <NavControllerBase[]> activeNavs;
|
||||
}
|
||||
|
||||
getRootNav(): any {
|
||||
@@ -398,8 +419,31 @@ export class App {
|
||||
}
|
||||
}
|
||||
|
||||
getNavByIdOrName(id: string) {
|
||||
const navs = Array.from(this._rootNavs.values());
|
||||
for (const navContainer of navs) {
|
||||
const match = getNavByIdOrName(navContainer, id);
|
||||
if (match) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getNavByIdOrName(nav: NavigationContainer, id: string): NavigationContainer {
|
||||
if (nav.id === id || nav.name === id) {
|
||||
return nav;
|
||||
}
|
||||
for (const child of nav.getAllChildNavs()) {
|
||||
const tmp = getNavByIdOrName(child, id);
|
||||
if (tmp) {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPoppableNav(nav: NavControllerBase): NavControllerBase {
|
||||
if (!nav) {
|
||||
@@ -434,6 +478,7 @@ export function findTopNavs(nav: NavigationContainer): NavigationContainer[] {
|
||||
return containers;
|
||||
}
|
||||
|
||||
|
||||
const SKIP_BLURRING = ['INPUT', 'TEXTAREA', 'ION-INPUT', 'ION-TEXTAREA'];
|
||||
const ACTIVE_SCROLLING_TIME = 100;
|
||||
const CLICK_BLOCK_BUFFER_IN_MILLIS = 64;
|
||||
|
||||
@@ -312,7 +312,7 @@ describe('App', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActiveNav', () => {
|
||||
describe('getActiveNavs', () => {
|
||||
|
||||
it('should get active NavController when using tabs with nested nav', () => {
|
||||
const nav = mockNavController();
|
||||
@@ -340,6 +340,11 @@ describe('App', () => {
|
||||
expect(activeNavs.length).toEqual(2);
|
||||
expect(activeNavs[0]).toEqual(nav2);
|
||||
expect(activeNavs[1]).toEqual(nav3);
|
||||
|
||||
const activeNavsTwo = app.getActiveNavs();
|
||||
expect(activeNavsTwo.length).toEqual(2);
|
||||
expect(activeNavsTwo[0]).toEqual(nav2);
|
||||
expect(activeNavsTwo[1]).toEqual(nav3);
|
||||
});
|
||||
|
||||
it('should get active NavController when using tabs, nested in a root nav', () => {
|
||||
@@ -355,10 +360,12 @@ describe('App', () => {
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNavs(nav.id)[0]).toBe(tab2);
|
||||
expect(app.getActiveNavs()[0]).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNavs(nav.id)[0]).toBe(tab3);
|
||||
expect(app.getActiveNavs()[0]).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active tab NavController when using tabs, and tabs is the root', () => {
|
||||
@@ -371,10 +378,12 @@ describe('App', () => {
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNavs(tabs.id)[0]).toBe(tab2);
|
||||
expect(app.getActiveNavs()[0]).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNavs(tabs.id)[0]).toBe(tab3);
|
||||
expect(app.getActiveNavs()[0]).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 3 deep', () => {
|
||||
@@ -387,6 +396,8 @@ describe('App', () => {
|
||||
nav2.registerChildNav(nav3);
|
||||
|
||||
expect(app.getActiveNavs(nav1.id)[0]).toBe(nav3);
|
||||
expect(app.getActiveNavs()[0]).toBe(nav3);
|
||||
expect(app.getActiveNavs().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 2 deep', () => {
|
||||
@@ -399,12 +410,15 @@ describe('App', () => {
|
||||
const activeNav = app.getActiveNavs(nav1.id)[0];
|
||||
|
||||
expect(activeNav).toBe(nav2);
|
||||
|
||||
expect(app.getActiveNavs()[0]).toBe(nav2);
|
||||
});
|
||||
|
||||
it('should get active NavController when only one nav controller', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
expect(app.getActiveNavs(nav.id)[0]).toBe(nav);
|
||||
expect(app.getActiveNavs()[0]).toBe(nav);
|
||||
});
|
||||
|
||||
it('should set/get the root nav controller', () => {
|
||||
@@ -414,9 +428,9 @@ describe('App', () => {
|
||||
});
|
||||
|
||||
it('should not get an active NavController if there is not root set', () => {
|
||||
const activeNav = app.getActiveNavs('');
|
||||
const activeNavs = app.getActiveNavs();
|
||||
const rootNav = app.getRootNavById('');
|
||||
expect(activeNav.length).toEqual(0);
|
||||
expect(activeNavs.length).toEqual(0);
|
||||
expect(rootNav).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -438,6 +452,9 @@ describe('App', () => {
|
||||
|
||||
expect(activeNavOne).toBe(childNavOne);
|
||||
expect(activeNavTwo).toBe(childNavTwo);
|
||||
|
||||
expect(app.getActiveNavs()[0]).toBe(childNavOne);
|
||||
expect(app.getActiveNavs()[1]).toBe(childNavTwo);
|
||||
});
|
||||
|
||||
it('should get the active nav when no id is provided assuming there is one nav', () => {
|
||||
@@ -451,6 +468,167 @@ describe('App', () => {
|
||||
|
||||
expect(result).toEqual(childNavOne);
|
||||
});
|
||||
|
||||
it('should return the all the active navs when there is not an id passed', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
|
||||
const rootNavTwo = mockNavController();
|
||||
app.registerRootNav(rootNavTwo);
|
||||
|
||||
const childNavOne = mockNavController();
|
||||
rootNavOne.registerChildNav(childNavOne);
|
||||
|
||||
const childChildNavOne = mockNavController();
|
||||
childNavOne.registerChildNav(childChildNavOne);
|
||||
|
||||
const childNavTwo = mockNavController();
|
||||
rootNavTwo.registerChildNav(childNavTwo);
|
||||
|
||||
const childChildNavTwo = mockNavController();
|
||||
childNavTwo.registerChildNav(childChildNavTwo);
|
||||
|
||||
const results = app.getActiveNavs();
|
||||
expect(results.length).toEqual(2);
|
||||
expect(results[0]).toEqual(childChildNavOne);
|
||||
expect(results[1]).toEqual(childChildNavTwo);
|
||||
|
||||
const withIdResultsOne = app.getActiveNavs(rootNavOne.id);
|
||||
expect(withIdResultsOne.length).toEqual(1);
|
||||
expect(withIdResultsOne[0]).toEqual(childChildNavOne);
|
||||
|
||||
const withIdResultsTwo = app.getActiveNavs(rootNavTwo.id);
|
||||
expect(withIdResultsTwo.length).toEqual(1);
|
||||
expect(withIdResultsTwo[0]).toEqual(childChildNavTwo);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActiveNav', () => {
|
||||
it('should get active NavController when using tabs with nested nav', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
const tabs = mockTabs();
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
nav.registerChildNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
const nav2 = mockNavController();
|
||||
nav2.name = 'nav2';
|
||||
const nav3 = mockNavController();
|
||||
nav3.name = 'nav3';
|
||||
const nav4 = mockNavController();
|
||||
nav4.name = 'nav4';
|
||||
|
||||
tab1.registerChildNav(nav4);
|
||||
// tab 2 registers two child navs!!
|
||||
tab2.registerChildNav(nav2);
|
||||
tab2.registerChildNav(nav3);
|
||||
|
||||
const activeNav = app.getActiveNav();
|
||||
expect(activeNav).toEqual(nav2);
|
||||
});
|
||||
|
||||
it('should get active NavController when using tabs, nested in a root nav', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
const tab3 = mockTab(tabs);
|
||||
nav.registerChildNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNav()).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNav()).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active tab NavController when using tabs, and tabs is the root', () => {
|
||||
const tabs = mockTabs();
|
||||
mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
const tab3 = mockTab(tabs);
|
||||
app.registerRootNav(tabs);
|
||||
|
||||
tab2.setSelected(true);
|
||||
|
||||
expect(app.getActiveNav()).toBe(tab2);
|
||||
|
||||
tab2.setSelected(false);
|
||||
tab3.setSelected(true);
|
||||
expect(app.getActiveNav()).toBe(tab3);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 3 deep', () => {
|
||||
const nav1 = mockNavController();
|
||||
const nav2 = mockNavController();
|
||||
const nav3 = mockNavController();
|
||||
app.registerRootNav(nav1);
|
||||
|
||||
nav1.registerChildNav(nav2);
|
||||
nav2.registerChildNav(nav3);
|
||||
|
||||
expect(app.getActiveNav()).toBe(nav3);
|
||||
});
|
||||
|
||||
it('should get active NavController when nested 2 deep', () => {
|
||||
const nav1 = mockNavController();
|
||||
const nav2 = mockNavController();
|
||||
app.registerRootNav(nav1);
|
||||
|
||||
nav1.registerChildNav(nav2);
|
||||
|
||||
const activeNav = app.getActiveNav();
|
||||
|
||||
expect(activeNav).toBe(nav2);
|
||||
});
|
||||
|
||||
it('should get active NavController when only one nav controller', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
expect(app.getActiveNav()).toBe(nav);
|
||||
});
|
||||
|
||||
it('should not get an active NavController if there is not root set', () => {
|
||||
const activeNav = app.getActiveNav();
|
||||
expect(activeNav).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();
|
||||
|
||||
expect(activeNavOne).toBe(childNavOne);
|
||||
});
|
||||
|
||||
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', () => {
|
||||
@@ -589,6 +767,149 @@ describe('App', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNavByIdOrName', () => {
|
||||
it('should return a basic root nav', () => {
|
||||
const nav = mockNavController();
|
||||
app.registerRootNav(nav);
|
||||
const result = app.getNavByIdOrName(nav.id);
|
||||
expect(result).toEqual(nav);
|
||||
});
|
||||
|
||||
it('should return a child nav', () => {
|
||||
const rootNav = mockNavController();
|
||||
app.registerRootNav(rootNav);
|
||||
|
||||
const childNav = mockNavController();
|
||||
childNav.parent = rootNav;
|
||||
rootNav.registerChildNav(childNav);
|
||||
|
||||
const childChildNav = mockNavController();
|
||||
childChildNav.parent = childNav;
|
||||
childNav.registerChildNav(childChildNav);
|
||||
|
||||
|
||||
const expectedChildNav = app.getNavByIdOrName(childNav.id);
|
||||
expect(expectedChildNav).toEqual(childNav);
|
||||
|
||||
const expectedChildChildNav = app.getNavByIdOrName(childChildNav.id);
|
||||
expect(expectedChildChildNav).toEqual(childChildNav);
|
||||
});
|
||||
|
||||
it('should return a child nav when there is a tabs in there', () => {
|
||||
const rootNav = mockNavController();
|
||||
app.registerRootNav(rootNav);
|
||||
|
||||
const tabs = mockTabs();
|
||||
tabs.parent = rootNav;
|
||||
rootNav.registerChildNav(tabs);
|
||||
|
||||
const tab1 = mockTab(tabs);
|
||||
const tab2 = mockTab(tabs);
|
||||
const tab3 = mockTab(tabs);
|
||||
|
||||
const tabChildNav = mockNavController();
|
||||
tabChildNav.parent = tab2;
|
||||
tab2.registerChildNav(tabChildNav);
|
||||
|
||||
const tabChildChildNav = mockNavController();
|
||||
tabChildChildNav.parent = tabChildNav;
|
||||
tabChildNav.registerChildNav(tabChildChildNav);
|
||||
|
||||
const expectedTab1 = app.getNavByIdOrName(tab1.id);
|
||||
expect(expectedTab1).toEqual(tab1);
|
||||
|
||||
const expectedTab2 = app.getNavByIdOrName(tab2.id);
|
||||
expect(expectedTab2).toEqual(tab2);
|
||||
|
||||
const expectedTab3 = app.getNavByIdOrName(tab3.id);
|
||||
expect(expectedTab3).toEqual(tab3);
|
||||
|
||||
const expectedTabChildNav = app.getNavByIdOrName(tabChildNav.id);
|
||||
expect(expectedTabChildNav).toEqual(tabChildNav);
|
||||
|
||||
const expectedTabChildChildNav = app.getNavByIdOrName(tabChildChildNav.id);
|
||||
expect(expectedTabChildChildNav).toEqual(tabChildChildNav);
|
||||
});
|
||||
|
||||
it('should return a basic root nav when the are multiple root navs', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
const rootNavTwo = mockNavController();
|
||||
const rootNavThree = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
app.registerRootNav(rootNavTwo);
|
||||
app.registerRootNav(rootNavThree);
|
||||
|
||||
const expectedRootNavOne = app.getNavByIdOrName(rootNavOne.id);
|
||||
expect(expectedRootNavOne).toEqual(rootNavOne);
|
||||
|
||||
const expectedRootNavTwo = app.getNavByIdOrName(rootNavTwo.id);
|
||||
expect(expectedRootNavTwo).toEqual(rootNavTwo);
|
||||
|
||||
const expectedRootNavThree = app.getNavByIdOrName(rootNavThree.id);
|
||||
expect(expectedRootNavThree).toEqual(rootNavThree);
|
||||
});
|
||||
|
||||
it('should return a proper navs when there are multiple root navs with nested navs', () => {
|
||||
const rootNavOne = mockNavController();
|
||||
const rootNavTwo = mockNavController();
|
||||
const rootNavThree = mockNavController();
|
||||
app.registerRootNav(rootNavOne);
|
||||
app.registerRootNav(rootNavTwo);
|
||||
app.registerRootNav(rootNavThree);
|
||||
|
||||
const childNavOne = mockNavController();
|
||||
childNavOne.parent = rootNavOne;
|
||||
rootNavOne.registerChildNav(childNavOne);
|
||||
|
||||
const childChildNavOne = mockNavController();
|
||||
childChildNavOne.parent = childNavOne;
|
||||
childNavOne.registerChildNav(childChildNavOne);
|
||||
|
||||
const childNavTwo = mockNavController();
|
||||
childNavOne.parent = rootNavTwo;
|
||||
rootNavTwo.registerChildNav(childNavTwo);
|
||||
|
||||
const childChildNavTwo = mockNavController();
|
||||
childChildNavTwo.parent = childNavTwo;
|
||||
childNavTwo.registerChildNav(childChildNavTwo);
|
||||
|
||||
const childNavThree = mockNavController();
|
||||
childNavThree.parent = rootNavThree;
|
||||
rootNavThree.registerChildNav(childNavThree);
|
||||
|
||||
const childChildNavThree = mockNavController();
|
||||
childChildNavThree.parent = childNavThree;
|
||||
childNavThree.registerChildNav(childChildNavThree);
|
||||
|
||||
const expectedRootNavOne = app.getNavByIdOrName(rootNavOne.id);
|
||||
expect(expectedRootNavOne).toEqual(rootNavOne);
|
||||
|
||||
const expectedChildNavOne = app.getNavByIdOrName(childNavOne.id);
|
||||
expect(expectedChildNavOne).toEqual(childNavOne);
|
||||
|
||||
const expectedChildChildNavOne = app.getNavByIdOrName(childChildNavOne.id);
|
||||
expect(expectedChildChildNavOne).toEqual(childChildNavOne);
|
||||
|
||||
const expectedRootNavTwo = app.getNavByIdOrName(rootNavTwo.id);
|
||||
expect(expectedRootNavTwo).toEqual(rootNavTwo);
|
||||
|
||||
const expectedChildNavTwo = app.getNavByIdOrName(childNavTwo.id);
|
||||
expect(expectedChildNavTwo).toEqual(childNavTwo);
|
||||
|
||||
const expectedChildChildNavTwo = app.getNavByIdOrName(childChildNavTwo.id);
|
||||
expect(expectedChildChildNavTwo).toEqual(childChildNavTwo);
|
||||
|
||||
const expectedRootNavThree = app.getNavByIdOrName(rootNavThree.id);
|
||||
expect(expectedRootNavThree).toEqual(rootNavThree);
|
||||
|
||||
const expectedChildNavThree = app.getNavByIdOrName(childNavThree.id);
|
||||
expect(expectedChildNavThree).toEqual(childNavThree);
|
||||
|
||||
const expectedChildChildNavThree = app.getNavByIdOrName(childChildNavThree.id);
|
||||
expect(expectedChildChildNavThree).toEqual(childChildNavThree);
|
||||
});
|
||||
});
|
||||
|
||||
let app: App;
|
||||
let config: Config;
|
||||
let plt: MockPlatform;
|
||||
|
||||
@@ -126,6 +126,7 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, OnDes
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.value = !this.value;
|
||||
this._fireTouched();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,5 +142,4 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, OnDes
|
||||
_inputUpdated() {
|
||||
this._item && this._item.setElementClass('item-checkbox-checked', this._value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,40 +91,66 @@ ion-app [no-padding] .scroll-content {
|
||||
}
|
||||
|
||||
@mixin content-padding($mode, $content-padding) {
|
||||
ion-app.#{$mode} [padding],
|
||||
ion-app.#{$mode} [padding] .scroll-content {
|
||||
ion-app.#{$mode} [padding] {
|
||||
@include padding($content-padding);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-top],
|
||||
ion-app.#{$mode} [padding-top] .scroll-content {
|
||||
ion-app.#{$mode} [padding-top] {
|
||||
@include padding($content-padding, null, null, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-left],
|
||||
ion-app.#{$mode} [padding-left] .scroll-content {
|
||||
ion-app.#{$mode} [padding-left] {
|
||||
@include padding-horizontal($content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-right],
|
||||
ion-app.#{$mode} [padding-right] .scroll-content {
|
||||
ion-app.#{$mode} [padding-right] {
|
||||
@include padding-horizontal(null, $content-padding);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-bottom],
|
||||
ion-app.#{$mode} [padding-bottom] .scroll-content {
|
||||
ion-app.#{$mode} [padding-bottom] {
|
||||
@include padding(null, null, $content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-vertical],
|
||||
ion-app.#{$mode} [padding-vertical] .scroll-content {
|
||||
ion-app.#{$mode} [padding-vertical] {
|
||||
@include padding($content-padding, null, $content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-horizontal],
|
||||
ion-app.#{$mode} [padding-horizontal] .scroll-content {
|
||||
ion-app.#{$mode} [padding-horizontal] {
|
||||
@include padding-horizontal($content-padding);
|
||||
}
|
||||
|
||||
// Scroll content should use safe-area-padding
|
||||
ion-app.#{$mode} [padding] .scroll-content {
|
||||
@include safe-area-padding($content-padding);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} .scroll-content {
|
||||
@include safe-area-no-padding($content-padding);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-top] .scroll-content {
|
||||
@include safe-area-padding($content-padding, null, null, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-left] .scroll-content {
|
||||
@include safe-area-padding-horizontal($content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-right] .scroll-content {
|
||||
@include safe-area-padding-horizontal(null, $content-padding);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-bottom] .scroll-content {
|
||||
@include safe-area-padding(null, null, $content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-vertical] .scroll-content {
|
||||
@include safe-area-padding($content-padding, null, $content-padding, null);
|
||||
}
|
||||
|
||||
ion-app.#{$mode} [padding-horizontal] .scroll-content {
|
||||
@include safe-area-padding-horizontal($content-padding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
@@ -31,7 +31,7 @@ export class EventEmitterProxy<T> extends EventEmitter<T> {
|
||||
* The Content component provides an easy to use content area with
|
||||
* some useful methods to control the scrollable area. There should
|
||||
* only be one content in a single view component. If additional scrollable
|
||||
* elements are need, use [ionScroll](../../scroll/Scroll).
|
||||
* elements are needed, use [ionScroll](../../scroll/Scroll).
|
||||
*
|
||||
*
|
||||
* The content area can also implement pull-to-refresh with the
|
||||
@@ -670,6 +670,7 @@ export class Content extends Ion implements OnDestroy, AfterViewInit, IContent {
|
||||
* Tell the content to recalculate its dimensions. This should be called
|
||||
* after dynamically adding/removing headers, footers, or tabs.
|
||||
*/
|
||||
@HostListener('window:resize')
|
||||
resize() {
|
||||
this._dom.read(this._readDimensions.bind(this));
|
||||
this._dom.write(this._writeDimensions.bind(this));
|
||||
|
||||
@@ -135,6 +135,8 @@ import {
|
||||
* to serialize and pass within JSON objects, and sending databases a standardized
|
||||
* format which it can be easily parsed if need be.
|
||||
*
|
||||
* To create an ISO datetime string for the current date and time, e.g. use `const currentDate = (new Date()).toISOString();`.
|
||||
*
|
||||
* An ISO format can be used as a simple year, or just the hour and minute, or get more
|
||||
* detailed down to the millisecond and timezone. Any of the ISO formats below can be used,
|
||||
* and after a user selects a new value, Ionic will continue to use the same ISO format
|
||||
@@ -167,7 +169,7 @@ import {
|
||||
* ## Min and Max Datetimes
|
||||
*
|
||||
* Dates are infinite in either direction, so for a user's selection there should be at
|
||||
* least some form of restricting the dates that can be selected. Be default, the maximum
|
||||
* least some form of restricting the dates that can be selected. By default, the maximum
|
||||
* date is to the end of the current year, and the minimum date is from the beginning
|
||||
* of the year that was 100 years ago.
|
||||
*
|
||||
|
||||
@@ -736,7 +736,7 @@ describe('DateTime', () => {
|
||||
|
||||
function zoned(fn: () => any): (done: DoneFn) => void {
|
||||
return () => {
|
||||
const zone = new NgZone(false);
|
||||
const zone = new NgZone({enableLongStackTrace: false});
|
||||
zone.run(fn);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -211,12 +211,12 @@ export class TextInput extends BaseInput<string> implements IonicFormInput {
|
||||
@ViewChild('textInput', { read: ElementRef }) _native: ElementRef;
|
||||
|
||||
/**
|
||||
* @input {string} Instructional text that shows before the input has a value.
|
||||
* @input {string} Set the input's autocomplete property. Values: `"on"`, `"off"`. Default `"off"`.
|
||||
*/
|
||||
@Input() autocomplete: string = '';
|
||||
|
||||
/**
|
||||
* @input {string} Instructional text that shows before the input has a value.
|
||||
* @input {string} Set the input's autocorrect property. Values: `"on"`, `"off"`. Default `"off"`.
|
||||
*/
|
||||
@Input() autocorrect: string = '';
|
||||
|
||||
|
||||
@@ -87,14 +87,14 @@ $list-md-header-color: #757575 !default;
|
||||
}
|
||||
|
||||
.list-md ion-item-options .button {
|
||||
@include margin(1px, 0);
|
||||
@include margin(0);
|
||||
@include border-radius(0);
|
||||
|
||||
display: inline-flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
height: calc(100% - 2px);
|
||||
height: 100%;
|
||||
|
||||
border: 0;
|
||||
|
||||
|
||||
@@ -47,12 +47,12 @@ import { LoadingOptions } from './loading-options';
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* constructor(public loadingCtrl: LoadingController) {
|
||||
* import { LoadingController } from 'ionic-angular';
|
||||
*
|
||||
* }
|
||||
* constructor(public loadingCtrl: LoadingController) { }
|
||||
*
|
||||
* presentLoadingDefault() {
|
||||
* let loading = this.loadingCtrl.create({
|
||||
* const loading = this.loadingCtrl.create({
|
||||
* content: 'Please wait...'
|
||||
* });
|
||||
*
|
||||
@@ -64,7 +64,7 @@ import { LoadingOptions } from './loading-options';
|
||||
* }
|
||||
*
|
||||
* presentLoadingCustom() {
|
||||
* let loading = this.loadingCtrl.create({
|
||||
* const loading = this.loadingCtrl.create({
|
||||
* spinner: 'hide',
|
||||
* content: `
|
||||
* <div class="custom-spinner-container">
|
||||
@@ -81,7 +81,7 @@ import { LoadingOptions } from './loading-options';
|
||||
* }
|
||||
*
|
||||
* presentLoadingText() {
|
||||
* let loading = this.loadingCtrl.create({
|
||||
* const loading = this.loadingCtrl.create({
|
||||
* spinner: 'hide',
|
||||
* content: 'Loading Please Wait...'
|
||||
* });
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
* @name MenuToggle
|
||||
* @description
|
||||
* The `menuToggle` directive can be placed on any button to toggle a menu open or closed.
|
||||
* If it is added to the [NavBar](../../navbar/NavBar) of a page, the button will only appear
|
||||
* If it is added to the [NavBar](../../toolbar/Navbar) of a page, the button will only appear
|
||||
* when the page it's in is currently a root page. See the [Menu Navigation Bar Behavior](../Menu#navigation-bar-behavior)
|
||||
* docs for more information.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@ import { DeepLinker } from '../../navigation/deep-linker';
|
||||
*
|
||||
* When a modal (or any other overlay such as an alert or actionsheet) is
|
||||
* "presented" to a nav controller, the overlay is added to the app's root nav.
|
||||
* After the modal has been presented, from within the component instance The
|
||||
* After the modal has been presented, from within the component instance, the
|
||||
* modal can later be closed or "dismissed" by using the ViewController's
|
||||
* `dismiss` method. Additionally, you can dismiss any overlay by using `pop`
|
||||
* on the root nav controller. Modals are not reusable. When a modal is dismissed
|
||||
@@ -38,12 +38,10 @@ import { DeepLinker } from '../../navigation/deep-linker';
|
||||
* @Component(...)
|
||||
* class HomePage {
|
||||
*
|
||||
* constructor(public modalCtrl: ModalController) {
|
||||
*
|
||||
* }
|
||||
* constructor(public modalCtrl: ModalController) { }
|
||||
*
|
||||
* presentProfileModal() {
|
||||
* let profileModal = this.modalCtrl.create(Profile, { userId: 8675309 });
|
||||
* const profileModal = this.modalCtrl.create(Profile, { userId: 8675309 });
|
||||
* profileModal.present();
|
||||
* }
|
||||
*
|
||||
@@ -112,6 +110,25 @@ import { DeepLinker } from '../../navigation/deep-linker';
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* A common issue is that a developer may try to implement navigation in a modal, but when you try NavController.push(),
|
||||
* you will notice that the status bar on iOS gets cut off. The proper way to implement navigation in a modal is to
|
||||
* make the modal component a navigation container, and set the root page to the page you want to show in your modal.
|
||||
*
|
||||
* ```ts
|
||||
* @Component({
|
||||
* template: '<ion-nav [root]="rootPage" [rootParams]="rootParams"></ion-nav>'
|
||||
* })
|
||||
* export class MyModalWrapper {
|
||||
* rootPage = 'MyModalContentPage'; // This is the page you want your modal to display
|
||||
* rootParams;
|
||||
*
|
||||
* constructor(navParams: NavParams, private viewCtrl: ViewController) {
|
||||
* this.rootParams = Object.assign({}, navParams.data, {viewCtrl: viewCtrl});
|
||||
* // This line will send the view controller into your child views, so you can dismiss the modals from there.
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @demo /docs/demos/src/modal/
|
||||
* @see {@link /docs/components#modals Modal Component Docs}
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,8 @@ import { Page } from '../../navigation/nav-util';
|
||||
* template: `<button ion-button [navPush]="pushPage" [navParams]="params">Go</button>`
|
||||
* })
|
||||
* class MyPage {
|
||||
* params: Object;
|
||||
* pushPage: any;
|
||||
* params: Object;
|
||||
* constructor(){
|
||||
* this.pushPage = LoginPage;
|
||||
* this.params = { id: 42 };
|
||||
|
||||
@@ -114,7 +114,7 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
|
||||
if (segment && (segment.component || segment.loadChildren)) {
|
||||
return this._linker.initViews(segment).then(views => {
|
||||
this.setPages(views, null, null);
|
||||
return this.setPages(views, null, null);
|
||||
});
|
||||
} else if (this._root) {
|
||||
// no segment match, so use the root property but don't set the url I guess
|
||||
@@ -133,6 +133,7 @@ export class Nav extends NavControllerBase implements AfterViewInit, RootNode, I
|
||||
get root(): any {
|
||||
return this._root;
|
||||
}
|
||||
|
||||
set root(page: any) {
|
||||
this._root = page;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ 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-nav [root]="rootOne" name="left"></ion-nav>
|
||||
<ion-nav [root]="rootTwo" main #content name="right"></ion-nav>
|
||||
|
||||
</ion-split-pane>
|
||||
`
|
||||
|
||||
@@ -19,7 +19,6 @@ import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
<div>
|
||||
Name: {{paramTwo}}
|
||||
</div>
|
||||
<button ion-button (click)="goToNext()">Next</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
|
||||
@@ -14,10 +14,10 @@ import { IonicPage, NavController, NavParams } from '../../../../../../..';
|
||||
<ion-content>
|
||||
Tabs 1 Tab 2 Page 3
|
||||
<div>
|
||||
Param One: {{userId}}
|
||||
Param One: {{paramOne}}
|
||||
</div>
|
||||
<div>
|
||||
Param Two: {{name}}
|
||||
Param Two: {{paramTwo}}
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `<ion-nav [root]="root"></ion-nav>`
|
||||
})
|
||||
export class AppComponent {
|
||||
root = 'LoginPage';
|
||||
}
|
||||
@@ -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 { LandingPage } from './landing-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(LandingPage)
|
||||
],
|
||||
declarations: [
|
||||
LandingPage
|
||||
]
|
||||
})
|
||||
export class LandingPageModule { }
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>My Super Cool, multi-pane App</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col style="height: 1000px; background-color: blue">
|
||||
<ion-nav root="FirstPage" name="left"></ion-nav>
|
||||
</ion-col>
|
||||
<ion-col style="height: 1000px; background-color: green">
|
||||
<ion-nav root="FourthPage" name="right"></ion-nav>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class LandingPage {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../..';
|
||||
import { LoginPage } from './login-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(LoginPage)
|
||||
],
|
||||
declarations: [
|
||||
LoginPage
|
||||
]
|
||||
})
|
||||
export class LoginPageModule { }
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Login</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<button ion-button (click)="clickMe()">Login</button>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class LoginPage {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
clickMe() {
|
||||
this.nav.push('LandingPage');
|
||||
}
|
||||
}
|
||||
@@ -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'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page Four</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h2>Page Four</h2>
|
||||
<button ion-button (click)="goToPageTwo()">Next</button>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from '../../../../../../..';
|
||||
import { FourthPage } from './fourth-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(FourthPage)
|
||||
],
|
||||
declarations: [
|
||||
FourthPage
|
||||
]
|
||||
})
|
||||
export class FourthPageModule { }
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, } from '../../../../../../..';
|
||||
|
||||
@IonicPage()
|
||||
@Component({
|
||||
templateUrl: 'fourth-page.html'
|
||||
})
|
||||
export class FourthPage {
|
||||
constructor(public nav: NavController) {
|
||||
}
|
||||
|
||||
goToPageTwo() {
|
||||
this.nav.push('FifthPage', { userId: '567', name: 'Pamela Beasley'});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Page Six</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
Page Six
|
||||
<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 { SixthPage } from './sixth-page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicPageModule.forChild(SixthPage)
|
||||
],
|
||||
declarations: [
|
||||
SixthPage
|
||||
]
|
||||
})
|
||||
export class SixthPageModule { }
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavController, NavParams} from '../../../../../../..';
|
||||
|
||||
@IonicPage({
|
||||
segment: 'sixthPage/paramOne/:paramOne/paramTwo/:paramTwo'
|
||||
})
|
||||
@Component({
|
||||
templateUrl: 'sixth-page.html'
|
||||
})
|
||||
export class SixthPage {
|
||||
|
||||
paramOne: string;
|
||||
paramTwo: string;
|
||||
constructor(public nav: NavController, public params: NavParams) {
|
||||
this.paramOne = params.data.paramOne;
|
||||
this.paramTwo = params.data.paramTwo;
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ ion-picker-cmp {
|
||||
}
|
||||
|
||||
.picker-columns {
|
||||
@include margin(null, null, constant(safe-area-inset-bottom), null);
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
|
||||
@@ -42,15 +42,18 @@ export class PageOne {
|
||||
}
|
||||
|
||||
setApple() {
|
||||
this.fruitsCtrl.updateValueAndValidity('apple');
|
||||
this.fruitsCtrl.setValue('apple');
|
||||
this.fruitsCtrl.updateValueAndValidity();
|
||||
}
|
||||
|
||||
setBanana() {
|
||||
this.fruitsCtrl.updateValueAndValidity('banana');
|
||||
this.fruitsCtrl.setValue('banana');
|
||||
this.fruitsCtrl.updateValueAndValidity();
|
||||
}
|
||||
|
||||
setCherry() {
|
||||
this.fruitsCtrl.updateValueAndValidity('cherry');
|
||||
this.fruitsCtrl.setValue('cherry');
|
||||
this.fruitsCtrl.updateValueAndValidity();
|
||||
}
|
||||
|
||||
doSubmit(ev: UIEvent) {
|
||||
|
||||
@@ -90,7 +90,10 @@ export class Segment extends BaseInput<string> implements AfterContentInit {
|
||||
ngAfterContentInit() {
|
||||
this._initialize();
|
||||
this._buttons.forEach(button => {
|
||||
button.ionSelect.subscribe((selectedButton: any) => this.value = selectedButton.value);
|
||||
button.ionSelect.subscribe((selectedButton: any) => {
|
||||
this.value = selectedButton.value;
|
||||
this._fireTouched();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +112,4 @@ export class Segment extends BaseInput<string> implements AfterContentInit {
|
||||
button.isActive = (button.value === value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -106,6 +106,34 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ### Zooming
|
||||
* If your slides contain images, you can enable zooming on them by setting `zoom="true" and
|
||||
* wrapping each image in a `div` with the class `swiper-zoom-container`. Zoom supports
|
||||
* `img`, `svg`, `canvas`, and `ion-img`.
|
||||
*
|
||||
* ```html
|
||||
* <ion-slidesj zoom="true">
|
||||
* <ion-slide>
|
||||
* <div class="swiper-zoom-container">
|
||||
* <img src="assets/img/dog.jpg">
|
||||
* </div>
|
||||
* <ion-label>Woof</ion-label>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <div class="swiper-zoom-container">
|
||||
* <img src="assets/img/cat.jpg">
|
||||
* </div>
|
||||
* <ion-label>Meow</ion-label>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <div class="swiper-zoom-container">
|
||||
* <img src="assets/img/fish.jpg">
|
||||
* </div>
|
||||
* <ion-label>Just keep swimming</ion-label>
|
||||
* </ion-slide>
|
||||
* </ion-slides>
|
||||
* ```
|
||||
*
|
||||
* @advanced
|
||||
*
|
||||
* There are several options available to create customized slides. Ionic exposes
|
||||
|
||||
@@ -462,7 +462,7 @@ export function resetZoomEvents(s: Slides, plt: Platform) {
|
||||
|
||||
// Scale image
|
||||
if (s._supportGestures) {
|
||||
for (var i = 0; i < slides.length; i++) {
|
||||
for (let i = 0; i < slides.length; i++) {
|
||||
slide = slides[i];
|
||||
// gesturestart
|
||||
plt.registerListener(slide, 'gesturestart', (ev: TouchEvent) => {
|
||||
|
||||
@@ -693,8 +693,10 @@ function destroyLoop(s: Slides) {
|
||||
eachChild(s._wrapper, '.' + CLS.slide + '.' + CLS.slideDuplicate, ele => {
|
||||
ele.parentElement.removeChild(ele);
|
||||
});
|
||||
for (var i = 0; i < s._slides.length; i++) {
|
||||
s._slides[i].removeAttribute('data-swiper-slide-index');
|
||||
if (s._slides) {
|
||||
for (var i = 0; i < s._slides.length; i++) {
|
||||
s._slides[i].removeAttribute('data-swiper-slide-index');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { isTrueProperty } from '../../util/util';
|
||||
import { Tab as ITab } from '../../navigation/nav-interfaces';
|
||||
import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
import { NavOptions } from '../../navigation/nav-util';
|
||||
import { NavOptions, TransitionDoneFn } from '../../navigation/nav-util';
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { TabButton } from './tab-button';
|
||||
import { Tabs } from './tabs';
|
||||
@@ -98,7 +98,7 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
* ```html
|
||||
* <ion-tabs>
|
||||
* <ion-tab (ionSelect)="chat()" tabTitle="Show Modal"></ion-tab>
|
||||
* </ion-tabs>
|
||||
* </ion-tabs>pop
|
||||
* ```
|
||||
*
|
||||
* ```ts
|
||||
@@ -304,7 +304,7 @@ export class Tab extends NavControllerBase implements ITab {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
load(opts: NavOptions, done?: () => void) {
|
||||
load(opts: NavOptions, done?: TransitionDoneFn) {
|
||||
if (this._lazyRootFromUrl || (!this._loaded && this.root)) {
|
||||
this.setElementClass('show-tab', true);
|
||||
// okay, first thing we need to do if check if the view already exists
|
||||
@@ -317,7 +317,10 @@ export class Tab extends NavControllerBase implements ITab {
|
||||
if (i === numViews) {
|
||||
// this is the last view in the stack and it's the same
|
||||
// as the segment so there's no change needed
|
||||
return done();
|
||||
if (done) {
|
||||
done(false, false);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// it's not the exact view as the end
|
||||
// let's have this nav go back to this exact view
|
||||
@@ -343,7 +346,10 @@ export class Tab extends NavControllerBase implements ITab {
|
||||
this._dom.read(() => {
|
||||
this.resize();
|
||||
});
|
||||
return done();
|
||||
if (done) {
|
||||
done(false, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ $tabs-ios-tab-icon-color-active: $tabs-ios-tab-color-active !default;
|
||||
/// @prop - Font size of the tab button text
|
||||
$tabs-ios-tab-font-size: 10px !default;
|
||||
|
||||
/// @prop - Font weight of the tab button text
|
||||
$tabs-ios-tab-font-weight: 500 !default;
|
||||
|
||||
/// @prop - Size of the tab button icon
|
||||
$tabs-ios-tab-icon-size: 30px !default;
|
||||
|
||||
@@ -63,6 +66,7 @@ $tabs-ios-tab-icon-size: 30px !default;
|
||||
min-height: $tabs-ios-tab-min-height;
|
||||
|
||||
font-size: $tabs-ios-tab-font-size;
|
||||
font-weight: $tabs-ios-tab-font-weight;
|
||||
color: $tabs-ios-tab-text-color;
|
||||
|
||||
@include deprecated-variable(padding, $tabs-ios-tab-padding) {
|
||||
|
||||
@@ -507,6 +507,13 @@ export class Tabs extends Ion implements AfterViewInit, RootNode, ITabs, Navigat
|
||||
return selected ? [selected] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getAllChildNavs(): any[] {
|
||||
return this._tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -635,7 +642,7 @@ export class Tabs extends Ion implements AfterViewInit, RootNode, ITabs, Navigat
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getSelectedTabIndex(secondaryId: string, fallbackIndex: number = 0): number {
|
||||
_getSelectedTabIndex(secondaryId: string = '', fallbackIndex: number = 0): number {
|
||||
// we found a segment which probably represents which tab to select
|
||||
const indexMatch = secondaryId.match(/tab-(\d+)/);
|
||||
if (indexMatch) {
|
||||
|
||||
@@ -37,12 +37,12 @@ import { ToastOptions } from './toast-options';
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* constructor(private toastCtrl: ToastController) {
|
||||
* import { ToastController } from 'ionic-angular';
|
||||
*
|
||||
* }
|
||||
* constructor(public toastCtrl: ToastController) { }
|
||||
*
|
||||
* presentToast() {
|
||||
* let toast = this.toastCtrl.create({
|
||||
* const toast = this.toastCtrl.create({
|
||||
* message: 'User was added successfully',
|
||||
* duration: 3000,
|
||||
* position: 'top'
|
||||
|
||||
@@ -48,6 +48,7 @@ $toast-ios-title-padding-start: $toast-ios-title-padding-end !
|
||||
|
||||
.toast-ios .toast-wrapper.toast-top {
|
||||
@include transform(translate3d(0, -100%, 0));
|
||||
@include margin(constant(safe-area-inset-top), auto, auto, auto);
|
||||
|
||||
top: 0;
|
||||
}
|
||||
@@ -55,6 +56,7 @@ $toast-ios-title-padding-start: $toast-ios-title-padding-end !
|
||||
.toast-ios .toast-wrapper.toast-bottom {
|
||||
@include transform(translate3d(0, 100%, 0));
|
||||
|
||||
@include margin(auto, auto, constant(safe-area-inset-bottom), auto);
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
* @name Header
|
||||
* @description
|
||||
* Header is a parent component that holds the navbar and toolbar component.
|
||||
* It's important to note that `ion-header` needs to be the one of the three root elements of a page
|
||||
* It's important to note that `ion-header` needs to be one of the three root elements of a page
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
|
||||
@@ -88,7 +88,7 @@ import { VirtualHeader } from './virtual-header';
|
||||
* ### Approximate Widths and Heights
|
||||
*
|
||||
* If the height of items in the virtual scroll are not close to the
|
||||
* default size of 40px, it is extremely important to provide an value for
|
||||
* default size of 40px, it is extremely important to provide a value for
|
||||
* approxItemHeight height. An exact pixel-perfect size is not necessary,
|
||||
* but without an estimate the virtual scroll will not render correctly.
|
||||
*
|
||||
|
||||
@@ -118,6 +118,7 @@ import { isArray, isDefined, isFunction, isObject } from '../util/util';
|
||||
* | `popoverEnter` | `string` | The name of the transition to use while a popover is presented. |
|
||||
* | `popoverLeave` | `string` | The name of the transition to use while a popover is dismissed. |
|
||||
* | `spinner` | `string` | The default spinner to use when a name is not defined. |
|
||||
* | `statusbarPadding` | `boolean` | Whether to hide extra padding for statusbar. |
|
||||
* | `swipeBackEnabled` | `boolean` | Whether native iOS swipe to go back functionality is enabled. |
|
||||
* | `tabsHighlight` | `boolean` | Whether to show a highlight line under the tab when it is selected. |
|
||||
* | `tabsLayout` | `string` | The layout to use for all tabs. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"title-hide"`. |
|
||||
|
||||
@@ -69,7 +69,7 @@ export class Simulate {
|
||||
velocity(vel: number): Simulate {
|
||||
let p1 = this.getLastPoint();
|
||||
let p2 = this.getPreviousPoint();
|
||||
let d = distance(p1, p2);
|
||||
let d = distance(p1.coord, p2.coord);
|
||||
return this.duration(d / vel);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('recognizers', () => {
|
||||
let p = new PanRecognizer('x', 2, 2);
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
Simulate.from(0, 0).to(99, 0).run((coord: Coordinates) => {
|
||||
Simulate.from(0, 0).to(99, 0).run((coord: any) => {
|
||||
expect(p.detect(coord)).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
Simulate.from(0, 0).to(10, 0).run((coord: Coordinates) => {
|
||||
Simulate.from(0, 0).to(10, 0).run((coord: any) => {
|
||||
p.detect(coord);
|
||||
});
|
||||
expect(p.pan()).toEqual(1);
|
||||
@@ -26,7 +26,7 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
Simulate.from(0, 0).to(-10, 0).run((coord: Coordinates) => {
|
||||
Simulate.from(0, 0).to(-10, 0).run((coord: any) => {
|
||||
p.detect(coord);
|
||||
});
|
||||
expect(p.pan()).toEqual(-1);
|
||||
@@ -40,11 +40,11 @@ describe('recognizers', () => {
|
||||
Simulate
|
||||
.from(0, 0).to(99, 0)
|
||||
// Since threshold is 100, it should not fire yet
|
||||
.run((coord: Coordinates) => expect(p.detect(coord)).toEqual(false))
|
||||
.run((coord: any) => expect(p.detect(coord)).toEqual(false))
|
||||
|
||||
// Now it should fire
|
||||
.delta(2, 0)
|
||||
.run((coord: Coordinates) => {
|
||||
.run((coord: any) => {
|
||||
if (p.detect(coord)) {
|
||||
// it should detect a horizontal pan
|
||||
expect(p.pan()).toEqual(1);
|
||||
@@ -56,7 +56,7 @@ describe('recognizers', () => {
|
||||
.delta(20, 0)
|
||||
.to(0, 0)
|
||||
.to(102, 0)
|
||||
.run((coord: Coordinates) => expect(p.detect(coord)).toEqual(false));
|
||||
.run((coord: any) => expect(p.detect(coord)).toEqual(false));
|
||||
|
||||
expect(detected).toEqual(true);
|
||||
});
|
||||
@@ -66,13 +66,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(19, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(1);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-19, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(1);
|
||||
});
|
||||
|
||||
@@ -81,13 +81,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(180 - 19, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(-1);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(180 + 19, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(-1);
|
||||
});
|
||||
|
||||
@@ -96,13 +96,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(21, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-21, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -111,13 +111,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(180 - 21, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(180 + 21, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -128,13 +128,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(90 - 19, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(1);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(90 + 19, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(1);
|
||||
});
|
||||
|
||||
@@ -143,13 +143,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-90 + 19, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(-1);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-90 - 19, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(-1);
|
||||
});
|
||||
|
||||
@@ -158,13 +158,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(90 - 21, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(90 + 21, 21).delta(-30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -173,13 +173,13 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-90 + 21, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(-90 - 21, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -188,7 +188,7 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).deltaPolar(90, 21).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
@@ -198,7 +198,7 @@ describe('recognizers', () => {
|
||||
p.start({ x: 0, y: 0 });
|
||||
Simulate
|
||||
.from(0, 0).delta(30, 0)
|
||||
.run((coord: Coordinates) => p.detect(coord));
|
||||
.run((coord: any) => p.detect(coord));
|
||||
|
||||
expect(p.pan()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -445,7 +445,7 @@ export class IonicModule {
|
||||
|
||||
{ provide: ModuleLoader, useFactory: provideModuleLoader, deps: [NgModuleLoader, Injector]},
|
||||
{ provide: LocationStrategy, useFactory: provideLocationStrategy, deps: [ PlatformLocation, [new Inject(APP_BASE_HREF), new Optional()], Config ] },
|
||||
{ provide: UrlSerializer, useFactory: setupUrlSerializer, deps: [ DeepLinkConfigToken ] },
|
||||
{ provide: UrlSerializer, useFactory: setupUrlSerializer, deps: [ App, DeepLinkConfigToken ] },
|
||||
{ provide: DeepLinker, useFactory: setupDeepLinker, deps: [ App, UrlSerializer, Location, ModuleLoader, ComponentFactoryResolver ] },
|
||||
]
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ComponentFactory, ComponentFactoryResolver } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
|
||||
import { App } from '../components/app/app';
|
||||
import { DIRECTION_BACK, NavLink, NavSegment, convertToViews, isNav, isTab, isTabs, } from './nav-util';
|
||||
import { DIRECTION_BACK, NavLink, NavSegment, TransitionDoneFn, convertToViews, isNav, isTab, isTabs } from './nav-util';
|
||||
import { ModuleLoader } from '../util/module-loader';
|
||||
import { isArray, isPresent } from '../util/util';
|
||||
import { Tab, Tabs } from './nav-interfaces';
|
||||
@@ -131,18 +131,23 @@ export class DeepLinker {
|
||||
*/
|
||||
navChange(direction: string) {
|
||||
if (direction) {
|
||||
const rootNavContainers = this._app.getActiveNavContainers();
|
||||
const activeNavContainers = this._app.getActiveNavContainers();
|
||||
// the only time you'll ever get a TABS here is when loading directly from a URL
|
||||
// this method will be called again when the TAB is loaded
|
||||
// so just don't worry about the TABS for now
|
||||
// if you encounter a TABS, just return
|
||||
let segments: NavSegment[] = [];
|
||||
for (const rootNavContainer of rootNavContainers) {
|
||||
if (isTabs(rootNavContainer) || (rootNavContainer as NavController).isTransitioning()) {
|
||||
for (const activeNavContainer of activeNavContainers) {
|
||||
if (isTabs(activeNavContainer) || (activeNavContainer as NavController).isTransitioning()) {
|
||||
return;
|
||||
}
|
||||
const segmentsForNav = this.getSegmentsFromNav(rootNavContainer);
|
||||
segments = segments.concat(segmentsForNav);
|
||||
}
|
||||
|
||||
// okay, get the root navs and build the segments up
|
||||
let segments: NavSegment[] = [];
|
||||
const navContainers: NavigationContainer[] = this._app.getRootNavs();
|
||||
for (const navContainer of navContainers) {
|
||||
const segmentsForNav = this.getSegmentsFromNav(navContainer);
|
||||
segments = segments.concat(segmentsForNav);
|
||||
}
|
||||
segments = segments.filter(segment => !!segment);
|
||||
if (segments.length) {
|
||||
@@ -153,19 +158,16 @@ export class DeepLinker {
|
||||
}
|
||||
|
||||
getSegmentsFromNav(nav: NavigationContainer): NavSegment[] {
|
||||
const segments: NavSegment[] = [];
|
||||
while (nav) {
|
||||
if (isNav(nav)) {
|
||||
segments.push(this.getSegmentFromNav(nav as NavController));
|
||||
nav = nav.parent;
|
||||
} else if (isTab(nav)) {
|
||||
segments.push(this.getSegmentFromTab(nav));
|
||||
nav = nav.parent && nav.parent.parent;
|
||||
} else {
|
||||
nav = nav.parent;
|
||||
}
|
||||
let segments: NavSegment[] = [];
|
||||
if (isNav(nav)) {
|
||||
segments.push(this.getSegmentFromNav(nav as NavController));
|
||||
} else if (isTab(nav)) {
|
||||
segments.push(this.getSegmentFromTab(nav));
|
||||
}
|
||||
return segments.reverse();
|
||||
nav.getActiveChildNavs().forEach(child => {
|
||||
segments = segments.concat(this.getSegmentsFromNav(child));
|
||||
});
|
||||
return segments;
|
||||
}
|
||||
|
||||
getSegmentFromNav(nav: NavController, component?: any, data?: any): NavSegment {
|
||||
@@ -176,7 +178,7 @@ export class DeepLinker {
|
||||
data = viewController.data;
|
||||
}
|
||||
}
|
||||
return this._serializer.serializeComponent({ navId: nav.name && nav.name.length ? nav.name : nav.id, secondaryId: null, type: 'nav'}, component, data);
|
||||
return this._serializer.serializeComponent(nav, component, data);
|
||||
}
|
||||
|
||||
getSegmentFromTab(navContainer: NavigationContainer, component?: any, data?: any): NavSegment {
|
||||
@@ -190,7 +192,7 @@ export class DeepLinker {
|
||||
component = viewController.component;
|
||||
data = viewController.data;
|
||||
}
|
||||
return this._serializer.serializeComponent({ navId: tabsNavContainer.name || tabsNavContainer.id, secondaryId: tabsNavContainer.getSecondaryIdentifier(), type: 'tabs'}, component, data);
|
||||
return this._serializer.serializeComponent(tabsNavContainer, component, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,9 +380,9 @@ export class DeepLinker {
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
_loadViewForSegment(navContainer: NavigationContainer, segment: NavSegment, done: Function) {
|
||||
_loadViewForSegment(navContainer: NavigationContainer, segment: NavSegment, done: TransitionDoneFn) {
|
||||
if (!segment) {
|
||||
return done();
|
||||
return done(false, false);
|
||||
}
|
||||
|
||||
if (isTabs(navContainer) || (isTab(navContainer) && navContainer.parent)) {
|
||||
@@ -393,7 +395,7 @@ export class DeepLinker {
|
||||
updateUrl: false,
|
||||
animate: false
|
||||
}, true);
|
||||
return done();
|
||||
return done(false, false);
|
||||
}
|
||||
|
||||
const navController = <NavController> <any> navContainer;
|
||||
@@ -408,7 +410,7 @@ export class DeepLinker {
|
||||
if (i === numViews) {
|
||||
// this is the last view in the stack and it's the same
|
||||
// as the segment so there's no change needed
|
||||
return done();
|
||||
return done(false, false);
|
||||
} else {
|
||||
// it's not the exact view as the end
|
||||
// let's have this nav go back to this exact view
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
STATE_DESTROYED,
|
||||
STATE_INITIALIZED,
|
||||
STATE_NEW,
|
||||
TransitionDoneFn,
|
||||
TransitionInstruction,
|
||||
convertToViews,
|
||||
} from './nav-util';
|
||||
@@ -62,6 +63,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
_viewport: ViewContainerRef;
|
||||
_views: ViewController[] = [];
|
||||
_zIndexOffset: number = 0;
|
||||
_destroyed: boolean;
|
||||
|
||||
viewDidLoad: EventEmitter<any> = new EventEmitter();
|
||||
viewWillEnter: EventEmitter<any> = new EventEmitter();
|
||||
@@ -102,9 +104,10 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
this._sbEnabled = config.getBoolean('swipeBackEnabled');
|
||||
this._children = [];
|
||||
this.id = 'n' + (++ctrlIds);
|
||||
this._destroyed = false;
|
||||
}
|
||||
|
||||
push(page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
push(page: any, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
insertStart: -1,
|
||||
insertViews: [{ page: page, params: params }],
|
||||
@@ -112,7 +115,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: [{ page: page, params: params }],
|
||||
@@ -120,7 +123,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: insertPages,
|
||||
@@ -128,7 +131,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
pop(opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
pop(opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
@@ -136,7 +139,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
let config: TransitionInstruction = {
|
||||
removeStart: -1,
|
||||
removeCount: -1,
|
||||
@@ -151,7 +154,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
return this._queueTrns(config, done);
|
||||
}
|
||||
|
||||
popToRoot(opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
popToRoot(opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
removeStart: 1,
|
||||
removeCount: -1,
|
||||
@@ -167,7 +170,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
remove(startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
remove(startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
removeStart: startIndex,
|
||||
removeCount: removeCount,
|
||||
@@ -175,7 +178,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
removeView(viewController: ViewController, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
removeView(viewController: ViewController, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this._queueTrns({
|
||||
removeView: viewController,
|
||||
removeStart: 0,
|
||||
@@ -184,12 +187,12 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}, done);
|
||||
}
|
||||
|
||||
setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
return this.setPages([{ page: pageOrViewCtrl, params: params }], opts, done);
|
||||
}
|
||||
|
||||
|
||||
setPages(viewControllers: any[], opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
setPages(viewControllers: any[], opts?: NavOptions, done?: TransitionDoneFn): Promise<any> {
|
||||
if (isBlank(opts)) {
|
||||
opts = {};
|
||||
}
|
||||
@@ -216,7 +219,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
// 7. _transitionStart(): called once the transition actually starts, it initializes the Animation underneath.
|
||||
// 8. _transitionFinish(): called once the transition finishes
|
||||
// 9. _cleanup(): syncs the navigation internal state with the DOM. For example it removes the pages from the DOM or hides/show them.
|
||||
_queueTrns(ti: TransitionInstruction, done: () => void): Promise<boolean> {
|
||||
_queueTrns(ti: TransitionInstruction, done: TransitionDoneFn): Promise<boolean> {
|
||||
const promise = new Promise<boolean>((resolve, reject) => {
|
||||
ti.resolve = resolve;
|
||||
ti.reject = reject;
|
||||
@@ -284,7 +287,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
if (ti.done) {
|
||||
ti.done(false, false, rejectReason);
|
||||
}
|
||||
if (ti.reject) {
|
||||
if (ti.reject && !this._destroyed) {
|
||||
ti.reject(rejectReason);
|
||||
} else {
|
||||
ti.resolve(false);
|
||||
@@ -594,7 +597,6 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}
|
||||
|
||||
_transition(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): Promise<NavResult> {
|
||||
|
||||
if (!ti.requiresTransition) {
|
||||
// transition is not required, so we are already done!
|
||||
// they're inserting/removing the views somewhere in the middle or
|
||||
@@ -856,35 +858,38 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
_cleanup(activeView: ViewController) {
|
||||
// ok, cleanup time!! Destroy all of the views that are
|
||||
// INACTIVE and come after the active view
|
||||
const activeViewIndex = this._views.indexOf(activeView);
|
||||
const views = this._views;
|
||||
let reorderZIndexes = false;
|
||||
let view: ViewController;
|
||||
let i: number;
|
||||
// only do this if the views exist, though
|
||||
if (!this._destroyed) {
|
||||
const activeViewIndex = this._views.indexOf(activeView);
|
||||
const views = this._views;
|
||||
let reorderZIndexes = false;
|
||||
let view: ViewController;
|
||||
let i: number;
|
||||
|
||||
for (i = views.length - 1; i >= 0; i--) {
|
||||
view = views[i];
|
||||
if (i > activeViewIndex) {
|
||||
// this view comes after the active view
|
||||
// let's unload it
|
||||
this._willUnload(view);
|
||||
this._destroyView(view);
|
||||
|
||||
} else if (i < activeViewIndex && !this._isPortal) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
view._domShow(false, this._renderer);
|
||||
}
|
||||
if (view._zIndex <= 0) {
|
||||
reorderZIndexes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._isPortal && reorderZIndexes) {
|
||||
for (i = 0; i < views.length; i++) {
|
||||
for (i = views.length - 1; i >= 0; i--) {
|
||||
view = views[i];
|
||||
// ******** DOM WRITE ****************
|
||||
view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer);
|
||||
if (i > activeViewIndex) {
|
||||
// this view comes after the active view
|
||||
// let's unload it
|
||||
this._willUnload(view);
|
||||
this._destroyView(view);
|
||||
|
||||
} else if (i < activeViewIndex && !this._isPortal) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
view._domShow(false, this._renderer);
|
||||
}
|
||||
if (view._zIndex <= 0) {
|
||||
reorderZIndexes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._isPortal && reorderZIndexes) {
|
||||
for (i = 0; i < views.length; i++) {
|
||||
view = views[i];
|
||||
// ******** DOM WRITE ****************
|
||||
view._setZIndex(view._zIndex + INIT_ZINDEX + 1, this._renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -991,6 +996,10 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
getAllChildNavs(): any[] {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
registerChildNav(container: NavigationContainer) {
|
||||
this._children.push(container);
|
||||
}
|
||||
@@ -1017,6 +1026,8 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
if (this.parent && this.parent.unregisterChildNav) {
|
||||
this.parent.unregisterChildNav(this);
|
||||
}
|
||||
|
||||
this._destroyed = true;
|
||||
}
|
||||
|
||||
swipeBackStart() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EventEmitter } from '@angular/core';
|
||||
|
||||
import { Config } from '../config/config';
|
||||
import { NavOptions } from './nav-util';
|
||||
import { NavOptions, TransitionDoneFn } from './nav-util';
|
||||
import { Page } from './nav-util';
|
||||
import { ViewController } from './view-controller';
|
||||
import { NavigationContainer } from './navigation-container';
|
||||
@@ -420,7 +420,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract push(page: Page | string, params?: any, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract push(page: Page | string, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Inserts a component into the nav stack at the specified index. This is useful if
|
||||
@@ -433,7 +433,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract insert(insertIndex: number, page: Page | string, params?: any, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract insert(insertIndex: number, page: Page | string, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Inserts an array of components into the nav stack at the specified index.
|
||||
@@ -445,7 +445,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract insertPages(insertIndex: number, insertPages: Array<{page: Page | string, params?: any}>, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract insertPages(insertIndex: number, insertPages: Array<{page: Page | string, params?: any}>, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Call to navigate back from a current component. Similar to `push()`, you
|
||||
@@ -454,7 +454,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract pop(opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract pop(opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Navigate back to the root of the stack, no matter how far back that is.
|
||||
@@ -462,7 +462,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract popToRoot(opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract popToRoot(opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
@@ -475,11 +475,10 @@ export abstract class NavController implements NavigationContainer {
|
||||
* when a new instance needs to be created.
|
||||
*
|
||||
* @param {Page|string|ViewController} page The component class or deeplink name you want to push onto the navigation stack.
|
||||
* @param {object} [params={}] Any NavParams to be used when a new view instance is created at the root.
|
||||
* @param {object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract popTo(page: Page | string | ViewController, params?: any, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract popTo(page: Page | string | ViewController, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
@@ -497,7 +496,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Any options you want to use pass to transtion.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract remove(startIndex: number, removeCount?: number, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract remove(startIndex: number, removeCount?: number, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Removes the specified view controller from the nav stack.
|
||||
@@ -506,7 +505,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {object} [opts={}] Any options you want to use pass to transtion.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract removeView(viewController: ViewController, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract removeView(viewController: ViewController, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* Set the root for the current navigation stack.
|
||||
@@ -516,7 +515,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {Function} done Callback function on done.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract setRoot(pageOrViewCtrl: Page | string | ViewController, params?: any, opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract setRoot(pageOrViewCtrl: Page | string | ViewController, params?: any, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
abstract goToRoot(options: NavOptions): Promise<any>;
|
||||
|
||||
/**
|
||||
@@ -529,7 +528,7 @@ export abstract class NavController implements NavigationContainer {
|
||||
* @param {Object} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
abstract setPages(pages: ({page: Page | string, params?: any} | ViewController)[], opts?: NavOptions, done?: Function): Promise<any>;
|
||||
abstract setPages(pages: ({page: Page | string, params?: any} | ViewController)[], opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;
|
||||
|
||||
/**
|
||||
* @param {number} index The index of the page to get.
|
||||
@@ -599,6 +598,11 @@ export abstract class NavController implements NavigationContainer {
|
||||
*/
|
||||
abstract getActiveChildNav(): any;
|
||||
|
||||
/**
|
||||
* Returns a list of all child navigation containers
|
||||
*/
|
||||
abstract getAllChildNavs(): any[];
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the nav controller is actively transitioning or not.
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* import { NavParams } from 'ionic-angular';
|
||||
*
|
||||
* export class MyClass{
|
||||
* constructor(public navParams: NavParams){
|
||||
*
|
||||
* constructor(navParams: NavParams){
|
||||
* // userParams is an object we have in our nav-parameters
|
||||
* this.navParams.get('userParams');
|
||||
* navParams.get('userParams');
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
* @demo /docs/demos/src/nav-params/
|
||||
@@ -32,6 +36,8 @@ export class NavParams {
|
||||
* Get the value of a nav-parameter for the current view
|
||||
*
|
||||
* ```ts
|
||||
* import { NavParams } from 'ionic-angular';
|
||||
*
|
||||
* export class MyClass{
|
||||
* constructor(public navParams: NavParams){
|
||||
* // userParams is an object we have in our nav-parameters
|
||||
|
||||
@@ -163,16 +163,26 @@ export interface NavResult {
|
||||
direction?: string;
|
||||
}
|
||||
|
||||
export interface NavSegment {
|
||||
export interface NavSegment extends DehydratedSegment {
|
||||
type: string;
|
||||
navId: string;
|
||||
secondaryId: string;
|
||||
requiresExplicitNavPrefix?: boolean;
|
||||
}
|
||||
|
||||
export interface DehydratedSegment {
|
||||
id: string;
|
||||
name: string;
|
||||
component?: any;
|
||||
loadChildren?: string;
|
||||
data: any;
|
||||
type: string;
|
||||
navId: string;
|
||||
secondaryId: string;
|
||||
defaultHistory?: NavSegment[];
|
||||
secondaryId?: string;
|
||||
}
|
||||
|
||||
export interface DehydratedSegmentPair {
|
||||
segments: DehydratedSegment[];
|
||||
navGroup: NavGroup;
|
||||
}
|
||||
|
||||
export interface NavGroup {
|
||||
@@ -211,6 +221,10 @@ export interface TransitionRejectFn {
|
||||
(rejectReason: any, transition?: Transition): void;
|
||||
}
|
||||
|
||||
export interface TransitionDoneFn {
|
||||
(hasCompleted: boolean, requiresTransition: boolean, enteringName?: string, leavingName?: string, direction?: string): void;
|
||||
}
|
||||
|
||||
export interface TransitionInstruction {
|
||||
opts: NavOptions;
|
||||
insertStart?: number;
|
||||
@@ -220,7 +234,7 @@ export interface TransitionInstruction {
|
||||
removeCount?: number;
|
||||
resolve?: (hasCompleted: boolean) => void;
|
||||
reject?: (rejectReason: string) => void;
|
||||
done?: Function;
|
||||
done?: TransitionDoneFn;
|
||||
leavingRequiresTransition?: boolean;
|
||||
enteringRequiresTransition?: boolean;
|
||||
requiresTransition?: boolean;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { NavController } from './nav-controller';
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export interface NavigationContainer {
|
||||
id: string;
|
||||
name: string;
|
||||
parent: NavController;
|
||||
getActiveChildNavs(): NavigationContainer[];
|
||||
getAllChildNavs?(): NavigationContainer[];
|
||||
getType(): string;
|
||||
getSecondaryIdentifier(): string;
|
||||
}
|
||||
|
||||
@@ -457,9 +457,7 @@ describe('DeepLinker', () => {
|
||||
|
||||
linker.getSegmentFromNav(mockNav, null, null);
|
||||
|
||||
expect(spy.calls.first().args[0].navId).toEqual(mockNav.name);
|
||||
expect(spy.calls.first().args[0].secondaryId).toBeFalsy();
|
||||
expect(spy.calls.first().args[0].type).toEqual('nav');
|
||||
expect(spy.calls.first().args[0]).toEqual(mockNav);
|
||||
});
|
||||
|
||||
it('should use the id of the nav when name doesnt exists', () => {
|
||||
@@ -472,9 +470,7 @@ describe('DeepLinker', () => {
|
||||
|
||||
linker.getSegmentFromNav(mockNav, null, null);
|
||||
|
||||
expect(spy.calls.first().args[0].navId).toEqual(mockNav.id);
|
||||
expect(spy.calls.first().args[0].secondaryId).toBeFalsy();
|
||||
expect(spy.calls.first().args[0].type).toEqual('nav');
|
||||
expect(spy.calls.first().args[0]).toEqual(mockNav);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -493,7 +489,7 @@ describe('DeepLinker', () => {
|
||||
linker.getSegmentFromTab(tabOne, null, null);
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.first().args[0].navId).toEqual(tabs.name);
|
||||
expect(spy.calls.first().args[0]).toEqual(tabs);
|
||||
|
||||
});
|
||||
|
||||
@@ -511,7 +507,7 @@ describe('DeepLinker', () => {
|
||||
linker.getSegmentFromTab(tabOne, null, null);
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.first().args[0].navId).toEqual(tabs.id);
|
||||
expect(spy.calls.first().args[0]).toEqual(tabs);
|
||||
|
||||
});
|
||||
});
|
||||
@@ -685,7 +681,7 @@ describe('DeepLinker', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
let linkConfig = mockDeepLinkConfig();
|
||||
serializer = new UrlSerializer(linkConfig);
|
||||
serializer = new UrlSerializer(mockApp(), linkConfig);
|
||||
|
||||
let moduleLoader = mockModuleLoader();
|
||||
let baseCfr: any = null;
|
||||
|
||||
@@ -1099,13 +1099,13 @@ describe('NavController', () => {
|
||||
|
||||
it('should not crash when destroyed while transitioning', (done) => {
|
||||
let view1 = mockView(MockView1);
|
||||
nav.push(view1).then(() => {
|
||||
fail('it should not succeed');
|
||||
nav.push(view1).then((succeded: boolean) => {
|
||||
expect(succeded).toEqual(false);
|
||||
done();
|
||||
}).catch((err: any) => {
|
||||
expect(err).toEqual('nav controller was destroyed');
|
||||
}).catch(() => {
|
||||
fail('should never get here');
|
||||
done();
|
||||
});
|
||||
});
|
||||
nav.destroy();
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { NavLink, NavSegment } from '../nav-util';
|
||||
import {
|
||||
NavGroup,
|
||||
UrlSerializer,
|
||||
convertUrlToDehydratedSegments,
|
||||
convertUrlToSegments,
|
||||
createMatchedData,
|
||||
findLinkByComponentData,
|
||||
formatUrlPart,
|
||||
isPartMatch,
|
||||
navGroupStringtoObjects,
|
||||
normalizeLinks,
|
||||
parseUrlParts,
|
||||
urlToNavGroupStrings,
|
||||
} from '../url-serializer';
|
||||
import { MockView1, MockView2, MockView3, mockDeepLinkConfig, mockNavController, noop } from '../../util/mock-providers';
|
||||
import { MockView1, MockView2, MockView3, mockApp, mockDeepLinkConfig, mockNavController, mockTab, mockTabs, noop } from '../../util/mock-providers';
|
||||
|
||||
|
||||
describe('UrlSerializer', () => {
|
||||
@@ -22,32 +22,37 @@ describe('UrlSerializer', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view/:param1' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view/:param1/:param2' };
|
||||
const navGroup: NavGroup = { type: 'nav', navId: 'n1', secondaryId: null, segmentPieces: ['view']};
|
||||
serializer = mockSerializer([link1, link2, link3]);
|
||||
serializer._createSegment = noop;
|
||||
spyOn(serializer, '_createSegment');
|
||||
serializer.serializeComponent(navGroup, MockView1, null);
|
||||
expect(serializer._createSegment).toHaveBeenCalledWith(navGroup, link1, null);
|
||||
const nav = mockNavController();
|
||||
serializer.serializeComponent(nav, MockView1, null);
|
||||
expect(serializer._createSegment).toHaveBeenCalledWith(serializer._app, nav, link1, null);
|
||||
});
|
||||
|
||||
it('should create segment if component found in links', () => {
|
||||
serializer._createSegment = noop;
|
||||
spyOn(serializer, '_createSegment');
|
||||
serializer.serializeComponent({ type: 'nav', navId: 'n1', secondaryId: null, segmentPieces: ['view']}, MockView1, null);
|
||||
const nav = mockNavController();
|
||||
serializer.serializeComponent(nav, MockView1, null);
|
||||
expect(serializer._createSegment).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return null if component not found in links', () => {
|
||||
serializer._createSegment = noop;
|
||||
spyOn(serializer, '_createSegment');
|
||||
serializer.serializeComponent({ type: 'nav', navId: 'n1', secondaryId: null, segmentPieces: ['view']}, NotFound, null);
|
||||
const nav = mockNavController();
|
||||
serializer.serializeComponent(nav, NotFound, null);
|
||||
expect(serializer._createSegment).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create tab segment if component found in deep links', () => {
|
||||
serializer._createSegment = noop;
|
||||
spyOn(serializer, '_createSegment');
|
||||
serializer.serializeComponent({ type: 'nav', navId: 'n1', secondaryId: null, segmentPieces: ['view']}, MockView1, null);
|
||||
|
||||
const tabs = mockTabs();
|
||||
const tab = mockTab(tabs);
|
||||
serializer.serializeComponent(tab, MockView1, null);
|
||||
expect(serializer._createSegment).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -65,7 +70,8 @@ describe('UrlSerializer', () => {
|
||||
name: 'jenny'
|
||||
};
|
||||
|
||||
const segment = serializer._createSegment({ navId: '1', type: 'nav', secondaryId: null}, link, data);
|
||||
const nav = mockNavController();
|
||||
const segment = serializer._createSegment(serializer._app, nav, link, data);
|
||||
expect(segment.id).toEqual('userId/8675309/name/jenny');
|
||||
expect(segment.component).toEqual(link.component);
|
||||
expect(segment.data.id).toEqual(data.id);
|
||||
@@ -84,7 +90,8 @@ describe('UrlSerializer', () => {
|
||||
id: char,
|
||||
name: 'jenny'
|
||||
};
|
||||
const segment = serializer._createSegment({ navId: '1', type: 'nav', secondaryId: null}, link, data);
|
||||
const nav = mockNavController();
|
||||
const segment = serializer._createSegment(serializer._app, nav, link, data);
|
||||
expect(segment.id).toEqual(`userId/${encoded}/name/${data.name}`);
|
||||
expect(segment.component).toEqual(MockView1);
|
||||
expect(segment.data.id).toEqual(char);
|
||||
@@ -95,7 +102,8 @@ describe('UrlSerializer', () => {
|
||||
segmentParts: ['settings-view'],
|
||||
component: MockView1
|
||||
};
|
||||
const segment = serializer._createSegment({ navId: '1', type: 'nav', secondaryId: null}, link, null);
|
||||
const nav = mockNavController();
|
||||
const segment = serializer._createSegment(serializer._app, nav, link, null);
|
||||
expect(segment.id).toEqual('settings-view');
|
||||
expect(segment.component).toEqual(MockView1);
|
||||
expect(segment.data).toEqual(null);
|
||||
@@ -103,182 +111,66 @@ describe('UrlSerializer', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('urlToNavGroupStrings', () => {
|
||||
it('should return an empty array of groups when there isnt a nav/tabs keyword', () => {
|
||||
const url = 'some/bogus/url';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should return a single nav group', () => {
|
||||
const url = 'nav/23/chunk/of/segment';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(url);
|
||||
});
|
||||
|
||||
it('should return multiple nav groups', () => {
|
||||
const urlGroupOne = 'nav/1/chunk/of/segment';
|
||||
const urlGroupTwo = 'nav/2/chunk/two';
|
||||
const urlGroupThree = 'nav/3/chunk/three';
|
||||
const url = `${urlGroupOne}/${urlGroupTwo}/${urlGroupThree}`;
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual(urlGroupOne);
|
||||
expect(result[1]).toEqual(urlGroupTwo);
|
||||
expect(result[2]).toEqual(urlGroupThree);
|
||||
});
|
||||
|
||||
it('should return a single tabs group', () => {
|
||||
const url = 'tabs/1/tab-one/chunk/of/segment';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual(url);
|
||||
});
|
||||
|
||||
it('should return multiple tabs groups', () => {
|
||||
const urlGroupOne = 'tabs/1/tab-one/chunk/of/segment';
|
||||
const urlGroupTwo = 'tabs/2/tab-one/chunk/two';
|
||||
const urlGroupThree = 'tabs/3/tab-two/chunk/three';
|
||||
const url = `${urlGroupOne}/${urlGroupTwo}/${urlGroupThree}`;
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual(urlGroupOne);
|
||||
expect(result[1]).toEqual(urlGroupTwo);
|
||||
expect(result[2]).toEqual(urlGroupThree);
|
||||
});
|
||||
|
||||
it('should return groups when url has both nav and tabs and starts with tabs', () => {
|
||||
const urlGroupOne = 'tabs/1/tab-one/chunk/of/segment';
|
||||
const urlGroupTwo = 'nav/2/chunk/two';
|
||||
const urlGroupThree = 'tabs/3/tab-two/chunk/three';
|
||||
const urlGroupFour = 'nav/4/chunk/four';
|
||||
const url = `${urlGroupOne}/${urlGroupTwo}/${urlGroupThree}/${urlGroupFour}`;
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(4);
|
||||
expect(result[0]).toEqual(urlGroupOne);
|
||||
expect(result[1]).toEqual(urlGroupTwo);
|
||||
expect(result[2]).toEqual(urlGroupThree);
|
||||
expect(result[3]).toEqual(urlGroupFour);
|
||||
});
|
||||
|
||||
it('should return groups when url has both nav and tabs and starts with nav', () => {
|
||||
const urlGroupOne = 'nav/1/chunk/of/segment';
|
||||
const urlGroupTwo = 'tabs/1/tab-one/chunk/of/segment';
|
||||
const urlGroupThree = 'tabs/3/tab-two/chunk/three';
|
||||
const urlGroupFour = 'nav/4/chunk/four';
|
||||
const url = `${urlGroupOne}/${urlGroupTwo}/${urlGroupThree}/${urlGroupFour}`;
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(4);
|
||||
expect(result[0]).toEqual(urlGroupOne);
|
||||
expect(result[1]).toEqual(urlGroupTwo);
|
||||
expect(result[2]).toEqual(urlGroupThree);
|
||||
expect(result[3]).toEqual(urlGroupFour);
|
||||
});
|
||||
});
|
||||
|
||||
describe('navGroupStringtoObjects', () => {
|
||||
it('should convert the nav group strings to objects', () => {
|
||||
const urlChunks = ['nav/1/chunk/of/segment', 'tabs/1/tab-one/chunk/of/segment'];
|
||||
const urlChunks = ['taco/burrito/pizza/nachos', 'nav/1/chunk/of/segment', 'tabs/1/tab-one/chunk/of/segment', 'schedule', 'taco/burrito'];
|
||||
const objects = navGroupStringtoObjects(urlChunks);
|
||||
expect(objects.length).toEqual(2);
|
||||
expect(objects[0].type).toEqual('nav');
|
||||
expect(objects[0].navId).toEqual('1');
|
||||
expect(objects.length).toEqual(5);
|
||||
expect(objects[0].type).toEqual(null);
|
||||
expect(objects[0].navId).toEqual(null);
|
||||
expect(objects[0].secondaryId).toEqual(null);
|
||||
expect(objects[0].segmentPieces.length).toEqual(3);
|
||||
expect(objects[0].segmentPieces[0]).toEqual('chunk');
|
||||
expect(objects[0].segmentPieces[1]).toEqual('of');
|
||||
expect(objects[0].segmentPieces[2]).toEqual('segment');
|
||||
expect(objects[1].type).toEqual('tabs');
|
||||
expect(objects[0].segmentPieces.length).toEqual(4);
|
||||
expect(objects[0].segmentPieces[0]).toEqual('taco');
|
||||
expect(objects[0].segmentPieces[1]).toEqual('burrito');
|
||||
expect(objects[0].segmentPieces[2]).toEqual('pizza');
|
||||
expect(objects[0].segmentPieces[3]).toEqual('nachos');
|
||||
expect(objects[1].type).toEqual('nav');
|
||||
expect(objects[1].navId).toEqual('1');
|
||||
expect(objects[1].secondaryId).toEqual('tab-one');
|
||||
expect(objects[1].secondaryId).toEqual(null);
|
||||
expect(objects[1].segmentPieces.length).toEqual(3);
|
||||
expect(objects[1].segmentPieces[0]).toEqual('chunk');
|
||||
expect(objects[1].segmentPieces[1]).toEqual('of');
|
||||
expect(objects[1].segmentPieces[2]).toEqual('segment');
|
||||
});
|
||||
});
|
||||
expect(objects[2].type).toEqual('tabs');
|
||||
expect(objects[2].navId).toEqual('1');
|
||||
expect(objects[2].secondaryId).toEqual('tab-one');
|
||||
expect(objects[2].segmentPieces.length).toEqual(3);
|
||||
expect(objects[2].segmentPieces[0]).toEqual('chunk');
|
||||
expect(objects[2].segmentPieces[1]).toEqual('of');
|
||||
expect(objects[2].segmentPieces[2]).toEqual('segment');
|
||||
|
||||
describe('parse', () => {
|
||||
expect(objects[3].type).toEqual(null);
|
||||
expect(objects[3].navId).toEqual(null);
|
||||
expect(objects[3].secondaryId).toEqual(null);
|
||||
expect(objects[3].segmentPieces.length).toEqual(1);
|
||||
expect(objects[3].segmentPieces[0]).toEqual('schedule');
|
||||
|
||||
it('should return empty list of segments for bogus url', () => {
|
||||
serializer = mockSerializer([]);
|
||||
|
||||
const segments = serializer.parse('/some/bogus/url');
|
||||
expect(segments.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should return empty list of segments when there isnt a match', () => {
|
||||
serializer = mockSerializer([
|
||||
{ segment: 'some/chunk/of/url', name: 'viewone', component: MockView1 },
|
||||
{ segment: 'another/section/of/url', name: 'viewtwo', component: MockView2 }
|
||||
]);
|
||||
const segments = serializer.parse('/nav/n1/not/a/matching/url');
|
||||
expect(segments.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should return the segments from the url with multiple navs', () => {
|
||||
serializer = mockSerializer([
|
||||
{ segment: 'userId/:id/name/:name', name: 'viewone', component: MockView1 },
|
||||
{ segment: 'selectedId/:id/food/:food', name: 'viewtwo', component: MockView2 }
|
||||
]);
|
||||
const segments = serializer.parse('/nav/n1/userId/123/name/Stanley/nav/n2/selectedId/456/food/tacos');
|
||||
expect(segments.length).toEqual(2);
|
||||
expect(segments[0].name).toEqual('viewone');
|
||||
expect(segments[0].data.id).toEqual('123');
|
||||
expect(segments[0].data.name).toEqual('Stanley');
|
||||
expect(segments[1].name).toEqual('viewtwo');
|
||||
expect(segments[1].data.id).toEqual('456');
|
||||
expect(segments[1].data.food).toEqual('tacos');
|
||||
});
|
||||
|
||||
it('should return the segments from the url with multiple tabs', () => {
|
||||
serializer = mockSerializer([
|
||||
{ segment: 'userId/:id/name/:name', name: 'viewone', component: MockView1 },
|
||||
{ segment: 'selectedId/:id/food/:food', name: 'viewtwo', component: MockView2 }
|
||||
]);
|
||||
const segments = serializer.parse('/tabs/t1/tab-one/userId/123/name/Stanley/tabs/t2/tab-three/selectedId/456/food/tacos');
|
||||
expect(segments.length).toEqual(2);
|
||||
expect(segments[0].name).toEqual('viewone');
|
||||
expect(segments[0].navId).toEqual('t1');
|
||||
expect(segments[0].data.id).toEqual('123');
|
||||
expect(segments[0].data.name).toEqual('Stanley');
|
||||
expect(segments[0].secondaryId).toEqual('tab-one');
|
||||
expect(segments[1].name).toEqual('viewtwo');
|
||||
expect(segments[1].navId).toEqual('t2');
|
||||
expect(segments[1].data.id).toEqual('456');
|
||||
expect(segments[1].data.food).toEqual('tacos');
|
||||
expect(segments[1].secondaryId).toEqual('tab-three');
|
||||
});
|
||||
|
||||
it('should return the segments from a mixed nav/tabs url', () => {
|
||||
serializer = mockSerializer([
|
||||
{ segment: 'userId/:id/name/:name', name: 'viewone', component: MockView1 },
|
||||
{ segment: 'selectedId/:id/food/:food', name: 'viewtwo', component: MockView2 }
|
||||
]);
|
||||
const segments = serializer.parse('/tabs/t1/tab-one/userId/123/name/Stanley/nav/n1/selectedId/456/food/tacos');
|
||||
expect(segments.length).toEqual(2);
|
||||
expect(segments[0].name).toEqual('viewone');
|
||||
expect(segments[0].navId).toEqual('t1');
|
||||
expect(segments[0].data.id).toEqual('123');
|
||||
expect(segments[0].data.name).toEqual('Stanley');
|
||||
expect(segments[0].secondaryId).toEqual('tab-one');
|
||||
expect(segments[1].name).toEqual('viewtwo');
|
||||
expect(segments[1].navId).toEqual('n1');
|
||||
expect(segments[1].data.id).toEqual('456');
|
||||
expect(segments[1].data.food).toEqual('tacos');
|
||||
expect(segments[1].secondaryId).toEqual(null);
|
||||
expect(objects[4].type).toEqual(null);
|
||||
expect(objects[4].navId).toEqual(null);
|
||||
expect(objects[4].secondaryId).toEqual(null);
|
||||
expect(objects[4].segmentPieces.length).toEqual(2);
|
||||
expect(objects[4].segmentPieces[0]).toEqual('taco');
|
||||
expect(objects[4].segmentPieces[1]).toEqual('burrito');
|
||||
});
|
||||
});
|
||||
|
||||
describe('serialize', () => {
|
||||
it('should serialize multiple segments into a url with explicit prefixs', () => {
|
||||
let paths: NavSegment[] = [
|
||||
{ type: 'nav', navId: 'whatup', secondaryId: null, id: 'some/url/chunks', name: 'viewOne', component: MockView1, data: null, requiresExplicitNavPrefix: true},
|
||||
{ type: 'tabs', navId: 't1', secondaryId: 'tab-one', id: 'some/more/url/chunks', name: 'viewTwo', component: MockView1, data: null, requiresExplicitNavPrefix: true }
|
||||
];
|
||||
const result = serializer.serialize(paths);
|
||||
expect(result).toEqual('/nav/whatup/some/url/chunks/tabs/t1/tab-one/some/more/url/chunks');
|
||||
});
|
||||
|
||||
it('should serialize multiple segments into a url', () => {
|
||||
let paths: NavSegment[] = [
|
||||
{ type: 'nav', navId: 'whatup', secondaryId: null, id: 'some/url/chunks', name: 'viewOne', component: MockView1, data: null },
|
||||
{ type: 'tabs', navId: 't1', secondaryId: 'tab-one', id: 'some/more/url/chunks', name: 'viewTwo', component: MockView1, data: null }
|
||||
];
|
||||
const result = serializer.serialize(paths);
|
||||
expect(result).toEqual('/nav/whatup/some/url/chunks/tabs/t1/tab-one/some/more/url/chunks');
|
||||
expect(result).toEqual('/some/url/chunks/tab-one/some/more/url/chunks');
|
||||
});
|
||||
|
||||
it('should return default url when given empty list of segments', () => {
|
||||
@@ -342,194 +234,6 @@ describe('UrlSerializer', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('parseUrlParts', () => {
|
||||
|
||||
it('should return a single matching segment', () => {
|
||||
// arrange
|
||||
const navGroups = [];
|
||||
const configLinks = [];
|
||||
const segmentPieces = ['some', 'part', 'of', 'url'];
|
||||
|
||||
const navGroup = { type: 'nav', navId: '1', secondaryId: '', segmentPieces: segmentPieces };
|
||||
navGroups.push(navGroup);
|
||||
|
||||
const configLink = {
|
||||
segmentParts: segmentPieces,
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'someName',
|
||||
loadChildren: 'someValue',
|
||||
};
|
||||
configLinks.push(configLink);
|
||||
|
||||
// act
|
||||
const segments = parseUrlParts(navGroups, configLinks);
|
||||
|
||||
// assert
|
||||
expect(segments.length).toEqual(1);
|
||||
expect(segments[0].id).toEqual(configLink.segmentParts.join('/'));
|
||||
expect(segments[0].component).toEqual(configLink.component);
|
||||
expect(segments[0].name).toEqual(configLink.name);
|
||||
expect(segments[0].loadChildren).toEqual(configLink.loadChildren);
|
||||
expect(segments[0].type).toEqual(navGroup.type);
|
||||
expect(segments[0].navId).toEqual(navGroup.navId);
|
||||
expect(segments[0].secondaryId).toEqual(navGroup.secondaryId);
|
||||
});
|
||||
|
||||
it('should return single matching segment for tabs', () => {
|
||||
// arrange
|
||||
const navGroups = [];
|
||||
const configLinks = [];
|
||||
const segmentPieces = ['some', 'part', 'of', 'url'];
|
||||
|
||||
const navGroup = { type: 'tabs', navId: '1', secondaryId: 'tab-one', segmentPieces: segmentPieces };
|
||||
navGroups.push(navGroup);
|
||||
|
||||
const configLink = {
|
||||
segmentParts: ['some', ':someVariable', 'of', ':someVariable2'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'someName',
|
||||
loadChildren: 'someValue',
|
||||
};
|
||||
configLinks.push(configLink);
|
||||
|
||||
// act
|
||||
const segments = parseUrlParts(navGroups, configLinks);
|
||||
|
||||
// assert
|
||||
expect(segments.length).toEqual(1);
|
||||
expect(segments[0].id).toEqual(configLink.segmentParts.join('/'));
|
||||
expect(segments[0].component).toEqual(configLink.component);
|
||||
expect(segments[0].name).toEqual(configLink.name);
|
||||
expect(segments[0].loadChildren).toEqual(configLink.loadChildren);
|
||||
expect(segments[0].type).toEqual(navGroup.type);
|
||||
expect(segments[0].navId).toEqual(navGroup.navId);
|
||||
expect(segments[0].secondaryId).toEqual(navGroup.secondaryId);
|
||||
expect(segments[0].data.someVariable).toEqual('part');
|
||||
expect(segments[0].data.someVariable2).toEqual('url');
|
||||
});
|
||||
|
||||
it('should return an empty list of segments when there isnt a nav group', () => {
|
||||
// arrange
|
||||
const configLinks = [];
|
||||
|
||||
const configLink = {
|
||||
segmentParts: ['some', ':someVariable', 'of', ':someVariable2'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'someName',
|
||||
loadChildren: 'someValue',
|
||||
};
|
||||
configLinks.push(configLink);
|
||||
|
||||
// act
|
||||
const segments = parseUrlParts([], configLinks);
|
||||
|
||||
// assert
|
||||
expect(segments.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should return a list of segments', () => {
|
||||
// arrange
|
||||
const navGroups = [];
|
||||
const configLinks = [];
|
||||
const segmentPiecesOne = ['some', 'part', 'of', 'url'];
|
||||
const navGroup = { type: 'tabs', navId: '1', secondaryId: 'tab-one', segmentPieces: segmentPiecesOne };
|
||||
const segmentPiecesTwo = ['userId', '123', 'name', 'Stanley Hudson'];
|
||||
const navGroupTwo = { type: 'nav', navId: '2', secondaryId: '', segmentPieces: segmentPiecesTwo };
|
||||
|
||||
navGroups.push(navGroup);
|
||||
navGroups.push(navGroupTwo);
|
||||
|
||||
const configLink = {
|
||||
segmentParts: ['some', ':someVariable', 'of', ':someVariable2'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'someName',
|
||||
loadChildren: 'someValue',
|
||||
};
|
||||
const configLinkTwo = {
|
||||
segmentParts: ['userId', ':userId', 'name', ':name'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'nameTwo',
|
||||
loadChildren: 'valueTwo',
|
||||
};
|
||||
configLinks.push(configLink);
|
||||
configLinks.push(configLinkTwo);
|
||||
|
||||
// act
|
||||
const segments = parseUrlParts(navGroups, configLinks);
|
||||
|
||||
// assert
|
||||
expect(segments.length).toEqual(2);
|
||||
expect(segments[0].id).toEqual(configLink.segmentParts.join('/'));
|
||||
expect(segments[0].component).toEqual(configLink.component);
|
||||
expect(segments[0].name).toEqual(configLink.name);
|
||||
expect(segments[0].loadChildren).toEqual(configLink.loadChildren);
|
||||
expect(segments[0].type).toEqual(navGroup.type);
|
||||
expect(segments[0].navId).toEqual(navGroup.navId);
|
||||
expect(segments[0].secondaryId).toEqual(navGroup.secondaryId);
|
||||
expect(segments[0].data.someVariable).toEqual('part');
|
||||
expect(segments[0].data.someVariable2).toEqual('url');
|
||||
|
||||
expect(segments[1].id).toEqual(configLinkTwo.segmentParts.join('/'));
|
||||
expect(segments[1].component).toEqual(configLinkTwo.component);
|
||||
expect(segments[1].name).toEqual(configLinkTwo.name);
|
||||
expect(segments[1].loadChildren).toEqual(configLinkTwo.loadChildren);
|
||||
expect(segments[1].type).toEqual(navGroupTwo.type);
|
||||
expect(segments[1].navId).toEqual(navGroupTwo.navId);
|
||||
expect(segments[1].secondaryId).toEqual(navGroupTwo.secondaryId);
|
||||
expect(segments[1].data.userId).toEqual('123');
|
||||
expect(segments[1].data.name).toEqual('Stanley Hudson');
|
||||
});
|
||||
|
||||
it('should return only matching segments for the nav groups', () => {
|
||||
// arrange
|
||||
const navGroups = [];
|
||||
const configLinks = [];
|
||||
const segmentPiecesOne = ['some', 'part', 'of', 'url'];
|
||||
const navGroup = { type: 'tabs', navId: '1', secondaryId: 'tab-one', segmentPieces: segmentPiecesOne };
|
||||
const segmentPiecesTwo = ['userId', '123', 'name', 'Stanley Hudson'];
|
||||
const navGroupTwo = { type: 'nav', navId: '2', secondaryId: '', segmentPieces: segmentPiecesTwo };
|
||||
|
||||
navGroups.push(navGroup);
|
||||
navGroups.push(navGroupTwo);
|
||||
|
||||
const configLink = {
|
||||
segmentParts: ['some', ':someVariable', 'of', ':someVariable2'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'someName',
|
||||
loadChildren: 'someValue',
|
||||
};
|
||||
const configLinkTwo = {
|
||||
segmentParts: ['some', 'bogus', 'content', 'wewontmatch'],
|
||||
segmentPartsLen: 4,
|
||||
component: {},
|
||||
name: 'nameTwo',
|
||||
loadChildren: 'valueTwo',
|
||||
};
|
||||
const configLinkThree = {
|
||||
segmentParts: ['hi'],
|
||||
segmentPartsLen: 1,
|
||||
component: {},
|
||||
name: 'nameThree',
|
||||
loadChildren: 'valueThree',
|
||||
};
|
||||
configLinks.push(configLink);
|
||||
configLinks.push(configLinkTwo);
|
||||
configLinks.push(configLinkThree);
|
||||
|
||||
const segments = parseUrlParts(navGroups, configLinks);
|
||||
|
||||
expect(segments.length).toEqual(1);
|
||||
expect(segments[0].name).toEqual(configLink.name);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('isPartMatch', () => {
|
||||
|
||||
it('should match if parts are equal', () => {
|
||||
@@ -764,6 +468,358 @@ describe('UrlSerializer', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('urlToNavGroupStrings', () => {
|
||||
it('should get an array with a single piece url back', () => {
|
||||
const url = 'test';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual('test');
|
||||
});
|
||||
|
||||
it('should get an array with multiple pieces back', () => {
|
||||
const url = 'the/dog/jumps/high';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual('the/dog/jumps/high');
|
||||
});
|
||||
|
||||
it('should return a single entry with the nav prefix', () => {
|
||||
const url = 'nav/myApp/the/dog/jumps/high';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual('nav/myApp/the/dog/jumps/high');
|
||||
});
|
||||
|
||||
it('should return a single entry with the tabs prefix', () => {
|
||||
const url = 'tabs/myApp/tab-one/the/dog/jumps/high';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0]).toEqual('tabs/myApp/tab-one/the/dog/jumps/high');
|
||||
});
|
||||
|
||||
it('should return multiple entries with the nav prefix', () => {
|
||||
const url = 'nav/myApp/the/dog/jumps/high/nav/someSubNav/taco/burrito/nav/thirdNav/banana/apple/orange';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual('nav/myApp/the/dog/jumps/high');
|
||||
expect(result[1]).toEqual('nav/someSubNav/taco/burrito');
|
||||
expect(result[2]).toEqual('nav/thirdNav/banana/apple/orange');
|
||||
});
|
||||
|
||||
it('should return multiple entries with the tabs prefix', () => {
|
||||
const url = 'tabs/myApp/tab-one/the/dog/jumps/high/tabs/someSubNav/tab-two/taco/burrito/tabs/thirdNav/tab-three/banana/apple/orange';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual('tabs/myApp/tab-one/the/dog/jumps/high');
|
||||
expect(result[1]).toEqual('tabs/someSubNav/tab-two/taco/burrito');
|
||||
expect(result[2]).toEqual('tabs/thirdNav/tab-three/banana/apple/orange');
|
||||
});
|
||||
|
||||
it('should handle a nav in the middle of the url', () => {
|
||||
const url = 'the/dog/jumps/high/nav/someSubNav/taco/burrito/nav/thirdNav/banana/apple/orange';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual('the/dog/jumps/high');
|
||||
expect(result[1]).toEqual('nav/someSubNav/taco/burrito');
|
||||
expect(result[2]).toEqual('nav/thirdNav/banana/apple/orange');
|
||||
});
|
||||
|
||||
it('should handle a tabs in the middle of the url', () => {
|
||||
const url = 'the/dog/jumps/high/tabs/someSubNav/tab-two/taco/burrito/tabs/thirdNav/tab-three/banana/apple/orange';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual('the/dog/jumps/high');
|
||||
expect(result[1]).toEqual('tabs/someSubNav/tab-two/taco/burrito');
|
||||
expect(result[2]).toEqual('tabs/thirdNav/tab-three/banana/apple/orange');
|
||||
});
|
||||
|
||||
it('should handle a mixed url', () => {
|
||||
const url = 'the/dog/jumps/high/tabs/someSubNav/tab-two/taco/burrito/nav/thirdNav/banana/apple/orange';
|
||||
const result = urlToNavGroupStrings(url);
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result[0]).toEqual('the/dog/jumps/high');
|
||||
expect(result[1]).toEqual('tabs/someSubNav/tab-two/taco/burrito');
|
||||
expect(result[2]).toEqual('nav/thirdNav/banana/apple/orange');
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertUrlToDehydratedSegments', () => {
|
||||
it('it should return a vanilla single segment', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3]);
|
||||
const url = 'view-two';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two');
|
||||
});
|
||||
|
||||
it('it should return a data-driven single segment', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3]);
|
||||
const url = 'view-two/paramOne/taco/paramTwo/burrito';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[0].segments[0].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[0].segments[0].data.paramTwo).toEqual('burrito');
|
||||
});
|
||||
|
||||
it('it should return a vanilla set of segments', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'view-two/view-one/view-three';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two');
|
||||
expect(segmentPairs[0].segments[1].id).toEqual('view-one');
|
||||
expect(segmentPairs[0].segments[2].id).toEqual('view-three');
|
||||
});
|
||||
|
||||
it('it should return a data-driven set of segments', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'view-two/user/fred/view-one/paramOne/taco/paramTwo/burrito/view-three/12345';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
expect(segmentPairs[0].segments[1].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[0].segments[1].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[0].segments[1].data.paramTwo).toEqual('burrito');
|
||||
expect(segmentPairs[0].segments[2].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[0].segments[2].data.itemId).toEqual('12345');
|
||||
});
|
||||
|
||||
it('it should return a data-driven set of segments with a root nav prefix', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'nav/123/view-two/user/fred/view-one/paramOne/taco/paramTwo/burrito/view-three/12345';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
expect(segmentPairs[0].segments[1].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[0].segments[1].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[0].segments[1].data.paramTwo).toEqual('burrito');
|
||||
expect(segmentPairs[0].segments[2].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[0].segments[2].data.itemId).toEqual('12345');
|
||||
});
|
||||
|
||||
it('it should return a data-driven set of segments with multiple nav segments in the middle', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'view-two/user/fred/nav/123/view-one/paramOne/taco/paramTwo/burrito/nav/456/view-three/12345';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
|
||||
expect(segmentPairs[1].segments.length).toEqual(1);
|
||||
expect(segmentPairs[1].segments[0].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[1].segments[0].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[1].segments[0].data.paramTwo).toEqual('burrito');
|
||||
|
||||
expect(segmentPairs[2].segments.length).toEqual(1);
|
||||
expect(segmentPairs[2].segments[0].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[2].segments[0].data.itemId).toEqual('12345');
|
||||
});
|
||||
|
||||
it('it should return a data-driven set of segments with a root nav and multiple nav segments in the middle', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'nav/app/view-two/user/fred/nav/123/view-one/paramOne/taco/paramTwo/burrito/nav/456/view-three/12345';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
|
||||
expect(segmentPairs[1].segments.length).toEqual(1);
|
||||
expect(segmentPairs[1].segments[0].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[1].segments[0].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[1].segments[0].data.paramTwo).toEqual('burrito');
|
||||
|
||||
expect(segmentPairs[2].segments.length).toEqual(1);
|
||||
expect(segmentPairs[2].segments[0].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[2].segments[0].data.itemId).toEqual('12345');
|
||||
});
|
||||
|
||||
it('it should return a data-driven set of segments with a root tabs and multiple tabs segments in the middle', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'tabs/app/tab-two/view-two/user/fred/tabs/123/tab-three/view-one/paramOne/taco/paramTwo/burrito/tabs/456/tab-four/view-three/12345';
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
|
||||
expect(segmentPairs[1].segments.length).toEqual(1);
|
||||
expect(segmentPairs[1].segments[0].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[1].segments[0].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[1].segments[0].data.paramTwo).toEqual('burrito');
|
||||
|
||||
expect(segmentPairs[2].segments.length).toEqual(1);
|
||||
expect(segmentPairs[2].segments[0].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[2].segments[0].data.itemId).toEqual('12345');
|
||||
});
|
||||
|
||||
it('should return a data-driven set of segments where the root tabs is implied but the secondary identifier is actually grabed', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'viewfour', segment: 'view-four' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'tab-two/view-two/user/fred' + '/tab-three/view-one/paramOne/taco/paramTwo/burrito' + '/tab-four/view-three/12345';
|
||||
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(3);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('view-two/user/fred');
|
||||
expect(segmentPairs[0].segments[0].name).toEqual('viewtwo');
|
||||
expect(segmentPairs[0].segments[0].secondaryId).toEqual('tab-two');
|
||||
expect(segmentPairs[0].segments[0].data.userId).toEqual('fred');
|
||||
|
||||
expect(segmentPairs[0].segments[1].id).toEqual('view-one/paramOne/taco/paramTwo/burrito');
|
||||
expect(segmentPairs[0].segments[1].name).toEqual('viewone');
|
||||
expect(segmentPairs[0].segments[1].data.paramOne).toEqual('taco');
|
||||
expect(segmentPairs[0].segments[1].data.paramTwo).toEqual('burrito');
|
||||
expect(segmentPairs[0].segments[1].secondaryId).toEqual('tab-three');
|
||||
|
||||
expect(segmentPairs[0].segments[2].id).toEqual('view-three/12345');
|
||||
expect(segmentPairs[0].segments[2].name).toEqual('viewthree');
|
||||
expect(segmentPairs[0].segments[2].data.itemId).toEqual('12345');
|
||||
expect(segmentPairs[0].segments[2].secondaryId).toEqual('tab-four');
|
||||
});
|
||||
|
||||
it('should return a segment w/ secondary id even if it has the same name as a router link basic', () => {
|
||||
const link1 = { component: MockView1, name: 'viewone', segment: 'view-one/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link2 = { component: MockView1, name: 'viewtwo', segment: 'view-two/user/:userId' };
|
||||
const link3 = { component: MockView1, name: 'viewthree', segment: 'view-three/:itemId' };
|
||||
const link4 = { component: MockView1, name: 'schedule', segment: 'schedule' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4]);
|
||||
const url = 'schedule/schedule';
|
||||
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments.length).toEqual(1);
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('schedule');
|
||||
expect(segmentPairs[0].segments[0].name).toEqual('schedule');
|
||||
expect(segmentPairs[0].segments[0].secondaryId).toEqual('schedule');
|
||||
});
|
||||
|
||||
it('should return a segment for the secondary id even if it has the same name as a router link advanced', () => {
|
||||
const link1 = { component: MockView1, name: 'about', segment: 'about/:id' };
|
||||
const link2 = { component: MockView1, name: 'schedule', segment: 'schedule/paramOne/:paramOne/paramTwo/:paramTwo' };
|
||||
const link3 = { component: MockView1, name: 'ThirdPage', segment: 'third-page' };
|
||||
const link4 = { component: MockView1, name: 'FourthPage', segment: 'fourth-page/object/:objectId' };
|
||||
const link5 = { component: MockView1, name: 'taco-page', segment: 'taco-page' };
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3, link4, link5]);
|
||||
const url = 'schedule/schedule/paramOne/hello/paramTwo/goodbye'
|
||||
+ '/about/about/123'
|
||||
+ '/tabs/t1/tab-one/third-page'
|
||||
+ '/tabs/t2/tab-two/fourth-page/object/456'
|
||||
+ '/fifth-page/taco-page';
|
||||
|
||||
const segmentPairs = convertUrlToDehydratedSegments(url, links);
|
||||
expect(segmentPairs.length).toEqual(3);
|
||||
|
||||
expect(segmentPairs[0].segments.length).toEqual(2);
|
||||
|
||||
expect(segmentPairs[0].segments[0].id).toEqual('schedule/paramOne/hello/paramTwo/goodbye');
|
||||
expect(segmentPairs[0].segments[0].name).toEqual('schedule');
|
||||
expect(segmentPairs[0].segments[0].secondaryId).toEqual('schedule');
|
||||
expect(segmentPairs[0].segments[0].data.paramOne).toEqual('hello');
|
||||
expect(segmentPairs[0].segments[0].data.paramTwo).toEqual('goodbye');
|
||||
|
||||
expect(segmentPairs[0].segments[1].id).toEqual('about/123');
|
||||
expect(segmentPairs[0].segments[1].name).toEqual('about');
|
||||
expect(segmentPairs[0].segments[1].secondaryId).toEqual('about');
|
||||
expect(segmentPairs[0].segments[1].data.id).toEqual('123');
|
||||
|
||||
expect(segmentPairs[1].segments.length).toEqual(1);
|
||||
|
||||
expect(segmentPairs[1].navGroup.navId).toEqual('t1');
|
||||
expect(segmentPairs[1].navGroup.type).toEqual('tabs');
|
||||
expect(segmentPairs[1].segments[0].id).toEqual('third-page');
|
||||
expect(segmentPairs[1].segments[0].name).toEqual('ThirdPage');
|
||||
expect(segmentPairs[1].segments[0].secondaryId).toEqual('tab-one');
|
||||
|
||||
expect(segmentPairs[2].segments.length).toEqual(2);
|
||||
|
||||
expect(segmentPairs[2].navGroup.navId).toEqual('t2');
|
||||
expect(segmentPairs[2].navGroup.type).toEqual('tabs');
|
||||
expect(segmentPairs[2].segments[0].id).toEqual('fourth-page/object/456');
|
||||
expect(segmentPairs[2].segments[0].name).toEqual('FourthPage');
|
||||
expect(segmentPairs[2].segments[0].secondaryId).toEqual('tab-two');
|
||||
expect(segmentPairs[2].segments[0].data.objectId).toEqual('456');
|
||||
|
||||
expect(segmentPairs[2].segments[1].id).toEqual('taco-page');
|
||||
expect(segmentPairs[2].segments[1].name).toEqual('taco-page');
|
||||
expect(segmentPairs[2].segments[1].secondaryId).toEqual('fifth-page');
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertUrlToSegments', () => {
|
||||
it('it should return a vanilla single segment', () => {
|
||||
|
||||
const link1 = { component: MockView1, name: 'login-page', segment: 'login-page' };
|
||||
const link2 = { component: MockView1, name: 'settings-page', segment: 'settings-page' };
|
||||
const link3 = { component: MockView1, name: 'details-page', segment: 'details-page' };
|
||||
|
||||
const mockNav = mockNavController();
|
||||
serializer._app.registerRootNav(mockNav);
|
||||
|
||||
const links = normalizeLinks([link1, link2, link3]);
|
||||
const url = 'settings-page';
|
||||
|
||||
|
||||
const segments = convertUrlToSegments(serializer._app, url, links);
|
||||
expect(segments.length).toEqual(1);
|
||||
expect(segments[0].type).toEqual('nav');
|
||||
expect(segments[0].navId).toEqual(mockNav.id);
|
||||
});
|
||||
});
|
||||
|
||||
var serializer: UrlSerializer;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -778,5 +834,5 @@ class NotFound {}
|
||||
|
||||
function mockSerializer(navLinks?: NavLink[]) {
|
||||
let deepLinkConfig = mockDeepLinkConfig(navLinks);
|
||||
return new UrlSerializer(deepLinkConfig);
|
||||
return new UrlSerializer(mockApp(), deepLinkConfig);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { OpaqueToken } from '@angular/core';
|
||||
|
||||
import { App } from '../components/app/app';
|
||||
import { NavigationContainer } from './navigation-container';
|
||||
import { DeepLinkConfig, NavLink, NavSegment } from './nav-util';
|
||||
import { DeepLinkConfig, DehydratedSegment, DehydratedSegmentPair, NavGroup, NavLink, NavSegment } from './nav-util';
|
||||
import { isArray, isBlank, isPresent } from '../util/util';
|
||||
|
||||
|
||||
@@ -11,7 +12,7 @@ import { isArray, isBlank, isPresent } from '../util/util';
|
||||
export class UrlSerializer {
|
||||
links: NavLink[];
|
||||
|
||||
constructor(config: DeepLinkConfig) {
|
||||
constructor(public _app: App, config: DeepLinkConfig) {
|
||||
if (config && isArray(config.links)) {
|
||||
this.links = normalizeLinks(config.links);
|
||||
|
||||
@@ -31,9 +32,7 @@ export class UrlSerializer {
|
||||
|
||||
// trim off data after ? and #
|
||||
browserUrl = browserUrl.split('?')[0].split('#')[0];
|
||||
const navGroupStrings = urlToNavGroupStrings(browserUrl);
|
||||
const navGroups = navGroupStringtoObjects(navGroupStrings);
|
||||
return parseUrlParts(navGroups, this.links);
|
||||
return convertUrlToSegments(this._app, browserUrl, this.links);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +40,7 @@ export class UrlSerializer {
|
||||
createSegmentFromName(navContainer: NavigationContainer, nameOrComponent: any): NavSegment {
|
||||
const configLink = this.getLinkFromName(nameOrComponent);
|
||||
if (configLink) {
|
||||
return this._createSegment({ navId: navContainer.id, secondaryId: navContainer.getSecondaryIdentifier(), type: 'tabs'}, configLink, null);
|
||||
return this._createSegment(this._app, navContainer, configLink, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -63,9 +62,16 @@ export class UrlSerializer {
|
||||
}
|
||||
const sections = segments.map(segment => {
|
||||
if (segment.type === 'tabs') {
|
||||
return `/${segment.type}/${segment.navId}/${segment.secondaryId}/${segment.id}`;
|
||||
if (segment.requiresExplicitNavPrefix) {
|
||||
return `/${segment.type}/${segment.navId}/${segment.secondaryId}/${segment.id}`;
|
||||
}
|
||||
return `/${segment.secondaryId}/${segment.id}`;
|
||||
}
|
||||
return `/${segment.type}/${segment.navId}/${segment.id}`;
|
||||
// it's a nav
|
||||
if (segment.requiresExplicitNavPrefix) {
|
||||
return `/${segment.type}/${segment.navId}/${segment.id}`;
|
||||
}
|
||||
return `/${segment.id}`;
|
||||
});
|
||||
return sections.join('');
|
||||
}
|
||||
@@ -73,18 +79,20 @@ export class UrlSerializer {
|
||||
/**
|
||||
* Serializes a component and its data into a NavSegment.
|
||||
*/
|
||||
serializeComponent(navGroup: NavGroup, component: any, data: any): NavSegment {
|
||||
serializeComponent(navContainer: NavigationContainer, component: any, data: any): NavSegment {
|
||||
if (component) {
|
||||
const link = findLinkByComponentData(this.links, component, data);
|
||||
if (link) {
|
||||
return this._createSegment(navGroup, link, data);
|
||||
return this._createSegment(this._app, navContainer, link, data);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_createSegment(navGroup: NavGroup, configLink: NavLink, data: any): NavSegment {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_createSegment(app: App, navContainer: NavigationContainer, configLink: NavLink, data: any): NavSegment {
|
||||
let urlParts = configLink.segmentParts;
|
||||
|
||||
if (isPresent(data)) {
|
||||
@@ -110,6 +118,14 @@ export class UrlSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
let requiresExplicitPrefix = true;
|
||||
if (navContainer.parent) {
|
||||
requiresExplicitPrefix = navContainer.parent && navContainer.parent.getAllChildNavs().length > 1;
|
||||
} else {
|
||||
// if it's a root nav, and there are multiple root navs, we need an explicit prefix
|
||||
requiresExplicitPrefix = app.getRootNavById(navContainer.id) && app.getRootNavs().length > 1;
|
||||
}
|
||||
|
||||
return {
|
||||
id: urlParts.join('/'),
|
||||
name: configLink.name,
|
||||
@@ -117,9 +133,10 @@ export class UrlSerializer {
|
||||
loadChildren: configLink.loadChildren,
|
||||
data: data,
|
||||
defaultHistory: configLink.defaultHistory,
|
||||
navId: navGroup.navId,
|
||||
type: navGroup.type,
|
||||
secondaryId: navGroup.secondaryId
|
||||
navId: navContainer.name || navContainer.id,
|
||||
type: navContainer.getType(),
|
||||
secondaryId: navContainer.getSecondaryIdentifier(),
|
||||
requiresExplicitNavPrefix: requiresExplicitPrefix
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -141,39 +158,6 @@ export function formatUrlPart(name: string): string {
|
||||
return encodeURIComponent(name);
|
||||
}
|
||||
|
||||
export const parseUrlParts = (navGroups: NavGroup[], configLinks: NavLink[]): NavSegment[] => {
|
||||
const segments: NavSegment[] = [];
|
||||
for (const link of configLinks) {
|
||||
for (const navGroup of navGroups) {
|
||||
if (link.segmentPartsLen === navGroup.segmentPieces.length) {
|
||||
// check if the segment pieces are a match
|
||||
let allSegmentsMatch = true;
|
||||
for (let i = 0; i < navGroup.segmentPieces.length; i++) {
|
||||
if (!isPartMatch(navGroup.segmentPieces[i], link.segmentParts[i])) {
|
||||
allSegmentsMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// sweet, we found a match!
|
||||
if (allSegmentsMatch) {
|
||||
segments.push({
|
||||
id: link.segmentParts.join('/'),
|
||||
name: link.name,
|
||||
component: link.component,
|
||||
loadChildren: link.loadChildren,
|
||||
data: createMatchedData(navGroup.segmentPieces, link),
|
||||
defaultHistory: link.defaultHistory,
|
||||
navId: navGroup.navId,
|
||||
type: navGroup.type,
|
||||
secondaryId: navGroup.secondaryId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return segments;
|
||||
};
|
||||
|
||||
export const isPartMatch = (urlPart: string, configLinkPart: string) => {
|
||||
if (isPresent(urlPart) && isPresent(configLinkPart)) {
|
||||
if (configLinkPart.charAt(0) === ':') {
|
||||
@@ -300,26 +284,8 @@ const URL_REPLACE_REG = /\s+|\?|\!|\$|\,|\.|\+|\"|\'|\*|\^|\||\/|\\|\[|\]|#|%|`|
|
||||
*/
|
||||
export const DeepLinkConfigToken = new OpaqueToken('USERLINKS');
|
||||
|
||||
export function setupUrlSerializer(userDeepLinkConfig: any): UrlSerializer {
|
||||
return new UrlSerializer(userDeepLinkConfig);
|
||||
}
|
||||
|
||||
export function urlToNavGroupStrings(url: string): string[] {
|
||||
const tokens = url.split('/');
|
||||
const keywordIndexes = [];
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i] === 'nav' || tokens[i] === 'tabs') {
|
||||
keywordIndexes.push(i);
|
||||
}
|
||||
}
|
||||
const groupings: string[] = [];
|
||||
for (let i = 0; i < keywordIndexes.length; i++) {
|
||||
const startIndex = keywordIndexes[i];
|
||||
const endIndex = keywordIndexes[i + 1 < keywordIndexes.length ? i + 1 : keywordIndexes.length];
|
||||
const group = tokens.slice(startIndex, endIndex);
|
||||
groupings.push(group.join('/'));
|
||||
}
|
||||
return groupings;
|
||||
export function setupUrlSerializer(app: App, userDeepLinkConfig: any): UrlSerializer {
|
||||
return new UrlSerializer(app, userDeepLinkConfig);
|
||||
}
|
||||
|
||||
export function navGroupStringtoObjects(navGroupStrings: string[]): NavGroup[] {
|
||||
@@ -334,20 +300,251 @@ export function navGroupStringtoObjects(navGroupStrings: string[]): NavGroup[] {
|
||||
secondaryId: null,
|
||||
segmentPieces: sections.splice(2)
|
||||
};
|
||||
} else if (sections[0] === 'tabs') {
|
||||
return {
|
||||
type: 'tabs',
|
||||
navId: sections[1],
|
||||
niceId: sections[1],
|
||||
secondaryId: sections[2],
|
||||
segmentPieces: sections.splice(3)
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'tabs',
|
||||
navId: sections[1],
|
||||
niceId: sections[1],
|
||||
secondaryId: sections[2],
|
||||
segmentPieces: sections.splice(3)
|
||||
type: null,
|
||||
navId: null,
|
||||
niceId: null,
|
||||
secondaryId: null,
|
||||
segmentPieces: sections
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export interface NavGroup {
|
||||
type: string;
|
||||
navId: string;
|
||||
secondaryId: string;
|
||||
segmentPieces?: string[];
|
||||
export function urlToNavGroupStrings(url: string) {
|
||||
const tokens = url.split('/');
|
||||
const keywordIndexes = [];
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (i !== 0 && (tokens[i] === 'nav' || tokens[i] === 'tabs')) {
|
||||
keywordIndexes.push(i);
|
||||
}
|
||||
}
|
||||
// append the last index + 1 to the list no matter what
|
||||
keywordIndexes.push(tokens.length);
|
||||
const groupings: string[] = [];
|
||||
let activeKeywordIndex = 0;
|
||||
let tmpArray: string[] = [];
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (i >= keywordIndexes[activeKeywordIndex]) {
|
||||
groupings.push(tmpArray.join('/'));
|
||||
tmpArray = [];
|
||||
activeKeywordIndex++;
|
||||
}
|
||||
tmpArray.push(tokens[i]);
|
||||
}
|
||||
// okay, after the loop we've gotta push one more time just to be safe
|
||||
groupings.push(tmpArray.join('/'));
|
||||
return groupings;
|
||||
}
|
||||
|
||||
export function convertUrlToSegments(app: App, url: string, navLinks: NavLink[]): NavSegment[] {
|
||||
const pairs = convertUrlToDehydratedSegments(url, navLinks);
|
||||
return hydrateSegmentsWithNav(app, pairs);
|
||||
}
|
||||
|
||||
export function convertUrlToDehydratedSegments(url: string, navLinks: NavLink[]): DehydratedSegmentPair[] {
|
||||
const navGroupStrings = urlToNavGroupStrings(url);
|
||||
const navGroups = navGroupStringtoObjects(navGroupStrings);
|
||||
return getSegmentsFromNavGroups(navGroups, navLinks);
|
||||
}
|
||||
|
||||
export function hydrateSegmentsWithNav(app: App, dehydratedSegmentPairs: DehydratedSegmentPair[]) {
|
||||
const segments: NavSegment[] = [];
|
||||
for (let i = 0; i < dehydratedSegmentPairs.length; i++) {
|
||||
let navs = getNavFromNavGroup(dehydratedSegmentPairs[i].navGroup, app);
|
||||
// okay, cool, let's walk through the segments and hydrate them
|
||||
for (const dehydratedSegment of dehydratedSegmentPairs[i].segments) {
|
||||
if (navs.length === 1) {
|
||||
segments.push(hydrateSegment(dehydratedSegment, navs[0]));
|
||||
navs = navs[0].getActiveChildNavs();
|
||||
} else if (navs.length > 1) {
|
||||
// this is almost certainly an async race condition bug in userland
|
||||
// if you're in this state, it would be nice to just bail here
|
||||
// but alas we must perservere and handle the issue
|
||||
// the simple solution is to just use the last child
|
||||
// because that is probably what the user wants anyway
|
||||
// remember, do not harm, even if it makes our shizzle ugly
|
||||
segments.push(hydrateSegment(dehydratedSegment, navs[navs.length - 1]));
|
||||
navs = navs[navs.length - 1].getActiveChildNavs();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
export function getNavFromNavGroup(navGroup: NavGroup, app: App): NavigationContainer[] {
|
||||
if (navGroup.navId) {
|
||||
const rootNav = app.getNavByIdOrName(navGroup.navId);
|
||||
if (rootNav) {
|
||||
return [rootNav];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
// we don't know what nav to use, so just use the root nav.
|
||||
// if there is more than one root nav, throw an error
|
||||
return app.getRootNavs();
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's face the facts: Getting a dehydrated segment from the url is really hard
|
||||
* because we need to do a ton of crazy looping
|
||||
* the are chunks of a url that are totally irrelevant at this stage, such as the secondary identifier
|
||||
* stating which tab is selected, etc.
|
||||
* but is necessary.
|
||||
* We look at segment pieces in reverse order to try to build segments
|
||||
* as in, if you had an array like this
|
||||
* ['my', 'super', 'cool', 'url']
|
||||
* we want to look at the pieces in reverse order:
|
||||
* url
|
||||
* cool url
|
||||
* super cool url
|
||||
* my super cool url
|
||||
* cool
|
||||
* super cool
|
||||
* my super cool
|
||||
* super
|
||||
* my super
|
||||
* my
|
||||
**/
|
||||
export function getSegmentsFromNavGroups(navGroups: NavGroup[], navLinks: NavLink[]) {
|
||||
const pairs: DehydratedSegmentPair[] = [];
|
||||
const usedNavLinks = new Set<string>();
|
||||
for (const navGroup of navGroups) {
|
||||
const segments: DehydratedSegment[] = [];
|
||||
|
||||
const segmentPieces = navGroup.segmentPieces.concat([]);
|
||||
|
||||
for (let i = segmentPieces.length; i >= 0; i--) {
|
||||
let created = false;
|
||||
for (let j = 0; j < i; j++) {
|
||||
const startIndex = i - j - 1;
|
||||
const endIndex = i;
|
||||
const subsetOfUrl = segmentPieces.slice(startIndex, endIndex);
|
||||
for (const navLink of navLinks) {
|
||||
if (!usedNavLinks.has(navLink.name)) {
|
||||
const segment = getSegmentsFromUrlPieces(subsetOfUrl, navLink);
|
||||
|
||||
if (segment) {
|
||||
i = startIndex + 1;
|
||||
usedNavLinks.add(navLink.name);
|
||||
created = true;
|
||||
// sweet, we found a segment
|
||||
segments.push(segment);
|
||||
// now we want to null out the url subsection in the segmentPieces
|
||||
for (let k = startIndex; k < endIndex; k++) {
|
||||
segmentPieces[k] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (created) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!created && segmentPieces[i - 1]) {
|
||||
// this is very likely a tab's secondary identifier
|
||||
segments.push({
|
||||
id: null,
|
||||
name: null,
|
||||
secondaryId: segmentPieces[i - 1],
|
||||
component: null,
|
||||
loadChildren: null,
|
||||
data: null,
|
||||
defaultHistory: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// since we're getting segments in from right-to-left in the url, reverse them
|
||||
// so they're in the correct order. Also filter out and bogus segments
|
||||
const orderedSegments = segments.reverse();
|
||||
|
||||
|
||||
// okay, this is the lazy persons approach here.
|
||||
// so here's the deal! Right now if section of the url is not a part of a segment
|
||||
// it is almost certainly the secondaryId for a tabs component
|
||||
// basically, knowing the segment for the `tab` itself is good, but we also need to know
|
||||
// which tab is selected, so we have an identifer in the url that is associated with the tabs component
|
||||
// telling us which tab is selected. With that in mind, we are going to go through and find the segments with only secondary identifiers,
|
||||
// and simply add the secondaryId to the next segment, and then remove the empty segment from the list
|
||||
for (let i = 0; i < orderedSegments.length; i++) {
|
||||
if (orderedSegments[i].secondaryId && !orderedSegments[i].id && ((i + 1) <= orderedSegments.length - 1)) {
|
||||
orderedSegments[i + 1].secondaryId = orderedSegments[i].secondaryId;
|
||||
orderedSegments[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
const cleanedSegments = segments.filter(segment => !!segment);
|
||||
// if the nav group has a secondary id, make sure the first segment also has it set
|
||||
if (navGroup.secondaryId && segments.length) {
|
||||
cleanedSegments[0].secondaryId = navGroup.secondaryId;
|
||||
}
|
||||
|
||||
pairs.push({
|
||||
navGroup: navGroup,
|
||||
segments: cleanedSegments
|
||||
});
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
export function getSegmentsFromUrlPieces(urlSections: string[], navLink: NavLink): DehydratedSegment {
|
||||
if (navLink.segmentPartsLen !== urlSections.length) {
|
||||
return null;
|
||||
}
|
||||
for (let i = 0; i < urlSections.length; i++) {
|
||||
if (!isPartMatch(urlSections[i], navLink.segmentParts[i])) {
|
||||
// just return an empty array if the part doesn't match
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: urlSections.join('/'),
|
||||
name: navLink.name,
|
||||
component: navLink.component,
|
||||
loadChildren: navLink.loadChildren,
|
||||
data: createMatchedData(urlSections, navLink),
|
||||
defaultHistory: navLink.defaultHistory
|
||||
};
|
||||
}
|
||||
|
||||
export function hydrateSegment(segment: DehydratedSegment, nav: NavigationContainer) {
|
||||
const hydratedSegment = Object.assign({}, segment) as NavSegment;
|
||||
hydratedSegment.type = nav.getType();
|
||||
hydratedSegment.navId = nav.name || nav.id;
|
||||
// secondaryId is set on an empty dehydrated segment in the case of tabs to identify which tab is selected
|
||||
hydratedSegment.secondaryId = segment.secondaryId;
|
||||
return hydratedSegment;
|
||||
}
|
||||
|
||||
export function getNonHydratedSegmentIfLinkAndUrlMatch(urlChunks: string[], navLink: NavLink): DehydratedSegment {
|
||||
let allSegmentsMatch = true;
|
||||
for (let i = 0; i < urlChunks.length; i++) {
|
||||
if (!isPartMatch(urlChunks[i], navLink.segmentParts[i])) {
|
||||
allSegmentsMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allSegmentsMatch) {
|
||||
return {
|
||||
id: navLink.segmentParts.join('/'),
|
||||
name: navLink.name,
|
||||
component: navLink.component,
|
||||
loadChildren: navLink.loadChildren,
|
||||
data: createMatchedData(urlChunks, navLink),
|
||||
defaultHistory: navLink.defaultHistory
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -11,5 +11,7 @@ $cordova-ios-statusbar-padding-modal-max-width: $cordova-statusbar-paddi
|
||||
|
||||
// Cordova mixins are in the main cordova file
|
||||
.ios {
|
||||
@include statusbar-padding($toolbar-ios-height, $toolbar-ios-padding, $content-ios-padding, $cordova-ios-statusbar-padding, $cordova-ios-statusbar-padding-modal-max-width, true);
|
||||
}
|
||||
@include statusbar-padding($toolbar-ios-height, $toolbar-ios-padding, $content-ios-padding, $cordova-ios-statusbar-padding, $cordova-ios-statusbar-padding-modal-max-width, true);
|
||||
|
||||
@include footer-safe-area($toolbar-ios-height, $toolbar-ios-padding);
|
||||
}
|
||||
|
||||
@@ -12,5 +12,7 @@ $cordova-md-statusbar-padding-modal-max-width: $cordova-statusbar-paddin
|
||||
// Cordova mixins are in the main cordova file
|
||||
.md {
|
||||
@include statusbar-padding($toolbar-md-height, $toolbar-md-padding, $content-md-padding, $cordova-md-statusbar-padding, $cordova-md-statusbar-padding-modal-max-width);
|
||||
|
||||
@include footer-safe-area($toolbar-md-height, $toolbar-md-padding);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ $cordova-statusbar-padding-modal-max-width: 767px !default;
|
||||
|
||||
ion-nav > .ion-page,
|
||||
ion-nav > .ion-page > ion-header,
|
||||
ion-tab > .ion-page,
|
||||
ion-tab > .ion-page > ion-header,
|
||||
ion-tabs > .ion-page.tab-subpage > ion-header,
|
||||
ion-menu > .menu-inner,
|
||||
@@ -20,7 +21,7 @@ $cordova-statusbar-padding-modal-max-width: 767px !default;
|
||||
|
||||
// If we should style the title elements in the toolbar
|
||||
@if ($style-title) {
|
||||
@include toolbar-title-statusbar-padding($toolbar-height, $content-padding, $cordova-statusbar-padding);
|
||||
@include toolbar-title-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $cordova-statusbar-padding);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +31,7 @@ $cordova-statusbar-padding-modal-max-width: 767px !default;
|
||||
|
||||
// If we should style the title elements in the toolbar
|
||||
@if ($style-title) {
|
||||
@include toolbar-title-statusbar-padding($toolbar-height, $content-padding, $cordova-statusbar-padding);
|
||||
@include toolbar-title-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $cordova-statusbar-padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,19 +43,24 @@ $cordova-statusbar-padding-modal-max-width: 767px !default;
|
||||
|
||||
@mixin toolbar-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $cordova-statusbar-padding) {
|
||||
|
||||
|
||||
> .toolbar.statusbar-padding:first-child {
|
||||
@include padding(calc(#{$cordova-statusbar-padding} + #{$toolbar-padding}), null, null, null);
|
||||
@include padding(calc(constant(safe-area-inset-top) + #{$toolbar-padding}), calc(constant(safe-area-inset-right) + #{$toolbar-padding}), null, calc(constant(safe-area-inset-left) + #{$toolbar-padding}));
|
||||
|
||||
min-height: calc(#{$toolbar-height} + #{$cordova-statusbar-padding});
|
||||
min-height: calc(#{$toolbar-height} + constant(safe-area-inset-top));
|
||||
}
|
||||
|
||||
> ion-content.statusbar-padding:first-child .scroll-content {
|
||||
@include padding($cordova-statusbar-padding, null, null, null);
|
||||
@include padding(calc(#{$cordova-statusbar-padding} + constant(safe-area-inset-top)), null, null, null);
|
||||
}
|
||||
|
||||
> ion-content.statusbar-padding:first-child[padding] .scroll-content,
|
||||
> ion-content.statusbar-padding:first-child[padding-top] .scroll-content {
|
||||
@include padding(calc(#{$content-padding} + #{$cordova-statusbar-padding}), null, null, null);
|
||||
@include padding(calc(#{$content-padding} + constant(safe-area-inset-top)), null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,14 +69,31 @@ $cordova-statusbar-padding-modal-max-width: 767px !default;
|
||||
// iOS is the only mode that uses this mixin and it should be removed with #5036
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
@mixin toolbar-title-statusbar-padding($toolbar-height, $content-padding, $cordova-statusbar-padding) {
|
||||
@mixin toolbar-title-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $cordova-statusbar-padding) {
|
||||
|
||||
> .toolbar.statusbar-padding:first-child ion-segment,
|
||||
> .toolbar.statusbar-padding:first-child ion-title {
|
||||
@include padding($cordova-statusbar-padding, null, null, null);
|
||||
@include padding(calc(constant(safe-area-inset-top) + #{$toolbar-padding}), null, null, null);
|
||||
|
||||
height: calc(#{$toolbar-height} + #{$cordova-statusbar-padding});
|
||||
height: calc(#{$toolbar-height} + constant(safe-area-inset-top));
|
||||
|
||||
min-height: calc(#{$toolbar-height} + #{$cordova-statusbar-padding});
|
||||
min-height: calc(#{$toolbar-height} + constant(safe-area-inset-top));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@mixin footer-safe-area($toolbar-height, $toolbar-padding) {
|
||||
.tabs .tabbar {
|
||||
@include padding(null, null, constant(safe-area-inset-bottom), null);
|
||||
}
|
||||
|
||||
ion-footer .toolbar:last-child {
|
||||
@include padding(null, null, calc(constant(safe-area-inset-top) + #{$toolbar-padding}), null);
|
||||
height: calc(#{$toolbar-height} + constant(safe-area-inset-top));
|
||||
min-height: calc(#{$toolbar-height} + constant(safe-area-inset-top));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,6 @@ $cordova-wp-statusbar-padding-modal-max-width: $cordova-statusbar-paddin
|
||||
// Cordova mixins are in the main cordova file
|
||||
.wp {
|
||||
@include statusbar-padding($toolbar-wp-height, $toolbar-wp-padding, $content-wp-padding, $cordova-wp-statusbar-padding, $cordova-wp-statusbar-padding-modal-max-width);
|
||||
|
||||
@include footer-safe-area($toolbar-wp-height, $toolbar-wp-padding);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user