mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
335 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4be0dde283 | ||
|
|
6f5e304e18 | ||
|
|
637f26b364 | ||
|
|
63c2008a86 | ||
|
|
033abe994b | ||
|
|
7ce916cc7c | ||
|
|
3c4e65ba97 | ||
|
|
bb32cea5c9 | ||
|
|
fcd7a5620b | ||
|
|
109b5fc633 | ||
|
|
bc56c4aa7b | ||
|
|
9b0bbc86b8 | ||
|
|
a7b964279b | ||
|
|
8706ecf9c3 | ||
|
|
aed2dba5aa | ||
|
|
3050e9fe88 | ||
|
|
02c1724978 | ||
|
|
790e0c69ea | ||
|
|
19ee21a06c | ||
|
|
dea1c2635d | ||
|
|
17614cdcb3 | ||
|
|
bfb704e2d2 | ||
|
|
9688f4d42f | ||
|
|
f4818a1f3a | ||
|
|
71b8853ff4 | ||
|
|
77658e61cc | ||
|
|
cdfd82a750 | ||
|
|
9f5ed231c3 | ||
|
|
3c846a7b06 | ||
|
|
cb26f73f80 | ||
|
|
a02319b06b | ||
|
|
c101dfe6db | ||
|
|
7768ab2307 | ||
|
|
26f50ca651 | ||
|
|
44ad07480b | ||
|
|
8a52c7d66b | ||
|
|
20ffc95ff1 | ||
|
|
b4d92c6241 | ||
|
|
a28e501272 | ||
|
|
f4b97fd74a | ||
|
|
8ca97ce42c | ||
|
|
eab0865fba | ||
|
|
c79e74b91f | ||
|
|
cf223e40c1 | ||
|
|
446cf78e58 | ||
|
|
0f05ea4245 | ||
|
|
bfa17d1594 | ||
|
|
61f04e50b1 | ||
|
|
e90e960294 | ||
|
|
1e081c0a22 | ||
|
|
bf2953cf85 | ||
|
|
7f76f94c9d | ||
|
|
a74754179c | ||
|
|
c5e1290dfe | ||
|
|
6b9abf22f0 | ||
|
|
e98769edd0 | ||
|
|
123d0f38b6 | ||
|
|
1b9593963e | ||
|
|
e7cbafd4b3 | ||
|
|
f7027fc9ad | ||
|
|
4a900964dd | ||
|
|
73dd70d756 | ||
|
|
aec2936725 | ||
|
|
70ba488502 | ||
|
|
151548b0bc | ||
|
|
1cbb52c55c | ||
|
|
e62780411f | ||
|
|
fea061215d | ||
|
|
2d39c07fec | ||
|
|
4e544f1d90 | ||
|
|
a3f345c06d | ||
|
|
e27962dcaf | ||
|
|
ff2aaadf41 | ||
|
|
696be833dc | ||
|
|
c15ae7cbf5 | ||
|
|
d9514801a8 | ||
|
|
923312ecd5 | ||
|
|
d9610cdbdf | ||
|
|
c959d75633 | ||
|
|
4cfd29f574 | ||
|
|
a81653bcdc | ||
|
|
07140cf2c5 | ||
|
|
c7b302c7a6 | ||
|
|
d1ee36b2c8 | ||
|
|
3d935978b3 | ||
|
|
4c30878fc7 | ||
|
|
9751f145e1 | ||
|
|
6eca5b0d7f | ||
|
|
93f2064927 | ||
|
|
da5d3f0e04 | ||
|
|
e1fa461e9b | ||
|
|
0e18f049c2 | ||
|
|
ef34402960 | ||
|
|
03bffc5d95 | ||
|
|
c3044f59df | ||
|
|
4902de4631 | ||
|
|
d031434b5d | ||
|
|
7f6664708c | ||
|
|
48a27636c7 | ||
|
|
b3c7436e01 | ||
|
|
a65d897214 | ||
|
|
3e63b3c2c4 | ||
|
|
d4db3af881 | ||
|
|
c7b6c7d563 | ||
|
|
b1c8fa39d6 | ||
|
|
fa958a5764 | ||
|
|
fb7098080a | ||
|
|
547f648433 | ||
|
|
0e8ab49d7f | ||
|
|
f2cfdf1bad | ||
|
|
c610406ba6 | ||
|
|
50a92c026c | ||
|
|
62a04d76f1 | ||
|
|
2923aac44e | ||
|
|
c6051e89a5 | ||
|
|
27d042fe38 | ||
|
|
c3871b0cda | ||
|
|
919c73f66d | ||
|
|
e0fa4a5276 | ||
|
|
3b51f8f27c | ||
|
|
cd75428785 | ||
|
|
45a59d13cc | ||
|
|
67ed89ded8 | ||
|
|
cbd230c67e | ||
|
|
5a2c441b3c | ||
|
|
fd65765bdf | ||
|
|
624e118b56 | ||
|
|
7f39f8c357 | ||
|
|
930b271a4a | ||
|
|
0b1e23f754 | ||
|
|
a2b7d57336 | ||
|
|
ce192713c3 | ||
|
|
94e525c10b | ||
|
|
30ca46ab12 | ||
|
|
e33cf854a9 | ||
|
|
e8cdda0fae | ||
|
|
1187dc2fc7 | ||
|
|
3c925bb27e | ||
|
|
ea3fdae2dd | ||
|
|
a5d3c6bcd2 | ||
|
|
5f869796be | ||
|
|
7c48500f27 | ||
|
|
e4357f9823 | ||
|
|
fb81966973 | ||
|
|
4ec74f8535 | ||
|
|
c9f7c47571 | ||
|
|
39f076847f | ||
|
|
c473b3ed92 | ||
|
|
6d7b221b86 | ||
|
|
a1b00a7804 | ||
|
|
2f7e3dbacd | ||
|
|
04b350ce0b | ||
|
|
7f4d3a36df | ||
|
|
cb149ddd19 | ||
|
|
a633db1688 | ||
|
|
3ec9607281 | ||
|
|
84e306c1a6 | ||
|
|
713ea8adaa | ||
|
|
8f7853c5e9 | ||
|
|
f94300cbb3 | ||
|
|
3a22105375 | ||
|
|
6bbdb80871 | ||
|
|
7cd68b59fc | ||
|
|
d237e808c2 | ||
|
|
e043ea9dae | ||
|
|
f9579bcd1d | ||
|
|
23f327ecb6 | ||
|
|
3e1dfc657b | ||
|
|
32bb1f7230 | ||
|
|
48352533ff | ||
|
|
e3a5d1f93a | ||
|
|
f08ac68e0b | ||
|
|
7951289460 | ||
|
|
9f32d0edd7 | ||
|
|
ee4c404bd3 | ||
|
|
27a68b3f7f | ||
|
|
962783bfba | ||
|
|
e82648bda2 | ||
|
|
9b85e13493 | ||
|
|
462cee5b2e | ||
|
|
d792560447 | ||
|
|
7272d481bf | ||
|
|
c83edd9329 | ||
|
|
a869ca0bba | ||
|
|
c2348f71a5 | ||
|
|
67ffe2f9cc | ||
|
|
2e02dc7319 | ||
|
|
b7761fe353 | ||
|
|
00891119f7 | ||
|
|
c91819c94f | ||
|
|
3ef6ecf422 | ||
|
|
7ba718c0db | ||
|
|
e8ab0fd317 | ||
|
|
815fa2eb06 | ||
|
|
c52b3b4997 | ||
|
|
23ce6fae9e | ||
|
|
a8455a90ff | ||
|
|
798103bf63 | ||
|
|
bd8ca63451 | ||
|
|
cf27063aae | ||
|
|
fb18f3ba25 | ||
|
|
71137a2ffa | ||
|
|
544e550286 | ||
|
|
854004cf2c | ||
|
|
6b5a59dc43 | ||
|
|
fbfc07688e | ||
|
|
9b075ef529 | ||
|
|
97fec92365 | ||
|
|
26e6d6f115 | ||
|
|
978cc39009 | ||
|
|
53179c475c | ||
|
|
7ae9303a97 | ||
|
|
045bc59b75 | ||
|
|
08af35aad2 | ||
|
|
5b932152f8 | ||
|
|
9993b73355 | ||
|
|
f1eeed1c91 | ||
|
|
ee81907713 | ||
|
|
1f40d8fffd | ||
|
|
723196a157 | ||
|
|
0b0dddf8ec | ||
|
|
e33bfc7f1d | ||
|
|
03c1d19e07 | ||
|
|
8beeff2c52 | ||
|
|
f060db5fe6 | ||
|
|
4a3ff61571 | ||
|
|
908f36f574 | ||
|
|
292cc867a5 | ||
|
|
ab20bf472d | ||
|
|
470615eb05 | ||
|
|
f56fea6a1f | ||
|
|
7fda509333 | ||
|
|
0031ab82b7 | ||
|
|
e059fc8048 | ||
|
|
7953088418 | ||
|
|
1add112be6 | ||
|
|
f16b118794 | ||
|
|
d71c1cd6b0 | ||
|
|
ccd46028f2 | ||
|
|
24840d4d99 | ||
|
|
a656dadf4b | ||
|
|
03c834c647 | ||
|
|
876ab41ba8 | ||
|
|
dfa2b13c3a | ||
|
|
c6bb2730a8 | ||
|
|
08daaeb1a3 | ||
|
|
1f51ab27c4 | ||
|
|
36a58df181 | ||
|
|
4038e0a60c | ||
|
|
6042b39313 | ||
|
|
dc04a4b8a9 | ||
|
|
98499acff9 | ||
|
|
2417d32316 | ||
|
|
735280168f | ||
|
|
ef10f190cd | ||
|
|
b9b60df0a4 | ||
|
|
b69fb69a1a | ||
|
|
92e0f98633 | ||
|
|
0d58101edc | ||
|
|
44c88ad908 | ||
|
|
45b82dc466 | ||
|
|
22ac160021 | ||
|
|
b46a025576 | ||
|
|
7d5477cf22 | ||
|
|
f48dc3dd1a | ||
|
|
301b0fc1d1 | ||
|
|
d4c7b036fc | ||
|
|
8a88dd25b6 | ||
|
|
ad00679da9 | ||
|
|
598a13ecc0 | ||
|
|
34dfc3ce98 | ||
|
|
78e477b2a7 | ||
|
|
832306cf6e | ||
|
|
73599c22aa | ||
|
|
26ecf2b10f | ||
|
|
1e014f0b14 | ||
|
|
b40f7d36d5 | ||
|
|
7f1829eb21 | ||
|
|
eb9bad7a31 | ||
|
|
5bdd16404e | ||
|
|
9e4346bb44 | ||
|
|
eca4121dc6 | ||
|
|
828eaaf3d3 | ||
|
|
335e02aa44 | ||
|
|
0f242fd956 | ||
|
|
8b8bbb8a8d | ||
|
|
36fd78281c | ||
|
|
b85b7c6b9d | ||
|
|
320719b904 | ||
|
|
4ad078a975 | ||
|
|
d075b2c6e2 | ||
|
|
64460b8efc | ||
|
|
a583902f30 | ||
|
|
aac60b1390 | ||
|
|
500edddcb1 | ||
|
|
43ed2b0d1d | ||
|
|
267e733109 | ||
|
|
05a407196f | ||
|
|
bba311653d | ||
|
|
b8b8d697f4 | ||
|
|
577318be15 | ||
|
|
0b78a00afb | ||
|
|
ef29b5fb04 | ||
|
|
b959e0b5ec | ||
|
|
20c146e1e5 | ||
|
|
8d2a47e881 | ||
|
|
055e12570d | ||
|
|
35c143a036 | ||
|
|
a3e23fc9fa | ||
|
|
58672fb221 | ||
|
|
5c5934bc24 | ||
|
|
7610787e09 | ||
|
|
54bdb367c2 | ||
|
|
10de1da948 | ||
|
|
4a0de23cab | ||
|
|
be8dd55c21 | ||
|
|
3a4f475889 | ||
|
|
49eba77c37 | ||
|
|
1899c13385 | ||
|
|
aac7a23fd5 | ||
|
|
5ba0aa9aac | ||
|
|
c8104a29ec | ||
|
|
17ad73ace2 | ||
|
|
b2290a6420 | ||
|
|
fbb76e63ad | ||
|
|
d53e7aa51c | ||
|
|
11cde99e20 | ||
|
|
0fd3e5d4c5 | ||
|
|
f0af70736b | ||
|
|
292b24ad8f | ||
|
|
6ddde3aa98 | ||
|
|
4bba540311 | ||
|
|
454510092e | ||
|
|
7ab9479f2c | ||
|
|
017febed96 |
@@ -60,7 +60,7 @@ jobs:
|
||||
working_directory: /tmp/workspace/core
|
||||
- save_cache: *save-cache-core
|
||||
- run:
|
||||
command: npm run build -- --max-workers 1
|
||||
command: npm run build -- --ci
|
||||
working_directory: /tmp/workspace/core
|
||||
- save_cache: *save-cache-core-stencil
|
||||
- persist_to_workspace:
|
||||
@@ -91,6 +91,75 @@ jobs:
|
||||
paths:
|
||||
- "*"
|
||||
|
||||
build-angular-server:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install
|
||||
working_directory: /tmp/workspace/packages/angular-server
|
||||
- run:
|
||||
command: npm run build.prod
|
||||
working_directory: /tmp/workspace/packages/angular-server
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- "*"
|
||||
|
||||
build-react:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/core
|
||||
- run:
|
||||
command: sudo npm link @ionic/core
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: npm run build
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- "*"
|
||||
|
||||
build-react-router:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/core
|
||||
- run:
|
||||
command: sudo npm link @ionic/core
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: sudo npm link @ionic/react
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
- run:
|
||||
command: npm run build
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- "*"
|
||||
|
||||
test-core-clean-build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -119,7 +188,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm run test.spec
|
||||
command: npm run test.spec --ci
|
||||
working_directory: /tmp/workspace/core
|
||||
|
||||
test-core-treeshake:
|
||||
@@ -129,7 +198,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm run test.treeshake
|
||||
command: npm run test.treeshake --ci
|
||||
working_directory: /tmp/workspace/core
|
||||
|
||||
test-core-screenshot:
|
||||
@@ -164,6 +233,64 @@ jobs:
|
||||
command: npm run lint
|
||||
working_directory: /tmp/workspace/angular
|
||||
|
||||
test-react-lint:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm run lint
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
|
||||
test-react-router-lint:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm run lint
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
|
||||
test-react-spec:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/core
|
||||
- run:
|
||||
command: sudo npm link @ionic/core
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: npm run test.spec
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
|
||||
test-react-router-spec:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/core
|
||||
- run:
|
||||
command: sudo npm link @ionic/core
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/packages/react
|
||||
- run:
|
||||
command: sudo npm link @ionic/react
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
- run:
|
||||
command: npm run test.spec
|
||||
working_directory: /tmp/workspace/packages/react-router
|
||||
|
||||
test-angular-e2e:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -173,6 +300,9 @@ jobs:
|
||||
- run:
|
||||
command: npm install
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
- run:
|
||||
command: npm run sync
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
- run:
|
||||
command: npm test
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
@@ -205,7 +335,23 @@ workflows:
|
||||
|
||||
- build-angular:
|
||||
requires: [build-core]
|
||||
- build-angular-server:
|
||||
requires: [build-angular]
|
||||
- build-react:
|
||||
requires: [build-core]
|
||||
- build-react-router:
|
||||
requires: [build-core, build-react]
|
||||
- test-react-lint:
|
||||
requires: [build-react]
|
||||
- test-react-router-lint:
|
||||
requires: [build-react-router]
|
||||
- test-react-spec:
|
||||
requires: [build-react]
|
||||
- test-react-router-spec:
|
||||
requires: [build-react-router]
|
||||
- test-angular-lint:
|
||||
requires: [build-angular]
|
||||
- test-angular-e2e:
|
||||
requires: [build-angular]
|
||||
requires:
|
||||
- build-angular
|
||||
- build-angular-server
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -37,6 +37,7 @@ assignees: ''
|
||||
A sample application via GitHub
|
||||
|
||||
StackBlitz (https://stackblitz.com)
|
||||
Ionic Angular StackBlitz: https://stackblitz.com/edit/ionic-v4-angular-tabs
|
||||
|
||||
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
|
||||
|
||||
|
||||
21
.github/PROCESS.md
vendored
21
.github/PROCESS.md
vendored
@@ -64,7 +64,7 @@ If the issue is a support question, the submitter should be redirected to our [f
|
||||
|
||||
### Incomplete Template
|
||||
|
||||
If the issue template has not been filled out completely, the issue should be closed and locked. The submitter should be informed top re-submit the issue making sure they fill the form out completely. Use the `ionitron: missing template` label to accomplish this.
|
||||
If the issue template has not been filled out completely, the issue should be closed and locked. The submitter should be informed to re-submit the issue making sure they fill the form out completely. Use the `ionitron: missing template` label to accomplish this.
|
||||
|
||||
### Issues with Open Questions
|
||||
|
||||
@@ -77,7 +77,7 @@ NOTE: be sure to perform those actions in the order stated. If you add the comme
|
||||
|
||||
If there is a response to the question, the bot will remove the `needs: reply` and apply the `triage` label. The issue will then go through the triage handling again.
|
||||
|
||||
if there is no response within 30 days, the issue will be closed and locked.
|
||||
If there is no response within 30 days, the issue will be closed and locked.
|
||||
|
||||
## Workflow
|
||||
|
||||
@@ -221,9 +221,11 @@ Hotfixes bypass `master` and should only be used for urgent fixes that can't wai
|
||||
|
||||
## Releasing
|
||||
|
||||
1. Create the release branch from `master`, for example: `release-4.1.0`.
|
||||
1. Create the release branch from `master`, for example: `release-4.5.0`.
|
||||
|
||||
1. Submit a pull request from the release branch into `stable`. Do not merge this pull request yet.
|
||||
1. For major or minor releases, create a version branch based off the latest version branch. For example, if releasing 4.5.0, create a branch called `4.5.x` based off `4.4.x`.
|
||||
|
||||
1. Submit a pull request from the release branch into the version branch. Do not merge this pull request yet.
|
||||
|
||||
1. Verify all tests are passing, fix any bugs if needed and make sure no undesired commits are in.
|
||||
|
||||
@@ -235,7 +237,8 @@ Hotfixes bypass `master` and should only be used for urgent fixes that can't wai
|
||||
- Select the version based on the type of commits and the [Ionic Versioning](https://ionicframework.com/docs/intro/versioning)
|
||||
- After the process completes, verify the version number in all packages (`core`, `docs`, `angular`)
|
||||
- Verify the changelog commits are accurate and follow the [proper format]((https://github.com/ionic-team/ionic/blob/master/.github/CONTRIBUTING.md#commit-message-format))
|
||||
- Commit these changes with the version number as the message, e.g. `git commit -m "4.1.0"`
|
||||
- For major or minor releases, ensure that the version number has an associated title (for example: `4.5.0 Boron`)
|
||||
- Commit these changes with the version number as the message, e.g. `git commit -m "4.5.0"`
|
||||
|
||||
1. Run `npm run release`
|
||||
|
||||
@@ -243,10 +246,6 @@ Hotfixes bypass `master` and should only be used for urgent fixes that can't wai
|
||||
|
||||
<img width="191" alt="Merge pull request button" src="https://user-images.githubusercontent.com/236501/47032669-8be1b980-d138-11e8-9a90-d1518c223184.png">
|
||||
|
||||
1. Rewrite the commit message to `merge release-4.1.0` with the proper release branch. For example, if this release is for `4.3.1`, the message would be `merge release-4.3.1`.
|
||||
1. Rewrite the commit message to `merge release-[VERSION]` with the proper release branch. For example, if this release is for `4.5.0`, the message would be `merge release-4.5.0`.
|
||||
|
||||
1. Submit a pull request from the `stable` branch into `master`. Merge this pull request using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.
|
||||
|
||||
1. Merge the release branch into its corresponding version branch.
|
||||
- If this is a major or minor release, create the version branch off the latest `stable`. For example, if this release was `4.2.0`, create a branch called `4.2.x` off of `stable`.
|
||||
- If this is a patch release, merge the release branch into the version branch. For example, if this release is `4.2.1`, merge the release branch into the `4.2.x` branch.
|
||||
1. Submit a pull request from the release branch into `master`. Merge this pull request using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -15,6 +15,7 @@ log.txt
|
||||
coverage/
|
||||
collection/
|
||||
dist/
|
||||
dist-transpiled/
|
||||
node_modules/
|
||||
tmp/
|
||||
temp/
|
||||
@@ -49,10 +50,17 @@ demos/src/**/*.ngfactory.ts
|
||||
demos/src/**/*.d.ts
|
||||
demos/src/**/*.metadata.json
|
||||
demos/src/**/*.css.shim.ts
|
||||
prerender.html
|
||||
prerender-domino.html
|
||||
prerender-hydrated.html
|
||||
prerender-static.html
|
||||
|
||||
# stencil
|
||||
angular/css/
|
||||
packages/react/css/
|
||||
core/css/
|
||||
core/hydrate/
|
||||
core/loader/
|
||||
core/www/
|
||||
.stencil/
|
||||
angular/build/
|
||||
|
||||
@@ -11,6 +11,8 @@ const packages = [
|
||||
'core',
|
||||
'docs',
|
||||
'angular',
|
||||
'packages/react',
|
||||
'packages/react-router'
|
||||
];
|
||||
|
||||
function readPkg(project) {
|
||||
@@ -36,33 +38,47 @@ function checkGit(tasks) {
|
||||
tasks.push(
|
||||
{
|
||||
title: 'Check current branch',
|
||||
task: () => execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
|
||||
if (branch.indexOf('release') === -1 && branch.indexOf('hotfix') === -1) {
|
||||
throw new Error(`Must be on a "release" or "hotfix" branch.`);
|
||||
}
|
||||
})
|
||||
task: () =>
|
||||
execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
|
||||
if (branch.indexOf('release') === -1 && branch.indexOf('hotfix') === -1) {
|
||||
throw new Error(`Must be on a "release" or "hotfix" branch.`);
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
title: 'Check local working tree',
|
||||
task: () => execa.stdout('git', ['status', '--porcelain']).then(status => {
|
||||
if (status !== '') {
|
||||
throw new Error(`Unclean working tree. Commit or stash changes first.`);
|
||||
}
|
||||
})
|
||||
task: () =>
|
||||
execa.stdout('git', ['status', '--porcelain']).then(status => {
|
||||
if (status !== '') {
|
||||
throw new Error(`Unclean working tree. Commit or stash changes first.`);
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
title: 'Check remote history',
|
||||
task: () => execa.stdout('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).then(result => {
|
||||
if (result !== '0') {
|
||||
throw new Error(`Remote history differs. Please pull changes.`);
|
||||
}
|
||||
})
|
||||
task: () =>
|
||||
execa.stdout('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).then(result => {
|
||||
if (result !== '0') {
|
||||
throw new Error(`Remote history differs. Please pull changes.`);
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const isValidVersion = input => Boolean(semver.valid(input));
|
||||
function checkTestDist(tasks) {
|
||||
tasks.push({
|
||||
title: 'Check dist folders for required files',
|
||||
task: () =>
|
||||
execa.stdout('node', ['.scripts/test-dist.js']).then(status => {
|
||||
if (status.indexOf('✅ test.dist') === -1) {
|
||||
throw new Error(`Test Dist did not find some required files`);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const isValidVersion = input => Boolean(semver.valid(input));
|
||||
|
||||
function preparePackage(tasks, package, version, install) {
|
||||
const projectRoot = projectPath(package);
|
||||
@@ -74,7 +90,9 @@ function preparePackage(tasks, package, version, install) {
|
||||
title: `${pkg.name}: validate new version`,
|
||||
task: () => {
|
||||
if (!isVersionGreater(pkg.version, version)) {
|
||||
throw new Error(`New version \`${version}\` should be higher than current version \`${pkg.version}\``);
|
||||
throw new Error(
|
||||
`New version \`${version}\` should be higher than current version \`${pkg.version}\``
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -82,7 +100,7 @@ function preparePackage(tasks, package, version, install) {
|
||||
projectTasks.push({
|
||||
title: `${pkg.name}: install npm dependencies`,
|
||||
task: async () => {
|
||||
await fs.remove(path.join(projectRoot, 'node_modules'))
|
||||
await fs.remove(path.join(projectRoot, 'node_modules'));
|
||||
await execa('npm', ['i'], { cwd: projectRoot });
|
||||
}
|
||||
});
|
||||
@@ -95,6 +113,13 @@ function preparePackage(tasks, package, version, install) {
|
||||
title: `${pkg.name}: npm link @ionic/core`,
|
||||
task: () => execa('npm', ['link', '@ionic/core'], { cwd: projectRoot })
|
||||
});
|
||||
|
||||
if (package === 'packages/react-router') {
|
||||
projectTasks.push({
|
||||
title: `${pkg.name}: npm link @ionic/react`,
|
||||
task: () => execa('npm', ['link', '@ionic/react'], { cwd: projectRoot })
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (version) {
|
||||
@@ -105,7 +130,7 @@ function preparePackage(tasks, package, version, install) {
|
||||
projectTasks.push({
|
||||
title: `${pkg.name}: update ionic/core dep to ${version}`,
|
||||
task: () => {
|
||||
updateDependency(pkg, "@ionic/core", version);
|
||||
updateDependency(pkg, '@ionic/core', version);
|
||||
writePkg(package, pkg);
|
||||
}
|
||||
});
|
||||
@@ -134,7 +159,6 @@ function preparePackage(tasks, package, version, install) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function prepareDevPackage(tasks, package, version) {
|
||||
const projectRoot = projectPath(package);
|
||||
const pkg = readPkg(package);
|
||||
@@ -152,7 +176,7 @@ function prepareDevPackage(tasks, package, version) {
|
||||
projectTasks.push({
|
||||
title: `${pkg.name}: update ionic/core dep to ${version}`,
|
||||
task: () => {
|
||||
updateDependency(pkg, "@ionic/core", version);
|
||||
updateDependency(pkg, '@ionic/core', version);
|
||||
writePkg(package, pkg);
|
||||
}
|
||||
});
|
||||
@@ -181,33 +205,38 @@ function updatePackageVersions(tasks, packages, version) {
|
||||
packages.forEach(package => {
|
||||
updatePackageVersion(tasks, package, version);
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `${package} update @ionic/core dependency, if present ${tc.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
if (package !== 'core') {
|
||||
const pkg = readPkg(package);
|
||||
updateDependency(pkg, '@ionic/core', version);
|
||||
writePkg(package, pkg);
|
||||
}
|
||||
},
|
||||
tasks.push({
|
||||
title: `${package} update @ionic/core dependency, if present ${tc.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
if (package !== 'core') {
|
||||
const pkg = readPkg(package);
|
||||
updateDependency(pkg, '@ionic/core', version);
|
||||
writePkg(package, pkg);
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
if (package === 'packages/react-router') {
|
||||
tasks.push({
|
||||
title: `${package} update @ionic/react dependency, if present ${tc.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
const pkg = readPkg(package);
|
||||
updateDependency(pkg, '@ionic/react', version);
|
||||
writePkg(package, pkg);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function updatePackageVersion(tasks, package, version) {
|
||||
const projectRoot = projectPath(package);
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `${package}: update package.json ${tc.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
await execa('npm', ['version', version], { cwd: projectRoot });
|
||||
}
|
||||
tasks.push({
|
||||
title: `${package}: update package.json ${tc.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
await execa('npm', ['version', version], { cwd: projectRoot });
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function publishPackages(tasks, packages, version, tag = 'latest') {
|
||||
@@ -237,7 +266,7 @@ function publishPackages(tasks, packages, version, tag = 'latest') {
|
||||
title: `${package}: publish to ${tag} tag`,
|
||||
task: async () => {
|
||||
await execa('npm', ['publish', '--tag', tag], { cwd: projectRoot });
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -258,11 +287,19 @@ function isVersionGreater(oldVersion, newVersion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function copyCDNLoader(tasks, version) {
|
||||
tasks.push({
|
||||
title: `Copy CDN loader`,
|
||||
task: () => execa('node', ['copy-cdn-loader.js', version], { cwd: path.join(rootDir, 'core', 'scripts') })
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkTestDist,
|
||||
checkGit,
|
||||
isValidVersion,
|
||||
isVersionGreater,
|
||||
copyCDNLoader,
|
||||
packages,
|
||||
packagePath,
|
||||
prepareDevPackage,
|
||||
@@ -274,5 +311,5 @@ module.exports = {
|
||||
updateDependency,
|
||||
updatePackageVersion,
|
||||
updatePackageVersions,
|
||||
writePkg,
|
||||
writePkg
|
||||
};
|
||||
|
||||
@@ -107,15 +107,17 @@ async function preparePackages(packages, version, install) {
|
||||
});
|
||||
|
||||
// add update package.json of each project
|
||||
packages.forEach(package => {
|
||||
common.updatePackageVersion(tasks, package, version);
|
||||
});
|
||||
common.updatePackageVersions(tasks, packages, version);
|
||||
|
||||
// generate changelog
|
||||
generateChangeLog(tasks);
|
||||
|
||||
// check dist folders
|
||||
common.checkTestDist(tasks);
|
||||
|
||||
// update core readme with version number
|
||||
updateCoreReadme(tasks, version);
|
||||
common.copyCDNLoader(tasks, version);
|
||||
|
||||
const listr = new Listr(tasks, { showSubtasks: true });
|
||||
await listr.run();
|
||||
@@ -171,7 +173,6 @@ function updateCoreReadme(tasks, version) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const SEMVER_INCREMENTS = ['patch', 'minor', 'major'];
|
||||
|
||||
const isValidVersionInput = input => SEMVER_INCREMENTS.indexOf(input) !== -1 || common.isValidVersion(input);
|
||||
|
||||
@@ -7,6 +7,7 @@ const fs = require('fs-extra');
|
||||
|
||||
const common = require('./common');
|
||||
|
||||
const DIST_NPM_TAG = 'dev';
|
||||
const DIST_TAG = 'dev';
|
||||
|
||||
async function main() {
|
||||
@@ -37,7 +38,8 @@ async function main() {
|
||||
packages.forEach(package => {
|
||||
common.prepareDevPackage(tasks, package, devVersion);
|
||||
});
|
||||
common.publishPackages(tasks, packages, devVersion, DIST_TAG);
|
||||
common.copyCDNLoader(tasks, devVersion);
|
||||
common.publishPackages(tasks, packages, devVersion, DIST_NPM_TAG);
|
||||
|
||||
const listr = new Listr(tasks);
|
||||
await listr.run();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
const tc = require('turbocolor');
|
||||
const execa = require('execa');
|
||||
const Listr = require('listr');
|
||||
const path = require('path');
|
||||
const octokit = require('@octokit/rest')()
|
||||
const common = require('./common');
|
||||
const fs = require('fs-extra');
|
||||
@@ -16,6 +17,8 @@ async function main() {
|
||||
throw new Error('env.GH_TOKEN is undefined');
|
||||
}
|
||||
|
||||
checkProductionRelease();
|
||||
|
||||
const tasks = [];
|
||||
const { version } = common.readPkg('core');
|
||||
const changelog = findChangelog();
|
||||
@@ -39,6 +42,15 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
function checkProductionRelease() {
|
||||
const corePath = common.projectPath('core');
|
||||
const hasEsm = fs.existsSync(path.join(corePath, 'dist', 'esm'));
|
||||
const hasEsmEs5 = fs.existsSync(path.join(corePath, 'dist', 'esm-es5'));
|
||||
const hasCjs = fs.existsSync(path.join(corePath, 'dist', 'cjs'));
|
||||
if (!hasEsm || !hasEsmEs5 || !hasCjs) {
|
||||
throw new Error('core build is not a production build');
|
||||
}
|
||||
}
|
||||
|
||||
function publishGit(tasks, version, changelog) {
|
||||
const tag = `v${version}`;
|
||||
@@ -54,7 +66,7 @@ function publishGit(tasks, version, changelog) {
|
||||
},
|
||||
{
|
||||
title: 'Push tags to remove',
|
||||
task: () => execa('git', ['push', '--tags'], { cwd: common.rootDir })
|
||||
task: () => execa('git', ['push', '--follow-tags'], { cwd: common.rootDir })
|
||||
},
|
||||
{
|
||||
title: 'Publish Github release',
|
||||
|
||||
82
.scripts/test-dist.js
Normal file
82
.scripts/test-dist.js
Normal file
@@ -0,0 +1,82 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Test dist build:
|
||||
// Double-triple check all the packages
|
||||
// and files are good to go before publishing
|
||||
[
|
||||
// core
|
||||
{
|
||||
files: ['../core/dist/index.js', '../core/dist/ionic/index.esm.js']
|
||||
},
|
||||
// angular
|
||||
{
|
||||
files: ['../angular/dist/fesm5.cjs.js']
|
||||
},
|
||||
// react
|
||||
{
|
||||
files: ['../packages/react/dist/index.js']
|
||||
},
|
||||
// react-router
|
||||
{
|
||||
files: ['../packages/react-router/dist/index.js']
|
||||
}
|
||||
].forEach(testPackage);
|
||||
|
||||
function testPackage(testPkg) {
|
||||
if (testPkg.packageJson) {
|
||||
const pkgDir = path.dirname(testPkg.packageJson);
|
||||
const pkgJson = require(testPkg.packageJson);
|
||||
|
||||
if (!pkgJson.name) {
|
||||
throw new Error('missing package.json name: ' + testPkg.packageJson);
|
||||
}
|
||||
|
||||
if (!pkgJson.main) {
|
||||
throw new Error('missing package.json main: ' + testPkg.packageJson);
|
||||
}
|
||||
|
||||
const pkgPath = path.join(pkgDir, pkgJson.main);
|
||||
const pkgImport = require(pkgPath);
|
||||
|
||||
if (testPkg.files) {
|
||||
if (!Array.isArray(pkgJson.files)) {
|
||||
throw new Error(testPkg.packageJson + ' missing "files" property');
|
||||
}
|
||||
testPkg.files.forEach(testPkgFile => {
|
||||
if (!pkgJson.files.includes(testPkgFile)) {
|
||||
throw new Error(testPkg.packageJson + ' missing file ' + testPkgFile);
|
||||
}
|
||||
|
||||
const filePath = path.join(__dirname, pkgDir, testPkgFile);
|
||||
fs.accessSync(filePath);
|
||||
});
|
||||
}
|
||||
|
||||
if (pkgJson.module) {
|
||||
const moduleIndex = path.join(__dirname, pkgDir, pkgJson.module);
|
||||
fs.accessSync(moduleIndex);
|
||||
}
|
||||
|
||||
if (pkgJson.types) {
|
||||
const pkgTypes = path.join(__dirname, pkgDir, pkgJson.types);
|
||||
fs.accessSync(pkgTypes);
|
||||
}
|
||||
|
||||
if (testPkg.exports) {
|
||||
testPkg.exports.forEach(exportName => {
|
||||
const m = pkgImport[exportName];
|
||||
if (!m) {
|
||||
throw new Error('export "' + exportName + '" not found in: ' + testPkg.packageJson);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (testPkg.files) {
|
||||
testPkg.files.forEach(file => {
|
||||
const filePath = path.join(__dirname, file);
|
||||
fs.statSync(filePath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ test.dist`);
|
||||
330
CHANGELOG.md
330
CHANGELOG.md
@@ -1,3 +1,333 @@
|
||||
## [4.10.3](https://github.com/ionic-team/ionic/compare/v4.10.2...v4.10.3) (2019-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **content:** set overscroll only on iOS ([#19470](https://github.com/ionic-team/ionic/issues/19470)) ([63c2008](https://github.com/ionic-team/ionic/commit/63c2008a86de19847677fda7b9fedce73ed7669f)), closes [#19465](https://github.com/ionic-team/ionic/issues/19465)
|
||||
* **searchbar:** update alignment of chips and other elements in toolbar ([#19596](https://github.com/ionic-team/ionic/issues/19596)) ([637f26b](https://github.com/ionic-team/ionic/commit/637f26b3642a266b6ef3b9d3d71b7327a5d3cc37)), closes [#19495](https://github.com/ionic-team/ionic/issues/19495) [#19502](https://github.com/ionic-team/ionic/issues/19502)
|
||||
|
||||
|
||||
|
||||
## [4.10.2](https://github.com/ionic-team/ionic/compare/v4.10.1...v4.10.2) (2019-10-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **overlay:** ensure lifecycle events fire properly ([#19579](https://github.com/ionic-team/ionic/issues/19579)) ([a7b9642](https://github.com/ionic-team/ionic/commit/a7b9642)), closes [#19576](https://github.com/ionic-team/ionic/issues/19576)
|
||||
|
||||
|
||||
|
||||
## [4.10.1](https://github.com/ionic-team/ionic/compare/v4.10.0...v4.10.1) (2019-10-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animation:** animation timer fallback now accounts for iterations ([#19527](https://github.com/ionic-team/ionic/issues/19527)) ([9f5ed23](https://github.com/ionic-team/ionic/commit/9f5ed23))
|
||||
* **css:** update deprecations to remove wrap ([#19535](https://github.com/ionic-team/ionic/issues/19535)) ([bfb704e](https://github.com/ionic-team/ionic/commit/bfb704e)), closes [#19499](https://github.com/ionic-team/ionic/issues/19499)
|
||||
* **header:** fix collapsing iOS header when using with split pane ([#19480](https://github.com/ionic-team/ionic/issues/19480)) ([dea1c26](https://github.com/ionic-team/ionic/commit/dea1c26)), closes [#19541](https://github.com/ionic-team/ionic/issues/19541)
|
||||
* **list:** add bottom border for first item in inset list ([#19525](https://github.com/ionic-team/ionic/issues/19525)) ([71b8853](https://github.com/ionic-team/ionic/commit/71b8853)), closes [#19507](https://github.com/ionic-team/ionic/issues/19507)
|
||||
* **md:** fix flicker when navigating back in MD mode on certain Android devices ([#19553](https://github.com/ionic-team/ionic/issues/19553)) ([19ee21a](https://github.com/ionic-team/ionic/commit/19ee21a)), closes [#19491](https://github.com/ionic-team/ionic/issues/19491)
|
||||
* **searchbar:** update padding and button alignment ([#19532](https://github.com/ionic-team/ionic/issues/19532)) ([77658e6](https://github.com/ionic-team/ionic/commit/77658e6)), closes [#19502](https://github.com/ionic-team/ionic/issues/19502)
|
||||
|
||||
|
||||
|
||||
# [4.10.0 Neon](https://github.com/ionic-team/ionic/compare/v4.9.1...v4.10.0) (2019-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** add warning if initialized more than once ([#19393](https://github.com/ionic-team/ionic/issues/19393)) ([e98769e](https://github.com/ionic-team/ionic/commit/e98769e))
|
||||
* **animation:** set property defaults to avoid inconsistencies ([#19321](https://github.com/ionic-team/ionic/issues/19321)) ([1cbb52c](https://github.com/ionic-team/ionic/commit/1cbb52c))
|
||||
* **animation:** fallback to CSS Animations on older versions of Chrome ([#19288](https://github.com/ionic-team/ionic/issues/19288)) ([2d39c07](https://github.com/ionic-team/ionic/commit/2d39c07)), closes [#19272](https://github.com/ionic-team/ionic/issues/19272)
|
||||
* **animation:** animations of duration 0 now run in Safari ([#19287](https://github.com/ionic-team/ionic/issues/19287)) ([4e544f1](https://github.com/ionic-team/ionic/commit/4e544f1)), closes [#19285](https://github.com/ionic-team/ionic/issues/19285)
|
||||
* **components:** fix crash in IE11 when using classList add() or remove() ([#19460](https://github.com/ionic-team/ionic/issues/19460)) ([b4d92c6](https://github.com/ionic-team/ionic/commit/b4d92c6))
|
||||
* **components:** improve CSS Variable support in IE11 ([#19473](https://github.com/ionic-team/ionic/issues/19473)) ([44ad074](https://github.com/ionic-team/ionic/commit/44ad074))
|
||||
* **content:** remove pointer-events from iOS transition shadow ([#19471](https://github.com/ionic-team/ionic/issues/19471)) ([8a52c7d](https://github.com/ionic-team/ionic/commit/8a52c7d)), closes [#19466](https://github.com/ionic-team/ionic/issues/19466)
|
||||
* **menu:** menus show proper drop shadows ([#19454](https://github.com/ionic-team/ionic/issues/19454)) ([eab0865](https://github.com/ionic-team/ionic/commit/eab0865)), closes [#19387](https://github.com/ionic-team/ionic/issues/19387)
|
||||
* **radio-group:** get radios before caching value to avoid infinite loop ([#19448](https://github.com/ionic-team/ionic/issues/19448)) ([cf223e4](https://github.com/ionic-team/ionic/commit/cf223e4)), closes [#19277](https://github.com/ionic-team/ionic/issues/19277)
|
||||
* **react:** update events to use proper types ([c79e74b](https://github.com/ionic-team/ionic/commit/c79e74b))
|
||||
* **router-outlet:** hide leaving view after transition finishes ([#19335](https://github.com/ionic-team/ionic/issues/19335)) ([bfa17d1](https://github.com/ionic-team/ionic/commit/bfa17d1))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **config:** expose getMode() and deprecate Config.set() ([#19104](https://github.com/ionic-team/ionic/issues/19104)) ([0f05ea4](https://github.com/ionic-team/ionic/commit/0f05ea4))
|
||||
* **docs:** add VSCode docs support ([#19309](https://github.com/ionic-team/ionic/issues/19309)) ([a3f345c](https://github.com/ionic-team/ionic/commit/a3f345c))
|
||||
* **title:** add support for small title ([#19215](https://github.com/ionic-team/ionic/issues/19215)) ([e27962d](https://github.com/ionic-team/ionic/commit/e27962d)), closes [#18898](https://github.com/ionic-team/ionic/issues/18898)
|
||||
* **title:** add support for large title (experimental) ([#19268](https://github.com/ionic-team/ionic/issues/19268)) ([923312e](https://github.com/ionic-team/ionic/commit/923312e)), closes [#16885](https://github.com/ionic-team/ionic/issues/16885)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **animation:** avoid ngzone with requestAnimationFrame ([#19457](https://github.com/ionic-team/ionic/issues/19457)) ([8ca97ce](https://github.com/ionic-team/ionic/commit/8ca97ce))
|
||||
|
||||
|
||||
|
||||
## [4.9.1](https://github.com/ionic-team/ionic/compare/v4.9.0...v4.9.1) (2019-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **platform:** properly detect iPads running iPadOS ([#19258](https://github.com/ionic-team/ionic/issues/19258)) ([4a90096](https://github.com/ionic-team/ionic/commit/4a90096))
|
||||
|
||||
|
||||
|
||||
# [4.9.0 Fluorine](https://github.com/ionic-team/ionic/compare/v4.8.1...v4.9.0) (2019-09-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **all:** allow elements to be reused once removed from the DOM ([#18963](https://github.com/ionic-team/ionic/pull/18963)) ([48a2763](https://github.com/ionic-team/ionic/commit/48a2763)), closes [#18843](https://github.com/ionic-team/ionic/issues/18843) [#17344](https://github.com/ionic-team/ionic/issues/17344) [#16453](https://github.com/ionic-team/ionic/issues/16453) [#15879](https://github.com/ionic-team/ionic/issues/15879) [#15788](https://github.com/ionic-team/ionic/issues/15788) [#15484](https://github.com/ionic-team/ionic/issues/15484) [#17890](https://github.com/ionic-team/ionic/issues/17890) [#16364](https://github.com/ionic-team/ionic/issues/16364)
|
||||
* **animation:** add correct `onFinish` interface parameters ([#19199](https://github.com/ionic-team/ionic/issues/19199)) ([a81653b](https://github.com/ionic-team/ionic/commit/a81653b))
|
||||
* **animation:** improve Web Animation feature detection accuracy ([#19212](https://github.com/ionic-team/ionic/issues/19212)) ([6eca5b0](https://github.com/ionic-team/ionic/commit/6eca5b0)), closes [#19205](https://github.com/ionic-team/ionic/issues/19205)
|
||||
* **animation:** properly clean up elements when using `destroy` ([#19210](https://github.com/ionic-team/ionic/issues/19210)) ([93f2064](https://github.com/ionic-team/ionic/commit/93f2064))
|
||||
* **segment:** do not emit ionChange until didLoad ([#19218](https://github.com/ionic-team/ionic/issues/19218)) ([9751f14](https://github.com/ionic-team/ionic/commit/9751f14)), closes [#19204](https://github.com/ionic-team/ionic/issues/19204)
|
||||
|
||||
### Features
|
||||
|
||||
* **nav-link:** add `nav-link` and deprecate `nav-push`, `nav-pop`, and `nav-set-root` ([#18909](https://github.com/ionic-team/ionic/issues/18909)) ([c3044f5](https://github.com/ionic-team/ionic/commit/c3044f5))
|
||||
* **slides:** expose full Swiper API ([#19137](https://github.com/ionic-team/ionic/issues/19137)) ([e1fa461](https://github.com/ionic-team/ionic/commit/e1fa461))
|
||||
|
||||
|
||||
|
||||
## [4.8.1](https://github.com/ionic-team/ionic/compare/v4.8.0...v4.8.1) (2019-08-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animation:** enable backwards compatibility for overlay animations ([#19160](https://github.com/ionic-team/ionic/issues/19160)) ([fb70980](https://github.com/ionic-team/ionic/commit/fb70980))
|
||||
* **gesture:** account for negative step values with Web Animations ([#19196](https://github.com/ionic-team/ionic/issues/19196)) ([b3c7436](https://github.com/ionic-team/ionic/commit/b3c7436))
|
||||
* **ios:** clear opacity on toolbar background after iOS transition ([#19169](https://github.com/ionic-team/ionic/issues/19169)) ([fa958a5](https://github.com/ionic-team/ionic/commit/fa958a5))
|
||||
* **md:** set fill mode on MD transition to `both` ([#19161](https://github.com/ionic-team/ionic/issues/19161)) ([0e8ab49](https://github.com/ionic-team/ionic/commit/0e8ab49))
|
||||
|
||||
|
||||
|
||||
# [4.8.0 Oxygen](https://github.com/ionic-team/ionic/compare/v4.7.4...v4.8.0) (2019-08-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** apply styling to disabled items ([#18545](https://github.com/ionic-team/ionic/issues/18545)) ([67ed89d](https://github.com/ionic-team/ionic/commit/67ed89d))
|
||||
* **platform:** properly detect Electron platform ([#19044](https://github.com/ionic-team/ionic/issues/19044)) ([e8cdda0](https://github.com/ionic-team/ionic/commit/e8cdda0)), closes [#19043](https://github.com/ionic-team/ionic/issues/19043)
|
||||
* **toggle:** change background to use CSS variable ([#19012](https://github.com/ionic-team/ionic/issues/19012)) ([94e525c](https://github.com/ionic-team/ionic/commit/94e525c)), closes [#18940](https://github.com/ionic-team/ionic/issues/18940)
|
||||
* **transition:** enable iOS transition shadow by default ([#19051](https://github.com/ionic-team/ionic/issues/19051)) ([a5d3c6b](https://github.com/ionic-team/ionic/commit/a5d3c6b))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **animation:** add animation utility (experimental) ([#18918](https://github.com/ionic-team/ionic/issues/18918)) ([30ca46a](https://github.com/ionic-team/ionic/commit/30ca46a))
|
||||
* **gesture:** add gesture utility (experimental) ([#18918](https://github.com/ionic-team/ionic/issues/18918)) ([30ca46a](https://github.com/ionic-team/ionic/commit/30ca46a))
|
||||
* **searchbar:** add `inputmode` property ([#18980](https://github.com/ionic-team/ionic/issues/18980)) ([1187dc2](https://github.com/ionic-team/ionic/commit/1187dc2))
|
||||
* **spinner:** add circular spinner for MD default ([#19052](https://github.com/ionic-team/ionic/issues/19052)) ([e33cf85](https://github.com/ionic-team/ionic/commit/e33cf85))
|
||||
|
||||
|
||||
|
||||
## [4.7.4](https://github.com/ionic-team/ionic/compare/v4.7.3...v4.7.4) (2019-08-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** remove extra semicolons being rendered ([#19033](https://github.com/ionic-team/ionic/issues/19033)) ([39f0768](https://github.com/ionic-team/ionic/commit/39f0768))
|
||||
|
||||
|
||||
|
||||
## [4.7.3](https://github.com/ionic-team/ionic/compare/v4.7.2...v4.7.3) (2019-08-07)
|
||||
|
||||
* **core:** fix an issue with production builds of `@ionic/core`
|
||||
|
||||
|
||||
|
||||
## [4.7.2](https://github.com/ionic-team/ionic/compare/v4.7.1...v4.7.2) (2019-08-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** hardware back button subscribeWithPriority triggers change detection ([#18962](https://github.com/ionic-team/ionic/issues/18962)) ([3a22105](https://github.com/ionic-team/ionic/commit/3a22105)), closes [#18959](https://github.com/ionic-team/ionic/issues/18959)
|
||||
* **angular:** nested inputs no longer conflict with each other ([#18976](https://github.com/ionic-team/ionic/issues/18976)) ([6bbdb80](https://github.com/ionic-team/ionic/commit/6bbdb80)), closes [#18248](https://github.com/ionic-team/ionic/issues/18248)
|
||||
* **range:** ion-range value now submitted with form ([#19008](https://github.com/ionic-team/ionic/issues/19008)) ([8f7853c](https://github.com/ionic-team/ionic/commit/8f7853c))
|
||||
* **reorder:** only move item if reorder happens ([#19007](https://github.com/ionic-team/ionic/issues/19007)) ([d237e80](https://github.com/ionic-team/ionic/commit/d237e80))
|
||||
* **router:** partial swipe to go back gesture no longer breaks view([#18977](https://github.com/ionic-team/ionic/issues/18977)) ([713ea8a](https://github.com/ionic-team/ionic/commit/713ea8a)), closes [#18462](https://github.com/ionic-team/ionic/issues/18462)
|
||||
* **toast:** allow loading ion-icon from asset path ([#18969](https://github.com/ionic-team/ionic/issues/18969)) ([23f327e](https://github.com/ionic-team/ionic/commit/23f327e))
|
||||
* **vue:** rename swipeEnable to swipeGesture ([#17346](https://github.com/ionic-team/ionic/issues/17346)) ([c2348f7](https://github.com/ionic-team/ionic/commit/c2348f7)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
|
||||
|
||||
|
||||
|
||||
## [4.7.1](https://github.com/ionic-team/ionic/compare/v4.7.0...v4.7.1) (2019-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** ensure change detection fires properly ([#18896](https://github.com/ionic-team/ionic/issues/18896)) ([962783b](https://github.com/ionic-team/ionic/commit/962783b)), closes [#18894](https://github.com/ionic-team/ionic/issues/18894)
|
||||
|
||||
|
||||
|
||||
# [4.7.0 Nitrogen](https://github.com/ionic-team/ionic/compare/v4.6.2...v4.7.0) (2019-07-24)
|
||||
|
||||
|
||||
### Angular 8 Support
|
||||
|
||||
With this version comes support for Angular 8! Follow the below steps to update.
|
||||
|
||||
1. Update `@ionic/angular` and `@ionic/angular-toolkit` to the latest releases:
|
||||
|
||||
```shell
|
||||
$ npm install @ionic/angular@4.7.0
|
||||
$ npm install @ionic/angular-toolkit@2.0.0 -D
|
||||
```
|
||||
|
||||
1. Update `@angular/core` and `@angular/cli`:
|
||||
|
||||
```shell
|
||||
$ npx ng update @angular/core @angular/cli
|
||||
```
|
||||
|
||||
1. Update `@angular-devkit` dependencies:
|
||||
|
||||
```shell
|
||||
$ npm i @angular-devkit/architect@latest @angular-devkit/build-angular@latest @angular-devkit/core@latest @angular-devkit/schematics@latest
|
||||
```
|
||||
|
||||
View our [Angular 8 Update Guide](https://docs.google.com/document/d/1QOpQeDifPSg6F9WycDLcbQnpqjN96ew-Ap0_CB7CcCQ/edit?usp=sharing) for tips on potential issues!
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** copy input form classes to parent ion-item ([#18820](https://github.com/ionic-team/ionic/issues/18820)) ([53179c4](https://github.com/ionic-team/ionic/commit/53179c4)), closes [#18800](https://github.com/ionic-team/ionic/issues/18800)
|
||||
* **angular:** add the swipeGesture method for enabling or disabling the ability to swipe open a menu ([#18806](https://github.com/ionic-team/ionic/issues/18806)) ([fbfc076](https://github.com/ionic-team/ionic/commit/fbfc076)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
|
||||
* **angular:** webview "pause", "resume", and "resize" events now trigger change detection ([#18853](https://github.com/ionic-team/ionic/issues/18853)) ([544e550](https://github.com/ionic-team/ionic/commit/544e550)), closes [#18831](https://github.com/ionic-team/ionic/issues/18831)
|
||||
* **core:** apply translucent if backdrop-filter is supported ([#18832](https://github.com/ionic-team/ionic/issues/18832)) ([6b5a59d](https://github.com/ionic-team/ionic/commit/6b5a59d)), closes [ionic-team/ionic-docs#666](https://github.com/ionic-team/ionic-docs/issues/666)
|
||||
* **datetime:** allow AM/PM to be changed ([#18684](https://github.com/ionic-team/ionic/issues/18684)) ([b7761fe](https://github.com/ionic-team/ionic/commit/b7761fe)), closes [#18585](https://github.com/ionic-team/ionic/issues/18585)
|
||||
* **datetime:** properly apply disabled classes when updating columns ([#18875](https://github.com/ionic-team/ionic/issues/18875)) ([7ba718c](https://github.com/ionic-team/ionic/commit/7ba718c)), closes [#18793](https://github.com/ionic-team/ionic/issues/18793)
|
||||
* **hardware-back-button:** hardware back button no longer erroneously restarts app ([#18794](https://github.com/ionic-team/ionic/issues/18794)) ([978cc39](https://github.com/ionic-team/ionic/commit/978cc39)), closes [#18792](https://github.com/ionic-team/ionic/issues/18792)
|
||||
* **ripple-effect:** ensure ripple is removed from components after pointer release ([#18854](https://github.com/ionic-team/ionic/issues/18854)) ([71137a2](https://github.com/ionic-team/ionic/commit/71137a2)), closes [#18836](https://github.com/ionic-team/ionic/issues/18836)
|
||||
* **searchbar:** add aria and role for improved accessibility ([#18797](https://github.com/ionic-team/ionic/issues/18797)) ([798103b](https://github.com/ionic-team/ionic/commit/798103b)), closes [#18796](https://github.com/ionic-team/ionic/issues/18796)
|
||||
* **ssr:** avoid window reference ([#18865](https://github.com/ionic-team/ionic/issues/18865)) ([23ce6fa](https://github.com/ionic-team/ionic/commit/23ce6fa))
|
||||
* **ssr:** check for client runtime method ([#18866](https://github.com/ionic-team/ionic/issues/18866)) ([c52b3b4](https://github.com/ionic-team/ionic/commit/c52b3b4))
|
||||
* **textarea:** autogrow now resets textarea back to original number of rows when text is cleared ([#18822](https://github.com/ionic-team/ionic/issues/18822)) ([26e6d6f](https://github.com/ionic-team/ionic/commit/26e6d6f)), closes [#18744](https://github.com/ionic-team/ionic/issues/18744)
|
||||
* **theming:** update components to use the proper colors for dark themes ([#18735](https://github.com/ionic-team/ionic/issues/18735)) ([045bc59](https://github.com/ionic-team/ionic/commit/045bc59)), closes [#18713](https://github.com/ionic-team/ionic/issues/18713)
|
||||
* **virtual-scroll:** card rendering is no longer distorted ([#18877](https://github.com/ionic-team/ionic/issues/18877)) ([3ef6ecf](https://github.com/ionic-team/ionic/commit/3ef6ecf)), closes [#18870](https://github.com/ionic-team/ionic/issues/18870)
|
||||
* **virtual-scroll:** element dimensions are recalculated on resize ([#18878](https://github.com/ionic-team/ionic/issues/18878)) ([c91819c](https://github.com/ionic-team/ionic/commit/c91819c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** add support for Stackblitz ([#18846](https://github.com/ionic-team/ionic/issues/18846)) ([fb18f3b](https://github.com/ionic-team/ionic/commit/fb18f3b))
|
||||
* **ssr:** add @ionic/core/hydrate app ([#18867](https://github.com/ionic-team/ionic/issues/18867)) ([815fa2e](https://github.com/ionic-team/ionic/commit/815fa2e))
|
||||
* **navigation:** add experimental shadow to iOS page transitions ([#18695](https://github.com/ionic-team/ionic/issues/18695)) ([9b075ef](https://github.com/ionic-team/ionic/commit/9b075ef)), closes [#18661](https://github.com/ionic-team/ionic/issues/18661)
|
||||
* **virtual-scroll:** adds headerHeight and footerHeight to help prevent flickering ([#18851](https://github.com/ionic-team/ionic/issues/18851)) ([0089111](https://github.com/ionic-team/ionic/commit/0089111)), closes [#17540](https://github.com/ionic-team/ionic/issues/17540)
|
||||
|
||||
|
||||
### Performance
|
||||
|
||||
* **angular:** attach entering view before first change detection and detach leaving page ([#18821](https://github.com/ionic-team/ionic/issues/18821)) ([97fec92](https://github.com/ionic-team/ionic/commit/97fec92))
|
||||
|
||||
|
||||
## [4.6.2](https://github.com/ionic-team/ionic/compare/v4.6.1...v4.6.2) (2019-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **menu-button:** hide menu button when auto hide or split pane ([#18702](https://github.com/ionic-team/ionic/issues/18702)) ([24840d4](https://github.com/ionic-team/ionic/commit/24840d4)), closes [#18666](https://github.com/ionic-team/ionic/issues/18666)
|
||||
* **menu-button:** move font-size to host for easier customization ([#18699](https://github.com/ionic-team/ionic/issues/18699)) ([876ab41](https://github.com/ionic-team/ionic/commit/876ab41)), closes [#18667](https://github.com/ionic-team/ionic/issues/18667)
|
||||
* **overlays:** fallback to step color if overlay background variable is unset ([#18709](https://github.com/ionic-team/ionic/issues/18709)) ([f16b118](https://github.com/ionic-team/ionic/commit/f16b118)), closes [#18658](https://github.com/ionic-team/ionic/issues/18658)
|
||||
* **virtual-scroll:** remove runOutsideAngular error ([#18752](https://github.com/ionic-team/ionic/issues/18752)) ([8beeff2](https://github.com/ionic-team/ionic/commit/8beeff2)), closes [#18746](https://github.com/ionic-team/ionic/issues/18746)
|
||||
* **vue:** update imports for types and ionicons ([f56fea6](https://github.com/ionic-team/ionic/commit/f56fea6)), closes [#18701](https://github.com/ionic-team/ionic/issues/18701)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **all:** minify better by using arrow functions ([#18730](https://github.com/ionic-team/ionic/issues/18730)) ([03c1d19](https://github.com/ionic-team/ionic/commit/03c1d19))
|
||||
|
||||
|
||||
|
||||
## [4.6.1](https://github.com/ionic-team/ionic/compare/v4.6.0...v4.6.1) (2019-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **app:** add hydrated to hide white screen with multiple ionic dependencies ([#18649](https://github.com/ionic-team/ionic/issues/18649))
|
||||
* **datetime:** datetime no longer reports having a value if none is set ([#18541](https://github.com/ionic-team/ionic/issues/18541)) ([92e0f98](https://github.com/ionic-team/ionic/commit/92e0f98)), closes [#17979](https://github.com/ionic-team/ionic/issues/17979) [#18540](https://github.com/ionic-team/ionic/issues/18540)
|
||||
* **fab-button:** set opacity on disabled fab button ([#18685](https://github.com/ionic-team/ionic/issues/18685)) ([6042b39](https://github.com/ionic-team/ionic/commit/6042b39)), closes [#18682](https://github.com/ionic-team/ionic/issues/18682)
|
||||
* **icon:** load icons properly with baseHref ([#18650](https://github.com/ionic-team/ionic/issues/18650)), ([#18637](https://github.com/ionic-team/ionic/issues/18637))
|
||||
* **icon:** bind icon name properly ([#18707](https://github.com/ionic-team/ionic/issues/18707))
|
||||
* **infinite-scroll:** fix scroll listener ([0d58101](https://github.com/ionic-team/ionic/commit/0d58101))
|
||||
* **item:** do not disable entire item if there are multiple inputs ([#18696](https://github.com/ionic-team/ionic/issues/18696)) ([dfa2b13](https://github.com/ionic-team/ionic/commit/dfa2b13)), closes [#18655](https://github.com/ionic-team/ionic/issues/18655) [#18670](https://github.com/ionic-team/ionic/issues/18670)
|
||||
* **router-link:** add missing target prop ([#18659](https://github.com/ionic-team/ionic/issues/18659)) ([1f51ab2](https://github.com/ionic-team/ionic/commit/1f51ab2)), closes [#18655](https://github.com/ionic-team/ionic/issues/18655)
|
||||
* **router-outlet:** fix swipe to go back ([b69fb69](https://github.com/ionic-team/ionic/commit/b69fb69))
|
||||
* **scss:** copy all scss files ([36a58df](https://github.com/ionic-team/ionic/commit/36a58df))
|
||||
* **searchbar:** proper styling after navigating ([#18642](https://github.com/ionic-team/ionic/issues/18642))
|
||||
* **slides:** use correct order for pushing slides dynamically ([#18633](https://github.com/ionic-team/ionic/issues/18633))
|
||||
* **tabs:** select proper tab by default and do not emit tab change if selectedTab is undefined ([03c834c](https://github.com/ionic-team/ionic/commit/03c834c))
|
||||
* **overlay:** make create opts optional ([44c88ad](https://github.com/ionic-team/ionic/commit/44c88ad))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **angular:** skip zone ([e059fc8](https://github.com/ionic-team/ionic/commit/e059fc8))
|
||||
|
||||
|
||||
|
||||
# [4.6.0 Carbon](https://github.com/ionic-team/ionic/compare/v4.5.0...v4.6.0) (2019-06-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** default opacity for disabled clear buttons ([#18560](https://github.com/ionic-team/ionic/issues/18560)) ([f48dc3d](https://github.com/ionic-team/ionic/commit/f48dc3d)), closes [#18555](https://github.com/ionic-team/ionic/issues/18555)
|
||||
* **button:** update solid buttons to use tint and shade colors ([#18537](https://github.com/ionic-team/ionic/issues/18537)) ([26ecf2b](https://github.com/ionic-team/ionic/commit/26ecf2b))
|
||||
* **menu:** change ARIA role from complementary to navigation ([#18330](https://github.com/ionic-team/ionic/issues/18330)) ([9e4346b](https://github.com/ionic-team/ionic/commit/9e4346b)), closes [#18318](https://github.com/ionic-team/ionic/issues/18318)
|
||||
* **segment:** apply hover properly for segment with color ([#18549](https://github.com/ionic-team/ionic/issues/18549)) ([78e477b](https://github.com/ionic-team/ionic/commit/78e477b))
|
||||
* **segment:** default ripple to currentColor ([#18547](https://github.com/ionic-team/ionic/issues/18547)) ([832306c](https://github.com/ionic-team/ionic/commit/832306c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **components:** add missing button/a props to components that render them ([#17883](https://github.com/ionic-team/ionic/issues/17883)) ([eca4121](https://github.com/ionic-team/ionic/commit/eca4121)), closes [#16848](https://github.com/ionic-team/ionic/issues/16848) [#16889](https://github.com/ionic-team/ionic/issues/16889)
|
||||
* **fab-button:** add hover state using tint colors ([#18536](https://github.com/ionic-team/ionic/issues/18536)) ([ad00679](https://github.com/ionic-team/ionic/commit/ad00679)), closes [#17624](https://github.com/ionic-team/ionic/issues/17624)
|
||||
* **item:** add hover and focused states ([#18606](https://github.com/ionic-team/ionic/issues/18606)) ([8a88dd2](https://github.com/ionic-team/ionic/commit/8a88dd2)), closes [#18279](https://github.com/ionic-team/ionic/issues/18279) [#17624](https://github.com/ionic-team/ionic/issues/17624)
|
||||
* **router-link:** add router-link and deprecate anchor ([#18620](https://github.com/ionic-team/ionic/issues/18620)) ([d4c7b03](https://github.com/ionic-team/ionic/commit/d4c7b03))
|
||||
|
||||
|
||||
### Enhancements
|
||||
|
||||
* **stencil:** update to Stencil One to improve app performance 🎉🎊 ([b40f7d3](https://github.com/ionic-team/ionic/commit/b40f7d3))
|
||||
|
||||
|
||||
|
||||
# [4.5.0 Boron](https://github.com/ionic-team/ionic/compare/v4.4.2...v4.5.0) (2019-06-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** ensure all NavigationExtras values are preserved when navigating ([#18468](https://github.com/ionic-team/ionic/issues/18468)) ([7610787](https://github.com/ionic-team/ionic/commit/7610787)), closes [#18469](https://github.com/ionic-team/ionic/issues/18469)
|
||||
* **button:** set opacity on the host element for disabled button ([#18509](https://github.com/ionic-team/ionic/issues/18509)) ([320719b](https://github.com/ionic-team/ionic/commit/320719b)), closes [#16965](https://github.com/ionic-team/ionic/issues/16965)
|
||||
* **button:** use correct border-radius on menu and back button ([#18501](https://github.com/ionic-team/ionic/issues/18501)) ([055e125](https://github.com/ionic-team/ionic/commit/055e125)), closes [#17624](https://github.com/ionic-team/ionic/issues/17624)
|
||||
* **button:** use correct size on a dynamic button in an item ([#18395](https://github.com/ionic-team/ionic/issues/18395)) ([a3e23fc](https://github.com/ionic-team/ionic/commit/a3e23fc)), closes [#18085](https://github.com/ionic-team/ionic/issues/18085)
|
||||
* **card:** remove white space from bottom of card ([#18328](https://github.com/ionic-team/ionic/issues/18328)) ([d53e7aa](https://github.com/ionic-team/ionic/commit/d53e7aa))
|
||||
* **content:** prevent ion-searchbar from receiving padding adjustment when keyboard is open ([#18008](https://github.com/ionic-team/ionic/issues/18008)) ([b2290a6](https://github.com/ionic-team/ionic/commit/b2290a6)), closes [#18007](https://github.com/ionic-team/ionic/issues/18007)
|
||||
* **datetime:** recalculate time columns on change ([#18380](https://github.com/ionic-team/ionic/issues/18380)) ([292b24a](https://github.com/ionic-team/ionic/commit/292b24a))
|
||||
* **item:** start align the content under stacked and floating labels ([#18379](https://github.com/ionic-team/ionic/issues/18379)) ([f0af707](https://github.com/ionic-team/ionic/commit/f0af707)), closes [#16375](https://github.com/ionic-team/ionic/issues/16375)
|
||||
* **item:** inherit overflow to allow better customization ([#18502](https://github.com/ionic-team/ionic/issues/18502)) ([8d2a47e](https://github.com/ionic-team/ionic/commit/8d2a47e)), closes [#17670](https://github.com/ionic-team/ionic/issues/17670)
|
||||
* **item:** use a step color if the activated background is not set ([#18450](https://github.com/ionic-team/ionic/issues/18450)) ([1899c13](https://github.com/ionic-team/ionic/commit/1899c13)), closes [#18449](https://github.com/ionic-team/ionic/issues/18449)
|
||||
* **item-sliding:** use the correct gesture direction and side for rtl ([#18366](https://github.com/ionic-team/ionic/issues/18366)) ([4545100](https://github.com/ionic-team/ionic/commit/4545100)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
|
||||
* **label:** include the ion-text-wrap class styles for larger font ([#18374](https://github.com/ionic-team/ionic/issues/18374)) ([4bba540](https://github.com/ionic-team/ionic/commit/4bba540))
|
||||
* **platform:** prevent error with Platform.is on Android 4.4 ([#18387](https://github.com/ionic-team/ionic/issues/18387)) ([54bdb36](https://github.com/ionic-team/ionic/commit/54bdb36))
|
||||
* **react:** ensure element exists in controller before dismissing it ([0fd3e5d](https://github.com/ionic-team/ionic/commit/0fd3e5d))
|
||||
* **slides:** resolve issue where double tap to zoom was enabled by default ([10de1da](https://github.com/ionic-team/ionic/commit/10de1da)), closes [#18035](https://github.com/ionic-team/ionic/issues/18035)
|
||||
* **tabs:** allow selection on enter and spacebar press ([#18381](https://github.com/ionic-team/ionic/issues/18381)) ([11cde99](https://github.com/ionic-team/ionic/commit/11cde99)), closes [#18363](https://github.com/ionic-team/ionic/issues/18363)
|
||||
* **textarea:** inherit white-space for better customization ([#18508](https://github.com/ionic-team/ionic/issues/18508)) ([a583902](https://github.com/ionic-team/ionic/commit/a583902)), closes [#18495](https://github.com/ionic-team/ionic/issues/18495)
|
||||
* **virtual-scroll:** do not crash with an empty cell list ([#17799](https://github.com/ionic-team/ionic/issues/17799)) ([20c146e](https://github.com/ionic-team/ionic/commit/20c146e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **back-button:** add variables and support for focused and hover states ([#18451](https://github.com/ionic-team/ionic/issues/18451)) ([58672fb](https://github.com/ionic-team/ionic/commit/58672fb)), closes [#18465](https://github.com/ionic-team/ionic/issues/18465)
|
||||
* **button:** add variables for customizing hover state ([#18499](https://github.com/ionic-team/ionic/issues/18499)) ([5c5934b](https://github.com/ionic-team/ionic/commit/5c5934b)), closes [#17974](https://github.com/ionic-team/ionic/issues/17974)
|
||||
* **item-divider:** add inner padding CSS variables ([#18490](https://github.com/ionic-team/ionic/issues/18490)) ([35c143a](https://github.com/ionic-team/ionic/commit/35c143a)), closes [#18484](https://github.com/ionic-team/ionic/issues/18484)
|
||||
* **menu-button:** add variables for hover and focused states ([#18434](https://github.com/ionic-team/ionic/issues/18434)) ([5ba0aa9](https://github.com/ionic-team/ionic/commit/5ba0aa9)), closes [#18279](https://github.com/ionic-team/ionic/issues/18279)
|
||||
* **searchbar:** add cancel button options ([b959e0b](https://github.com/ionic-team/ionic/commit/b959e0b))
|
||||
* **toast:** allow html content ([#18423](https://github.com/ionic-team/ionic/issues/18423)) ([c8104a2](https://github.com/ionic-team/ionic/commit/c8104a2))
|
||||
|
||||
|
||||
|
||||
## [4.4.2](https://github.com/ionic-team/ionic/compare/v4.4.1...v4.4.2) (2019-05-22)
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Ionic is based on [Web Components](https://www.webcomponents.org/introduction) a
|
||||
| **Core** | [`@ionic/core`](https://www.npmjs.com/package/@ionic/core) | [](https://www.npmjs.com/package/@ionic/core) | [`README.md`](core/README.md)
|
||||
| **Angular** | [`@ionic/angular`](https://www.npmjs.com/package/@ionic/angular) | [](https://www.npmjs.com/package/@ionic/angular) | [`README.md`](angular/README.md)
|
||||
| **Vue** | [`@ionic/vue`](https://www.npmjs.com/package/@ionic/vue) | [](https://www.npmjs.com/package/@ionic/vue) | [`README.md`](vue/README.md)
|
||||
| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [](https://www.npmjs.com/package/@ionic/react) | [`README.md`](react/README.md)
|
||||
| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [](https://www.npmjs.com/package/@ionic/react) | [`README.md`](packages/react/README.md)
|
||||
|
||||
Looking for the `ionic-angular` package? Ionic 3 has been moved to the [`ionic-v3`](https://github.com/ionic-team/ionic-v3) repo. See [Earlier Versions](#earlier-versions).
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ A list of the breaking changes introduced to each component in Ionic Angular v4.
|
||||
|
||||
## Action Sheet
|
||||
|
||||
The `title`, `subTitle` and `enableBackdropDismiss` properties has been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
|
||||
The `title`, `subTitle` and `enableBackdropDismiss` properties have been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
@@ -89,7 +89,7 @@ await actionSheet.present();
|
||||
|
||||
## Alert
|
||||
|
||||
The `title`, `subTitle` and `enableBackdropDismiss` properties has been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
|
||||
The `title`, `subTitle` and `enableBackdropDismiss` properties have been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
@@ -498,7 +498,7 @@ The `<ion-fab>` container was previously placed inside of the fixed content by d
|
||||
|
||||
### Markup Changed
|
||||
|
||||
The Grid has been refactored in order to support css variables and a dynamic number of columns. The following column attributes have been changed.
|
||||
The Grid has been refactored in order to support CSS variables and a dynamic number of columns. The following column attributes have been changed.
|
||||
|
||||
_In the following examples, `{breakpoint}` refers to the optional screen breakpoint (xs, sm, md, lg, xl) and `{value}` refers to the number of columns (`auto` or a number between `1` and `12`)._
|
||||
|
||||
@@ -507,7 +507,7 @@ _In the following examples, `{breakpoint}` refers to the optional screen breakpo
|
||||
- `push-{breakpoint}-{value}` attributes have been renamed to `push-{breakpoint}=“{value}”`
|
||||
- `pull-{breakpoint}-{value}` attributes have been renamed to `pull-{breakpoint}=“{value}”`
|
||||
|
||||
Customizing the padding and width of a grid should now be done with css variables. For more information, see [Grid Layout](https://github.com/ionic-team/ionic-docs/blob/master/src/content/layout/grid.md).
|
||||
Customizing the padding and width of a grid should now be done with CSS variables. For more information, see [Grid Layout](https://github.com/ionic-team/ionic-docs/blob/master/src/content/layout/grid.md).
|
||||
|
||||
## Icon
|
||||
|
||||
@@ -1092,7 +1092,7 @@ openLoading() {
|
||||
```javascript
|
||||
async openLoading() {
|
||||
let loading = this.loadingCtrl.create({
|
||||
content: 'Loading...'
|
||||
message: 'Loading...'
|
||||
});
|
||||
|
||||
await loading.present();
|
||||
@@ -1798,7 +1798,7 @@ To include the stylesheet for testing such as in a Plunker, Codepen, or anywhere
|
||||
|
||||
#### Production
|
||||
|
||||
To use the css in production, we recommend importing it into a global file, such as `app/global.scss`:
|
||||
To use the CSS in production, we recommend importing it into a global file, such as `app/global.scss`:
|
||||
|
||||
```css
|
||||
/** Basic CSS for Ionic Apps */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "4.4.2",
|
||||
"version": "4.10.3",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -19,6 +19,10 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/ionic-team/ionic.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ionic-team/ionic/issues"
|
||||
},
|
||||
"homepage": "https://ionicframework.com/",
|
||||
"scripts": {
|
||||
"build": "npm run clean && npm run build.core && npm run build.ng && npm run clean-generated",
|
||||
"build.core": "node scripts/build-core.js",
|
||||
@@ -38,29 +42,29 @@
|
||||
"validate": "npm i && npm run lint && npm run test && npm run build"
|
||||
},
|
||||
"module": "dist/fesm5.js",
|
||||
"main": "dist/fesm5.js",
|
||||
"main": "dist/fesm5.cjs.js",
|
||||
"types": "dist/core.d.ts",
|
||||
"files": [
|
||||
"dist/",
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "4.4.2",
|
||||
"@ionic/core": "4.10.3",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular-devkit/core": "^7.2.1",
|
||||
"@angular-devkit/schematics": "^7.2.1",
|
||||
"@angular/core": "^7.2.1",
|
||||
"@angular/common": "^7.2.1",
|
||||
"@angular/forms": "^7.2.1",
|
||||
"@angular/router": "^7.2.1",
|
||||
"@angular/compiler": "^7.2.1",
|
||||
"@angular/compiler-cli": "^7.2.1",
|
||||
"@angular/platform-browser": "^7.2.1",
|
||||
"@angular/platform-browser-dynamic": "^7.2.1",
|
||||
"@angular-devkit/core": "7.2.1 - 8",
|
||||
"@angular-devkit/schematics": "7.2.1 - 8",
|
||||
"@angular/core": "7.2.1 - 8",
|
||||
"@angular/common": "7.2.1 - 8",
|
||||
"@angular/forms": "7.2.1 - 8",
|
||||
"@angular/router": "7.2.1 - 8",
|
||||
"@angular/compiler": "7.2.1 - 8",
|
||||
"@angular/compiler-cli": "7.2.1 - 8",
|
||||
"@angular/platform-browser": "7.2.1 - 8",
|
||||
"@angular/platform-browser-dynamic": "7.2.1 - 8",
|
||||
"rxjs": ">=6.2.0",
|
||||
"zone.js": "^0.8.26"
|
||||
"zone.js": ">=0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/core": "^7.2.1",
|
||||
@@ -73,17 +77,17 @@
|
||||
"@angular/platform-browser": "^7.2.1",
|
||||
"@angular/platform-browser-dynamic": "^7.2.1",
|
||||
"@angular/router": "^7.2.1",
|
||||
"@types/node": "~10.12.0",
|
||||
"@types/node": "~12.0.12",
|
||||
"fs-extra": "^7.0.0",
|
||||
"glob": "^7.1.3",
|
||||
"rollup": "^1.1.2",
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rxjs": "^6.2.0",
|
||||
"glob": "^7.1.4",
|
||||
"rollup": "~1.17.0",
|
||||
"rollup-plugin-node-resolve": "~5.2.0",
|
||||
"rxjs": "^6.5.2",
|
||||
"tsickle": "^0.34.0",
|
||||
"tslint": "^5.12.1",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
"typescript": "3.2.4",
|
||||
"zone.js": "^0.8.28"
|
||||
"typescript": "~3.2.2",
|
||||
"zone.js": "~0.8.26"
|
||||
},
|
||||
"schematics": "./dist/schematics/collection.json"
|
||||
}
|
||||
|
||||
@@ -15,3 +15,7 @@
|
||||
npm run build.link ../ionic-conference-app
|
||||
|
||||
When the command above is ran from the `angular` directory, it will build `@ionic/angular` and copy the `dist` directory to the correct location of another local project. In the example above, the end result is that it copies the `dist` directory to `../ionic-conference-app/node_modules/@ionic/angular/dist`. The path given should be relative to the root of this mono repo.
|
||||
|
||||
## package.json note
|
||||
|
||||
The `package.json` file in this directory references __Ionic 3__ and is in here to get GitHub to properly show the Used By counts on the repo. __Do not remove it!__
|
||||
|
||||
6
angular/scripts/clean.js
vendored
6
angular/scripts/clean.js
vendored
@@ -1,12 +1,12 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, '..');
|
||||
|
||||
const cleanDirs = [
|
||||
'dist'
|
||||
path.join(ROOT_DIR, 'dist')
|
||||
];
|
||||
|
||||
cleanDirs.forEach(dir => {
|
||||
const cleanDir = path.join(__dirname, '../', dir);
|
||||
fs.removeSync(cleanDir);
|
||||
fs.emptyDirSync(dir);
|
||||
});
|
||||
|
||||
16
angular/scripts/package.json
Normal file
16
angular/scripts/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "ionic-angular",
|
||||
"version": "`gulp package` generates dist/package.json from this template using the root ./package.json",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ionic-team/ionic.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "umd/index.js",
|
||||
"module": "index.js",
|
||||
"es2015": "es2015/index.js",
|
||||
"peerDependencies": {
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,13 @@ import resolve from 'rollup-plugin-node-resolve';
|
||||
|
||||
export default {
|
||||
input: 'build/es2015/core.js',
|
||||
output: {
|
||||
file: 'dist/fesm2015.js',
|
||||
format: 'es'
|
||||
},
|
||||
external: (id) => {
|
||||
// inline @ionic/core deps
|
||||
if (id === '@ionic/core') {
|
||||
return false;
|
||||
output: [
|
||||
{
|
||||
file: 'dist/fesm2015.js',
|
||||
format: 'es'
|
||||
}
|
||||
],
|
||||
external: (id) => {
|
||||
// anything else is external
|
||||
// Windows: C:\xxxxxx\xxx
|
||||
const colonPosition = 1;
|
||||
|
||||
@@ -4,6 +4,15 @@ const newConfig = {
|
||||
...config,
|
||||
input: 'build/es5/core.js',
|
||||
};
|
||||
newConfig.output.file = 'dist/fesm5.js';
|
||||
newConfig.output = [
|
||||
{
|
||||
file: 'dist/fesm5.js',
|
||||
format: 'es'
|
||||
},
|
||||
{
|
||||
file: 'dist/fesm5.cjs.js',
|
||||
format: 'cjs'
|
||||
}
|
||||
];
|
||||
|
||||
export { newConfig as default };
|
||||
|
||||
@@ -1,55 +1,45 @@
|
||||
import { defineCustomElements } from '@ionic/core/loader';
|
||||
import { NgZone } from '@angular/core';
|
||||
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
|
||||
|
||||
import { Config } from './providers/config';
|
||||
import { IonicWindow } from './types/interfaces';
|
||||
import { raf } from './util/util';
|
||||
|
||||
export function appInitialize(config: Config, doc: Document) {
|
||||
let didInitialize = false;
|
||||
|
||||
export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
|
||||
return (): any => {
|
||||
const win: IonicWindow | undefined = doc.defaultView as any;
|
||||
if (win) {
|
||||
if (didInitialize) {
|
||||
console.warn('Ionic Angular was already initialized. Make sure IonicModule.forRoot() is just called once.');
|
||||
}
|
||||
didInitialize = true;
|
||||
const Ionic = win.Ionic = win.Ionic || {};
|
||||
|
||||
Ionic.config = config;
|
||||
Ionic.asyncQueue = false;
|
||||
|
||||
Ionic.ael = (elm, eventName, cb, opts) => {
|
||||
if (elm.__zone_symbol__addEventListener && skipZone(eventName)) {
|
||||
elm.__zone_symbol__addEventListener(eventName, cb, opts);
|
||||
} else {
|
||||
elm.addEventListener(eventName, cb, opts);
|
||||
}
|
||||
Ionic.config = {
|
||||
...config,
|
||||
_zoneGate: (h: any) => zone.run(h)
|
||||
};
|
||||
|
||||
Ionic.rel = (elm, eventName, cb, opts) => {
|
||||
if (elm.__zone_symbol__removeEventListener && skipZone(eventName)) {
|
||||
elm.__zone_symbol__removeEventListener(eventName, cb, opts);
|
||||
} else {
|
||||
elm.removeEventListener(eventName, cb, opts);
|
||||
}
|
||||
};
|
||||
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
|
||||
? '__zone_symbol__addEventListener'
|
||||
: 'addEventListener';
|
||||
|
||||
return defineCustomElements(win, {
|
||||
exclude: ['ion-tabs', 'ion-tab']
|
||||
return applyPolyfills().then(() => {
|
||||
return defineCustomElements(win, {
|
||||
exclude: ['ion-tabs', 'ion-tab'],
|
||||
syncQueue: true,
|
||||
raf,
|
||||
jmp: (h: any) => zone.runOutsideAngular(h),
|
||||
ael(elm, eventName, cb, opts) {
|
||||
(elm as any)[aelFn](eventName, cb, opts);
|
||||
},
|
||||
rel(elm, eventName, cb, opts) {
|
||||
elm.removeEventListener(eventName, cb, opts);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const SKIP_ZONE = [
|
||||
'scroll',
|
||||
'resize',
|
||||
|
||||
'touchstart',
|
||||
'touchmove',
|
||||
'touchend',
|
||||
|
||||
'mousedown',
|
||||
'mousemove',
|
||||
'mouseup',
|
||||
|
||||
'ionStyle',
|
||||
];
|
||||
|
||||
function skipZone(eventName: string) {
|
||||
return SKIP_ZONE.indexOf(eventName) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,8 +25,8 @@ export class BooleanValueAccessor extends ValueAccessor {
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.checked'])
|
||||
_handleIonChange(value: any) {
|
||||
this.handleChangeEvent(value);
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleIonChange(el: any) {
|
||||
this.handleChangeEvent(el, el.checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ export class NumericValueAccessor extends ValueAccessor {
|
||||
super(el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.value'])
|
||||
_handleIonChange(value: any) {
|
||||
this.handleChangeEvent(value);
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleIonChange(el: any) {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: number | null) => void) {
|
||||
|
||||
@@ -20,8 +20,8 @@ export class RadioValueAccessor extends ValueAccessor {
|
||||
super(el);
|
||||
}
|
||||
|
||||
@HostListener('ionSelect', ['$event.target.checked'])
|
||||
_handleIonSelect(value: any) {
|
||||
this.handleChangeEvent(value);
|
||||
@HostListener('ionSelect', ['$event.target'])
|
||||
_handleIonSelect(el: any) {
|
||||
this.handleChangeEvent(el, el.checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ export class SelectValueAccessor extends ValueAccessor {
|
||||
super(el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.value'])
|
||||
_handleChangeEvent(value: any) {
|
||||
this.handleChangeEvent(value);
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleChangeEvent(el: any) {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ export class TextValueAccessor extends ValueAccessor {
|
||||
super(el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.value'])
|
||||
_handleInputEvent(value: any) {
|
||||
this.handleChangeEvent(value);
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleInputEvent(el: any) {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor } from '@angular/forms';
|
||||
|
||||
import { raf } from '../../util/util';
|
||||
|
||||
export class ValueAccessor implements ControlValueAccessor {
|
||||
|
||||
private onChange: (value: any) => void = () => {/**/};
|
||||
@@ -14,18 +16,22 @@ export class ValueAccessor implements ControlValueAccessor {
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
|
||||
handleChangeEvent(value: any) {
|
||||
if (value !== this.lastValue) {
|
||||
this.lastValue = value;
|
||||
this.onChange(value);
|
||||
handleChangeEvent(el: HTMLElement, value: any) {
|
||||
if (el === this.el.nativeElement) {
|
||||
if (value !== this.lastValue) {
|
||||
this.lastValue = value;
|
||||
this.onChange(value);
|
||||
}
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setIonicClasses(this.el);
|
||||
@HostListener('ionBlur', ['$event.target'])
|
||||
_handleBlurEvent(el: any) {
|
||||
if (el === this.el.nativeElement) {
|
||||
this.onTouched();
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => void) {
|
||||
@@ -41,8 +47,8 @@ export class ValueAccessor implements ControlValueAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
export function setIonicClasses(element: ElementRef) {
|
||||
requestAnimationFrame(() => {
|
||||
export const setIonicClasses = (element: ElementRef) => {
|
||||
raf(() => {
|
||||
const input = element.nativeElement as HTMLElement;
|
||||
const classes = getClasses(input);
|
||||
setClasses(input, classes);
|
||||
@@ -52,9 +58,9 @@ export function setIonicClasses(element: ElementRef) {
|
||||
setClasses(item, classes);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getClasses(element: HTMLElement) {
|
||||
const getClasses = (element: HTMLElement) => {
|
||||
const classList = element.classList;
|
||||
const classes = [];
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
@@ -64,22 +70,22 @@ function getClasses(element: HTMLElement) {
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
};
|
||||
|
||||
function setClasses(element: HTMLElement, classes: string[]) {
|
||||
const setClasses = (element: HTMLElement, classes: string[]) => {
|
||||
const classList = element.classList;
|
||||
|
||||
classList.remove(
|
||||
[
|
||||
'ion-valid',
|
||||
'ion-invalid',
|
||||
'ion-touched',
|
||||
'ion-untouched',
|
||||
'ion-dirty',
|
||||
'ion-pristine'
|
||||
);
|
||||
classList.add(...classes);
|
||||
}
|
||||
].forEach(c => classList.remove(c));
|
||||
|
||||
function startsWith(input: string, search: string): boolean {
|
||||
classes.forEach(c => classList.add(c));
|
||||
};
|
||||
|
||||
const startsWith = (input: string, search: string): boolean => {
|
||||
return input.substr(0, search.length) === search;
|
||||
}
|
||||
};
|
||||
|
||||
134
angular/src/directives/css-utils-deprecations.ts
Normal file
134
angular/src/directives/css-utils-deprecations.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[align-self-start], [align-self-end], [align-self-center], [align-self-stretch], [align-self-baseline], [align-self-auto], [wrap-reverse], [justify-content-start], [justify-content-center], [justify-content-end], [justify-content-around], [justify-content-between], [justify-content-evenly], [align-items-start], [align-items-center], [align-items-end], [align-items-stretch], [align-items-baseline], [float-left], [float-right], [float-start], [float-end], [float-sm-left], [float-sm-right], [float-sm-start], [float-sm-end], [float-md-left], [float-md-right], [float-md-start], [float-md-end], [float-lg-left], [float-lg-right], [float-lg-start], [float-lg-end], [float-xl-left], [float-xl-right], [float-xl-start], [float-xl-end], [text-center], [text-justify], [text-start], [text-end], [text-left], [text-right], [text-nowrap], [text-wrap], [text-sm-center], [text-sm-justify], [text-sm-start], [text-sm-end], [text-sm-left], [text-sm-right], [text-sm-nowrap], [text-sm-wrap], [text-md-center], [text-md-justify], [text-md-start], [text-md-end], [text-md-left], [text-md-right], [text-md-nowrap], [text-md-wrap], [text-lg-center], [text-lg-justify], [text-lg-start], [text-lg-end], [text-lg-left], [text-lg-right], [text-lg-nowrap], [text-lg-wrap], [text-xl-center], [text-xl-justify], [text-xl-start], [text-xl-end], [text-xl-left], [text-xl-right], [text-xl-nowrap], [text-xl-wrap], [text-uppercase], [text-lowercase], [text-capitalize], [text-sm-uppercase], [text-sm-lowercase], [text-sm-capitalize], [text-md-uppercase], [text-md-lowercase], [text-md-capitalize], [text-lg-uppercase], [text-lg-lowercase], [text-lg-capitalize], [text-xl-uppercase], [text-xl-lowercase], [text-xl-capitalize], [no-padding], [padding], [padding-top], [padding-bottom], [padding-start], [padding-end], [padding-vertical], [padding-horizontal], [no-margin], [margin], [margin-top], [margin-bottom], [margin-start], [margin-end], [margin-vertical], [margin-horizontal]',
|
||||
})
|
||||
export class CssUtilsDeprecations {
|
||||
constructor(ref: ElementRef) {
|
||||
const el = (ref.nativeElement as HTMLElement);
|
||||
const attributes = Array.from(el.attributes)
|
||||
.map(a => a.name)
|
||||
.filter(n => DEPRECATED_ATTRIBUTES.includes(n));
|
||||
|
||||
if (attributes.length > 0) {
|
||||
console.warn(`[DEPRECATED][CSS] Ionic CSS attributes are deprecated.
|
||||
Replace:
|
||||
'<${el.tagName.toLowerCase()} ${attributes.map(n => `${n}`).join(' ')}>'
|
||||
|
||||
With:
|
||||
'<${el.tagName.toLowerCase()} class="${attributes.map(n => `ion-${n}`).join(' ')}">'
|
||||
`);
|
||||
}
|
||||
}
|
||||
}
|
||||
const DEPRECATED_ATTRIBUTES = [
|
||||
'align-self-start',
|
||||
'align-self-end',
|
||||
'align-self-center',
|
||||
'align-self-stretch',
|
||||
'align-self-baseline',
|
||||
'align-self-auto',
|
||||
'wrap-reverse',
|
||||
'justify-content-start',
|
||||
'justify-content-center',
|
||||
'justify-content-end',
|
||||
'justify-content-around',
|
||||
'justify-content-between',
|
||||
'justify-content-evenly',
|
||||
'align-items-start',
|
||||
'align-items-center',
|
||||
'align-items-end',
|
||||
'align-items-stretch',
|
||||
'align-items-baseline',
|
||||
'float-left',
|
||||
'float-right',
|
||||
'float-start',
|
||||
'float-end',
|
||||
'float-sm-left',
|
||||
'float-sm-right',
|
||||
'float-sm-start',
|
||||
'float-sm-end',
|
||||
'float-md-left',
|
||||
'float-md-right',
|
||||
'float-md-start',
|
||||
'float-md-end',
|
||||
'float-lg-left',
|
||||
'float-lg-right',
|
||||
'float-lg-start',
|
||||
'float-lg-end',
|
||||
'float-xl-left',
|
||||
'float-xl-right',
|
||||
'float-xl-start',
|
||||
'float-xl-end',
|
||||
'text-center',
|
||||
'text-justify',
|
||||
'text-start',
|
||||
'text-end',
|
||||
'text-left',
|
||||
'text-right',
|
||||
'text-nowrap',
|
||||
'text-wrap',
|
||||
'text-sm-center',
|
||||
'text-sm-justify',
|
||||
'text-sm-start',
|
||||
'text-sm-end',
|
||||
'text-sm-left',
|
||||
'text-sm-right',
|
||||
'text-sm-nowrap',
|
||||
'text-sm-wrap',
|
||||
'text-md-center',
|
||||
'text-md-justify',
|
||||
'text-md-start',
|
||||
'text-md-end',
|
||||
'text-md-left',
|
||||
'text-md-right',
|
||||
'text-md-nowrap',
|
||||
'text-md-wrap',
|
||||
'text-lg-center',
|
||||
'text-lg-justify',
|
||||
'text-lg-start',
|
||||
'text-lg-end',
|
||||
'text-lg-left',
|
||||
'text-lg-right',
|
||||
'text-lg-nowrap',
|
||||
'text-lg-wrap',
|
||||
'text-xl-center',
|
||||
'text-xl-justify',
|
||||
'text-xl-start',
|
||||
'text-xl-end',
|
||||
'text-xl-left',
|
||||
'text-xl-right',
|
||||
'text-xl-nowrap',
|
||||
'text-xl-wrap',
|
||||
'text-uppercase',
|
||||
'text-lowercase',
|
||||
'text-capitalize',
|
||||
'text-sm-uppercase',
|
||||
'text-sm-lowercase',
|
||||
'text-sm-capitalize',
|
||||
'text-md-uppercase',
|
||||
'text-md-lowercase',
|
||||
'text-md-capitalize',
|
||||
'text-lg-uppercase',
|
||||
'text-lg-lowercase',
|
||||
'text-lg-capitalize',
|
||||
'text-xl-uppercase',
|
||||
'text-xl-lowercase',
|
||||
'text-xl-capitalize',
|
||||
'no-padding',
|
||||
'padding',
|
||||
'padding-top',
|
||||
'padding-bottom',
|
||||
'padding-start',
|
||||
'padding-end',
|
||||
'padding-vertical',
|
||||
'padding-horizontal',
|
||||
'no-margin',
|
||||
'margin',
|
||||
'margin-top',
|
||||
'margin-bottom',
|
||||
'margin-start',
|
||||
'margin-end',
|
||||
'margin-vertical',
|
||||
'margin-horizontal'
|
||||
];
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
|
||||
import { Attribute, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
|
||||
@@ -57,7 +57,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
private resolver: ComponentFactoryResolver,
|
||||
@Attribute('name') name: string,
|
||||
@Optional() @Attribute('tabs') tabs: string,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
private config: Config,
|
||||
private navCtrl: NavController,
|
||||
commonLocation: Location,
|
||||
@@ -94,7 +93,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
if ((this.nativeEl as any).componentOnReady) {
|
||||
this.nativeEl.componentOnReady().then(() => {
|
||||
if (this._swipeGesture === undefined) {
|
||||
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', this.nativeEl.mode === 'ios');
|
||||
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -210,8 +209,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
// Store references to the proxy by component
|
||||
this.proxyMap.set(cmpRef.instance, activatedRouteProxy);
|
||||
this.currentActivatedRoute$.next({ component: cmpRef.instance, activatedRoute });
|
||||
|
||||
this.changeDetector.markForCheck();
|
||||
}
|
||||
|
||||
this.activatedView = enteringView;
|
||||
|
||||
@@ -31,7 +31,7 @@ export class StackController {
|
||||
createView(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
|
||||
const url = getUrl(this.router, activatedRoute);
|
||||
const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
|
||||
const unlistenEvents = bindLifecycleEvents(ref.instance, element);
|
||||
const unlistenEvents = bindLifecycleEvents(this.zone, ref.instance, element);
|
||||
return {
|
||||
id: this.nextId++,
|
||||
stackId: computeStackId(this.tabsPrefix, url),
|
||||
@@ -59,6 +59,7 @@ export class StackController {
|
||||
direction = 'back';
|
||||
animation = undefined;
|
||||
}
|
||||
|
||||
const viewsSnapshot = this.views.slice();
|
||||
|
||||
let currentNavigation;
|
||||
@@ -94,16 +95,36 @@ export class StackController {
|
||||
}
|
||||
}
|
||||
|
||||
const reused = this.views.includes(enteringView);
|
||||
const views = this.insertView(enteringView, direction);
|
||||
return this.wait(async () => {
|
||||
await this.transition(enteringView, leavingView, animation, this.canGoBack(1), false);
|
||||
await cleanupAsync(enteringView, views, viewsSnapshot, this.location);
|
||||
return {
|
||||
enteringView,
|
||||
direction,
|
||||
animation,
|
||||
tabSwitch
|
||||
};
|
||||
|
||||
// Trigger change detection before transition starts
|
||||
// This will call ngOnInit() the first time too, just after the view
|
||||
// was attached to the dom, but BEFORE the transition starts
|
||||
if (!reused) {
|
||||
enteringView.ref.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
// Wait until previous transitions finish
|
||||
return this.zone.runOutsideAngular(() => {
|
||||
return this.wait(() => {
|
||||
// disconnect leaving page from change detection to
|
||||
// reduce jank during the page transition
|
||||
if (leavingView) {
|
||||
leavingView.ref.changeDetectorRef.detach();
|
||||
}
|
||||
// In case the enteringView is the same as the leavingPage we need to reattach()
|
||||
enteringView.ref.changeDetectorRef.reattach();
|
||||
|
||||
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
|
||||
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
|
||||
.then(() => ({
|
||||
enteringView,
|
||||
direction,
|
||||
animation,
|
||||
tabSwitch
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,28 +159,30 @@ export class StackController {
|
||||
});
|
||||
}
|
||||
|
||||
async startBackTransition() {
|
||||
startBackTransition() {
|
||||
const leavingView = this.activeView;
|
||||
if (leavingView) {
|
||||
const views = this.getStack(leavingView.stackId);
|
||||
const enteringView = views[views.length - 2];
|
||||
enteringView.ref.changeDetectorRef.reattach();
|
||||
await this.wait(() => {
|
||||
return this.wait(() => {
|
||||
return this.transition(
|
||||
enteringView, // entering view
|
||||
leavingView, // leaving view
|
||||
'back',
|
||||
true,
|
||||
this.canGoBack(2),
|
||||
true
|
||||
);
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
endBackTransition(shouldComplete: boolean) {
|
||||
if (shouldComplete) {
|
||||
this.skipTransition = true;
|
||||
this.pop(1);
|
||||
} else if (this.activeView) {
|
||||
cleanup(this.activeView, this.views, this.views, this.location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +212,7 @@ export class StackController {
|
||||
return this.views.slice();
|
||||
}
|
||||
|
||||
private async transition(
|
||||
private transition(
|
||||
enteringView: RouteView | undefined,
|
||||
leavingView: RouteView | undefined,
|
||||
direction: 'forward' | 'back' | undefined,
|
||||
@@ -198,26 +221,32 @@ export class StackController {
|
||||
) {
|
||||
if (this.skipTransition) {
|
||||
this.skipTransition = false;
|
||||
return;
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
if (leavingView === enteringView) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
const enteringEl = enteringView ? enteringView.element : undefined;
|
||||
const leavingEl = leavingView ? leavingView.element : undefined;
|
||||
const containerEl = this.containerEl;
|
||||
if (enteringEl && enteringEl !== leavingEl) {
|
||||
enteringEl.classList.add('ion-page', 'ion-page-invisible');
|
||||
enteringEl.classList.add('ion-page');
|
||||
enteringEl.classList.add('ion-page-invisible');
|
||||
if (enteringEl.parentElement !== containerEl) {
|
||||
containerEl.appendChild(enteringEl);
|
||||
}
|
||||
|
||||
await containerEl.componentOnReady();
|
||||
await containerEl.commit(enteringEl, leavingEl, {
|
||||
deepWait: true,
|
||||
duration: direction === undefined ? 0 : undefined,
|
||||
direction,
|
||||
showGoBack,
|
||||
progressAnimation
|
||||
});
|
||||
if ((containerEl as any).commit) {
|
||||
return containerEl.commit(enteringEl, leavingEl, {
|
||||
deepWait: true,
|
||||
duration: direction === undefined ? 0 : undefined,
|
||||
direction,
|
||||
showGoBack,
|
||||
progressAnimation
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
private async wait<T>(task: () => Promise<T>): Promise<T> {
|
||||
@@ -230,22 +259,24 @@ export class StackController {
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupAsync(activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) {
|
||||
return new Promise(resolve => {
|
||||
requestAnimationFrame(() => {
|
||||
cleanup(activeRoute, views, viewsSnapshot, location);
|
||||
resolve();
|
||||
const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
|
||||
if (typeof (requestAnimationFrame as any) === 'function') {
|
||||
return new Promise<any>(resolve => {
|
||||
requestAnimationFrame(() => {
|
||||
cleanup(activeRoute, views, viewsSnapshot, location);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
function cleanup(activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) {
|
||||
const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
|
||||
viewsSnapshot
|
||||
.filter(view => !views.includes(view))
|
||||
.forEach(destroyView);
|
||||
|
||||
views.forEach(view => {
|
||||
|
||||
/**
|
||||
* In the event that a user navigated multiple
|
||||
* times in rapid succession, we want to make sure
|
||||
@@ -265,4 +296,4 @@ function cleanup(activeRoute: RouteView, views: RouteView[], viewsSnapshot: Rout
|
||||
view.ref.changeDetectorRef.detach();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ComponentRef } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
||||
import { NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
export function insertView(views: RouteView[], view: RouteView, direction: RouterDirection) {
|
||||
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
|
||||
if (direction === 'root') {
|
||||
return setRoot(views, view);
|
||||
} else if (direction === 'forward') {
|
||||
@@ -10,15 +10,15 @@ export function insertView(views: RouteView[], view: RouteView, direction: Route
|
||||
} else {
|
||||
return setBack(views, view);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setRoot(views: RouteView[], view: RouteView) {
|
||||
const setRoot = (views: RouteView[], view: RouteView) => {
|
||||
views = views.filter(v => v.stackId !== view.stackId);
|
||||
views.push(view);
|
||||
return views;
|
||||
}
|
||||
};
|
||||
|
||||
function setForward(views: RouteView[], view: RouteView) {
|
||||
const setForward = (views: RouteView[], view: RouteView) => {
|
||||
const index = views.indexOf(view);
|
||||
if (index >= 0) {
|
||||
views = views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
|
||||
@@ -26,30 +26,30 @@ function setForward(views: RouteView[], view: RouteView) {
|
||||
views.push(view);
|
||||
}
|
||||
return views;
|
||||
}
|
||||
};
|
||||
|
||||
function setBack(views: RouteView[], view: RouteView) {
|
||||
const setBack = (views: RouteView[], view: RouteView) => {
|
||||
const index = views.indexOf(view);
|
||||
if (index >= 0) {
|
||||
return views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
|
||||
} else {
|
||||
return setRoot(views, view);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function getUrl(router: Router, activatedRoute: ActivatedRoute) {
|
||||
export const getUrl = (router: Router, activatedRoute: ActivatedRoute) => {
|
||||
const urlTree = router.createUrlTree(['.'], { relativeTo: activatedRoute });
|
||||
return router.serializeUrl(urlTree);
|
||||
}
|
||||
};
|
||||
|
||||
export function isTabSwitch(enteringView: RouteView, leavingView: RouteView | undefined) {
|
||||
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined) => {
|
||||
if (!leavingView) {
|
||||
return true;
|
||||
}
|
||||
return enteringView.stackId !== leavingView.stackId;
|
||||
}
|
||||
};
|
||||
|
||||
export function computeStackId(prefixUrl: string[] | undefined, url: string) {
|
||||
export const computeStackId = (prefixUrl: string[] | undefined, url: string) => {
|
||||
if (!prefixUrl) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -63,22 +63,22 @@ export function computeStackId(prefixUrl: string[] | undefined, url: string) {
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export function toSegments(path: string): string[] {
|
||||
export const toSegments = (path: string) => {
|
||||
return path
|
||||
.split('/')
|
||||
.map(s => s.trim())
|
||||
.filter(s => s !== '');
|
||||
}
|
||||
};
|
||||
|
||||
export function destroyView(view: RouteView | undefined) {
|
||||
export const destroyView = (view: RouteView | undefined) => {
|
||||
if (view) {
|
||||
// TODO lifecycle event
|
||||
view.ref.destroy();
|
||||
view.unlistenEvents();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export interface StackEvent {
|
||||
enteringView: RouteView;
|
||||
|
||||
@@ -43,6 +43,7 @@ d.IonApp,
|
||||
d.IonMenuButton,
|
||||
d.IonMenuToggle,
|
||||
d.IonNav,
|
||||
d.IonNavLink,
|
||||
d.IonNavPop,
|
||||
d.IonNavPush,
|
||||
d.IonNavSetRoot,
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
/* tslint:disable */
|
||||
import { fromEvent } from 'rxjs';
|
||||
|
||||
export function proxyInputs(Cmp: any, inputs: string[]) {
|
||||
export const proxyInputs = (Cmp: any, inputs: string[]) => {
|
||||
const Prototype = Cmp.prototype;
|
||||
inputs.forEach(item => {
|
||||
Object.defineProperty(Prototype, item, {
|
||||
get() { return this.el[item]; },
|
||||
set(val: any) { this.el[item] = val; },
|
||||
set(val: any) {
|
||||
this.z.runOutsideAngular(() => this.el[item] = val);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function proxyMethods(Cmp: any, methods: string[]) {
|
||||
export const proxyMethods = (Cmp: any, methods: string[]) => {
|
||||
const Prototype = Cmp.prototype;
|
||||
methods.forEach(methodName => {
|
||||
Prototype[methodName] = function() {
|
||||
const args = arguments;
|
||||
return this.el.componentOnReady().then((el: any) => el[methodName].apply(el, args));
|
||||
return this.z.runOutsideAngular(() => this.el[methodName].apply(this.el, args));
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function proxyOutputs(instance: any, el: any, events: string[]) {
|
||||
export const proxyOutputs = (instance: any, el: any, events: string[]) => {
|
||||
events.forEach(eventName => instance[eventName] = fromEvent(el, eventName));
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EmbeddedViewRef, IterableDiffer, IterableDiffers, NgZone, SimpleChanges, TrackByFunction } from '@angular/core';
|
||||
import { Cell, CellType, HeaderFn, ItemHeightFn } from '@ionic/core';
|
||||
import { Cell, CellType, FooterHeightFn, HeaderFn, HeaderHeightFn, ItemHeightFn } from '@ionic/core';
|
||||
|
||||
import { proxyInputs, proxyMethods } from '../proxies-utils';
|
||||
|
||||
@@ -75,7 +75,7 @@ export declare interface IonVirtualScroll {
|
||||
|
||||
/**
|
||||
* An optional function that maps each item within their height.
|
||||
* When this function is provides, heavy optimizations and fast path can be taked by
|
||||
* When this function is provided, heavy optimizations and fast path can be taked by
|
||||
* `ion-virtual-scroll` leading to massive performance improvements.
|
||||
*
|
||||
* This function allows to skip all DOM reads, which can be Doing so leads
|
||||
@@ -83,6 +83,16 @@ export declare interface IonVirtualScroll {
|
||||
*/
|
||||
itemHeight?: ItemHeightFn;
|
||||
|
||||
/**
|
||||
* An optional function that maps each item header within their height.
|
||||
*/
|
||||
headerHeight?: HeaderHeightFn;
|
||||
|
||||
/**
|
||||
* An optional function that maps each item footer within their height.
|
||||
*/
|
||||
footerHeight?: FooterHeightFn;
|
||||
|
||||
/**
|
||||
* Same as `ngForTrackBy` which can be used on `ngFor`.
|
||||
*/
|
||||
@@ -114,6 +124,8 @@ export declare interface IonVirtualScroll {
|
||||
'footerFn',
|
||||
'items',
|
||||
'itemHeight',
|
||||
'headerHeight',
|
||||
'footerHeight',
|
||||
'trackBy'
|
||||
]
|
||||
})
|
||||
@@ -128,7 +140,7 @@ export class IonVirtualScroll {
|
||||
@ContentChild(VirtualFooter) ftrTmp!: VirtualFooter;
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private z: NgZone,
|
||||
private iterableDiffers: IterableDiffers,
|
||||
elementRef: ElementRef,
|
||||
) {
|
||||
@@ -162,7 +174,7 @@ export class IonVirtualScroll {
|
||||
}
|
||||
|
||||
private nodeRender(el: HTMLElement | null, cell: Cell, index: number): HTMLElement {
|
||||
return this.zone.run(() => {
|
||||
return this.z.run(() => {
|
||||
let node: EmbeddedViewRef<VirtualContext>;
|
||||
if (!el) {
|
||||
node = this.itmTmp.viewContainer.createEmbeddedView(
|
||||
@@ -194,7 +206,7 @@ export class IonVirtualScroll {
|
||||
}
|
||||
}
|
||||
|
||||
function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement {
|
||||
const getElement = (view: EmbeddedViewRef<VirtualContext>): HTMLElement => {
|
||||
const rootNodes = view.rootNodes;
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
if (rootNodes[i].nodeType === 1) {
|
||||
@@ -202,7 +214,7 @@ function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement {
|
||||
}
|
||||
}
|
||||
throw new Error('virtual element was not created');
|
||||
}
|
||||
};
|
||||
|
||||
proxyInputs(IonVirtualScroll, [
|
||||
'approxItemHeight',
|
||||
@@ -211,7 +223,9 @@ proxyInputs(IonVirtualScroll, [
|
||||
'headerFn',
|
||||
'footerFn',
|
||||
'items',
|
||||
'itemHeight'
|
||||
'itemHeight',
|
||||
'headerHeight',
|
||||
'footerHeight'
|
||||
]);
|
||||
|
||||
proxyMethods(IonVirtualScroll, [
|
||||
|
||||
@@ -14,6 +14,7 @@ export { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
|
||||
export { VirtualItem } from './directives/virtual-scroll/virtual-item';
|
||||
export { VirtualHeader } from './directives/virtual-scroll/virtual-header';
|
||||
export { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
|
||||
export { CssUtilsDeprecations } from './directives/css-utils-deprecations';
|
||||
export * from './directives/proxies';
|
||||
|
||||
// PROVIDERS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CommonModule, DOCUMENT } from '@angular/common';
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule, NgZone } from '@angular/core';
|
||||
import { IonicConfig } from '@ionic/core';
|
||||
|
||||
import { appInitialize } from './app-initialize';
|
||||
@@ -8,12 +8,13 @@ import { NumericValueAccessor } from './directives/control-value-accessors/numer
|
||||
import { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
|
||||
import { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
|
||||
import { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
|
||||
import { CssUtilsDeprecations } from './directives/css-utils-deprecations';
|
||||
import { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
|
||||
import { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
|
||||
import { IonTabs } from './directives/navigation/ion-tabs';
|
||||
import { NavDelegate } from './directives/navigation/nav-delegate';
|
||||
import { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
|
||||
import { IonApp, IonAvatar, IonBackButton, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInfiniteScrollContent, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonListHeader, IonMenu, IonMenuButton, IonMenuToggle, IonNav, IonNavPop, IonNavPush, IonNavSetRoot, IonNote, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTabBar, IonTabButton, IonText, IonTextarea, IonThumbnail, IonTitle, IonToggle, IonToolbar } from './directives/proxies';
|
||||
import { IonApp, IonAvatar, IonBackButton, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInfiniteScrollContent, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonListHeader, IonMenu, IonMenuButton, IonMenuToggle, IonNav, IonNavLink, IonNavPop, IonNavPush, IonNavSetRoot, IonNote, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTabBar, IonTabButton, IonText, IonTextarea, IonThumbnail, IonTitle, IonToggle, IonToolbar } from './directives/proxies';
|
||||
import { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
|
||||
import { VirtualHeader } from './directives/virtual-scroll/virtual-header';
|
||||
import { VirtualItem } from './directives/virtual-scroll/virtual-item';
|
||||
@@ -66,6 +67,7 @@ const DECLARATIONS = [
|
||||
IonMenuButton,
|
||||
IonMenuToggle,
|
||||
IonNav,
|
||||
IonNavLink,
|
||||
IonNavPop,
|
||||
IonNavPush,
|
||||
IonNavSetRoot,
|
||||
@@ -118,7 +120,10 @@ const DECLARATIONS = [
|
||||
VirtualFooter,
|
||||
VirtualHeader,
|
||||
VirtualItem,
|
||||
IonVirtualScroll
|
||||
IonVirtualScroll,
|
||||
|
||||
// Deprecations
|
||||
CssUtilsDeprecations
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
@@ -142,7 +147,8 @@ export class IonicModule {
|
||||
multi: true,
|
||||
deps: [
|
||||
ConfigToken,
|
||||
DOCUMENT
|
||||
DOCUMENT,
|
||||
NgZone
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ActionSheetOptions } from '@ionic/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionSheetOptions, actionSheetController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ActionSheetController extends OverlayBaseController<ActionSheetOptions, HTMLIonActionSheetElement> {
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super('ion-action-sheet-controller', doc);
|
||||
constructor() {
|
||||
super(actionSheetController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { AlertOptions } from '@ionic/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AlertOptions, alertController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AlertController extends OverlayBaseController<AlertOptions, HTMLIonAlertElement> {
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super('ion-alert-controller', doc);
|
||||
constructor() {
|
||||
super(alertController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
) {}
|
||||
|
||||
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
this.zone.run(() => {
|
||||
return this.zone.run(() => {
|
||||
return new Promise(resolve => {
|
||||
const el = attachView(
|
||||
this.resolver, this.injector, this.location, this.appRef,
|
||||
this.zone, this.resolver, this.injector, this.location, this.appRef,
|
||||
this.elRefMap, this.elEventsMap,
|
||||
container, component, params, cssClasses
|
||||
);
|
||||
@@ -47,8 +47,8 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
}
|
||||
|
||||
removeViewFromDom(_container: any, component: any): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
this.zone.run(() => {
|
||||
return this.zone.run(() => {
|
||||
return new Promise(resolve => {
|
||||
const componentRef = this.elRefMap.get(component);
|
||||
if (componentRef) {
|
||||
componentRef.destroy();
|
||||
@@ -65,7 +65,8 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
export function attachView(
|
||||
export const attachView = (
|
||||
zone: NgZone,
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
location: ViewContainerRef | undefined,
|
||||
@@ -73,7 +74,7 @@ export function attachView(
|
||||
elRefMap: WeakMap<HTMLElement, any>,
|
||||
elEventsMap: WeakMap<HTMLElement, () => void>,
|
||||
container: any, component: any, params: any, cssClasses: string[] | undefined
|
||||
) {
|
||||
) => {
|
||||
const factory = resolver.resolveComponentFactory(component);
|
||||
const childInjector = Injector.create({
|
||||
providers: getProviders(params),
|
||||
@@ -93,7 +94,7 @@ export function attachView(
|
||||
hostElement.classList.add(clazz);
|
||||
}
|
||||
}
|
||||
const unbindEvents = bindLifecycleEvents(instance, hostElement);
|
||||
const unbindEvents = bindLifecycleEvents(zone, instance, hostElement);
|
||||
container.appendChild(hostElement);
|
||||
|
||||
if (!location) {
|
||||
@@ -103,7 +104,7 @@ export function attachView(
|
||||
elRefMap.set(hostElement, componentRef);
|
||||
elEventsMap.set(hostElement, unbindEvents);
|
||||
return hostElement;
|
||||
}
|
||||
};
|
||||
|
||||
const LIFECYCLES = [
|
||||
LIFECYCLE_WILL_ENTER,
|
||||
@@ -113,26 +114,22 @@ const LIFECYCLES = [
|
||||
LIFECYCLE_WILL_UNLOAD
|
||||
];
|
||||
|
||||
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
|
||||
const unregisters = LIFECYCLES.map(eventName => {
|
||||
const handler = (ev: any) => {
|
||||
if (typeof instance[eventName] === 'function') {
|
||||
instance[eventName](ev.detail);
|
||||
}
|
||||
};
|
||||
element.addEventListener(eventName, handler);
|
||||
return () => {
|
||||
element.removeEventListener(eventName, handler);
|
||||
};
|
||||
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
|
||||
return zone.run(() => {
|
||||
const unregisters = LIFECYCLES
|
||||
.filter(eventName => typeof instance[eventName] === 'function')
|
||||
.map(eventName => {
|
||||
const handler = (ev: any) => instance[eventName](ev.detail);
|
||||
element.addEventListener(eventName, handler);
|
||||
return () => element.removeEventListener(eventName, handler);
|
||||
});
|
||||
return () => unregisters.forEach(fn => fn());
|
||||
});
|
||||
return () => {
|
||||
unregisters.forEach(fn => fn());
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
|
||||
|
||||
function getProviders(params: {[key: string]: any}) {
|
||||
const getProviders = (params: {[key: string]: any}) => {
|
||||
return [
|
||||
{
|
||||
provide: NavParamsToken, useValue: params
|
||||
@@ -141,8 +138,8 @@ function getProviders(params: {[key: string]: any}) {
|
||||
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
function provideNavParamsInjectable(params: {[key: string]: any}) {
|
||||
const provideNavParamsInjectable = (params: {[key: string]: any}) => {
|
||||
return new NavParams(params);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ export class Config {
|
||||
}
|
||||
|
||||
set(key: keyof IonicConfig, value?: any) {
|
||||
console.warn(`[DEPRECATION][Config]: The Config.set() method is deprecated and will be removed in the next major release.`);
|
||||
const c = getConfig();
|
||||
if (c) {
|
||||
c.set(key, value);
|
||||
@@ -42,12 +43,12 @@ export class Config {
|
||||
|
||||
export const ConfigToken = new InjectionToken<any>('USERCONFIG');
|
||||
|
||||
function getConfig(): CoreConfig | null {
|
||||
const getConfig = (): CoreConfig | null => {
|
||||
if (typeof (window as any) !== 'undefined') {
|
||||
const Ionic = (window as IonicWindow).Ionic;
|
||||
const Ionic = (window as any as IonicWindow).Ionic;
|
||||
if (Ionic && Ionic.config) {
|
||||
return Ionic.config;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ export class DomController {
|
||||
}
|
||||
}
|
||||
|
||||
function getQueue() {
|
||||
const getQueue = () => {
|
||||
const win = typeof (window as any) !== 'undefined' ? window : null as any;
|
||||
|
||||
if (win != null) {
|
||||
@@ -41,6 +41,6 @@ function getQueue() {
|
||||
read: (cb: any) => cb(),
|
||||
write: (cb: any) => cb()
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export type RafCallback = (timeStamp?: number) => void;
|
||||
|
||||
@@ -7,6 +7,11 @@ export type EventHandler = (...args: any[]) => any;
|
||||
export class Events {
|
||||
private c = new Map<string, EventHandler[]>();
|
||||
|
||||
constructor() {
|
||||
console.warn(`[DEPRECATION][Events]: The Events provider is deprecated and it will be removed in the next major release.
|
||||
- Use "Observables" for a similar pub/sub architecture: https://angular.io/guide/observables
|
||||
- Use "Redux" for advanced state management: https://ngrx.io`);
|
||||
}
|
||||
/**
|
||||
* Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { LoadingOptions } from '@ionic/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { LoadingOptions, loadingController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LoadingController extends OverlayBaseController<LoadingOptions, HTMLIonLoadingElement> {
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super('ion-loading-controller', doc);
|
||||
constructor() {
|
||||
super(loadingController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { menuController } from '@ionic/core';
|
||||
|
||||
import { proxyMethod } from '../util/util';
|
||||
|
||||
const CTRL = 'ion-menu-controller';
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MenuController {
|
||||
|
||||
constructor(@Inject(DOCUMENT) private doc: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Programmatically open the Menu.
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu is fully opened
|
||||
*/
|
||||
open(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, this.doc, 'open', menuId);
|
||||
open(menuId?: string) {
|
||||
return menuController.open(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,8 +22,8 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu is fully closed
|
||||
*/
|
||||
close(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, this.doc, 'close', menuId);
|
||||
close(menuId?: string) {
|
||||
return menuController.close(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,8 +32,8 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu has been toggled
|
||||
*/
|
||||
toggle(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, this.doc, 'toggle', menuId);
|
||||
toggle(menuId?: string) {
|
||||
return menuController.toggle(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,8 +44,20 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, this.doc, 'enable', shouldEnable, menuId);
|
||||
enable(shouldEnable: boolean, menuId?: string) {
|
||||
return menuController.enable(shouldEnable, menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable or disable the ability to swipe open the menu.
|
||||
* @param shouldEnable True if it should be swipe-able, false if not.
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu, which is useful for chaining.
|
||||
* @deprecated Use swipeGesture() instead.
|
||||
*/
|
||||
swipeEnable(shouldEnable: boolean, menuId?: string) {
|
||||
console.warn('[DEPRECATED][ion-menu-controller] swipeEnable() is deprecated. Use MenuController.swipeGesture() instead');
|
||||
return this.swipeGesture(shouldEnable, menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,8 +66,8 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, this.doc, 'swipeEnable', shouldEnable, menuId);
|
||||
swipeGesture(shouldEnable: boolean, menuId?: string) {
|
||||
return menuController.swipeGesture(shouldEnable, menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,16 +75,16 @@ export class MenuController {
|
||||
* @return Returns true if the specified menu is currently open, otherwise false.
|
||||
* If the menuId is not specified, it returns true if ANY menu is currenly open.
|
||||
*/
|
||||
isOpen(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, this.doc, 'isOpen', menuId);
|
||||
isOpen(menuId?: string) {
|
||||
return menuController.isOpen(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns true if the menu is currently enabled, otherwise false.
|
||||
*/
|
||||
isEnabled(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, this.doc, 'isEnabled', menuId);
|
||||
isEnabled(menuId?: string) {
|
||||
return menuController.isEnabled(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,21 +96,21 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu if found, otherwise `null`.
|
||||
*/
|
||||
get(menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, this.doc, 'get', menuId);
|
||||
get(menuId?: string) {
|
||||
return menuController.get(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the instance of the menu already opened, otherwise `null`.
|
||||
*/
|
||||
getOpen(): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, this.doc, 'getOpen');
|
||||
getOpen() {
|
||||
return menuController.getOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns an array of all menu instances.
|
||||
*/
|
||||
getMenus(): Promise<HTMLIonMenuElement[]> {
|
||||
return proxyMethod(CTRL, this.doc, 'getMenus');
|
||||
getMenus() {
|
||||
return menuController.getMenus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ComponentFactoryResolver, Inject, Injectable, Injector } from '@angular/core';
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { ModalOptions, modalController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -13,9 +12,8 @@ export class ModalController extends OverlayBaseController<ModalOptions, HTMLIon
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
@Inject(DOCUMENT) doc: any
|
||||
) {
|
||||
super('ion-modal-controller', doc);
|
||||
super(modalController);
|
||||
}
|
||||
|
||||
create(opts: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
|
||||
@@ -50,12 +50,12 @@ export class NavController {
|
||||
|
||||
/**
|
||||
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
|
||||
* it's equivalent to call `this.router.navigateByUrl()`, but it's explicit about the **direction** of the transition.
|
||||
* it's equivalent to calling `this.router.navigateByUrl()`, but it's explicit about the **direction** of the transition.
|
||||
*
|
||||
* Going **forward** means that a new page it's going to be pushed to the stack of the outlet (ion-router-outlet),
|
||||
* Going **forward** means that a new page is going to be pushed to the stack of the outlet (ion-router-outlet),
|
||||
* and that it will show a "forward" animation by default.
|
||||
*
|
||||
* Navigating forward can also be trigger in a declarative manner by using the `[routerDirection]` directive:
|
||||
* Navigating forward can also be triggered in a declarative manner by using the `[routerDirection]` directive:
|
||||
*
|
||||
* ```html
|
||||
* <a routerLink="/path/to/page" routerDirection="forward">Link</a>
|
||||
@@ -68,17 +68,17 @@ export class NavController {
|
||||
|
||||
/**
|
||||
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
|
||||
* it's equivalent to call:
|
||||
* it's equivalent to calling:
|
||||
*
|
||||
* ```ts
|
||||
* this.navController.setDirection('back');
|
||||
* this.router.navigateByUrl(path);
|
||||
* ```
|
||||
*
|
||||
* Going **back** means that all the pages in the stack until the navigated page is found will be pop,
|
||||
* Going **back** means that all the pages in the stack until the navigated page is found will be popped,
|
||||
* and that it will show a "back" animation by default.
|
||||
*
|
||||
* Navigating back can also be trigger in a declarative manner by using the `[routerDirection]` directive:
|
||||
* Navigating back can also be triggered in a declarative manner by using the `[routerDirection]` directive:
|
||||
*
|
||||
* ```html
|
||||
* <a routerLink="/path/to/page" routerDirection="back">Link</a>
|
||||
@@ -91,7 +91,7 @@ export class NavController {
|
||||
|
||||
/**
|
||||
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
|
||||
* it's equivalent to call:
|
||||
* it's equivalent to calling:
|
||||
*
|
||||
* ```ts
|
||||
* this.navController.setDirection('root');
|
||||
@@ -101,7 +101,7 @@ export class NavController {
|
||||
* Going **root** means that all existing pages in the stack will be removed,
|
||||
* and the navigated page will become the single page in the stack.
|
||||
*
|
||||
* Navigating root can also be trigger in a declarative manner by using the `[routerDirection]` directive:
|
||||
* Navigating root can also be triggered in a declarative manner by using the `[routerDirection]` directive:
|
||||
*
|
||||
* ```html
|
||||
* <a routerLink="/path/to/page" routerDirection="root">Link</a>
|
||||
@@ -114,7 +114,8 @@ export class NavController {
|
||||
|
||||
/**
|
||||
* Same as [Location](https://angular.io/api/common/Location)'s back() method.
|
||||
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation.
|
||||
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation
|
||||
* by default.
|
||||
*/
|
||||
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
|
||||
this.setDirection('back', options.animated, options.animationDirection);
|
||||
@@ -122,9 +123,9 @@ export class NavController {
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods goes back in the context of ionic's stack navigation.
|
||||
* This methods goes back in the context of Ionic's stack navigation.
|
||||
*
|
||||
* It recursivelly finds the top active `ion-router-outlet` and calls `pop()`.
|
||||
* It recursively finds the top active `ion-router-outlet` and calls `pop()`.
|
||||
* This is the recommended way to go back when you are using `ion-router-outlet`.
|
||||
*/
|
||||
async pop() {
|
||||
@@ -140,11 +141,11 @@ export class NavController {
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods specifies the direction of the next navigation performed by the angular router.
|
||||
* This methods specifies the direction of the next navigation performed by the Angular router.
|
||||
*
|
||||
* `setDirection()` does not trigger any transition, it just sets a set of flags to be consumed by `ion-router-outlet`.
|
||||
* `setDirection()` does not trigger any transition, it just sets some flags to be consumed by `ion-router-outlet`.
|
||||
*
|
||||
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateBack()` instead of `setDirection()`.
|
||||
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
|
||||
*/
|
||||
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
|
||||
this.direction = direction;
|
||||
@@ -202,12 +203,17 @@ export class NavController {
|
||||
urlTree.fragment = options.fragment;
|
||||
}
|
||||
|
||||
return this.router!.navigateByUrl(urlTree);
|
||||
/**
|
||||
* `navigateByUrl` will still apply `NavigationExtras` properties
|
||||
* that do not modify the url, such as `replaceUrl` which is why
|
||||
* `options` is passed in here.
|
||||
*/
|
||||
return this.router!.navigateByUrl(urlTree, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAnimation(direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined {
|
||||
const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
|
||||
if (animated === false) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -220,7 +226,7 @@ function getAnimation(direction: RouterDirection, animated: boolean | undefined,
|
||||
return 'forward';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const DEFAULT_DIRECTION = 'auto';
|
||||
const DEFAULT_ANIMATED = undefined;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { PickerOptions } from '@ionic/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PickerOptions, pickerController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PickerController extends OverlayBaseController<PickerOptions, HTMLIonPickerElement> {
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super('ion-picker-controller', doc);
|
||||
constructor() {
|
||||
super(pickerController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Inject, Injectable, NgZone } from '@angular/core';
|
||||
import { BackButtonEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
|
||||
@@ -42,29 +42,30 @@ export class Platform {
|
||||
*/
|
||||
resize = new Subject<void>();
|
||||
|
||||
constructor(@Inject(DOCUMENT) private doc: any) {
|
||||
this.win = doc.defaultView;
|
||||
constructor(@Inject(DOCUMENT) private doc: any, zone: NgZone) {
|
||||
zone.run(() => {
|
||||
this.win = doc.defaultView;
|
||||
this.backButton.subscribeWithPriority = function(priority, callback) {
|
||||
return this.subscribe(ev => (
|
||||
ev.register(priority, () => zone.run(callback))
|
||||
));
|
||||
};
|
||||
|
||||
this.backButton.subscribeWithPriority = function(priority, callback) {
|
||||
return this.subscribe(ev => {
|
||||
ev.register(priority, callback);
|
||||
});
|
||||
};
|
||||
proxyEvent(this.pause, doc, 'pause');
|
||||
proxyEvent(this.resume, doc, 'resume');
|
||||
proxyEvent(this.backButton, doc, 'ionBackButton');
|
||||
proxyEvent(this.resize, this.win, 'resize');
|
||||
|
||||
proxyEvent(this.pause, doc, 'pause');
|
||||
proxyEvent(this.resume, doc, 'resume');
|
||||
proxyEvent(this.backButton, doc, 'ionBackButton');
|
||||
proxyEvent(this.resize, this.win, 'resize');
|
||||
|
||||
let readyResolve: (value: string) => void;
|
||||
this._readyPromise = new Promise(res => { readyResolve = res; });
|
||||
if (this.win && this.win['cordova']) {
|
||||
doc.addEventListener('deviceready', () => {
|
||||
readyResolve('cordova');
|
||||
}, { once: true });
|
||||
} else {
|
||||
readyResolve!('dom');
|
||||
}
|
||||
let readyResolve: (value: string) => void;
|
||||
this._readyPromise = new Promise(res => { readyResolve = res; });
|
||||
if (this.win && this.win['cordova']) {
|
||||
doc.addEventListener('deviceready', () => {
|
||||
readyResolve('cordova');
|
||||
}, { once: true });
|
||||
} else {
|
||||
readyResolve!('dom');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ComponentFactoryResolver, Inject, Injectable, Injector } from '@angular/core';
|
||||
import { PopoverOptions } from '@ionic/core';
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { PopoverOptions, popoverController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -13,9 +12,8 @@ export class PopoverController extends OverlayBaseController<PopoverOptions, HTM
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
@Inject(DOCUMENT) doc: any
|
||||
) {
|
||||
super('ion-popover-controller', doc);
|
||||
super(popoverController);
|
||||
}
|
||||
|
||||
create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ToastOptions } from '@ionic/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ToastOptions, toastController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToastController extends OverlayBaseController<ToastOptions, HTMLIonToastElement> {
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super('ion-toast-controller', doc);
|
||||
constructor() {
|
||||
super(toastController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
|
||||
export interface IonicGlobal {
|
||||
config?: any;
|
||||
ael?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
|
||||
raf?: (ts: number) => void;
|
||||
rel?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
|
||||
asyncQueue?: boolean;
|
||||
}
|
||||
|
||||
export interface IonicWindow extends Window {
|
||||
Ionic: IonicGlobal;
|
||||
__zone_symbol__requestAnimationFrame: (ts: number) => void;
|
||||
__zone_symbol__requestAnimationFrame?: (ts: FrameRequestCallback) => number;
|
||||
}
|
||||
|
||||
export interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady(): Promise<this>;
|
||||
forceUpdate(): void;
|
||||
}
|
||||
|
||||
@@ -25,9 +25,6 @@ export class IonicRouteStrategy implements RouteReuseStrategy {
|
||||
if (future.routeConfig !== curr.routeConfig) {
|
||||
return false;
|
||||
}
|
||||
if (future.component !== curr.component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// checking router params
|
||||
const futureParams = future.params;
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
import { proxyMethod } from './util';
|
||||
|
||||
export class OverlayBaseController<Opts, Overlay> {
|
||||
constructor(private ctrl: string, private doc: Document) {}
|
||||
interface ControllerShape<Opts, HTMLElm> {
|
||||
create(options: Opts): Promise<HTMLElm>;
|
||||
dismiss(data?: any, role?: string, id?: string): Promise<boolean>;
|
||||
getTop(): Promise<HTMLElm | undefined>;
|
||||
}
|
||||
|
||||
export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opts, Overlay> {
|
||||
constructor(private ctrl: ControllerShape<Opts, Overlay>) {}
|
||||
|
||||
/**
|
||||
* Creates a new overlay
|
||||
*/
|
||||
create(opts?: Opts): Promise<Overlay> {
|
||||
return proxyMethod(this.ctrl, this.doc, 'create', opts);
|
||||
create(opts?: Opts) {
|
||||
// TODO: next major release opts is not optional
|
||||
return this.ctrl.create((opts || {}) as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* When `id` is not provided, it dismisses the top overlay.
|
||||
*/
|
||||
dismiss(data?: any, role?: string, id?: string): Promise<void> {
|
||||
return proxyMethod(this.ctrl, this.doc, 'dismiss', data, role, id);
|
||||
dismiss(data?: any, role?: string, id?: string) {
|
||||
return this.ctrl.dismiss(data, role, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top overlay.
|
||||
*/
|
||||
getTop(): Promise<Overlay | undefined> {
|
||||
return proxyMethod(this.ctrl, this.doc, 'getTop');
|
||||
getTop() {
|
||||
return this.ctrl.getTop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
|
||||
export function proxyMethod(ctrlName: string, doc: Document, methodName: string, ...args: any[]) {
|
||||
const controller = ensureElementInBody(ctrlName, doc);
|
||||
return controller.componentOnReady()
|
||||
.then(() => (controller as any)[methodName].apply(controller, args));
|
||||
}
|
||||
declare const __zone_symbol__requestAnimationFrame: any;
|
||||
declare const requestAnimationFrame: any;
|
||||
|
||||
export function ensureElementInBody(elementName: string, doc: Document) {
|
||||
let element = doc.querySelector(elementName);
|
||||
if (!element) {
|
||||
element = doc.createElement(elementName);
|
||||
doc.body.appendChild(element);
|
||||
export const raf = (h: any) => {
|
||||
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
|
||||
return __zone_symbol__requestAnimationFrame(h);
|
||||
}
|
||||
return element as HTMLStencilElement;
|
||||
}
|
||||
if (typeof requestAnimationFrame === 'function') {
|
||||
return requestAnimationFrame(h);
|
||||
}
|
||||
return setTimeout(h);
|
||||
};
|
||||
|
||||
@@ -13,18 +13,25 @@
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/test-app",
|
||||
"outputPath": "dist/browser",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*.svg",
|
||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||
"output": "./svg"
|
||||
}
|
||||
],
|
||||
"styles": ["src/styles.css"],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
@@ -77,37 +84,13 @@
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"styles": ["src/styles.css"],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
]
|
||||
"assets": ["src/favicon.ico", "src/assets"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test-app-e2e": {
|
||||
"root": "e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
@@ -117,20 +100,39 @@
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "test-app:serve:production"
|
||||
},
|
||||
"ci": {
|
||||
"devServerTarget": "test-app:serve:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
|
||||
"exclude": ["**/node_modules/**"]
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"options": {
|
||||
"outputPath": "dist/server",
|
||||
"main": "src/main.server.ts",
|
||||
"tsConfig": "tsconfig.server.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"src": "src/environments/environment.ts",
|
||||
"replaceWith": "src/environments/environment.prod.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "test-app"
|
||||
}
|
||||
}
|
||||
|
||||
12
angular/test/test-app/browserslist
Normal file
12
angular/test/test-app/browserslist
Normal file
@@ -0,0 +1,12 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
@@ -1,19 +1,22 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./**/*.e2e-spec.ts'
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
|
||||
chromeOptions: {
|
||||
args: [ "--headless", "--disable-gpu", "--window-size=400,1000", "--start-maximized" ]
|
||||
}
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
chromeOptions: {
|
||||
args: [ "--headless", "--disable-gpu", "--window-size=400,1000", "--start-maximized" ]
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
@@ -25,8 +28,8 @@ exports.config = {
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,12 +4,13 @@ import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
|
||||
describe('form', () => {
|
||||
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
describe('change', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/form');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should have default values', async () => {
|
||||
@@ -81,6 +82,7 @@ describe('form', () => {
|
||||
describe('blur', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/form#blur');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('ion-toggle should change only after blur', async () => {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { getProperty, setProperty, handleErrorMessages } from './utils';
|
||||
import { getProperty, setProperty, handleErrorMessages, waitTime } from './utils';
|
||||
|
||||
describe('inputs', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await browser.get('/inputs');
|
||||
await waitTime(30);
|
||||
});
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should have default value', async () => {
|
||||
@@ -59,4 +60,10 @@ describe('inputs', () => {
|
||||
expect(await element(by.css('#select-note')).getText()).toEqual('playstation');
|
||||
expect(await element(by.css('#range-note')).getText()).toEqual('20');
|
||||
});
|
||||
|
||||
it('nested components should not interfere with NgModel', async () => {
|
||||
expect(await element(by.css('#range-note')).getText()).toEqual('10');
|
||||
await element(by.css('#nested-toggle')).click();
|
||||
expect(await element(by.css('#range-note')).getText()).toEqual('10');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,9 +5,10 @@ describe('modals', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await browser.get('/modals');
|
||||
await waitTime(30);
|
||||
});
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should open standalone modal and close', async () => {
|
||||
|
||||
@@ -4,9 +4,44 @@ import { handleErrorMessages, waitTime, testStack } from './utils';
|
||||
describe('navigation', () => {
|
||||
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
// TODO: Fix flaky tests
|
||||
xit ('should swipe and abort', async () => {
|
||||
await browser.get('/router-link?ionic:mode=ios');
|
||||
await waitTime(500);
|
||||
await element(by.css('#routerLink')).click();
|
||||
await waitTime(500);
|
||||
await swipeLeft(5);
|
||||
await waitTime(500);
|
||||
|
||||
const pageHidden = element(by.css('app-router-link'));
|
||||
expect(await pageHidden.getAttribute('aria-hidden')).toEqual('true');
|
||||
expect(await pageHidden.getAttribute('class')).toEqual('ion-page ion-page-hidden');
|
||||
|
||||
const pageVisible = element(by.css('app-router-link-page'));
|
||||
expect(await pageVisible.getAttribute('aria-hidden')).toEqual(null);
|
||||
expect(await pageVisible.getAttribute('class')).toEqual('ion-page can-go-back');
|
||||
});
|
||||
|
||||
xit ('should swipe and go back', async () => {
|
||||
await browser.get('/router-link?ionic:mode=ios');
|
||||
await waitTime(500);
|
||||
await element(by.css('#routerLink')).click();
|
||||
await waitTime(500);
|
||||
await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
|
||||
|
||||
await swipeLeft(300);
|
||||
|
||||
await waitTime(1000);
|
||||
await testStack('ion-router-outlet', ['app-router-link']);
|
||||
|
||||
const page = element(by.css('app-router-link'));
|
||||
expect(await page.getAttribute('aria-hidden')).toEqual(null);
|
||||
expect(await page.getAttribute('class')).toEqual('ion-page');
|
||||
})
|
||||
|
||||
it('should navigate correctly', async () => {
|
||||
await browser.get('/navigation/page1');
|
||||
await waitTime(2000);
|
||||
@@ -22,3 +57,17 @@ describe('navigation', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function swipeLeft(end: number) {
|
||||
return browser.driver.touchActions()
|
||||
.tapAndHold({x: 5, y: 1})
|
||||
.move({x: 6, y: 1})
|
||||
.move({x: 7, y: 1})
|
||||
.move({x: 8, y: 1})
|
||||
.move({x: 30, y: 1})
|
||||
.move({x: 300, y: 1})
|
||||
.move({x: end, y: 1})
|
||||
.move({x: end, y: 1})
|
||||
.release({x: end, y: 1})
|
||||
.perform();
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { waitTime, handleErrorMessages, goBack } from './utils';
|
||||
describe('nested-outlet', () => {
|
||||
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should navigate correctly', async () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { handleErrorMessages, waitTime } from './utils';
|
||||
describe('providers', () => {
|
||||
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should load all providers', async () => {
|
||||
@@ -12,6 +12,9 @@ describe('providers', () => {
|
||||
|
||||
expect(await element(by.css('#is-loaded')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-ready')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-paused')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-resumed')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-resized')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-testing')).getText()).toEqual('false');
|
||||
expect(await element(by.css('#is-desktop')).getText()).toEqual('true');
|
||||
expect(await element(by.css('#is-mobile')).getText()).toEqual('false');
|
||||
|
||||
@@ -1,13 +1,61 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { waitTime, testStack, testLifeCycle, handleErrorMessages } from './utils';
|
||||
import { browser, element, by, protractor } from 'protractor';
|
||||
import { waitTime, testStack, testLifeCycle, handleErrorMessages, getText } from './utils';
|
||||
|
||||
const EC = protractor.ExpectedConditions;
|
||||
|
||||
describe('router-link params and fragments', () => {
|
||||
const queryParam = 'A&=#Y';
|
||||
const fragment = 'myDiv1';
|
||||
const id = 'MyPageID==';
|
||||
|
||||
afterEach(() => {
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should go to a page with properly encoded values', async () => {
|
||||
await browser.get('/router-link?ionic:_testing=true');
|
||||
await element(by.css('#queryParamsFragment')).click();
|
||||
|
||||
const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
|
||||
|
||||
browser.wait(EC.urlContains(expectedRoute), 5000);
|
||||
});
|
||||
|
||||
it('should return to a page with preserved query param and fragment', async () => {
|
||||
await browser.get('/router-link?ionic:_testing=true');
|
||||
await waitTime(30);
|
||||
await element(by.css('#queryParamsFragment')).click();
|
||||
await waitTime(400);
|
||||
await element(by.css('#goToPage3')).click();
|
||||
|
||||
browser.wait(EC.urlContains('router-link-page3'), 5000);
|
||||
await waitTime(400);
|
||||
|
||||
await element(by.css('#goBackFromPage3')).click();
|
||||
|
||||
const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
|
||||
browser.wait(EC.urlContains(expectedRoute), 5000);
|
||||
});
|
||||
|
||||
it('should preserve query param and fragment with defaultHref string', async () => {
|
||||
await browser.get('/router-link-page3?ionic:_testing=true');
|
||||
await waitTime(30);
|
||||
|
||||
await element(by.css('#goBackFromPage3')).click();
|
||||
|
||||
const expectedRoute = '?token=ABC#fragment';
|
||||
browser.wait(EC.urlContains(expectedRoute), 5000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('router-link', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await browser.get('/router-link');
|
||||
await waitTime(30);
|
||||
});
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
|
||||
@@ -25,18 +73,6 @@ describe('router-link', () => {
|
||||
it('should go forward with ion-button[routerLink]', async () => {
|
||||
await element(by.css('#routerLink')).click();
|
||||
await testForward();
|
||||
|
||||
// test go back
|
||||
await element(by.css('ion-back-button')).click();
|
||||
await waitTime(500);
|
||||
|
||||
await testStack('ion-router-outlet', ['app-router-link']);
|
||||
await testLifeCycle('app-router-link', {
|
||||
ionViewWillEnter: 2,
|
||||
ionViewDidEnter: 2,
|
||||
ionViewWillLeave: 1,
|
||||
ionViewDidLeave: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should go forward with a[routerLink]', async () => {
|
||||
@@ -77,7 +113,6 @@ describe('router-link', () => {
|
||||
|
||||
it('should go back with ion-button[routerLink][routerDirection=back]', async () => {
|
||||
await element(by.css('#routerLink-back')).click();
|
||||
await testBack();
|
||||
});
|
||||
|
||||
it('should go back with a[routerLink][routerDirection=back]', async () => {
|
||||
@@ -93,21 +128,25 @@ describe('router-link', () => {
|
||||
});
|
||||
|
||||
async function testForward() {
|
||||
await waitTime(500);
|
||||
await waitTime(2500);
|
||||
await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
|
||||
await testLifeCycle('app-router-link', {
|
||||
ionViewWillEnter: 1,
|
||||
ionViewDidEnter: 1,
|
||||
ionViewWillLeave: 1,
|
||||
ionViewDidLeave: 1,
|
||||
});
|
||||
await testLifeCycle('app-router-link-page', {
|
||||
ionViewWillEnter: 1,
|
||||
ionViewDidEnter: 1,
|
||||
ionViewWillLeave: 0,
|
||||
ionViewDidLeave: 0,
|
||||
});
|
||||
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('true');
|
||||
|
||||
await browser.navigate().back();
|
||||
await waitTime(100);
|
||||
await testStack('ion-router-outlet', ['app-router-link']);
|
||||
await testLifeCycle('app-router-link', {
|
||||
ionViewWillEnter: 2,
|
||||
ionViewDidEnter: 2,
|
||||
ionViewWillLeave: 1,
|
||||
ionViewDidLeave: 1,
|
||||
});
|
||||
}
|
||||
|
||||
async function testRoot() {
|
||||
@@ -119,6 +158,17 @@ async function testRoot() {
|
||||
ionViewWillLeave: 0,
|
||||
ionViewDidLeave: 0,
|
||||
});
|
||||
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
|
||||
|
||||
await browser.navigate().back();
|
||||
await waitTime(100);
|
||||
await testStack('ion-router-outlet', ['app-router-link']);
|
||||
await testLifeCycle('app-router-link', {
|
||||
ionViewWillEnter: 1,
|
||||
ionViewDidEnter: 1,
|
||||
ionViewWillLeave: 0,
|
||||
ionViewDidLeave: 0,
|
||||
});
|
||||
}
|
||||
|
||||
async function testBack() {
|
||||
@@ -130,4 +180,15 @@ async function testBack() {
|
||||
ionViewWillLeave: 0,
|
||||
ionViewDidLeave: 0,
|
||||
});
|
||||
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
|
||||
|
||||
await browser.navigate().back();
|
||||
await waitTime(100);
|
||||
await testStack('ion-router-outlet', ['app-router-link']);
|
||||
await testLifeCycle('app-router-link', {
|
||||
ionViewWillEnter: 1,
|
||||
ionViewDidEnter: 1,
|
||||
ionViewWillLeave: 0,
|
||||
ionViewDidLeave: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ describe('slides', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await browser.get('/slides');
|
||||
await waitTime(30);
|
||||
});
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should change index on slide change', async () => {
|
||||
|
||||
@@ -3,11 +3,12 @@ import { waitTime, testStack, handleErrorMessages } from './utils';
|
||||
|
||||
describe('tabs', () => {
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
describe('entry url - /tabs', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/tabs');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should redirect and load tab-account', async () => {
|
||||
@@ -16,10 +17,19 @@ describe('tabs', () => {
|
||||
await testState(1, 'account');
|
||||
});
|
||||
|
||||
it('should navigate between tabs and ionChange events should be dispatched ', async () => {
|
||||
let tab = await testTabTitle('Tab 1 - Page 1');
|
||||
expect(await tab.$('.segment-changed').getText()).toEqual('false');
|
||||
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
tab = await testTabTitle('Tab 2 - Page 1');
|
||||
expect(await tab.$('.segment-changed').getText()).toEqual('false');
|
||||
});
|
||||
|
||||
it('should simulate stack + double tab click', async () => {
|
||||
let tab = await getSelectedTab() as ElementFinder;
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']);
|
||||
await testState(1, 'account');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
@@ -30,7 +40,7 @@ describe('tabs', () => {
|
||||
await testState(2, 'contact');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
|
||||
await testState(3, 'account');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
@@ -44,7 +54,7 @@ describe('tabs', () => {
|
||||
it('should simulate stack + back button click', async () => {
|
||||
const tab = await getSelectedTab();
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testState(1, 'account');
|
||||
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
@@ -52,7 +62,7 @@ describe('tabs', () => {
|
||||
await testState(2, 'contact');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testState(3, 'account');
|
||||
|
||||
await element(by.css('ion-back-button')).click();
|
||||
@@ -61,6 +71,33 @@ describe('tabs', () => {
|
||||
await testState(3, 'account');
|
||||
});
|
||||
|
||||
it('should navigate deep then go home', async () => {
|
||||
let tab = await getSelectedTab();
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
tab = await testTabTitle('Tab 2 - Page 1');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await testStack('ion-tabs ion-router-outlet', [
|
||||
'app-tabs-tab1',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab2'
|
||||
]);
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 1');
|
||||
await testStack('ion-tabs ion-router-outlet', [
|
||||
'app-tabs-tab1',
|
||||
'app-tabs-tab2'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should switch tabs and go back', async () => {
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
const tab = await testTabTitle('Tab 2 - Page 1');
|
||||
@@ -75,7 +112,7 @@ describe('tabs', () => {
|
||||
const tab = await testTabTitle('Tab 2 - Page 1');
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']);
|
||||
});
|
||||
|
||||
@@ -96,13 +133,14 @@ describe('tabs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry url - /tabs/account/nested/12', () => {
|
||||
describe('entry url - /tabs/account/nested/1', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/tabs/account/nested/12');
|
||||
await browser.get('/tabs/account/nested/1');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should only display the back-button when there is a page in the stack', async () => {
|
||||
let tab = await testTabTitle('Tab 1 - Page 2') as ElementFinder;
|
||||
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
|
||||
@@ -110,14 +148,38 @@ describe('tabs', () => {
|
||||
tab = await testTabTitle('Tab 1 - Page 1');
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not reuse the same page', async () => {
|
||||
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (3)');
|
||||
|
||||
await testStack('ion-tabs ion-router-outlet',[
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested'
|
||||
]);
|
||||
|
||||
await tab.$('ion-back-button').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await tab.$('ion-back-button').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry url - /tabs/lazy', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/tabs/lazy');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should not display the back-button if coming from a different stack', async () => {
|
||||
@@ -125,7 +187,7 @@ describe('tabs', () => {
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']);
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']);
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
});
|
||||
@@ -134,12 +196,14 @@ describe('tabs', () => {
|
||||
describe('enter url - /tabs/contact/one', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/tabs/contact/one');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should return to correct tab after going to page in different outlet', async () => {
|
||||
const tab = await getSelectedTab();
|
||||
await tab.$('#goto-nested-page1').click();
|
||||
|
||||
await waitTime(600);
|
||||
await testStack('app-nested-outlet ion-router-outlet', ['app-nested-outlet-page']);
|
||||
|
||||
const nestedOutlet = await element(by.css('app-nested-outlet'));
|
||||
|
||||
@@ -37,29 +37,30 @@ export interface LifeCycleCount {
|
||||
}
|
||||
|
||||
export function handleErrorMessages() {
|
||||
browser.manage().logs().get('browser').then(function(browserLog) {
|
||||
let severWarnings = false;
|
||||
|
||||
for (let i; i <= browserLog.length - 1; i++) {
|
||||
if (browserLog[i].level.name === 'SEVERE') {
|
||||
console.log('\n' + browserLog[i].level.name);
|
||||
console.log('(Possibly exception) \n' + browserLog[i].message);
|
||||
|
||||
severWarnings = true;
|
||||
}
|
||||
return browser.manage().logs().get('browser').then(function (browserLog) {
|
||||
for (let i = 0; i <= browserLog.length - 1; i++) {
|
||||
if (browserLog[i].level.name_ === 'SEVERE') {
|
||||
fail(browserLog[i].message);
|
||||
}
|
||||
}
|
||||
|
||||
expect(severWarnings).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
export async function testLifeCycle(selector: string, expected: LifeCycleCount) {
|
||||
await waitTime(50);
|
||||
expect(await getText(`${selector} #ngOnInit`)).toEqual('1');
|
||||
expect(await getText(`${selector} #ionViewWillEnter`)).toEqual(expected.ionViewWillEnter.toString());
|
||||
expect(await getText(`${selector} #ionViewDidEnter`)).toEqual(expected.ionViewDidEnter.toString());
|
||||
expect(await getText(`${selector} #ionViewWillLeave`)).toEqual(expected.ionViewWillLeave.toString());
|
||||
expect(await getText(`${selector} #ionViewDidLeave`)).toEqual(expected.ionViewDidLeave.toString());
|
||||
const results = await Promise.all([
|
||||
getText(`${selector} #ngOnInit`),
|
||||
getText(`${selector} #ionViewWillEnter`),
|
||||
getText(`${selector} #ionViewDidEnter`),
|
||||
getText(`${selector} #ionViewWillLeave`),
|
||||
getText(`${selector} #ionViewDidLeave`),
|
||||
]);
|
||||
|
||||
expect(results[0]).toEqual('1');
|
||||
expect(results[1]).toEqual(expected.ionViewWillEnter.toString());
|
||||
expect(results[2]).toEqual(expected.ionViewDidEnter.toString());
|
||||
expect(results[3]).toEqual(expected.ionViewWillLeave.toString());
|
||||
expect(results[4]).toEqual(expected.ionViewDidLeave.toString());
|
||||
}
|
||||
|
||||
export async function testStack(selector: string, expected: string[]) {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { handleErrorMessages } from './utils';
|
||||
import { handleErrorMessages, waitTime } from './utils';
|
||||
|
||||
describe('view-child', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await browser.get('/view-child');
|
||||
await waitTime(30);
|
||||
});
|
||||
afterEach(() => {
|
||||
handleErrorMessages();
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
it('should get a reference to all children', async () => {
|
||||
|
||||
18
angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
Normal file
18
angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { waitTime, handleErrorMessages } from './utils';
|
||||
|
||||
describe('virtual-scroll', () => {
|
||||
afterEach(() => {
|
||||
return handleErrorMessages();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await browser.get('/virtual-scroll');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should open virtual-scroll', () => {
|
||||
const virtualElements = element.all(by.css('ion-virtual-scroll > *'));
|
||||
expect(virtualElements.count()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -8,8 +8,6 @@ module.exports = function (config) {
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
11108
angular/test/test-app/package-lock.json
generated
11108
angular/test/test-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,60 @@
|
||||
{
|
||||
"name": "test-app",
|
||||
"name": "ionic-angular-test-app",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "npm run sync && ng serve",
|
||||
"sync:build": "sh scripts/build-ionic.sh",
|
||||
"sync": "sh scripts/sync.sh",
|
||||
"build": "ng build --prod --no-progress",
|
||||
"build": "npm run sync && ng build --prod --no-progress",
|
||||
"test": "ng e2e --prod",
|
||||
"test.dev": "npm run sync && ng e2e",
|
||||
"lint": "ng lint",
|
||||
"postinstall": "npm run sync"
|
||||
"postinstall": "npm run sync",
|
||||
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
|
||||
"serve:ssr": "node dist/server",
|
||||
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
|
||||
"build:client-and-server-bundles": "npm run build && ng run test-app:server:production --bundleDependencies all"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~7.2.1",
|
||||
"@angular/common": "~7.2.1",
|
||||
"@angular/compiler": "~7.2.1",
|
||||
"@angular/core": "~7.2.1",
|
||||
"@angular/forms": "~7.2.1",
|
||||
"@angular/platform-browser": "~7.2.1",
|
||||
"@angular/platform-browser-dynamic": "~7.2.1",
|
||||
"@angular/router": "~7.2.1",
|
||||
"@ionic/angular": "^4.0.0-rc.1",
|
||||
"@angular/animations": "^8.2.8",
|
||||
"@angular/common": "^8.2.8",
|
||||
"@angular/compiler": "^8.2.8",
|
||||
"@angular/core": "^8.2.8",
|
||||
"@angular/forms": "^8.2.8",
|
||||
"@angular/platform-browser": "^8.2.8",
|
||||
"@angular/platform-browser-dynamic": "^8.2.8",
|
||||
"@angular/platform-server": "^8.2.8",
|
||||
"@angular/router": "^8.2.8",
|
||||
"@ionic/angular": "^4.7.0",
|
||||
"@ionic/angular-server": "^0.0.2",
|
||||
"@nguniversal/express-engine": "~8.1.1",
|
||||
"@nguniversal/module-map-ngfactory-loader": "~8.1.1",
|
||||
"core-js": "^2.6.2",
|
||||
"rxjs": "~6.3.3",
|
||||
"express": "^4.15.2",
|
||||
"rxjs": "^6.5.3",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "~0.8.26"
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.12.2",
|
||||
"@angular/cli": "~7.2.1",
|
||||
"@angular/compiler-cli": "~7.2.1",
|
||||
"@angular/language-service": "~7.2.1",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/jasmine": "~2.8.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "~4.5.0",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~3.1.4",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~1.1.2",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.4.2",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.12.1",
|
||||
"typescript": "~3.2.4"
|
||||
"@angular-devkit/build-angular": "^0.803.6",
|
||||
"@angular/cli": "^8.3.6",
|
||||
"@angular/compiler-cli": "^8.2.8",
|
||||
"@angular/language-service": "^8.2.8",
|
||||
"@types/jasmine": "3.4.1",
|
||||
"@types/node": "12.7.8",
|
||||
"codelyzer": "^5.1.2",
|
||||
"jasmine-core": "3.5.0",
|
||||
"jasmine-spec-reporter": "4.2.1",
|
||||
"karma": "4.3.0",
|
||||
"karma-chrome-launcher": "3.1.0",
|
||||
"karma-jasmine": "2.0.1",
|
||||
"protractor": "5.4.2",
|
||||
"ts-loader": "^6.1.2",
|
||||
"ts-node": "8.4.1",
|
||||
"tslint": "~5.18.0",
|
||||
"typescript": "~3.5.3",
|
||||
"webpack-cli": "^3.3.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,14 @@ popd
|
||||
pushd angular
|
||||
npm link @ionic/core
|
||||
npm run build
|
||||
npm link
|
||||
popd
|
||||
|
||||
# Build angular-server
|
||||
pushd packages/angular-server
|
||||
npm link @ionic/core
|
||||
npm link @ionic/angular
|
||||
npm run build
|
||||
popd
|
||||
|
||||
popd
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
# Copy angular dist
|
||||
rm -rf node_modules/@ionic/angular/dist
|
||||
rm -rf node_modules/@ionic/angular
|
||||
mkdir node_modules/@ionic/angular
|
||||
cp -a ../../dist node_modules/@ionic/angular/dist
|
||||
cp -a ../../css node_modules/@ionic/angular/css
|
||||
cp -a ../../package.json node_modules/@ionic/angular/package.json
|
||||
|
||||
# Copy core dist
|
||||
rm -rf node_modules/@ionic/core/dist
|
||||
# Copy angular server
|
||||
rm -rf node_modules/@ionic/angular-server
|
||||
mkdir node_modules/@ionic/angular-server
|
||||
cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server/dist
|
||||
cp -a ../../../packages/angular-server/package.json node_modules/@ionic/angular-server/package.json
|
||||
|
||||
# # Copy core dist
|
||||
rm -rf node_modules/@ionic/core
|
||||
mkdir node_modules/@ionic/core
|
||||
cp -a ../../../core/css node_modules/@ionic/core/css
|
||||
cp -a ../../../core/dist node_modules/@ionic/core/dist
|
||||
cp -a ../../../core/hydrate node_modules/@ionic/core/hydrate
|
||||
cp -a ../../../core/loader node_modules/@ionic/core/loader
|
||||
cp -a ../../../core/package.json node_modules/@ionic/core/package.json
|
||||
|
||||
# Copy ionicons
|
||||
# # Copy ionicons
|
||||
rm -rf node_modules/ionicons
|
||||
cp -a ../../../core/node_modules/ionicons node_modules/ionicons
|
||||
|
||||
58
angular/test/test-app/server.ts
Normal file
58
angular/test/test-app/server.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* *** NOTE ON IMPORTING FROM ANGULAR AND NGUNIVERSAL IN THIS FILE ***
|
||||
*
|
||||
* If your application uses third-party dependencies, you'll need to
|
||||
* either use Webpack or the Angular CLI's `bundleDependencies` feature
|
||||
* in order to adequately package them for use on the server without a
|
||||
* node_modules directory.
|
||||
*
|
||||
* However, due to the nature of the CLI's `bundleDependencies`, importing
|
||||
* Angular in this file will create a different instance of Angular than
|
||||
* the version in the compiled application code. This leads to unavoidable
|
||||
* conflicts. Therefore, please do not explicitly import from @angular or
|
||||
* @nguniversal in this file. You can export any needed resources
|
||||
* from your application's main.server.ts file, as seen below with the
|
||||
* import for `ngExpressEngine`.
|
||||
*/
|
||||
|
||||
import 'zone.js/dist/zone-node';
|
||||
|
||||
import * as express from 'express';
|
||||
import {join} from 'path';
|
||||
|
||||
// Express server
|
||||
const app = express();
|
||||
|
||||
const PORT = process.env.PORT || 4000;
|
||||
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
|
||||
|
||||
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
|
||||
const {AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap} = require('./dist/server/main');
|
||||
|
||||
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
|
||||
app.engine('html', ngExpressEngine({
|
||||
bootstrap: AppServerModuleNgFactory,
|
||||
providers: [
|
||||
provideModuleMap(LAZY_MODULE_MAP)
|
||||
]
|
||||
}));
|
||||
|
||||
app.set('view engine', 'html');
|
||||
app.set('views', DIST_FOLDER);
|
||||
|
||||
// Example Express Rest API endpoints
|
||||
// app.get('/api/**', (req, res) => { });
|
||||
// Serve static files from /browser
|
||||
app.get('*.*', express.static(DIST_FOLDER, {
|
||||
maxAge: '1y'
|
||||
}));
|
||||
|
||||
// All regular routes use the Universal engine
|
||||
app.get('*', (req, res) => {
|
||||
res.render('index', { req });
|
||||
});
|
||||
|
||||
// Start up the Node server
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Node Express server listening on http://localhost:${PORT}`);
|
||||
});
|
||||
10
angular/test/test-app/src/app/alert/alert.component.html
Normal file
10
angular/test/test-app/src/app/alert/alert.component.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
Alert test
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
|
||||
</ion-content>
|
||||
39
angular/test/test-app/src/app/alert/alert.component.ts
Normal file
39
angular/test/test-app/src/app/alert/alert.component.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Component, NgZone } from '@angular/core';
|
||||
import { AlertController } from '@ionic/angular';
|
||||
import { NavComponent } from '../nav/nav.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-alert',
|
||||
templateUrl: './alert.component.html',
|
||||
})
|
||||
export class AlertComponent {
|
||||
|
||||
changes = 0;
|
||||
|
||||
constructor(
|
||||
private alertCtrl: AlertController
|
||||
) { }
|
||||
|
||||
counter() {
|
||||
this.changes++;
|
||||
return Math.floor(this.changes / 2);
|
||||
}
|
||||
|
||||
async openAlert() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Hello',
|
||||
message: 'Some text',
|
||||
buttons: [
|
||||
{
|
||||
role: 'cancel',
|
||||
text: 'Cancel',
|
||||
handler: () => {
|
||||
console.log(NgZone.isInAngularZone());
|
||||
NgZone.assertInAngularZone();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
await alert.present();
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@ import { InputsComponent } from './inputs/inputs.component';
|
||||
import { ModalComponent } from './modal/modal.component';
|
||||
import { RouterLinkComponent } from './router-link/router-link.component';
|
||||
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
|
||||
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
|
||||
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { TabsComponent } from './tabs/tabs.component';
|
||||
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
|
||||
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
|
||||
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
|
||||
import { NestedOutletComponent } from './nested-outlet/nested-outlet.component';
|
||||
@@ -21,9 +19,11 @@ import { FormComponent } from './form/form.component';
|
||||
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
|
||||
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
|
||||
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
|
||||
import { AlertComponent } from './alert/alert.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: HomePageComponent },
|
||||
{ path: 'alerts', component: AlertComponent },
|
||||
{ path: 'inputs', component: InputsComponent },
|
||||
{ path: 'form', component: FormComponent },
|
||||
{ path: 'modals', component: ModalComponent },
|
||||
@@ -31,6 +31,8 @@ const routes: Routes = [
|
||||
{ path: 'providers', component: ProvidersComponent },
|
||||
{ path: 'router-link', component: RouterLinkComponent },
|
||||
{ path: 'router-link-page', component: RouterLinkPageComponent },
|
||||
{ path: 'router-link-page2/:id', component: RouterLinkPage2Component },
|
||||
{ path: 'router-link-page3', component: RouterLinkPage3Component },
|
||||
{ path: 'slides', component: SlidesComponent },
|
||||
{ path: 'virtual-scroll', component: VirtualScrollComponent },
|
||||
{ path: 'virtual-scroll-detail/:itemId', component: VirtualScrollDetailComponent },
|
||||
@@ -45,40 +47,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'tabs',
|
||||
component: TabsComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'account',
|
||||
children: [
|
||||
{
|
||||
path: 'nested/:id',
|
||||
component: TabsTab1NestedComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: TabsTab1Component
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
children: [
|
||||
{
|
||||
path: 'one',
|
||||
component: TabsTab2Component
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'one',
|
||||
pathMatch: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'lazy',
|
||||
loadChildren: './tabs-lazy/tabs-lazy.module#TabsLazyModule'
|
||||
}
|
||||
]
|
||||
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
|
||||
},
|
||||
{
|
||||
path: 'nested-outlet',
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { InputsComponent } from './inputs/inputs.component';
|
||||
import { ModalComponent } from './modal/modal.component';
|
||||
import { ModalExampleComponent } from './modal-example/modal-example.component';
|
||||
import { RouterLinkComponent } from './router-link/router-link.component';
|
||||
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
|
||||
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
|
||||
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { TabsComponent } from './tabs/tabs.component';
|
||||
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
|
||||
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
|
||||
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
|
||||
import { VirtualScrollInnerComponent } from './virtual-scroll-inner/virtual-scroll-inner.component';
|
||||
@@ -30,6 +29,7 @@ import { FormComponent } from './form/form.component';
|
||||
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
|
||||
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
|
||||
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
|
||||
import { AlertComponent } from './alert/alert.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -39,11 +39,9 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
|
||||
ModalExampleComponent,
|
||||
RouterLinkComponent,
|
||||
RouterLinkPageComponent,
|
||||
RouterLinkPage2Component,
|
||||
RouterLinkPage3Component,
|
||||
HomePageComponent,
|
||||
TabsComponent,
|
||||
TabsTab1Component,
|
||||
TabsTab2Component,
|
||||
TabsTab1NestedComponent,
|
||||
VirtualScrollComponent,
|
||||
VirtualScrollDetailComponent,
|
||||
VirtualScrollInnerComponent,
|
||||
@@ -57,10 +55,11 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
|
||||
FormComponent,
|
||||
NavigationPage1Component,
|
||||
NavigationPage2Component,
|
||||
NavigationPage3Component
|
||||
NavigationPage3Component,
|
||||
AlertComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserModule.withServerTransition({ appId: 'serverApp' }),
|
||||
AppRoutingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
@@ -70,7 +69,9 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
|
||||
ModalExampleComponent,
|
||||
NavComponent
|
||||
],
|
||||
providers: [],
|
||||
providers: [
|
||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
19
angular/test/test-app/src/app/app.server.module.ts
Normal file
19
angular/test/test-app/src/app/app.server.module.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ServerModule } from '@angular/platform-server';
|
||||
|
||||
import { IonicServerModule } from '@ionic/angular-server';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AppModule,
|
||||
ServerModule,
|
||||
ModuleMapLoaderModule,
|
||||
IonicServerModule
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppServerModule {}
|
||||
@@ -20,7 +20,9 @@ export class FormComponent {
|
||||
input2: ['Default Value'],
|
||||
checkbox: [false],
|
||||
range: [5, Validators.min(10)],
|
||||
}, {updateOn: window.location.hash === '#blur' ? 'blur' : 'change'});
|
||||
}, {
|
||||
updateOn: typeof (window as any) !== 'undefined' && window.location.hash === '#blur' ? 'blur' : 'change'
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit(_ev) {
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item routerLink="/alerts">
|
||||
<ion-label>
|
||||
Alerts test
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item routerLink="/inputs">
|
||||
<ion-label>
|
||||
Inputs test
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
|
||||
<ion-list>
|
||||
|
||||
<ion-item>
|
||||
@@ -89,10 +90,12 @@
|
||||
<ion-range [(ngModel)]="range"></ion-range>
|
||||
<ion-note slot="end" id="range-note">{{range}}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
|
||||
<ion-item color="dark">
|
||||
<ion-label>Range Mirror</ion-label>
|
||||
<ion-range [(ngModel)]="range"></ion-range>
|
||||
<ion-range [(ngModel)]="range">
|
||||
<ion-toggle slot="start" id="nested-toggle" [(ngModel)]="toggle"></ion-toggle>
|
||||
</ion-range>
|
||||
<ion-note slot="end">{{range}}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ export class InputsComponent {
|
||||
toggle = true;
|
||||
select = 'nes';
|
||||
range = 10;
|
||||
changes = 0;
|
||||
|
||||
setValues() {
|
||||
console.log('set values');
|
||||
@@ -32,4 +33,8 @@ export class InputsComponent {
|
||||
this.select = undefined;
|
||||
this.range = undefined;
|
||||
}
|
||||
counter() {
|
||||
this.changes++;
|
||||
return Math.floor(this.changes / 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<h1>Value</h1>
|
||||
<h2>{{value}}</h2>
|
||||
<h3>{{valueFromParams}}</h3>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<ion-button (click)="openModal()" id="action-button">Open Modal</ion-button>
|
||||
<ion-button (click)="openNav()" id="action-button-2">Open Nav in Modal</ion-button>
|
||||
<p>
|
||||
|
||||
@@ -5,13 +5,22 @@
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<p>
|
||||
isLoaded: <span id="is-loaded">{{isLoaded}}</span>
|
||||
</p>
|
||||
<p>
|
||||
isReady: <span id="is-ready">{{isReady}}</span>
|
||||
</p>
|
||||
<p>
|
||||
isResumed: <span id="is-resumed">{{isResumed}}</span>
|
||||
</p>
|
||||
<p>
|
||||
isPaused: <span id="is-paused">{{isPaused}}</span>
|
||||
</p>
|
||||
<p>
|
||||
isResized: <span id="is-resized">{{isResized}}</span>
|
||||
</p>
|
||||
<p>
|
||||
isTesting: <span id="is-testing">{{isTesting}}</span>
|
||||
</p>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, NgZone } from '@angular/core';
|
||||
import {
|
||||
Platform, Config, ModalController, AlertController, ActionSheetController,
|
||||
PopoverController, ToastController, Events, PickerController, MenuController,
|
||||
LoadingController, NavController, DomController
|
||||
Platform, ModalController, AlertController, ActionSheetController,
|
||||
PopoverController, ToastController, Events, PickerController, MenuController,
|
||||
LoadingController, NavController, DomController, Config
|
||||
} from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
@@ -14,6 +14,9 @@ export class ProvidersComponent {
|
||||
isLoaded = false;
|
||||
isReady = false;
|
||||
isEvent = false;
|
||||
isResumed = false;
|
||||
isPaused = false;
|
||||
isResized = false;
|
||||
isTesting: boolean = undefined;
|
||||
isDesktop: boolean = undefined;
|
||||
isMobile: boolean = undefined;
|
||||
@@ -32,7 +35,8 @@ export class ProvidersComponent {
|
||||
toastCtrl: ToastController,
|
||||
navCtrl: NavController,
|
||||
domCtrl: DomController,
|
||||
config: Config
|
||||
config: Config,
|
||||
zone: NgZone
|
||||
) {
|
||||
// test all providers load
|
||||
if (
|
||||
@@ -44,15 +48,31 @@ export class ProvidersComponent {
|
||||
|
||||
// test platform ready()
|
||||
platform.ready().then(() => {
|
||||
NgZone.assertInAngularZone();
|
||||
this.isReady = true;
|
||||
});
|
||||
|
||||
platform.resume.subscribe(() => {
|
||||
console.log('platform:resume');
|
||||
NgZone.assertInAngularZone();
|
||||
this.isResumed = true;
|
||||
});
|
||||
platform.pause.subscribe(() => {
|
||||
console.log('platform:pause');
|
||||
NgZone.assertInAngularZone();
|
||||
this.isPaused = true;
|
||||
});
|
||||
platform.resize.subscribe(() => {
|
||||
console.log('platform:resize');
|
||||
NgZone.assertInAngularZone();
|
||||
this.isResized = true;
|
||||
});
|
||||
this.isDesktop = platform.is('desktop');
|
||||
this.isMobile = platform.is('mobile');
|
||||
|
||||
// test events
|
||||
events.subscribe('topic', () => {
|
||||
this.isEvent = true;
|
||||
NgZone.assertInAngularZone();
|
||||
});
|
||||
events.publish('topic');
|
||||
|
||||
@@ -60,5 +80,11 @@ export class ProvidersComponent {
|
||||
this.isTesting = config.getBoolean('_testing');
|
||||
config.set('keyboardHeight', 12345);
|
||||
this.keyboardHeight = config.getNumber('keyboardHeight');
|
||||
|
||||
zone.runOutsideAngular(() => {
|
||||
document.dispatchEvent(new CustomEvent('pause'));
|
||||
document.dispatchEvent(new CustomEvent('resume'));
|
||||
window.dispatchEvent(new CustomEvent('resize'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
|
||||
<p>canGoBack: <span id="canGoBack">{{canGoBack}}</span></p>
|
||||
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
|
||||
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
|
||||
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, OnInit, NgZone } from '@angular/core';
|
||||
import { IonRouterOutlet } from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-router-link-page',
|
||||
@@ -11,9 +12,15 @@ export class RouterLinkPageComponent implements OnInit {
|
||||
didEnter = 0;
|
||||
willLeave = 0;
|
||||
didLeave = 0;
|
||||
canGoBack: boolean = null;
|
||||
|
||||
constructor(
|
||||
private ionRouterOutlet: IonRouterOutlet
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
NgZone.assertInAngularZone();
|
||||
this.canGoBack = this.ionRouterOutlet.canGoBack();
|
||||
this.onInit++;
|
||||
}
|
||||
|
||||
@@ -21,10 +28,16 @@ export class RouterLinkPageComponent implements OnInit {
|
||||
if (this.onInit !== 1) {
|
||||
throw new Error('ngOnInit was not called');
|
||||
}
|
||||
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
|
||||
throw new Error('canGoBack() changed');
|
||||
}
|
||||
NgZone.assertInAngularZone();
|
||||
this.willEnter++;
|
||||
}
|
||||
ionViewDidEnter() {
|
||||
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
|
||||
throw new Error('canGoBack() changed');
|
||||
}
|
||||
NgZone.assertInAngularZone();
|
||||
this.didEnter++;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Router Page 2</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
<ion-button routerLink="/router-link-page3" id="goToPage3">Go to Page 3</ion-button>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-router-link-page2',
|
||||
templateUrl: './router-link-page2.component.html'
|
||||
})
|
||||
export class RouterLinkPage2Component implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<ion-header>
|
||||
<ion-toolbar color="dark">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="/?token=ABC#fragment" id="goBackFromPage3"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Router Page 3</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
Page 3
|
||||
</ion-content>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-router-link-page3',
|
||||
templateUrl: './router-link-page3.component.html'
|
||||
})
|
||||
export class RouterLinkPage3Component implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,12 +5,13 @@
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
|
||||
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
|
||||
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
|
||||
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
|
||||
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
|
||||
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
|
||||
|
||||
<p>
|
||||
<ion-button routerLink="/router-link-page" expand="block" color="dark" id="routerLink">ion-button[routerLink]</ion-button>
|
||||
@@ -27,4 +28,6 @@
|
||||
<p><button (click)="navigateRoot()" id="button-root">navigateForward</button></p>
|
||||
<p><button (click)="navigateBack()" id="button-back">navigateBack</button></p>
|
||||
|
||||
<p><button id="queryParamsFragment" routerLink="/router-link-page2/MyPageID==" [queryParams]="{ token: 'A&=#Y' }" fragment="myDiv1">Query Params and Fragment</button></p>
|
||||
|
||||
</ion-content>
|
||||
|
||||
@@ -13,6 +13,7 @@ export class RouterLinkComponent implements OnInit {
|
||||
didEnter = 0;
|
||||
willLeave = 0;
|
||||
didLeave = 0;
|
||||
changes = 0;
|
||||
|
||||
constructor(
|
||||
private navCtrl: NavController,
|
||||
@@ -35,6 +36,11 @@ export class RouterLinkComponent implements OnInit {
|
||||
this.navCtrl.navigateRoot('/router-link-page');
|
||||
}
|
||||
|
||||
counter() {
|
||||
this.changes++;
|
||||
return Math.floor(this.changes / 2);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
NgZone.assertInAngularZone();
|
||||
this.onInit++;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
|
||||
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||
import { IonSlides } from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
@@ -6,7 +6,7 @@ import { IonSlides } from '@ionic/angular';
|
||||
templateUrl: './slides.component.html',
|
||||
})
|
||||
export class SlidesComponent implements AfterViewInit {
|
||||
@ViewChild(IonSlides) slides: IonSlides;
|
||||
@ViewChild(IonSlides, { static: true }) slides: IonSlides;
|
||||
|
||||
slideIndex = 0;
|
||||
slideIndex2 = 0;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<ion-content class="ion-padding">
|
||||
<h1>LAZY LOADED TAB</h1>
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
|
||||
|
||||
</p>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user