mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
333 Commits
v0.1.4-2
...
v4.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85245b6a97 | ||
|
|
51ac33192b | ||
|
|
d5129df970 | ||
|
|
b8c87c453a | ||
|
|
ae0541a465 | ||
|
|
3f8fcda366 | ||
|
|
c929dad2e9 | ||
|
|
822f60f603 | ||
|
|
c87f0c561e | ||
|
|
2b3c14b608 | ||
|
|
4ea8881f33 | ||
|
|
78bd146ad2 | ||
|
|
86a6cde4a1 | ||
|
|
861ce49363 | ||
|
|
20a8eec992 | ||
|
|
2aa2e6f3ca | ||
|
|
cccdb42fbd | ||
|
|
43d7538e66 | ||
|
|
099b3edda3 | ||
|
|
c1cbbc52d2 | ||
|
|
ab2e124528 | ||
|
|
9436723a8c | ||
|
|
a47f138b31 | ||
|
|
3f0d6f1871 | ||
|
|
9c11155732 | ||
|
|
fde878baf3 | ||
|
|
b1ee4b8e3a | ||
|
|
641113f161 | ||
|
|
8ad3df9736 | ||
|
|
db5313e45b | ||
|
|
47e6009901 | ||
|
|
c8071dd2ed | ||
|
|
91ccc86a52 | ||
|
|
bceece7bc1 | ||
|
|
b1778102fc | ||
|
|
3df6e94650 | ||
|
|
27fae3b70d | ||
|
|
b6348ca075 | ||
|
|
5899b0392d | ||
|
|
54d7a12bea | ||
|
|
d623b3b71f | ||
|
|
6a31f3960a | ||
|
|
12a27bc9d0 | ||
|
|
02c1e83096 | ||
|
|
a203534b27 | ||
|
|
49e5b7e016 | ||
|
|
229ee845da | ||
|
|
3a2c90416c | ||
|
|
e40a6b0e94 | ||
|
|
2c9d485d2d | ||
|
|
89b46ac52f | ||
|
|
9b9aab9f2b | ||
|
|
850d7fc74d | ||
|
|
4d23cba8a0 | ||
|
|
81dc67dda4 | ||
|
|
5c91101949 | ||
|
|
fd5c957787 | ||
|
|
ea24ad677d | ||
|
|
22ebbce57f | ||
|
|
d98421461e | ||
|
|
e02f9902a5 | ||
|
|
2bfcc4f0a9 | ||
|
|
eba40e8961 | ||
|
|
5f4250b8b5 | ||
|
|
5f9b74ca38 | ||
|
|
fcb08e1642 | ||
|
|
a1a3c7d37d | ||
|
|
d85e17c730 | ||
|
|
b1de56a41c | ||
|
|
64a9497f72 | ||
|
|
5e98939a70 | ||
|
|
79ba6391d6 | ||
|
|
a3cd5db3a7 | ||
|
|
c6e962c387 | ||
|
|
5153da458c | ||
|
|
b7395d5f0e | ||
|
|
80a94401fb | ||
|
|
b5f5812bb4 | ||
|
|
dc326c3887 | ||
|
|
6072a6e5ac | ||
|
|
5e0965260f | ||
|
|
2c5f5b3fe1 | ||
|
|
ddf2f2220d | ||
|
|
2215c6aaa1 | ||
|
|
3ba506c513 | ||
|
|
1bbd73cada | ||
|
|
25c852c2c8 | ||
|
|
f3b8ddb69d | ||
|
|
1db75aa72c | ||
|
|
9eb315fc05 | ||
|
|
8d13940188 | ||
|
|
d07246d7a0 | ||
|
|
3471dd66f7 | ||
|
|
57fbf6c396 | ||
|
|
c15772651a | ||
|
|
a436fdf201 | ||
|
|
d23108a16c | ||
|
|
2e5a6d6120 | ||
|
|
0a0959b3a7 | ||
|
|
219589598d | ||
|
|
6ecbe03b4f | ||
|
|
904af3901b | ||
|
|
974b949754 | ||
|
|
bb46b5f7b9 | ||
|
|
4db687ea17 | ||
|
|
7e97006753 | ||
|
|
11cb42facb | ||
|
|
6c8960abdd | ||
|
|
09e6b7e4a2 | ||
|
|
926c8859ce | ||
|
|
ae2cae635d | ||
|
|
1f78390c84 | ||
|
|
685d5a166c | ||
|
|
3d6a6bad8f | ||
|
|
14fedb9a44 | ||
|
|
5878ad9587 | ||
|
|
14f01177f9 | ||
|
|
a5e5403068 | ||
|
|
acd411dd6c | ||
|
|
af240a9ffa | ||
|
|
7aa5d059ad | ||
|
|
f237b7f3a9 | ||
|
|
853e55388b | ||
|
|
0793d2bf5e | ||
|
|
ff06dab3c0 | ||
|
|
0d44253da1 | ||
|
|
ff1ed888f0 | ||
|
|
230823915c | ||
|
|
cece447092 | ||
|
|
b35f95a4d8 | ||
|
|
238b7f9877 | ||
|
|
31de300256 | ||
|
|
062641d8ca | ||
|
|
f1987b6403 | ||
|
|
7923b55b84 | ||
|
|
3aa55bec17 | ||
|
|
94646fc81e | ||
|
|
6c6f867ce4 | ||
|
|
7887550166 | ||
|
|
aa085248b9 | ||
|
|
1508af4df8 | ||
|
|
172cf25380 | ||
|
|
d11bb1ed61 | ||
|
|
9c789ceac4 | ||
|
|
7b9a00e433 | ||
|
|
a36913e9db | ||
|
|
ce500858fe | ||
|
|
1f74d8dcd7 | ||
|
|
74e4b323ac | ||
|
|
9caeec7fcf | ||
|
|
d9d7462d87 | ||
|
|
a1346a9e89 | ||
|
|
88752dea51 | ||
|
|
54558c92af | ||
|
|
b0f8ca544d | ||
|
|
093feac6e4 | ||
|
|
2fa4623506 | ||
|
|
53b6471d2b | ||
|
|
f304480dfc | ||
|
|
a5d2a33016 | ||
|
|
67488b2eca | ||
|
|
0105a4ee47 | ||
|
|
b1b3c19908 | ||
|
|
eff2ef3892 | ||
|
|
d57122c382 | ||
|
|
b70837278d | ||
|
|
c31bcde720 | ||
|
|
5007c78a40 | ||
|
|
011a374f6b | ||
|
|
98403fa883 | ||
|
|
ce5b47ef99 | ||
|
|
6fbd708ae0 | ||
|
|
3f68031a09 | ||
|
|
57a5d490a6 | ||
|
|
726938f67c | ||
|
|
46bbd0fdf8 | ||
|
|
862e5719c6 | ||
|
|
49937eb98c | ||
|
|
4fdfddb6b8 | ||
|
|
113af9e53b | ||
|
|
00fc460c4e | ||
|
|
a428fdc48c | ||
|
|
7677e4f78a | ||
|
|
9e9f2a206f | ||
|
|
b26a56314b | ||
|
|
a718f7e1e3 | ||
|
|
ffaec1661a | ||
|
|
c9d2a0d33b | ||
|
|
8b4b5ba633 | ||
|
|
d0c5f53a08 | ||
|
|
1efc0f3a94 | ||
|
|
ac4ab0d767 | ||
|
|
97f1158cbc | ||
|
|
a1eabecc61 | ||
|
|
dddaee1719 | ||
|
|
076b7e55bd | ||
|
|
944140ce80 | ||
|
|
77fc792644 | ||
|
|
08f5976a57 | ||
|
|
153f8ca02c | ||
|
|
e6818369ff | ||
|
|
48d1bd412c | ||
|
|
44f343d3dc | ||
|
|
e20f76c3b1 | ||
|
|
ee1aaafd73 | ||
|
|
37345eee74 | ||
|
|
d86ee1f772 | ||
|
|
095f9c832e | ||
|
|
574c346d45 | ||
|
|
2b8e489f84 | ||
|
|
ce09978eee | ||
|
|
9836c60dae | ||
|
|
7a26162c5b | ||
|
|
69a6f8d012 | ||
|
|
eb0ff2f09d | ||
|
|
02173484eb | ||
|
|
a9bd76adc6 | ||
|
|
1f19cc48c7 | ||
|
|
59c6891249 | ||
|
|
1c06bfeaac | ||
|
|
5c2678f7ea | ||
|
|
4fcddadcc9 | ||
|
|
b29fce1b8f | ||
|
|
eae6869012 | ||
|
|
c2ce0f2d2d | ||
|
|
59a0341104 | ||
|
|
1a37493c79 | ||
|
|
332eaaebb0 | ||
|
|
7b50ea974f | ||
|
|
6f5b86982c | ||
|
|
2b8549bd3f | ||
|
|
f904fd111b | ||
|
|
7d53e49912 | ||
|
|
98b82537a9 | ||
|
|
72fab3665c | ||
|
|
814cf73a00 | ||
|
|
3829886a74 | ||
|
|
99610f7f08 | ||
|
|
943e2f73c0 | ||
|
|
f0a40fabb9 | ||
|
|
371fc19a06 | ||
|
|
605ec93179 | ||
|
|
08553f1bac | ||
|
|
fc30ba18f3 | ||
|
|
d26074a17f | ||
|
|
6e683c54e0 | ||
|
|
a98c764541 | ||
|
|
ee27549c84 | ||
|
|
c03afabc0f | ||
|
|
17a3001af5 | ||
|
|
4693229c84 | ||
|
|
779f02c932 | ||
|
|
e19b2142c5 | ||
|
|
97dc113a9f | ||
|
|
b49a45d81d | ||
|
|
7dbd42f9b2 | ||
|
|
fd0ceda0e9 | ||
|
|
9988c754ac | ||
|
|
769282935b | ||
|
|
9094c66f3d | ||
|
|
f39d3ad9dd | ||
|
|
d3105d1a76 | ||
|
|
b49e9eb027 | ||
|
|
f578122d15 | ||
|
|
41f54f8e2d | ||
|
|
3a26256a5c | ||
|
|
a73c461ed4 | ||
|
|
06ad60ea0c | ||
|
|
28215a3722 | ||
|
|
b82c38202f | ||
|
|
f16a9672b4 | ||
|
|
c85f7483c9 | ||
|
|
4d8a99f03b | ||
|
|
e8cf9927cc | ||
|
|
2afbd9dbb1 | ||
|
|
d8234e90dd | ||
|
|
50abcf5ab3 | ||
|
|
176d4994d1 | ||
|
|
7d2de18a7c | ||
|
|
a7373232da | ||
|
|
c41f9dd01c | ||
|
|
2bdf4add5a | ||
|
|
bb3f406ffc | ||
|
|
207f416686 | ||
|
|
f48d817a85 | ||
|
|
7c3cba0b92 | ||
|
|
147a6090e4 | ||
|
|
e729610dc8 | ||
|
|
b4f46ee3d2 | ||
|
|
3b5f758318 | ||
|
|
f398b3a945 | ||
|
|
9a0755a268 | ||
|
|
6e2ca85b2a | ||
|
|
cc4fecc1be | ||
|
|
de22ecae82 | ||
|
|
7dcf8a5bd4 | ||
|
|
73f2f2b2b2 | ||
|
|
c9f71dd2df | ||
|
|
a5923d6eb2 | ||
|
|
30f2ac2286 | ||
|
|
ba63d01f78 | ||
|
|
d37623a2ca | ||
|
|
097f1a2cd3 | ||
|
|
506b1ac53e | ||
|
|
6e2a9c936d | ||
|
|
12c78bcb62 | ||
|
|
fcdf35565f | ||
|
|
7df023abb7 | ||
|
|
cadcab9b40 | ||
|
|
22f6a34f5b | ||
|
|
b56c2a83e5 | ||
|
|
0b099ce2b8 | ||
|
|
6383a54f35 | ||
|
|
64f08669c2 | ||
|
|
7dcefe345c | ||
|
|
6b0327f2ef | ||
|
|
1ace0450cb | ||
|
|
f67100857b | ||
|
|
f5c6333417 | ||
|
|
88f2981044 | ||
|
|
f2ac6e3064 | ||
|
|
b075ae0e71 | ||
|
|
74e032a8cc | ||
|
|
64a787a9de | ||
|
|
8b6df5abbd | ||
|
|
743277eb6e | ||
|
|
7b67342690 | ||
|
|
5271f6845e | ||
|
|
3ce8a67409 | ||
|
|
d1263a8b9c | ||
|
|
1dad0adb03 | ||
|
|
878d7e64b0 | ||
|
|
4a3030f087 |
31
.github/ISSUE_TEMPLATE.md
vendored
31
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,12 +1,18 @@
|
||||
<!-- Before submitting an issue, please consult our troubleshooting guide (http://ionicframework.com/docs/troubleshooting/) and developer resources (http://ionicframework.com/docs/developer-resources/) -->
|
||||
|
||||
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Pro services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Pro support portal (http://support.ionicjs.com) -->
|
||||
|
||||
**Ionic version:** (check one with "x")
|
||||
[ ] **1.x** (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
|
||||
(For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
|
||||
[ ] **2.x**
|
||||
[ ] **3.x**
|
||||
[ ] **4.x**
|
||||
|
||||
**I'm submitting a ...** (check one with "x")
|
||||
[ ] bug report
|
||||
[ ] feature request
|
||||
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
|
||||
|
||||
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
|
||||
|
||||
**Current behavior:**
|
||||
<!-- Describe how the bug manifests. -->
|
||||
@@ -15,17 +21,22 @@
|
||||
<!-- Describe what the behavior would be without the bug. -->
|
||||
|
||||
**Steps to reproduce:**
|
||||
<!-- If you are able to illustrate the bug or feature request with an example, please provide steps to reproduce and if possible a demo using one of the following templates:
|
||||
|
||||
For Ionic V1 issues - http://plnkr.co/edit/Xo1QyAUx35ny1Xf9ODHx?p=preview
|
||||
|
||||
For Ionic issues - http://plnkr.co/edit/z0DzVL?p=preview
|
||||
-->
|
||||
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
|
||||
|
||||
**Related code:**
|
||||
|
||||
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
|
||||
|
||||
A sample application via GitHub
|
||||
|
||||
StackBlitz (https://stackblitz.com)
|
||||
|
||||
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
|
||||
|
||||
-->
|
||||
|
||||
```
|
||||
insert any relevant code here
|
||||
insert short code snippets here
|
||||
```
|
||||
|
||||
**Other information:**
|
||||
@@ -36,5 +47,3 @@ insert any relevant code here
|
||||
```
|
||||
insert the output from ionic info here
|
||||
```
|
||||
|
||||
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,6 +7,6 @@
|
||||
-
|
||||
-
|
||||
|
||||
**Ionic Version**: 1.x / 2.x / 3.x
|
||||
**Ionic Version**: 1.x / 2.x / 3.x / 4.x
|
||||
|
||||
**Fixes**: #
|
||||
|
||||
69
.github/ionic-issue-bot.yml
vendored
69
.github/ionic-issue-bot.yml
vendored
@@ -2,28 +2,69 @@ triage:
|
||||
label: triage
|
||||
dryRun: false
|
||||
|
||||
support:
|
||||
label: support
|
||||
closeAndLock:
|
||||
labels:
|
||||
- label: "ionitron: support"
|
||||
message: >
|
||||
Thanks for the issue! This issue appears to be a support request. We use this issue tracker exclusively for
|
||||
bug reports and feature requests. Please use our [forum](https://forum.ionicframework.com) or our
|
||||
[slack channel](https://ionicworldwide.herokuapp.com/) for questions about the framework.
|
||||
|
||||
|
||||
Thank you for using Ionic!
|
||||
- label: "ionitron: missing template"
|
||||
message: >
|
||||
Thanks for the issue! It appears that you have not filled out the provided issue template. We use this issue
|
||||
template in order to gather more information and further assist you. Please create a new issue and ensure the
|
||||
template is fully filled out.
|
||||
|
||||
|
||||
Thank you for using Ionic!
|
||||
close: true
|
||||
lock: true
|
||||
dryRun: false
|
||||
|
||||
stale:
|
||||
days: 365
|
||||
maxIssuesPerRun: 100
|
||||
exemptLabels:
|
||||
- good first issue
|
||||
- triage
|
||||
exemptProjects: true
|
||||
exemptMilestones: true
|
||||
label: "ionitron: stale issue"
|
||||
message: >
|
||||
Thanks for the issue! This issue appears to be a support request. We use this issue tracker exclusively for
|
||||
bug reports and feature requests. Please use our [forum](https://forum.ionicframework.com) or our
|
||||
[slack channel](https://ionicworldwide.herokuapp.com/) for questions about the framework.
|
||||
|
||||
|
||||
Thanks for the issue! This issue is being closed due to inactivity. If this is still
|
||||
an issue with the latest version of Ionic, please create a new issue and ensure the
|
||||
template is fully filled out.
|
||||
|
||||
|
||||
Thank you for using Ionic!
|
||||
close: true
|
||||
lock: true
|
||||
dryRun: false
|
||||
|
||||
incomplete:
|
||||
label: missing template
|
||||
message: >
|
||||
Thanks for the issue! It appears that you have not filled out the provided issue template. We use this issue
|
||||
template in order to gather more information and further assist you. Please create a new issue and ensure the
|
||||
template is fully filled out.
|
||||
wrongRepo:
|
||||
repos:
|
||||
- label: "ionitron: cli"
|
||||
repo: ionic-cli
|
||||
message: >
|
||||
Thanks for the issue! We use this issue tracker exclusively for bug reports and feature requests
|
||||
associated with the Ionic Framework. It appears that this issue is associated with the Ionic CLI.
|
||||
I am moving this issue to the Ionic CLI repository. Please track this issue over there.
|
||||
|
||||
|
||||
Thank you for using Ionic!
|
||||
Thank you for using Ionic!
|
||||
- label: "ionitron: stencil"
|
||||
repo: stencil
|
||||
message: >
|
||||
Thanks for the issue! We use this issue tracker exclusively for bug reports and feature requests
|
||||
associated with the Ionic Framework. It appears that this issue is associated with Stencil.
|
||||
I am moving this issue to the Stencil repository. Please track this issue over there.
|
||||
|
||||
|
||||
Thank you for using Ionic!
|
||||
close: true
|
||||
lock: true
|
||||
dryRun: false
|
||||
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -18,8 +18,8 @@ dist/
|
||||
node_modules/
|
||||
tmp/
|
||||
temp/
|
||||
packages/core/theme-builder/
|
||||
packages/core/test-components/
|
||||
core/theme-builder/
|
||||
core/test-components/
|
||||
$RECYCLE.BIN/
|
||||
|
||||
.DS_Store
|
||||
|
||||
26
.scripts/README.md
Normal file
26
.scripts/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Build Scripts
|
||||
|
||||
## Release
|
||||
|
||||
The deploy scripts at the root, make a new release of all the packages in this monorepo.
|
||||
All packages will be released with the same version.
|
||||
|
||||
In order to make a new release:
|
||||
|
||||
1. `npm run release.prepare`
|
||||
2. Review/update changelog
|
||||
3. Commit updates using the package name and version number as the commit message.
|
||||
4. `npm run release`
|
||||
5. :tada:
|
||||
|
||||
|
||||
## Prerelease
|
||||
|
||||
It's also possible to make prereleases of individual packages (@ionic/core, @ionic/angular).
|
||||
In order to do so, move to the package you want to make a new release and execute:
|
||||
```
|
||||
npm run prerelease
|
||||
```
|
||||
|
||||
It will publish a new prerelease in NPM, but it will not create any new git tag
|
||||
or update the CHANGELOG.
|
||||
73
.scripts/common.js
Normal file
73
.scripts/common.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const execa = require('execa');
|
||||
const Listr = require('listr');
|
||||
const semver = require('semver');
|
||||
|
||||
const rootDir = path.join(__dirname, '../');
|
||||
|
||||
const packages = [
|
||||
'core',
|
||||
'angular'
|
||||
];
|
||||
|
||||
function readPkg(project) {
|
||||
const packageJsonPath = packagePath(project);
|
||||
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
}
|
||||
|
||||
function writePkg(project, pkg) {
|
||||
const packageJsonPath = packagePath(project);
|
||||
const text = JSON.stringify(pkg, null, 2);
|
||||
return fs.writeFileSync(packageJsonPath, text);
|
||||
}
|
||||
|
||||
function packagePath(project) {
|
||||
return path.join(rootDir, project, 'package.json');
|
||||
}
|
||||
|
||||
function projectPath(project) {
|
||||
return path.join(rootDir, project);
|
||||
}
|
||||
|
||||
function checkGit(tasks) {
|
||||
tasks.push(
|
||||
{
|
||||
title: 'Check current branch',
|
||||
task: () => execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
|
||||
if (branch !== 'master') {
|
||||
throw new Error(`Not on "master" 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.`);
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
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.`);
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const isValidVersion = input => Boolean(semver.valid(input));
|
||||
|
||||
|
||||
module.exports = {
|
||||
isValidVersion,
|
||||
readPkg,
|
||||
writePkg,
|
||||
rootDir,
|
||||
projectPath,
|
||||
checkGit,
|
||||
packages
|
||||
};
|
||||
306
.scripts/prepare.js
Normal file
306
.scripts/prepare.js
Normal file
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* Deploy script adopted from https://github.com/sindresorhus/np
|
||||
* MIT License (c) Sindre Sorhus (sindresorhus.com)
|
||||
*/
|
||||
const chalk = require('chalk');
|
||||
const execa = require('execa');
|
||||
const inquirer = require('inquirer');
|
||||
const Listr = require('listr');
|
||||
const fs = require('fs-extra');
|
||||
const semver = require('semver');
|
||||
const common = require('./common');
|
||||
const path = require('path');
|
||||
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const version = await askVersion();
|
||||
|
||||
// compile and verify packages
|
||||
await preparePackages(common.packages, version);
|
||||
|
||||
console.log(`\nionic ${version} prepared 🤖\n`);
|
||||
console.log(`Next steps:`);
|
||||
console.log(` Verify CHANGELOG.md`);
|
||||
console.log(` git commit -m "${version}"`);
|
||||
console.log(` npm run release\n`);
|
||||
|
||||
} catch(err) {
|
||||
console.log('\n', chalk.red(err), '\n');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function askVersion() {
|
||||
const pkg = common.readPkg('core');
|
||||
const oldVersion = pkg.version;
|
||||
|
||||
const prompts = [
|
||||
{
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: 'Select semver increment or specify new version',
|
||||
pageSize: SEMVER_INCREMENTS.length + 2,
|
||||
choices: SEMVER_INCREMENTS
|
||||
.map(inc => ({
|
||||
name: `${inc} ${prettyVersionDiff(oldVersion, inc)}`,
|
||||
value: inc
|
||||
}))
|
||||
.concat([
|
||||
new inquirer.Separator(),
|
||||
{
|
||||
name: 'Other (specify)',
|
||||
value: null
|
||||
}
|
||||
]),
|
||||
filter: input => isValidVersionInput(input) ? getNewVersion(oldVersion, input) : input
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'version',
|
||||
message: 'Version',
|
||||
when: answers => !answers.version,
|
||||
filter: input => isValidVersionInput(input) ? getNewVersion(pkg.version, input) : input,
|
||||
validate: input => {
|
||||
if (!isValidVersionInput(input)) {
|
||||
return 'Please specify a valid semver, for example, `1.2.3`. See http://semver.org';
|
||||
} else if (!isVersionGreater(oldVersion, input)) {
|
||||
return `Version must be greater than ${oldVersion}`;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: answers => {
|
||||
return `Will bump from ${chalk.cyan(oldVersion)} to ${chalk.cyan(answers.version)}. Continue?`;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const {version} = await inquirer.prompt(prompts);
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
async function preparePackages(packages, version) {
|
||||
// execution order matters
|
||||
const tasks = [];
|
||||
|
||||
// check git is nice and clean local and remote
|
||||
common.checkGit(tasks);
|
||||
|
||||
// test we're good with git
|
||||
validateGit(tasks, version);
|
||||
|
||||
// add all the prepare scripts
|
||||
// run all these tasks before updating package.json version
|
||||
packages.forEach(package => {
|
||||
preparePackage(tasks, package, version);
|
||||
});
|
||||
|
||||
// add update package.json of each project
|
||||
packages.forEach(package => {
|
||||
updatePackageVersion(tasks, package, version);
|
||||
});
|
||||
|
||||
// generate changelog
|
||||
generateChangeLog(tasks);
|
||||
|
||||
const listr = new Listr(tasks, { showSubtasks: true });
|
||||
await listr.run();
|
||||
}
|
||||
|
||||
|
||||
function validateGit(tasks, version) {
|
||||
tasks.push(
|
||||
{
|
||||
title: `Validate git tag ${chalk.dim(`(v${version})`)}`,
|
||||
task: () => execa('git', ['fetch'])
|
||||
.then(() => {
|
||||
return execa.stdout('npm', ['config', 'get', 'tag-version-prefix']);
|
||||
})
|
||||
.then(
|
||||
output => {
|
||||
tagPrefix = output;
|
||||
},
|
||||
() => {}
|
||||
)
|
||||
.then(() => execa.stdout('git', ['rev-parse', '--quiet', '--verify', `refs/tags/${tagPrefix}${version}`]))
|
||||
.then(
|
||||
output => {
|
||||
if (output) {
|
||||
throw new Error(`Git tag \`${tagPrefix}${version}\` already exists.`);
|
||||
}
|
||||
},
|
||||
err => {
|
||||
// Command fails with code 1 and no output if the tag does not exist, even though `--quiet` is provided
|
||||
// https://github.com/sindresorhus/np/pull/73#discussion_r72385685
|
||||
if (err.stdout !== '' || err.stderr !== '') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function preparePackage(tasks, package, version) {
|
||||
const projectRoot = common.projectPath(package);
|
||||
const pkg = common.readPkg(package);
|
||||
|
||||
const projectTasks = [
|
||||
{
|
||||
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}\``);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: `${pkg.name}: install npm dependencies`,
|
||||
task: async () => {
|
||||
await fs.remove(path.join(projectRoot, 'node_modules'))
|
||||
await execa('npm', ['ci'], { cwd: projectRoot });
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (package !== 'core') {
|
||||
projectTasks.push(
|
||||
{
|
||||
title: `${pkg.name}: npm link @ionic/core`,
|
||||
task: () => execa('npm', ['link', '@ionic/core'], { cwd: projectRoot })
|
||||
},
|
||||
{
|
||||
title: `${pkg.name}: update ionic/core dep to ${version}`,
|
||||
task: () => {
|
||||
updateDependency(pkg, "@ionic/core", version);
|
||||
common.writePkg(package, pkg);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
projectTasks.push(
|
||||
{
|
||||
title: `${pkg.name}: lint`,
|
||||
task: () => execa('npm', ['run', 'lint'], { cwd: projectRoot })
|
||||
},
|
||||
{
|
||||
title: `${pkg.name}: build`,
|
||||
task: () => execa('npm', ['run', 'build'], { cwd: projectRoot })
|
||||
},
|
||||
{
|
||||
title: `${pkg.name}: test`,
|
||||
task: () => execa('npm', ['test'], { cwd: projectRoot })
|
||||
}
|
||||
);
|
||||
|
||||
if (package === 'core') {
|
||||
projectTasks.push(
|
||||
{
|
||||
title: `${pkg.name}: npm link`,
|
||||
task: () => execa('npm', ['link'], { cwd: projectRoot })
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Add project tasks
|
||||
tasks.push({
|
||||
title: `Prepare ${chalk.bold(pkg.name)}`,
|
||||
task: () => new Listr(projectTasks)
|
||||
});
|
||||
}
|
||||
|
||||
function updateDependency(pkg, dependency, version) {
|
||||
if (pkg.dependencies && pkg.dependencies[dependency]) {
|
||||
pkg.dependencies[dependency] = version;
|
||||
}
|
||||
if (pkg.devDependencies && pkg.devDependencies[dependency]) {
|
||||
pkg.devDependencies[dependency] = version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updatePackageVersion(tasks, package, version) {
|
||||
const projectRoot = common.projectPath(package);
|
||||
const pkg = common.readPkg(package);
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `${pkg.name}: update package.json ${chalk.dim(`(${version})`)}`,
|
||||
task: async () => {
|
||||
await execa('npm', ['version', version], { cwd: projectRoot });
|
||||
|
||||
const pkgLock = path.join(projectRoot, 'package-lock.json');
|
||||
const pkgLockData = JSON.parse(fs.readFileSync(pkgLock, 'utf-8'));
|
||||
pkgLockData.version = version;
|
||||
|
||||
fs.writeFileSync(pkgLock, JSON.stringify(pkgLockData));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async function generateChangeLog(tasks) {
|
||||
tasks.push(
|
||||
{
|
||||
title: `Generate CHANGELOG.md`,
|
||||
task: () => execa('npm', ['run', 'changelog'], { cwd: common.rootDir }),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const SEMVER_INCREMENTS = ['patch', 'minor', 'major'];
|
||||
|
||||
const isValidVersion = input => Boolean(semver.valid(input));
|
||||
|
||||
const isValidVersionInput = input => SEMVER_INCREMENTS.indexOf(input) !== -1 || common.isValidVersion(input);
|
||||
|
||||
function getNewVersion(oldVersion, input) {
|
||||
if (!isValidVersionInput(input)) {
|
||||
throw new Error(`Version should be either ${SEMVER_INCREMENTS.join(', ')} or a valid semver version.`);
|
||||
}
|
||||
|
||||
return SEMVER_INCREMENTS.indexOf(input) === -1 ? input : semver.inc(oldVersion, input);
|
||||
};
|
||||
|
||||
const isVersionGreater = (oldVersion, newVersion) => {
|
||||
if (!common.isValidVersion(newVersion)) {
|
||||
throw new Error('Version should be a valid semver version.');
|
||||
}
|
||||
|
||||
return semver.gt(newVersion, oldVersion);
|
||||
};
|
||||
|
||||
|
||||
function prettyVersionDiff(oldVersion, inc) {
|
||||
const newVersion = getNewVersion(oldVersion, inc).split('.');
|
||||
oldVersion = oldVersion.split('.');
|
||||
let firstVersionChange = false;
|
||||
const output = [];
|
||||
|
||||
for (let i = 0; i < newVersion.length; i++) {
|
||||
if ((newVersion[i] !== oldVersion[i] && !firstVersionChange)) {
|
||||
output.push(`${chalk.dim.cyan(newVersion[i])}`);
|
||||
firstVersionChange = true;
|
||||
} else if (newVersion[i].indexOf('-') >= 1) {
|
||||
let preVersion = [];
|
||||
preVersion = newVersion[i].split('-');
|
||||
output.push(`${chalk.dim.cyan(`${preVersion[0]}-${preVersion[1]}`)}`);
|
||||
} else {
|
||||
output.push(chalk.reset.dim(newVersion[i]));
|
||||
}
|
||||
}
|
||||
return output.join(chalk.reset.dim('.'));
|
||||
}
|
||||
|
||||
main();
|
||||
92
.scripts/release.js
Normal file
92
.scripts/release.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Deploy script adopted from https://github.com/sindresorhus/np
|
||||
* MIT License (c) Sindre Sorhus (sindresorhus.com)
|
||||
*/
|
||||
const chalk = require('chalk');
|
||||
const execa = require('execa');
|
||||
const Listr = require('listr');
|
||||
const common = require('./common');
|
||||
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const {version} = common.readPkg('core');
|
||||
|
||||
// publish each package in NPM
|
||||
await publishPackages(common.packages, version);
|
||||
|
||||
console.log(`\nionic ${version} published!! 🎉\n`);
|
||||
|
||||
} catch (err) {
|
||||
console.log('\n', chalk.red(err), '\n');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function publishPackages(packages, version) {
|
||||
const tasks = [];
|
||||
|
||||
// repo must be clean
|
||||
common.checkGit(tasks);
|
||||
|
||||
// first verify version
|
||||
packages.forEach(package => {
|
||||
if (package === 'core') return;
|
||||
|
||||
const pkg = common.readPkg(package);
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `${pkg.name}: check version (must match: ${version})`,
|
||||
task: () => {
|
||||
if (version !== pkg.version) {
|
||||
throw new Error(`${pkg.name} version ${pkg.version} must match ${version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// next publish
|
||||
packages.forEach(package => {
|
||||
const pkg = common.readPkg(package);
|
||||
const projectRoot = common.projectPath(package);
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `${pkg.name}: publish ${pkg.version}`,
|
||||
task: () =>execa('npm', ['publish', '--tag', 'latest'], { cwd: projectRoot })
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// push tag to git remote
|
||||
publishGitTag(tasks, version);
|
||||
|
||||
const listr = new Listr(tasks);
|
||||
await listr.run();
|
||||
}
|
||||
|
||||
|
||||
function publishGitTag(tasks, version) {
|
||||
const tag = `v${version}`;
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
title: `Tag latest commit ${chalk.dim(`(${tag})`)}`,
|
||||
task: () => execa('git', ['tag', `${tag}`], { cwd: common.rootDir })
|
||||
},
|
||||
{
|
||||
title: 'Push branches to Github',
|
||||
task: () => execa('git', ['push'], { cwd: common.rootDir })
|
||||
},
|
||||
{
|
||||
title: 'Push tags to Github',
|
||||
task: () => execa('git', ['push', '--tags'], { cwd: common.rootDir })
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
main();
|
||||
948
BREAKING.md
948
BREAKING.md
@@ -1,949 +1,3 @@
|
||||
|
||||
# Breaking Changes
|
||||
|
||||
A list of the breaking changes introduced in Ionic Angular v4.
|
||||
|
||||
- [Dynamic Mode](#dynamic-mode)
|
||||
- [Button](#button)
|
||||
- [Chip](#chip)
|
||||
- [Colors](#colors)
|
||||
- [Datetime](#datetime)
|
||||
- [FAB](#fab)
|
||||
- [Fixed Content](#fixed-content)
|
||||
- [Icon](#icon)
|
||||
- [Input](#Input)
|
||||
- [Item](#item)
|
||||
- [Item Divider](#item-divider)
|
||||
- [Item Sliding](#item-sliding)
|
||||
- [List Header](#list-header)
|
||||
- [Menu Toggle](#menu-toggle)
|
||||
- [Nav](#nav)
|
||||
- [Option](#option)
|
||||
- [Radio](#radio)
|
||||
- [Range](#range)
|
||||
- [Segment](#segment)
|
||||
- [Select](#select)
|
||||
- [Text/Typography](#text-typography)
|
||||
- [Theming](#theming)
|
||||
- [Toolbar](#toolbar)
|
||||
|
||||
|
||||
## Dynamic Mode
|
||||
|
||||
Components are no longer able to have their mode changed dynamically. You can change the mode before the first render, but after that it will not style properly because only the initial mode's styles are included.
|
||||
|
||||
## Button
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Button should now be written as an `<ion-button>` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<button ion-button (click)="doSomething()">
|
||||
Default Button
|
||||
</button>
|
||||
|
||||
<a ion-button href="#">
|
||||
Default Anchor
|
||||
</a>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-button (click)="doSomething()">
|
||||
Default Button
|
||||
</ion-button>
|
||||
|
||||
<ion-button href="#">
|
||||
Default Anchor
|
||||
</ion-button>
|
||||
```
|
||||
|
||||
### Attributes Renamed
|
||||
|
||||
Previously to style icons inside of a button the following attributes were used: `icon-left`, `icon-right`, (and with the added support of RTL) `icon-start`, `icon-end`.
|
||||
|
||||
These have been renamed to the following, and moved from the button element to the icon itself:
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
|---------------------------|----------------|-----------------------------------------------------------------------|
|
||||
| `icon-left`, `icon-start` | `slot="start"` | Positions to the left of the button in LTR, and to the right in RTL. |
|
||||
| `icon-right`, `icon-end` | `slot="end"` | Positions to the right of the button in LTR, and to the left in RTL. |
|
||||
|
||||
In addition, several sets of mutually exclusive boolean attributes have been combined into a single string attribute.
|
||||
|
||||
The `small` and `large` attributes are now combined under the `size` attribute. The `clear`, `outline`, and `solid` attributes have been combined under `fill`. And, lastly, the `full` and `block` attributes have been combined under `expand`.
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
| --------------------------- | ------------ | --------------------------- |
|
||||
| `small`, `large` | `size` | Sets the button size. |
|
||||
| `clear`, `outline`, `solid` | `fill` | Sets the button fill style. |
|
||||
| `full`, `block` | `expand` | Sets the button width. |
|
||||
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-button icon-left>
|
||||
<ion-icon name="home"></ion-icon>
|
||||
Icon Left
|
||||
</ion-button>
|
||||
|
||||
<ion-button icon-start>
|
||||
<ion-icon name="home"></ion-icon>
|
||||
Icon Left on LTR, Right on RTL
|
||||
</ion-button>
|
||||
|
||||
<ion-button icon-right>
|
||||
Icon Right
|
||||
<ion-icon name="home"></ion-icon>
|
||||
</ion-button>
|
||||
|
||||
<ion-button icon-end>
|
||||
Icon Right on LTR, Left on RTL
|
||||
<ion-icon name="home"></ion-icon>
|
||||
</ion-button>
|
||||
|
||||
<ion-button large>
|
||||
Large Button
|
||||
</ion-button>
|
||||
|
||||
<ion-button outline>
|
||||
Outline Button
|
||||
</ion-button>
|
||||
|
||||
<ion-button full>
|
||||
Full-width Button
|
||||
</ion-button>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-button>
|
||||
<ion-icon slot="start" name="home"></ion-icon>
|
||||
Icon Left on LTR, Right on RTL
|
||||
</ion-button>
|
||||
|
||||
<ion-button>
|
||||
Icon Right on LTR, Left on RTL
|
||||
<ion-icon slot="end" name="home"></ion-icon>
|
||||
</ion-button>
|
||||
|
||||
<ion-button size="large">
|
||||
Large Button
|
||||
</ion-button>
|
||||
|
||||
<ion-button fill="outline">
|
||||
Outline Button
|
||||
</ion-button>
|
||||
|
||||
<ion-button expand="full">
|
||||
Full-width Button
|
||||
</ion-button>
|
||||
```
|
||||
|
||||
## Chip
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Buttons inside of an `<ion-chip>` container should now be written as an `<ion-chip-button>` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-chip>
|
||||
<ion-label>Default</ion-label>
|
||||
<ion-button clear color="light">
|
||||
<ion-icon name="close-circle"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-chip>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-chip>
|
||||
<ion-label>Default</ion-label>
|
||||
<ion-chip-button fill="clear" color="light">
|
||||
<ion-icon name="close-circle"></ion-icon>
|
||||
</ion-chip-button>
|
||||
</ion-chip>
|
||||
```
|
||||
|
||||
|
||||
## Colors
|
||||
|
||||
The default Ionic theme colors have changed. Previously we had:
|
||||
|
||||
```
|
||||
primary: #327eff
|
||||
secondary: #32db64
|
||||
danger: #f53d3d
|
||||
light: #f4f4f4
|
||||
dark: #222
|
||||
```
|
||||
|
||||
Some of their values have changed and we now include more colors by default:
|
||||
|
||||
```
|
||||
primary: #3880ff
|
||||
secondary: #0cd1e8
|
||||
tertiary: #7044ff
|
||||
success: #10dc60
|
||||
warning: #ffce00
|
||||
danger: #f04141
|
||||
light: #f4f5f8
|
||||
medium: #989aa2
|
||||
dark: #222428
|
||||
```
|
||||
|
||||
The `secondary` color saw the largest change. If you were previously using our `secondary` color we recommend switching to `success` instead.
|
||||
|
||||
|
||||
## Datetime
|
||||
|
||||
The Datetime classes and interfaces have changed capitalization from `DateTime` to `Datetime`. This is more consistent with other components and their tags.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```javascript
|
||||
import { DateTime } from 'ionic-angular';
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```javascript
|
||||
import { Datetime } from 'ionic-angular';
|
||||
```
|
||||
|
||||
## FAB
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Buttons inside of an `<ion-fab>` container should now be written as an `<ion-fab-button>` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-fab top right edge>
|
||||
<button ion-fab>
|
||||
<ion-icon name="add"></ion-icon>
|
||||
</button>
|
||||
<ion-fab-list>
|
||||
<button ion-fab>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</button>
|
||||
<button ion-fab>
|
||||
<ion-icon name="logo-twitter"></ion-icon>
|
||||
</button>
|
||||
<button ion-fab>
|
||||
<ion-icon name="logo-vimeo"></ion-icon>
|
||||
</button>
|
||||
<button ion-fab>
|
||||
<ion-icon name="logo-googleplus"></ion-icon>
|
||||
</button>
|
||||
</ion-fab-list>
|
||||
</ion-fab>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-fab vertical="top" horizontal="right" edge>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="add"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-list>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="logo-twitter"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="logo-vimeo"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="logo-googleplus"></ion-icon>
|
||||
</ion-fab-button>
|
||||
</ion-fab-list>
|
||||
</ion-fab>
|
||||
```
|
||||
|
||||
### Attributes Renamed
|
||||
|
||||
The mutually exclusive boolean attributes to position the fab have been combined into two single string attributes.
|
||||
|
||||
The attributes to align the fab horizontally are now combined under the `horizontal` attribute and the attributes to align the fab vertically are now combined under the `vertical` attribute:
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
|--------------|----------------------|-------------------------------------------------------------------------|
|
||||
| left | `horizontal="left"` | Positions to the left of the viewport. |
|
||||
| right | `horizontal="right"` | Positions to the right of the viewport. |
|
||||
| center | `horizontal="center"`| Positions to the center of the viewport. |
|
||||
| start | `horizontal="start"` | Positions to the left of the viewport in LTR, and to the right in RTL. |
|
||||
| end | `horizontal="end"` | Positions to the right of the viewport in LTR, and to the left in RTL. |
|
||||
| top | `vertical="top"` | Positions at the top of the viewport. |
|
||||
| bottom | `vertical="bottom"` | Positions at the bottom of the viewport. |
|
||||
| middle | `vertical="center"` | Positions at the center of the viewport. |
|
||||
|
||||
_Note that `middle` has been changed to `center` for the vertical positioning._
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-fab top right edge>
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
|
||||
<ion-fab center middle>
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-fab vertical="top" horizontal="right" edge>
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
|
||||
<ion-fab vertical="center" horizontal="center">
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
```
|
||||
|
||||
### Fixed Content
|
||||
|
||||
The `<ion-fab>` container was previously placed inside of the fixed content by default. Now, any fixed content should use the `fixed` slot.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-content>
|
||||
<ion-fab top right edge>
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
Scrollable Content
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-fab vertical="top" horizontal="right" edge slot="fixed">
|
||||
<!-- fab buttons and lists -->
|
||||
</ion-fab>
|
||||
<ion-content>
|
||||
Scrollable Content
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
## Icon
|
||||
|
||||
### Fonts Removed
|
||||
|
||||
Icons have been refactored to use SVGs instead of fonts. Ionic will only fetch the SVG for the icon when it is needed, instead of having a large font file that is always loaded in.
|
||||
|
||||
If any `CSS` is being overridden for an icon it will need to change to override the SVG itself. Below is a usage example of the differences in changing the icon color.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```css
|
||||
.icon {
|
||||
color: #000;
|
||||
}
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```css
|
||||
.icon {
|
||||
fill: #000;
|
||||
}
|
||||
```
|
||||
|
||||
### Property Removed
|
||||
|
||||
The `isActive` property has been removed. It only worked for `ios` icons previously. If you would like to switch between an outline and solid icon you should set it in the `name`, or `ios`/`md` attribute and then change it when needed.
|
||||
|
||||
## Input
|
||||
|
||||
The Sass variables were all renamed from having `$text-input` as the prefix to `$input`.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```css
|
||||
$text-input-highlight-color-valid: #32db64;
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```css
|
||||
$input-highlight-color-valid: #32db64;
|
||||
```
|
||||
|
||||
|
||||
## Item
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Item should now be written as an `<ion-item>` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute, and a button tag based on the presence of an `onclick` or `tappable` attribute. Otherwise, it will render a div.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
Default Item
|
||||
</ion-item>
|
||||
|
||||
<button ion-item (click)="doSomething()">
|
||||
Button Item
|
||||
</button>
|
||||
|
||||
<a ion-item href="#">
|
||||
Anchor Item
|
||||
</a>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
Default Item
|
||||
</ion-item>
|
||||
|
||||
<ion-item tappable (click)="doSomething()">
|
||||
Button Item
|
||||
</ion-item>
|
||||
|
||||
<ion-item href="#">
|
||||
Anchor Item
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
### Label Required
|
||||
|
||||
Previously an `ion-label` would automatically get added to an `ion-item` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
<ion-label>Item Label</ion-label>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
### Attributes Renamed
|
||||
|
||||
Previously to position elements inside of an `ion-item` the following attributes were used: `item-left`, `item-right`, (and with the added support of RTL) `item-start`, `item-end`.
|
||||
|
||||
These have been renamed to the following:
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
|---------------------------|----------------|---------------------------------------------------------------------|
|
||||
| `item-left`, `item-start` | `slot="start"` | Positions to the left of the item in LTR, and to the right in RTL. |
|
||||
| `item-right`, `item-end` | `slot="end"` | Positions to the right of the item in LTR, and to the left in RTL. |
|
||||
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
<div item-left>Left</div>
|
||||
<ion-label>Item Label</ion-label>
|
||||
<div item-right>Right</div>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<div item-start>Left on LTR, Right on RTL</div>
|
||||
<ion-label>Item Label</ion-label>
|
||||
<div item-end>Right on LTR, Left on RTL</div>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
<div slot="start">Left on LTR, Right on RTL</div>
|
||||
<ion-label>Item Label</ion-label>
|
||||
<div slot="end">Right on LTR, Left on RTL</div>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
### Detail Push
|
||||
|
||||
The attributes to show/hide the detail arrows on items have been converted to a single property and value. Instead of writing `detail-push` or `detail-none` to show/hide the arrow, it should be written `detail`/`detail="true"` or `detail="false"`.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<button ion-item detail-none>
|
||||
<ion-label>Item Label</ion-label>
|
||||
</button>
|
||||
|
||||
<ion-item detail-push>
|
||||
<ion-label>Item Label</ion-label>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item tappable detail="false">
|
||||
<ion-label>Item Label</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item detail>
|
||||
<ion-label>Item Label</ion-label>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
By default, items that render buttons or anchor tags will show the arrow in `ios` mode.
|
||||
|
||||
## Item Divider
|
||||
|
||||
### Label Required
|
||||
|
||||
Previously an `ion-label` would automatically get added to an `ion-item-divider` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
|
||||
|
||||
```html
|
||||
<ion-item-divider>
|
||||
<ion-label>Item Divider Label</ion-label>
|
||||
</ion-item-divider>
|
||||
```
|
||||
|
||||
## List Header
|
||||
|
||||
### Label Required
|
||||
|
||||
Previously an `ion-label` would automatically get added to an `ion-list-header` if one wasn't provided. Now an `ion-label` should always be added if the component is used to display text.
|
||||
|
||||
```html
|
||||
<ion-list-header>
|
||||
<ion-label>List Header Label</ion-label>
|
||||
</ion-list-header>
|
||||
```
|
||||
|
||||
## Menu Toggle
|
||||
|
||||
### Markup Changed
|
||||
|
||||
The `menuToggle` attribute should not be added to an element anymore. Elements that should toggle a menu should be wrapped in an `ion-menu-toggle` element.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<button ion-button menuToggle>
|
||||
Toggle Menu
|
||||
</button>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-menu-toggle>
|
||||
<ion-button>
|
||||
Toggle Menu
|
||||
</ion-button>
|
||||
</ion-menu-toggle>
|
||||
```
|
||||
|
||||
## Item Sliding
|
||||
|
||||
### Markup Changed
|
||||
|
||||
The option component should not be written as a `button` with an `ion-button` directive anymore. It should be written as an `ion-item-option`. This will render a native button element inside of it.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
Item 1
|
||||
</ion-item>
|
||||
<ion-item-options side="right">
|
||||
<button ion-button expandable>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</button>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options side="right">
|
||||
<ion-item-option expandable>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
```
|
||||
|
||||
### Method Renamed
|
||||
|
||||
The `getSlidingPercent` method has been renamed to `getSlidingRatio` since the function is returning a ratio of the open amount of the item compared to the width of the options.
|
||||
|
||||
|
||||
## Toolbar
|
||||
|
||||
Previously if a `menuToggle` directive was added to an Ionic `button` in a toolbar, it would be positioned outside of the `ion-buttons` element. Since menu toggle is simply a wrapper to a button now, it should be placed inside of the `ion-buttons` element.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-toolbar>
|
||||
<button ion-button menuToggle>
|
||||
<ion-icon name="menu"></ion-icon>
|
||||
</button>
|
||||
<ion-title>Left side menu toggle</ion-title>
|
||||
</ion-toolbar>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-menu-toggle>
|
||||
<ion-button>
|
||||
<ion-icon slot="icon-only" name="menu"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-menu-toggle>
|
||||
</ion-buttons>
|
||||
<ion-title>Left side menu toggle</ion-title>
|
||||
</ion-toolbar>
|
||||
```
|
||||
|
||||
## Nav
|
||||
|
||||
### Method renamed
|
||||
|
||||
The `remove` method has been renamed to `removeIndex` to avoid conflicts with HTML and be more descriptive as to what it does.
|
||||
|
||||
The `getActiveChildNavs` method has been renamed to `getChildNavs`.
|
||||
|
||||
## Option
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Select's option element should now be written as `<ion-select-option>`. This makes it more obvious that the element should only be used with a Select.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select>
|
||||
<ion-option>Option 1</ion-option>
|
||||
<ion-option>Option 2</ion-option>
|
||||
<ion-option>Option 3</ion-option>
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select>
|
||||
<ion-select-option>Option 1</ion-select-option>
|
||||
<ion-select-option>Option 2</ion-select-option>
|
||||
<ion-select-option>Option 3</ion-select-option>
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
### Class Changed
|
||||
|
||||
The class has been renamed from `Option` to `SelectOption` to keep it consistent with the element tag name.
|
||||
|
||||
## Radio
|
||||
|
||||
### Slot Required
|
||||
|
||||
Previously radio was positioned inside of an item automatically or by using `item-left`/`item-right`. It is now required to have a `slot` to be positioned properly.
|
||||
|
||||
** Old Usage Example **
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
<ion-label>Apple</ion-label>
|
||||
<ion-radio value="apple"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Grape, checked, disabled</ion-label>
|
||||
<ion-radio item-left value="grape" checked disabled></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cherry</ion-label>
|
||||
<ion-radio item-right color="danger" value="cherry"></ion-radio>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
** New Usage Example **
|
||||
|
||||
```html
|
||||
<ion-item>
|
||||
<ion-label>Apple</ion-label>
|
||||
<ion-radio slot="start" value="apple"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Grape, checked, disabled</ion-label>
|
||||
<ion-radio slot="start" value="grape" checked disabled></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cherry</ion-label>
|
||||
<ion-radio slot="end" color="danger" value="cherry"></ion-radio>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
### Radio Group
|
||||
|
||||
Radio group has been changed to an element. It should now be wrapped around any `<ion-radio>` elements as `<ion-radio-group>`.
|
||||
|
||||
** Old Usage Example **
|
||||
|
||||
```html
|
||||
<ion-list radio-group>
|
||||
<ion-item>
|
||||
<ion-label>Apple</ion-label>
|
||||
<ion-radio value="apple"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Grape, checked, disabled</ion-label>
|
||||
<ion-radio value="grape" checked disabled></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cherry</ion-label>
|
||||
<ion-radio color="danger" value="cherry"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
** New Usage Example **
|
||||
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-radio-group>
|
||||
<ion-item>
|
||||
<ion-label>Apple</ion-label>
|
||||
<ion-radio slot="start" value="apple"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Grape, checked, disabled</ion-label>
|
||||
<ion-radio slot="start" value="grape" checked disabled></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cherry</ion-label>
|
||||
<ion-radio slot="start" color="danger" value="cherry"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
|
||||
## Range
|
||||
|
||||
### Attributes Renamed
|
||||
|
||||
Previously to place content inside of a range the following attributes were used: `range-left`, `range-right`, (and with the added support of RTL) `range-start`, `range-end`.
|
||||
|
||||
These have been renamed to the following:
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
|-----------------------------|----------------|-----------------------------------------------------------------------|
|
||||
| `range-left`, `range-start` | `slot="start"` | Positions to the left of the range in LTR, and to the right in RTL. |
|
||||
| `range-right`, `range-end` | `slot="end"` | Positions to the right of the range in LTR, and to the left in RTL. |
|
||||
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-range>
|
||||
<ion-icon name="sunny" range-left></ion-icon>
|
||||
<ion-icon name="sunny" range-right></ion-icon>
|
||||
</ion-range>
|
||||
|
||||
<ion-range>
|
||||
<ion-icon name="sunny" range-start></ion-icon>
|
||||
<ion-icon name="sunny" range-end></ion-icon>
|
||||
</ion-range>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-range>
|
||||
<ion-icon name="sunny" slot="start"></ion-icon>
|
||||
<ion-icon name="sunny" slot="end"></ion-icon>
|
||||
</ion-range>
|
||||
```
|
||||
|
||||
|
||||
## Segment
|
||||
|
||||
The markup hasn't changed for Segments, but now writing `<ion-segment-button>` will render a native button element inside of it.
|
||||
|
||||
|
||||
## Select
|
||||
|
||||
The `selectOptions` property was renamed to `interfaceOptions` since it directly correlates with the `interface` property.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select [selectOptions]="customOptions">
|
||||
...
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
```ts
|
||||
this.customOptions = {
|
||||
title: 'Pizza Toppings',
|
||||
subTitle: 'Select your toppings'
|
||||
};
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select [interfaceOptions]="customOptions">
|
||||
...
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
```ts
|
||||
this.customOptions = {
|
||||
title: 'Pizza Toppings',
|
||||
subTitle: 'Select your toppings'
|
||||
};
|
||||
```
|
||||
|
||||
## Text / Typography
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Typography should now be written as an `<ion-text>` element. Previously the `ion-text` attribute could be added to any HTML element to set its color. It should now be used as a wrapper around the HTML elements to style.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<h1 ion-text color="secondary">H1: The quick brown fox jumps over the lazy dog</h1>
|
||||
|
||||
<h2 ion-text color="primary">H2: The quick brown fox jumps over the lazy dog</h2>
|
||||
|
||||
<h3 ion-text color="light">H3: The quick brown fox jumps over the lazy dog</h3>
|
||||
|
||||
<p>
|
||||
I saw a werewolf with a Chinese menu in his hand.
|
||||
Walking through the <sub ion-text color="danger">streets</sub> of Soho in the rain.
|
||||
He <i ion-text color="primary">was</i> looking for a place called Lee Ho Fook's.
|
||||
Gonna get a <a ion-text color="secondary">big dish of beef chow mein.</a>
|
||||
</p>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-text color="secondary">
|
||||
<h1>H1: The quick brown fox jumps over the lazy dog</h1>
|
||||
</ion-text>
|
||||
|
||||
<ion-text color="primary">
|
||||
<h2>H2: The quick brown fox jumps over the lazy dog</h2>
|
||||
</ion-text>
|
||||
|
||||
<ion-text color="light">
|
||||
<h3>H3: The quick brown fox jumps over the lazy dog</h3>
|
||||
</ion-text>
|
||||
|
||||
<p>
|
||||
I saw a werewolf with a Chinese menu in his hand.
|
||||
Walking through the <ion-text color="danger"><sub>streets</sub></ion-text> of Soho in the rain.
|
||||
He <ion-text color="primary"><i>was</i></ion-text> looking for a place called Lee Ho Fook's.
|
||||
Gonna get a <ion-text color="secondary"><a>big dish of beef chow mein.</a></ion-text>
|
||||
</p>
|
||||
```
|
||||
|
||||
|
||||
## Theming
|
||||
|
||||
### Including Sass
|
||||
|
||||
Previously all `scss` files in the `src` directory were imported. Now each `scss` file should be included for the component via Angular's `styleUrls` metadata. View [Angular's Component Styles](https://angular.io/guide/component-styles) for more information.
|
||||
|
||||
This means that any styles wrapped with a page should now be removed since they will automatically be scoped to the component.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```scss
|
||||
page-schedule {
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```scss
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Sass Variables
|
||||
|
||||
Sass variables for changing the cordova statusbar have been renamed to app:
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```css
|
||||
$cordova-ios-statusbar-padding: 20px;
|
||||
$cordova-md-statusbar-padding: 20px;
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```css
|
||||
$app-ios-statusbar-padding: 20px;
|
||||
$app-md-statusbar-padding: 20px;
|
||||
```
|
||||
|
||||
|
||||
## Toolbar
|
||||
|
||||
### Attributes Renamed
|
||||
|
||||
The attributes to position an `ion-buttons` element inside of a toolbar have been renamed, as well as the behavior attached to the name. We noticed there was some confusion behind the behavior of the `start` and `end` attributes, and with the new support for RTL we wanted to make the behavior of these match RTL. In order to do this we had to rename the old `start`/`end` to something that makes more sense with their behavior.
|
||||
|
||||
The names and behavior of each of the properties was previously:
|
||||
|
||||
| Old Property | Property Behavior |
|
||||
|--------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| `start` | Positions element to the left of the content in `ios` mode, and directly to the right in `md` and `wp` mode. |
|
||||
| `end` | Positions element to the right of the content in `ios` mode, and to the far right in `md` and `wp` mode. |
|
||||
| `left` | Positions element to the left of all other elements. |
|
||||
| `right` | Positions element to the right of all other elements. |
|
||||
|
||||
The properties have been renamed to the following:
|
||||
|
||||
| Old Property | New Property | Property Behavior |
|
||||
|--------------|---------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| `start` | `slot="mode-start"` | Positions element to the `left` of the content in `ios` mode, and directly to the `right` in `md` and `wp` mode. |
|
||||
| `end` | `slot="mode-end"` | Positions element to the `right` of the content in `ios` mode, and to the far right in `md` and `wp` mode. |
|
||||
| `left` | `slot="start"` | Positions element to the `left` of all other elements in `LTR`, and to the `right` in `RTL`. |
|
||||
| `right` | `slot="end"` | Positions element to the `right` of all other elements in `LTR`, and to the `left` in `RTL`. |
|
||||
The list of the breaking changes introduced in Ionic Angular v4 has been moved to [angular/BREAKING.md](https://github.com/ionic-team/ionic/blob/master/angular/BREAKING.md).
|
||||
445
CHANGELOG.md
Normal file
445
CHANGELOG.md
Normal file
@@ -0,0 +1,445 @@
|
||||
<a name="4.0.0-alpha.3"></a>
|
||||
# [4.0.0-alpha.3](https://github.com/ionic-team/ionic/compare/v4.0.0-alpha.2...v4.0.0-alpha.3) (2018-04-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **all:** strong typed events ([d5129df](https://github.com/ionic-team/ionic/commit/d5129df))
|
||||
* **angular:** adds missing events ([c929dad](https://github.com/ionic-team/ionic/commit/c929dad))
|
||||
* **angular:** Config provider ([c87f0c5](https://github.com/ionic-team/ionic/commit/c87f0c5))
|
||||
* **angular:** platform ready() ([2b3c14b](https://github.com/ionic-team/ionic/commit/2b3c14b))
|
||||
* **overlay:** cssClasses applied to overlay ([43d7538](https://github.com/ionic-team/ionic/commit/43d7538))
|
||||
* **prerender:** local references to window/document ([78bd146](https://github.com/ionic-team/ionic/commit/78bd146))
|
||||
* **virtual-scroll:** queue.write ([c1cbbc5](https://github.com/ionic-team/ionic/commit/c1cbbc5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **angular:** animation is explicit ([099b3ed](https://github.com/ionic-team/ionic/commit/099b3ed))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **platform:** remove from critical path ([86a6cde](https://github.com/ionic-team/ionic/commit/86a6cde))
|
||||
|
||||
|
||||
|
||||
<a name="4.0.0-alpha.2"></a>
|
||||
# [4.0.0-alpha.2](https://github.com/ionic-team/ionic/compare/v4.0.0-alpha.1...v4.0.0-alpha.2) (2018-04-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** add NavParams ([22ebbce](https://github.com/ionic-team/ionic/commit/22ebbce))
|
||||
* **angular:** change detection in deep ViewContainers ([850d7fc](https://github.com/ionic-team/ionic/commit/850d7fc))
|
||||
* **angular:** emit es5 code ([02c1e83](https://github.com/ionic-team/ionic/commit/02c1e83))
|
||||
* **angular:** icon proxy ([db5313e](https://github.com/ionic-team/ionic/commit/db5313e))
|
||||
* **angular:** router-outlet uses stack by default ([5c91101](https://github.com/ionic-team/ionic/commit/5c91101))
|
||||
* **angular:** using es2017 types ([12a27bc](https://github.com/ionic-team/ionic/commit/12a27bc))
|
||||
* **angular:** viewContainer in overlays ([8ad3df9](https://github.com/ionic-team/ionic/commit/8ad3df9))
|
||||
* **back-button:** get the back button color working ([5f4250b](https://github.com/ionic-team/ionic/commit/5f4250b))
|
||||
* **fab:** fix fab activation ([a203534](https://github.com/ionic-team/ionic/commit/a203534))
|
||||
* **label:** inline position by default ([fde878b](https://github.com/ionic-team/ionic/commit/fde878b))
|
||||
* **label:** using prop for position ([b1ee4b8](https://github.com/ionic-team/ionic/commit/b1ee4b8)), closes [#14288](https://github.com/ionic-team/ionic/issues/14288)
|
||||
* **mode:** set mode css class on ion-app ([fcb08e1](https://github.com/ionic-team/ionic/commit/fcb08e1))
|
||||
* **props:** update stencil ([ea24ad6](https://github.com/ionic-team/ionic/commit/ea24ad6))
|
||||
* **react:** FrameworkDelegate matches API ([e40a6b0](https://github.com/ionic-team/ionic/commit/e40a6b0))
|
||||
* **toast:** account for safe-area on ios ([d984214](https://github.com/ionic-team/ionic/commit/d984214))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **angular:** adds DomController ([6a31f39](https://github.com/ionic-team/ionic/commit/6a31f39)), closes [#14286](https://github.com/ionic-team/ionic/issues/14286)
|
||||
* **angular:** push/setRoot/pop ([4d23cba](https://github.com/ionic-team/ionic/commit/4d23cba))
|
||||
* **DomController:** add DomController provider using stencil queue ([bceece7](https://github.com/ionic-team/ionic/commit/bceece7))
|
||||
* **queue:** use stencil's queue controller for dom read/writes ([d623b3b](https://github.com/ionic-team/ionic/commit/d623b3b))
|
||||
* **router:** dont reuse the component if the params are different ([5899b03](https://github.com/ionic-team/ionic/commit/5899b03))
|
||||
* **routerDirection:** refactors goBack ([54d7a12](https://github.com/ionic-team/ionic/commit/54d7a12))
|
||||
|
||||
|
||||
|
||||
<a name="4.0.0-alpha.1"></a>
|
||||
# [4.0.0-alpha.1](https://github.com/ionic-team/ionic/compare/v0.2.2...v4.0.0-alpha.1) (2018-04-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** change detection ([79ba639](https://github.com/ionic-team/ionic/commit/79ba639))
|
||||
* **angular:** proxy methods ([5153da4](https://github.com/ionic-team/ionic/commit/5153da4))
|
||||
* **angular:** proxy outputs ([64a9497](https://github.com/ionic-team/ionic/commit/64a9497))
|
||||
* **menu:** prerender ([a3cd5db](https://github.com/ionic-team/ionic/commit/a3cd5db))
|
||||
* **split-pane:** prerender ([c6e962c](https://github.com/ionic-team/ionic/commit/c6e962c))
|
||||
|
||||
|
||||
|
||||
<a name="0.2.2"></a>
|
||||
## [0.2.2](https://github.com/ionic-team/ionic/compare/v0.2.1...v0.2.2) (2018-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **back-button:** fix menu and back button alignment ([#14268](https://github.com/ionic-team/ionic/issues/14268)) ([57fbf6c](https://github.com/ionic-team/ionic/commit/57fbf6c))
|
||||
* **ripple-effect:** animation ([25c852c](https://github.com/ionic-team/ionic/commit/25c852c))
|
||||
* **sass:** add missing alert css properties ([#14269](https://github.com/ionic-team/ionic/issues/14269)) ([3471dd6](https://github.com/ionic-team/ionic/commit/3471dd6)), closes [#14258](https://github.com/ionic-team/ionic/issues/14258)
|
||||
* **script:** release script pushes tags ([d23108a](https://github.com/ionic-team/ionic/commit/d23108a))
|
||||
* **scripts:** improve script ([2215c6a](https://github.com/ionic-team/ionic/commit/2215c6a))
|
||||
* **select:** pass header and subHeader to interfaces ([2195895](https://github.com/ionic-team/ionic/commit/2195895))
|
||||
* **select:** wrap the text for the message in a popover ([0a0959b](https://github.com/ionic-team/ionic/commit/0a0959b))
|
||||
|
||||
|
||||
|
||||
<a name="0.2.1"></a>
|
||||
## [0.2.1](https://github.com/ionic-team/ionic/compare/v0.2.0...v0.2.1) (2018-04-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** back button prevents default ([4db687e](https://github.com/ionic-team/ionic/commit/4db687e))
|
||||
* **angular:** back-button ([1f78390](https://github.com/ionic-team/ionic/commit/1f78390))
|
||||
* **angular:** back-button does not push view ([bb46b5f](https://github.com/ionic-team/ionic/commit/bb46b5f))
|
||||
* **angular:** tabs flickering ([7e97006](https://github.com/ionic-team/ionic/commit/7e97006))
|
||||
* **app:** hide elements ([11cb42f](https://github.com/ionic-team/ionic/commit/11cb42f))
|
||||
* **scripts:** update dep version ([974b949](https://github.com/ionic-team/ionic/commit/974b949))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **angular:** href integration ([09e6b7e](https://github.com/ionic-team/ionic/commit/09e6b7e))
|
||||
|
||||
|
||||
|
||||
<a name="0.2.0"></a>
|
||||
# [0.2.0](https://github.com/ionic-team/ionic/compare/v0.1.6...v0.2.0) (2018-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** URL based tabs ([14fedb9](https://github.com/ionic-team/ionic/commit/14fedb9))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.6"></a>
|
||||
## [0.1.6](https://github.com/ionic-team/ionic/compare/v0.1.5...v0.1.6) (2018-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** lifecycles ([062641d](https://github.com/ionic-team/ionic/commit/062641d))
|
||||
* **angular:** modal and popover ([acd411d](https://github.com/ionic-team/ionic/commit/acd411d))
|
||||
* **angular:** module exports ([cece447](https://github.com/ionic-team/ionic/commit/cece447))
|
||||
* **angular:** proxies ([2308239](https://github.com/ionic-team/ionic/commit/2308239))
|
||||
* **angular:** tabs angular tests ([ff1ed88](https://github.com/ionic-team/ionic/commit/ff1ed88))
|
||||
* **router-outlet:** enteringEl !== leavingEl ([0d44253](https://github.com/ionic-team/ionic/commit/0d44253))
|
||||
* **router-outlet:** mutable prop ([ff06dab](https://github.com/ionic-team/ionic/commit/ff06dab))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.5"></a>
|
||||
## [0.1.5](https://github.com/ionic-team/ionic/compare/v0.1.4...v0.1.5) (2018-03-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **all:** absolute positioning ([4fcddad](https://github.com/ionic-team/ionic/commit/4fcddad))
|
||||
* **angular:** goback navigation ([7b9a00e](https://github.com/ionic-team/ionic/commit/7b9a00e))
|
||||
* **angular:** ion-back-button ([9c789ce](https://github.com/ionic-team/ionic/commit/9c789ce))
|
||||
* **angular:** stack based navigation ([726938f](https://github.com/ionic-team/ionic/commit/726938f))
|
||||
* **avatar:** adjust wide images to fill instead of squish ([b0f8ca5](https://github.com/ionic-team/ionic/commit/b0f8ca5))
|
||||
* **back-button:** empty text is a valid value ([eb0ff2f](https://github.com/ionic-team/ionic/commit/eb0ff2f))
|
||||
* **back-button:** ios style ([2b8e489](https://github.com/ionic-team/ionic/commit/2b8e489))
|
||||
* **button:** dynamic bar-button ([d0c5f53](https://github.com/ionic-team/ionic/commit/d0c5f53))
|
||||
* **checkbox:** update ios checkbox to be closer to native ([b29fce1](https://github.com/ionic-team/ionic/commit/b29fce1))
|
||||
* **components:** add font-smoothing to mixing components ([9caeec7](https://github.com/ionic-team/ionic/commit/9caeec7))
|
||||
* **covers:** absolute positioning ([ce09978](https://github.com/ionic-team/ionic/commit/ce09978))
|
||||
* **item-option:** remove outline on active/focus ([eae6869](https://github.com/ionic-team/ionic/commit/eae6869)), closes [#14191](https://github.com/ionic-team/ionic/issues/14191)
|
||||
* **label:** add missing text-wrap styles for ios ([a9bd76a](https://github.com/ionic-team/ionic/commit/a9bd76a)), closes [#13157](https://github.com/ionic-team/ionic/issues/13157)
|
||||
* **menu:** default menu mode ([c31bcde](https://github.com/ionic-team/ionic/commit/c31bcde))
|
||||
* **nav:** animated opts ([57a5d49](https://github.com/ionic-team/ionic/commit/57a5d49))
|
||||
* **nav:** no animation ([4fdfddb](https://github.com/ionic-team/ionic/commit/4fdfddb))
|
||||
* **nav:** transition name ([011a374](https://github.com/ionic-team/ionic/commit/011a374))
|
||||
* **picker:** do not scroll ([1c06bfe](https://github.com/ionic-team/ionic/commit/1c06bfe))
|
||||
* **ripple-effect:** tapclick is required in ionic ([d57122c](https://github.com/ionic-team/ionic/commit/d57122c))
|
||||
* **router:** change detection for componentProps ([a718f7e](https://github.com/ionic-team/ionic/commit/a718f7e))
|
||||
* **router:** explicit goback should not push ([7a26162](https://github.com/ionic-team/ionic/commit/7a26162))
|
||||
* **router:** fixes navChanged() ([dddaee1](https://github.com/ionic-team/ionic/commit/dddaee1))
|
||||
* **router:** ion-nav ([113af9e](https://github.com/ionic-team/ionic/commit/113af9e))
|
||||
* **router:** loging ([ffaec16](https://github.com/ionic-team/ionic/commit/ffaec16))
|
||||
* **router:** route change detection ([9e9f2a2](https://github.com/ionic-team/ionic/commit/9e9f2a2))
|
||||
* **router:** wait RAF ([b26a563](https://github.com/ionic-team/ionic/commit/b26a563))
|
||||
* **slides:** unload slides correctly ([59c6891](https://github.com/ionic-team/ionic/commit/59c6891))
|
||||
* **thumbnail:** adjust wide images to fill instead of squish ([54558c9](https://github.com/ionic-team/ionic/commit/54558c9))
|
||||
* **toast:** dismiss timeout ([44f343d](https://github.com/ionic-team/ionic/commit/44f343d))
|
||||
* **toolbar:** unused private ([c9d2a0d](https://github.com/ionic-team/ionic/commit/c9d2a0d))
|
||||
* **transition:** nav ios transition ([095f9c8](https://github.com/ionic-team/ionic/commit/095f9c8))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **button:** goback attribute ([00fc460](https://github.com/ionic-team/ionic/commit/00fc460))
|
||||
* **config:** add set to config ([69a6f8d](https://github.com/ionic-team/ionic/commit/69a6f8d))
|
||||
* **content:** scrollEnabled ([5c2678f](https://github.com/ionic-team/ionic/commit/5c2678f))
|
||||
* **menu-controller:** expose registerAnimation ([153f8ca](https://github.com/ionic-team/ionic/commit/153f8ca))
|
||||
* **nav:** goBack directive ([862e571](https://github.com/ionic-team/ionic/commit/862e571))
|
||||
* **nav-controller:** goback best guess ([46bbd0f](https://github.com/ionic-team/ionic/commit/46bbd0f))
|
||||
* **ripple:** css variable color ([77fc792](https://github.com/ionic-team/ionic/commit/77fc792))
|
||||
* **tab:** framework support ([48d1bd4](https://github.com/ionic-team/ionic/commit/48d1bd4))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **app:** platform is not needed ([e681836](https://github.com/ionic-team/ionic/commit/e681836))
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* **toolbar:** revert to use old button attributes ([574c346](https://github.com/ionic-team/ionic/commit/574c346)), closes [#14172](https://github.com/ionic-team/ionic/issues/14172)
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4"></a>
|
||||
## [0.1.4](https://github.com/ionic-team/ionic/compare/v0.1.4-9...v0.1.4) (2018-03-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **action-sheet:** update padding on title to match native ([f0a40fa](https://github.com/ionic-team/ionic/commit/f0a40fa))
|
||||
* **alert:** update colors for alert text and input borders ([605ec93](https://github.com/ionic-team/ionic/commit/605ec93)), closes [#14196](https://github.com/ionic-team/ionic/issues/14196)
|
||||
* **alert:** update md alert to closer match spec ([7d53e49](https://github.com/ionic-team/ionic/commit/7d53e49))
|
||||
* **all:** ts strict (part 4) ([4693229](https://github.com/ionic-team/ionic/commit/4693229))
|
||||
* **angular:** router-outlet animation ([943e2f7](https://github.com/ionic-team/ionic/commit/943e2f7))
|
||||
* **chip:** use lighter background color ([08553f1](https://github.com/ionic-team/ionic/commit/08553f1)), closes [#14196](https://github.com/ionic-team/ionic/issues/14196)
|
||||
* **picker:** does not scroll ([b49a45d](https://github.com/ionic-team/ionic/commit/b49a45d))
|
||||
* **router:** reusing checks params ([371fc19](https://github.com/ionic-team/ionic/commit/371fc19))
|
||||
* **router-outlet:** css and change logic ([6e683c5](https://github.com/ionic-team/ionic/commit/6e683c5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **fab:** add box shadow and transition for ios ([d26074a](https://github.com/ionic-team/ionic/commit/d26074a))
|
||||
* **ion-router-outlet:** adds router-outlet ([c03afab](https://github.com/ionic-team/ionic/commit/c03afab))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-9"></a>
|
||||
## [0.1.4-9](https://github.com/ionic-team/ionic/compare/v0.1.4-8...v0.1.4-9) (2018-03-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **all:** ts strict (part 3) ([06ad60e](https://github.com/ionic-team/ionic/commit/06ad60e))
|
||||
* **angular:** ion-nav no routing ([9094c66](https://github.com/ionic-team/ionic/commit/9094c66))
|
||||
* **angular:** removeViewFromDom ([41f54f8](https://github.com/ionic-team/ionic/commit/41f54f8))
|
||||
* **back-button:** use correct color for ios back button ([b82c382](https://github.com/ionic-team/ionic/commit/b82c382)), closes [#14177](https://github.com/ionic-team/ionic/issues/14177)
|
||||
* **overlays:** page is removed properly ([9988c75](https://github.com/ionic-team/ionic/commit/9988c75))
|
||||
* **theming:** update spinner classes to new names ([f578122](https://github.com/ionic-team/ionic/commit/f578122))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **angular:** ion-nav ([f39d3ad](https://github.com/ionic-team/ionic/commit/f39d3ad))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-8"></a>
|
||||
## [0.1.4-8](https://github.com/ionic-team/ionic/compare/v0.1.4-7...v0.1.4-8) (2018-03-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **back-button:** apply the proper color to the back button ([7d2de18](https://github.com/ionic-team/ionic/commit/7d2de18)), closes [#14177](https://github.com/ionic-team/ionic/issues/14177)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **nav:** support for rootParams ([50abcf5](https://github.com/ionic-team/ionic/commit/50abcf5))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-7"></a>
|
||||
## [0.1.4-7](https://github.com/ionic-team/ionic/compare/v0.1.4-6...v0.1.4-7) (2018-03-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **router:** wildcard redirects ([2bdf4ad](https://github.com/ionic-team/ionic/commit/2bdf4ad))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-6"></a>
|
||||
## [0.1.4-6](https://github.com/ionic-team/ionic/compare/v0.1.4-5...v0.1.4-6) (2018-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** backdrop calls cancel handler ([de22eca](https://github.com/ionic-team/ionic/commit/de22eca))
|
||||
* **alert:** set input value ([6e2a9c9](https://github.com/ionic-team/ionic/commit/6e2a9c9))
|
||||
* **angular:** create angular delegate ([3b5f758](https://github.com/ionic-team/ionic/commit/3b5f758))
|
||||
* **angular:** fix overlays ([cc4fecc](https://github.com/ionic-team/ionic/commit/cc4fecc))
|
||||
* **angular:** modal and popover support ([9a0755a](https://github.com/ionic-team/ionic/commit/9a0755a))
|
||||
* **demos:** fixes angular ([f398b3a](https://github.com/ionic-team/ionic/commit/f398b3a))
|
||||
* **overlay:** using hostData for zIndex ([64f0866](https://github.com/ionic-team/ionic/commit/64f0866))
|
||||
* **overlay:** wrong stencil import ([22f6a34](https://github.com/ionic-team/ionic/commit/22f6a34))
|
||||
* **overlays:** OverlayController interface ([6e2ca85](https://github.com/ionic-team/ionic/commit/6e2ca85))
|
||||
* **popover:** lifecycles ([b56c2a8](https://github.com/ionic-team/ionic/commit/b56c2a8))
|
||||
* **router:** ambiguous routes ([b4f46ee](https://github.com/ionic-team/ionic/commit/b4f46ee))
|
||||
* **router:** fix selection ([207f416](https://github.com/ionic-team/ionic/commit/207f416))
|
||||
* **router:** rename API to match stencil-router ([e729610](https://github.com/ionic-team/ionic/commit/e729610))
|
||||
* **router:** retuning string path ([f48d817](https://github.com/ionic-team/ionic/commit/f48d817))
|
||||
* **toggle:** ios shadow ([7df023a](https://github.com/ionic-team/ionic/commit/7df023a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ion-router:** dynamic routes ([7c3cba0](https://github.com/ionic-team/ionic/commit/7c3cba0))
|
||||
* **overlay:** adds lifecycle events ([0b099ce](https://github.com/ionic-team/ionic/commit/0b099ce))
|
||||
* **overlays:** adds onDidDismiss and onWillDismiss ([7dcf8a5](https://github.com/ionic-team/ionic/commit/7dcf8a5))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **scss:** optimize multi dir ([#14156](https://github.com/ionic-team/ionic/issues/14156)) ([ba63d01](https://github.com/ionic-team/ionic/commit/ba63d01))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-5"></a>
|
||||
## [0.1.4-5](https://github.com/ionic-team/ionic/compare/v0.1.4-4...v0.1.4-5) (2018-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **item:** button outline ([f671008](https://github.com/ionic-team/ionic/commit/f671008))
|
||||
* **router:** fix flickering ([f2ac6e3](https://github.com/ionic-team/ionic/commit/f2ac6e3))
|
||||
* **router:** flickering 2 ([88f2981](https://github.com/ionic-team/ionic/commit/88f2981))
|
||||
* **router:** tslint ([1ace045](https://github.com/ionic-team/ionic/commit/1ace045))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **router:** adds redirectTo ([f5c6333](https://github.com/ionic-team/ionic/commit/f5c6333))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-4"></a>
|
||||
## [0.1.4-4](https://github.com/ionic-team/ionic/compare/v0.1.4-3...v0.1.4-4) (2018-03-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **back-button:** implements back animation ([64a787a](https://github.com/ionic-team/ionic/commit/64a787a))
|
||||
* **route:** params is not undefined ([8b6df5a](https://github.com/ionic-team/ionic/commit/8b6df5a))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-3"></a>
|
||||
## [0.1.4-3](https://github.com/ionic-team/ionic/compare/v0.1.4-2...v0.1.4-3) (2018-03-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **router:** passing params to ion-nav ([d1263a8](https://github.com/ionic-team/ionic/commit/d1263a8))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **back-button:** adds defaultHref ([5271f68](https://github.com/ionic-team/ionic/commit/5271f68))
|
||||
* **nav:** params ([878d7e6](https://github.com/ionic-team/ionic/commit/878d7e6))
|
||||
* **route:** adds route-link ([4a3030f](https://github.com/ionic-team/ionic/commit/4a3030f))
|
||||
* **router:** reverse lookup with params ([3ce8a67](https://github.com/ionic-team/ionic/commit/3ce8a67))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-2"></a>
|
||||
## [0.1.4-2](https://github.com/ionic-team/ionic/compare/v0.1.4-0...v0.1.4-2) (2018-03-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **fab:** add side as a property for fab list ([7387d34](https://github.com/ionic-team/ionic/commit/7387d34))
|
||||
* **ion-router:** fixes routing algorithm ([c8a27b7](https://github.com/ionic-team/ionic/commit/c8a27b7))
|
||||
* **item:** href ([540c33b](https://github.com/ionic-team/ionic/commit/540c33b))
|
||||
* **overlays:** bundling of overlays ([9650bec](https://github.com/ionic-team/ionic/commit/9650bec))
|
||||
* **router:** invalid url ([c7fe694](https://github.com/ionic-team/ionic/commit/c7fe694))
|
||||
* **routing:** flickering (part 1) ([7b264f9](https://github.com/ionic-team/ionic/commit/7b264f9))
|
||||
* **tabs:** do not select when using router ([174d9b5](https://github.com/ionic-team/ionic/commit/174d9b5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **router:** adds parameters ([f29e3f4](https://github.com/ionic-team/ionic/commit/f29e3f4))
|
||||
* **virtual-scroll:** adds JSX support ([dc8b363](https://github.com/ionic-team/ionic/commit/dc8b363))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-1"></a>
|
||||
## [0.1.4-1](https://github.com/ionic-team/ionic/compare/v0.1.4-0...v0.1.4-1) (2018-03-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ion-router:** fixes routing algorithm ([c8a27b7](https://github.com/ionic-team/ionic/commit/c8a27b7))
|
||||
* **overlays:** bundling of overlays ([9650bec](https://github.com/ionic-team/ionic/commit/9650bec))
|
||||
* **routing:** flickering (part 1) ([7b264f9](https://github.com/ionic-team/ionic/commit/7b264f9))
|
||||
* **tabs:** do not select when using router ([174d9b5](https://github.com/ionic-team/ionic/commit/174d9b5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **virtual-scroll:** adds JSX support ([dc8b363](https://github.com/ionic-team/ionic/commit/dc8b363))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.4-0"></a>
|
||||
## [0.1.4-0](https://github.com/ionic-team/ionic/compare/v0.1.3...v0.1.4-0) (2018-03-06)
|
||||
|
||||
### Refactor
|
||||
|
||||
- Refactored navigation system
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **testing:** do not throw error for missing Ionic global ([aa91d11](https://github.com/ionic-team/ionic/commit/aa91d11))
|
||||
* **zone:** forgot to remove console.logs ([4ec3e48](https://github.com/ionic-team/ionic/commit/4ec3e48))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.3"></a>
|
||||
## [0.1.3](https://github.com/ionic-team/ionic/compare/v0.1.2...v0.1.3) (2018-03-03)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Updates to latest stencil, that includes the zone bypassing abilities.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ts:** ts strict fixes ([8ff02c7](https://github.com/ionic-team/ionic/commit/8ff02c7))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.2"></a>
|
||||
## [0.1.2](https://github.com/ionic-team/ionic/compare/v0.1.1...v0.1.2) (2018-03-03)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **events:** bypass ngzone ([7366c38](https://github.com/ionic-team/ionic/commit/7366c38))
|
||||
* **scroll:** watchdog + simplification ([33a6274](https://github.com/ionic-team/ionic/commit/33a6274))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scroll:** clearInterval just to be safe ([6da9882](https://github.com/ionic-team/ionic/commit/6da9882))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.1"></a>
|
||||
## [0.1.1](https://github.com/ionic-team/ionic/commit/291e85e61128b2f3101d9cea6b42d4cf751dc481) (2018-03-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** pass the property type instead of hardcoding button ([10e481a](https://github.com/ionic-team/ionic/commit/10e481a))
|
||||
|
||||
|
||||
|
||||
<a name="0.1.0"></a>
|
||||
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)
|
||||
@@ -8,8 +8,8 @@ Ionic is based on [Web Components](https://www.webcomponents.org/introduction) a
|
||||
|
||||
# Packages
|
||||
|
||||
- [Core](packages/core/README.md)
|
||||
- [Ionic Angular](packages/ionic-angular/README.md)
|
||||
- [Core](core/README.md)
|
||||
- [Ionic Angular](angular/README.md)
|
||||
|
||||
|
||||
### Getting Started
|
||||
@@ -46,3 +46,8 @@ As Ionic components migrate to the web component standard, a goal of ours is to
|
||||
|
||||
The source code for Ionic V1 has been moved to [ionic-team/ionic-v1](https://github.com/ionic-team/ionic-v1).
|
||||
Please open any issues and pull requests related to Ionic V1 on that repository.
|
||||
|
||||
|
||||
### Ionic V3
|
||||
|
||||
The source code for Ionic V3 has been moved to the [v3 branch](https://github.com/ionic-team/ionic/tree/v3).
|
||||
|
||||
1174
angular/BREAKING.md
Normal file
1174
angular/BREAKING.md
Normal file
File diff suppressed because it is too large
Load Diff
1
angular/package-lock.json
generated
Normal file
1
angular/package-lock.json
generated
Normal file
File diff suppressed because one or more lines are too long
66
angular/package.json
Normal file
66
angular/package.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "4.0.0-alpha.3",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
"framework",
|
||||
"angular",
|
||||
"mobile",
|
||||
"app",
|
||||
"webapp",
|
||||
"capacitor",
|
||||
"cordova",
|
||||
"progressive web app",
|
||||
"pwa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ionic-team/ionic.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run clean && npm run compile && npm run clean-generated && npm run ionic-core",
|
||||
"build.link": "npm run build && node scripts/link-copy.js",
|
||||
"clean": "node scripts/clean.js",
|
||||
"clean-generated": "node ./scripts/clean-generated.js",
|
||||
"compile": "./node_modules/.bin/ngc",
|
||||
"ionic-core": "node ../core/node_modules/.bin/stencil build",
|
||||
"ionic-core-dev": "node ../core/node_modules/.bin/stencil build --dev",
|
||||
"lint": "tslint --project .",
|
||||
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
|
||||
"test": "echo 'angular no tests yet'",
|
||||
"tsc": "tsc -p .",
|
||||
"validate": "npm i && npm run lint && npm run test && npm run build"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "4.0.0-alpha.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/common": "^6.0.0-rc.3",
|
||||
"@angular/compiler": "^6.0.0-rc.3",
|
||||
"@angular/compiler-cli": "^6.0.0-rc.3",
|
||||
"@angular/core": "^6.0.0-rc.3",
|
||||
"@angular/forms": "^6.0.0-rc.3",
|
||||
"@angular/platform-browser": "^6.0.0-rc.3",
|
||||
"@angular/platform-browser-dynamic": "^6.0.0-rc.3",
|
||||
"@angular/router": "^6.0.0-rc.3",
|
||||
"chalk": "^2.3.2",
|
||||
"execa": "^0.10.0",
|
||||
"fs-extra": "^5.0.0",
|
||||
"glob": "7.1.2",
|
||||
"inquirer": "^5.2.0",
|
||||
"listr": "^0.13.0",
|
||||
"rxjs": "^6.0.0-terrific-rc.3",
|
||||
"semver": "^5.5.0",
|
||||
"tslint": "^5.8.0",
|
||||
"tslint-ionic-rules": "0.0.14",
|
||||
"typescript": "2.7.2",
|
||||
"zone.js": "^0.8.20"
|
||||
}
|
||||
}
|
||||
19
angular/scripts/README.md
Normal file
19
angular/scripts/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Local @ionic/angular test app development
|
||||
|
||||
1. `npm install` at the root of `angular`
|
||||
2. `npm run build` to build local `@ionic/angular`
|
||||
3. `npm link` to locally link `@ionic/angular`
|
||||
4. `cd` to the test app, such as `angular/test/nav`
|
||||
5. `npm install` in the test app directory
|
||||
6. `npm link @ionic/angular` in the test app directory
|
||||
7. `ng serve` in the test app directory
|
||||
8. [http://localhost:4200/](http://localhost:4200/)
|
||||
|
||||
|
||||
# npm link local development
|
||||
|
||||
`npm link` doesn't work as expected due to the `devDependency` on `@angular/core`. This is the work around...
|
||||
|
||||
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.
|
||||
@@ -2,23 +2,12 @@ const path = require('path');
|
||||
const cwd = process.cwd();
|
||||
|
||||
const glob = require('glob');
|
||||
const rimRaf = require('rimraf');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const distDir = path.join(cwd, 'dist');
|
||||
const distDir = path.join(__dirname, '../dist');
|
||||
|
||||
const distGeneratedNodeModules = path.join(distDir, 'node_modules');
|
||||
|
||||
function rimRafAsync(dir) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rimRaf(dir, {}, err => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function doGlob(globString) {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(globString, (err, matches) => {
|
||||
@@ -40,15 +29,14 @@ function getCodegenedFilesToDelete() {
|
||||
const deleteFilePromises = [];
|
||||
listOfGlobResults.forEach(fileMatches => {
|
||||
fileMatches.forEach(filePath => {
|
||||
deleteFilePromises.push(rimRafAsync(filePath));
|
||||
deleteFilePromises.push(fs.remove(filePath));
|
||||
})
|
||||
})
|
||||
return Promise.all(deleteFilePromises);
|
||||
});
|
||||
}
|
||||
|
||||
const taskPromises = [];
|
||||
taskPromises.push(getCodegenedFilesToDelete());
|
||||
taskPromises.push(rimRafAsync(distGeneratedNodeModules));
|
||||
|
||||
return Promise.all(taskPromises);
|
||||
Promise.all([
|
||||
getCodegenedFilesToDelete(),
|
||||
fs.remove(distGeneratedNodeModules)
|
||||
]);
|
||||
28
angular/src/components.d.ts
vendored
Normal file
28
angular/src/components.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* This is an autogenerated file created by the Stencil build process.
|
||||
* It contains typing information for all components that exist in this project
|
||||
* and imports for stencil collections that might be configured in your stencil.config.js file
|
||||
*/
|
||||
|
||||
import '@stencil/core';
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface Element {}
|
||||
export interface IntrinsicElements {}
|
||||
}
|
||||
namespace JSXElements {}
|
||||
|
||||
interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady(): Promise<this>;
|
||||
componentOnReady(done: (ele?: this) => void): void;
|
||||
|
||||
forceUpdate(): void;
|
||||
}
|
||||
|
||||
interface HTMLAttributes {}
|
||||
}
|
||||
|
||||
import 'ionicons';
|
||||
import '@ionic/core';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { setIonicClasses } from './util/set-ionic-classes';
|
||||
@@ -15,7 +15,8 @@ import { setIonicClasses } from './util/set-ionic-classes';
|
||||
]
|
||||
})
|
||||
export class BooleanValueAccessor implements ControlValueAccessor {
|
||||
constructor(private element: ElementRef, private renderer: Renderer2) {
|
||||
|
||||
constructor(private element: ElementRef) {
|
||||
this.onChange = () => {/**/};
|
||||
this.onTouched = () => {/**/};
|
||||
}
|
||||
@@ -24,14 +25,15 @@ export class BooleanValueAccessor implements ControlValueAccessor {
|
||||
onTouched: () => void;
|
||||
|
||||
writeValue(value: any) {
|
||||
this.renderer.setProperty(this.element.nativeElement, 'checked', value);
|
||||
this.element.nativeElement.checked = value;
|
||||
setIonicClasses(this.element);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.checked'])
|
||||
_handleIonChange(value: any) {
|
||||
this.onChange(value);
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -39,24 +41,21 @@ export class BooleanValueAccessor implements ControlValueAccessor {
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => void): void {
|
||||
registerOnChange(fn: (value: any) => void) {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void): void {
|
||||
registerOnTouched(fn: () => void) {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'disabled',
|
||||
isDisabled
|
||||
);
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.element.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { setIonicClasses } from './util/set-ionic-classes';
|
||||
@@ -15,7 +15,8 @@ import { setIonicClasses } from './util/set-ionic-classes';
|
||||
]
|
||||
})
|
||||
export class NumericValueAccessor implements ControlValueAccessor {
|
||||
constructor(private element: ElementRef, private renderer: Renderer2) {
|
||||
|
||||
constructor(private element: ElementRef) {
|
||||
this.onChange = () => {/**/};
|
||||
this.onTouched = () => {/**/};
|
||||
}
|
||||
@@ -23,49 +24,42 @@ export class NumericValueAccessor implements ControlValueAccessor {
|
||||
onChange: (value: any) => void;
|
||||
onTouched: () => void;
|
||||
|
||||
writeValue(value: any): void {
|
||||
writeValue(value: any) {
|
||||
// The value needs to be normalized for IE9, otherwise it is set to 'null' when null
|
||||
// Probably not an issue for us, but it doesn't really cost anything either
|
||||
const normalizedValue = value == null ? '' : value;
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'value',
|
||||
normalizedValue
|
||||
);
|
||||
this.element.nativeElement.value = value == null ? '' : value;
|
||||
setIonicClasses(this.element);
|
||||
}
|
||||
|
||||
@HostListener('input', ['$event.target.value'])
|
||||
_handleInputEvent(value: any): void {
|
||||
_handleInputEvent(value: any) {
|
||||
this.onChange(value);
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent(): void {
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: number | null) => void): void {
|
||||
registerOnChange(fn: (_: number | null) => void) {
|
||||
this.onChange = value => {
|
||||
fn(value === '' ? null : parseFloat(value));
|
||||
};
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void): void {
|
||||
registerOnTouched(fn: () => void) {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'disabled',
|
||||
isDisabled
|
||||
);
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.element.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { setIonicClasses } from './util/set-ionic-classes';
|
||||
@@ -20,24 +20,24 @@ export class RadioValueAccessor implements ControlValueAccessor {
|
||||
onChange: (value: any) => void;
|
||||
onTouched: () => void;
|
||||
|
||||
constructor(private element: ElementRef, private renderer: Renderer2) {
|
||||
constructor(private element: ElementRef) {
|
||||
this.onChange = () => {/**/};
|
||||
this.onTouched = () => {/**/};
|
||||
}
|
||||
|
||||
writeValue(value: any) {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'checked',
|
||||
value === this.value
|
||||
);
|
||||
setIonicClasses(this.element);
|
||||
this.element.nativeElement.checked = this.value = value;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('ionSelect', ['$event.target.checked'])
|
||||
_handleIonSelect(value: any) {
|
||||
this.onChange(value);
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -45,26 +45,23 @@ export class RadioValueAccessor implements ControlValueAccessor {
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => void): void {
|
||||
registerOnChange(fn: (value: any) => void) {
|
||||
this.onChange = () => {
|
||||
fn(this.value);
|
||||
};
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void): void {
|
||||
registerOnTouched(fn: () => void) {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'disabled',
|
||||
isDisabled
|
||||
);
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.element.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { setIonicClasses } from './util/set-ionic-classes';
|
||||
|
||||
// NOTE: May need to look at this to see if we need anything else:
|
||||
// https://github.com/angular/angular/blob/5.0.2/packages/forms/src/directives/select_control_value_accessor.ts#L28-L158
|
||||
@Directive({
|
||||
/* tslint:disable-next-line:directive-selector */
|
||||
selector: 'ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime',
|
||||
@@ -17,7 +15,8 @@ import { setIonicClasses } from './util/set-ionic-classes';
|
||||
]
|
||||
})
|
||||
export class SelectValueAccessor implements ControlValueAccessor {
|
||||
constructor(private element: ElementRef, private renderer: Renderer2) {
|
||||
|
||||
constructor(private element: ElementRef) {
|
||||
this.onChange = () => {/**/};
|
||||
this.onTouched = () => {/**/};
|
||||
}
|
||||
@@ -26,14 +25,18 @@ export class SelectValueAccessor implements ControlValueAccessor {
|
||||
onTouched: () => void;
|
||||
|
||||
writeValue(value: any) {
|
||||
this.renderer.setProperty(this.element.nativeElement, 'value', value);
|
||||
setIonicClasses(this.element);
|
||||
this.element.nativeElement.value = value;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target.value'])
|
||||
_handleChangeEvent(value: any) {
|
||||
this.onChange(value);
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -41,7 +44,8 @@ export class SelectValueAccessor implements ControlValueAccessor {
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -54,11 +58,7 @@ export class SelectValueAccessor implements ControlValueAccessor {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'disabled',
|
||||
isDisabled
|
||||
);
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.element.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { setIonicClasses } from './util/set-ionic-classes';
|
||||
@@ -15,7 +15,8 @@ import { setIonicClasses } from './util/set-ionic-classes';
|
||||
]
|
||||
})
|
||||
export class TextValueAccessor implements ControlValueAccessor {
|
||||
constructor(private element: ElementRef, private renderer: Renderer2) {
|
||||
|
||||
constructor(private element: ElementRef) {
|
||||
this.onChange = () => {/**/};
|
||||
this.onTouched = () => {/**/};
|
||||
}
|
||||
@@ -24,14 +25,18 @@ export class TextValueAccessor implements ControlValueAccessor {
|
||||
onTouched: () => void;
|
||||
|
||||
writeValue(value: any) {
|
||||
this.renderer.setProperty(this.element.nativeElement, 'value', value);
|
||||
setIonicClasses(this.element);
|
||||
this.element.nativeElement.value = value;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('input', ['$event.target.value'])
|
||||
_handleInputEvent(value: any) {
|
||||
this.onChange(value);
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -39,7 +44,8 @@ export class TextValueAccessor implements ControlValueAccessor {
|
||||
@HostListener('ionBlur')
|
||||
_handleBlurEvent() {
|
||||
this.onTouched();
|
||||
setTimeout(() => {
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setIonicClasses(this.element);
|
||||
});
|
||||
}
|
||||
@@ -52,11 +58,7 @@ export class TextValueAccessor implements ControlValueAccessor {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.renderer.setProperty(
|
||||
this.element.nativeElement,
|
||||
'disabled',
|
||||
isDisabled
|
||||
);
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.element.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
}
|
||||
45
angular/src/directives/icon.ts
Normal file
45
angular/src/directives/icon.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Directive, ElementRef, Input } from '@angular/core';
|
||||
import { inputs } from '../util/util';
|
||||
|
||||
|
||||
@Directive({ selector: 'ion-icon' })
|
||||
export class Icon {
|
||||
|
||||
/**
|
||||
* The color to use from your Sass `$colors` map.
|
||||
* Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`.
|
||||
* For more information, see [Theming your App](/docs/theming/theming-your-app).
|
||||
*/
|
||||
@Input() color: string;
|
||||
|
||||
/**
|
||||
* Specifies the label to use for accessibility. Defaults to the icon name.
|
||||
*/
|
||||
@Input() ariaLabel = '';
|
||||
|
||||
/**
|
||||
* Specifies which icon to use on `ios` mode.
|
||||
*/
|
||||
@Input() ios = '';
|
||||
|
||||
/**
|
||||
* Specifies which icon to use on `md` mode.
|
||||
*/
|
||||
@Input() md = '';
|
||||
|
||||
/**
|
||||
* Specifies which icon to use. The appropriate icon will be used based on the mode.
|
||||
* For more information, see [Ionicons](/docs/ionicons/).
|
||||
*/
|
||||
@Input() name = '';
|
||||
|
||||
/**
|
||||
* The size of the icon.
|
||||
* Available options are: `"small"` and `"large"`.
|
||||
*/
|
||||
@Input() size: string;
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
inputs(this, el, ['color', 'ariaLabel', 'ios', 'md', 'name', 'size']);
|
||||
}
|
||||
}
|
||||
21
angular/src/directives/index.ts
Normal file
21
angular/src/directives/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
export { BooleanValueAccessor } from './control-value-accessors/boolean-value-accessor';
|
||||
export { NumericValueAccessor } from './control-value-accessors/numeric-value-accesssor';
|
||||
export { RadioValueAccessor } from './control-value-accessors/radio-value-accessor';
|
||||
export { SelectValueAccessor } from './control-value-accessors/select-value-accessor';
|
||||
export { TextValueAccessor } from './control-value-accessors/text-value-accessor';
|
||||
|
||||
export { RouterDirection } from './navigation/router-direction';
|
||||
export { IonBackButton } from './navigation/ion-back-button';
|
||||
export { NavDelegate } from './navigation/nav-delegate';
|
||||
export { TabDelegate } from './navigation/tab-delegate';
|
||||
export { TabsDelegate } from './navigation/tabs-delegate';
|
||||
export { IonRouterOutlet } from './navigation/ion-router-outlet';
|
||||
export { HrefDelegate } from './navigation/href-delegate';
|
||||
export { NavParams } from './navigation/nav-params';
|
||||
|
||||
export { Icon } from './icon';
|
||||
export { VirtualScroll } from './virtual-scroll/virtual-scroll';
|
||||
export { VirtualItem } from './virtual-scroll/virtual-item';
|
||||
export { VirtualHeader } from './virtual-scroll/virtual-header';
|
||||
export { VirtualFooter } from './virtual-scroll/virtual-footer';
|
||||
30
angular/src/directives/navigation/href-delegate.ts
Normal file
30
angular/src/directives/navigation/href-delegate.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-anchor,ion-button,ion-item'
|
||||
})
|
||||
export class HrefDelegate {
|
||||
|
||||
@Input()
|
||||
set href(value: string) {
|
||||
this.elementRef.nativeElement.href = value;
|
||||
}
|
||||
get href() {
|
||||
return this.elementRef.nativeElement.href;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Optional() private router: Router,
|
||||
private elementRef: ElementRef
|
||||
) {}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(ev: Event) {
|
||||
const url = this.href;
|
||||
if (this.router && url != null && url[0] !== '#' && url.indexOf('://') === -1) {
|
||||
ev.preventDefault();
|
||||
this.router.navigateByUrl(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
angular/src/directives/navigation/ion-back-button.ts
Normal file
37
angular/src/directives/navigation/ion-back-button.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Directive, ElementRef, HostListener, Input, Optional } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NavController, NavIntent } from '../../providers/nav-controller';
|
||||
import { IonRouterOutlet } from './ion-router-outlet';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-back-button'
|
||||
})
|
||||
export class IonBackButton {
|
||||
|
||||
@Input()
|
||||
set defaultHref(value: string) {
|
||||
this.elementRef.nativeElement.defaultHref = value;
|
||||
}
|
||||
get defaultHref() {
|
||||
return this.elementRef.nativeElement.defaultHref;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Optional() private router: Router,
|
||||
@Optional() private routerOutlet: IonRouterOutlet,
|
||||
private navCtrl: NavController,
|
||||
private elementRef: ElementRef,
|
||||
) {}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(ev: Event) {
|
||||
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
|
||||
this.routerOutlet.pop();
|
||||
ev.preventDefault();
|
||||
} else if (this.router && this.defaultHref != null) {
|
||||
this.navCtrl.setIntent(NavIntent.Back);
|
||||
this.router.navigateByUrl(this.defaultHref);
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,42 @@
|
||||
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts } from '@angular/router';
|
||||
import * as ctrl from './router-controller';
|
||||
import { runTransition } from './router-transition';
|
||||
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, OnDestroy, OnInit, Optional, Output, ViewContainerRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET, Router } from '@angular/router';
|
||||
import { StackController } from './router-controller';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
import { bindLifecycleEvents } from '../../providers/angular-delegate';
|
||||
|
||||
|
||||
@Directive({selector: 'ion-router-outlet', exportAs: 'ionOutlet'})
|
||||
@Directive({
|
||||
selector: 'ion-router-outlet',
|
||||
exportAs: 'outlet'
|
||||
})
|
||||
export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
|
||||
private activated: ComponentRef<any>|null = null;
|
||||
|
||||
private _activatedRoute: ActivatedRoute|null = null;
|
||||
private name: string;
|
||||
|
||||
private views: ctrl.RouteView[] = [];
|
||||
private stackCtrl: StackController;
|
||||
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
constructor(
|
||||
private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef,
|
||||
private resolver: ComponentFactoryResolver, @Attribute('name') name: string,
|
||||
private changeDetector: ChangeDetectorRef) {
|
||||
this.name = name || 'primary';
|
||||
private parentContexts: ChildrenOutletContexts,
|
||||
private location: ViewContainerRef,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private elementRef: ElementRef,
|
||||
@Attribute('name') name: string,
|
||||
@Optional() @Attribute('stack') stack: any,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
private navCtrl: NavController,
|
||||
router: Router
|
||||
) {
|
||||
this.name = name || PRIMARY_OUTLET;
|
||||
parentContexts.onChildOutletCreated(this.name, this as any);
|
||||
const hasStack = stack !== 'false' || stack !== false;
|
||||
this.stackCtrl = new StackController(hasStack, elementRef.nativeElement, router, this.navCtrl);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
ctrl.destoryViews(this.views);
|
||||
this.parentContexts.onChildOutletDestroyed(this.name);
|
||||
}
|
||||
|
||||
@@ -48,12 +60,16 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
get isActivated(): boolean { return !!this.activated; }
|
||||
|
||||
get component(): Object {
|
||||
if (!this.activated) throw new Error('Outlet is not activated');
|
||||
if (!this.activated) {
|
||||
throw new Error('Outlet is not activated');
|
||||
}
|
||||
return this.activated.instance;
|
||||
}
|
||||
|
||||
get activatedRoute(): ActivatedRoute {
|
||||
if (!this.activated) throw new Error('Outlet is not activated');
|
||||
if (!this.activated) {
|
||||
throw new Error('Outlet is not activated');
|
||||
}
|
||||
return this._activatedRoute as ActivatedRoute;
|
||||
}
|
||||
|
||||
@@ -68,7 +84,9 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
* Called when the `RouteReuseStrategy` instructs to detach the subtree
|
||||
*/
|
||||
detach(): ComponentRef<any> {
|
||||
if (!this.activated) throw new Error('Outlet is not activated');
|
||||
if (!this.activated) {
|
||||
throw new Error('Outlet is not activated');
|
||||
}
|
||||
this.location.detach();
|
||||
const cmp = this.activated;
|
||||
this.activated = null;
|
||||
@@ -82,38 +100,29 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute) {
|
||||
this.activated = ref;
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
ctrl.attachView(this.views, this.location, ref, activatedRoute);
|
||||
this.location.insert(ref.hostView);
|
||||
}
|
||||
|
||||
deactivate(): void {
|
||||
if (this.activated) {
|
||||
const c = this.component;
|
||||
|
||||
ctrl.deactivateView(this.views, this.activated);
|
||||
|
||||
this.activated = null;
|
||||
this._activatedRoute = null;
|
||||
this.deactivateEvents.emit(c);
|
||||
}
|
||||
}
|
||||
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
|
||||
async activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
|
||||
if (this.isActivated) {
|
||||
throw new Error('Cannot activate an already activated outlet');
|
||||
}
|
||||
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
const existingView = ctrl.getExistingView(this.views, activatedRoute);
|
||||
if (existingView) {
|
||||
// we've already got a view hanging around
|
||||
this.activated = existingView.ref;
|
||||
|
||||
let enteringView = this.stackCtrl.getExistingView(activatedRoute);
|
||||
if (enteringView) {
|
||||
this.activated = enteringView.ref;
|
||||
} else {
|
||||
// haven't created this view yet
|
||||
const snapshot = (activatedRoute as any)._futureSnapshot;
|
||||
|
||||
const component = <any>snapshot.routeConfig !.component;
|
||||
resolver = resolver || this.resolver;
|
||||
|
||||
@@ -121,30 +130,47 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
|
||||
|
||||
const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
|
||||
this.activated = this.location.createComponent(factory, this.location.length, injector);
|
||||
const cmp = this.activated = this.location.createComponent(factory, this.location.length, injector);
|
||||
|
||||
// keep a ref
|
||||
ctrl.initRouteViewElm(this.views, this.activated, activatedRoute);
|
||||
bindLifecycleEvents(cmp.instance, cmp.location.nativeElement);
|
||||
|
||||
// Calling `markForCheck` to make sure we will run the change detection when the
|
||||
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
|
||||
this.changeDetector.markForCheck();
|
||||
enteringView = this.stackCtrl.createView(this.activated, activatedRoute);
|
||||
}
|
||||
|
||||
// Calling `markForCheck` to make sure we will run the change detection when the
|
||||
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
|
||||
this.changeDetector.markForCheck();
|
||||
const {direction, animated} = this.navCtrl.consumeTransition();
|
||||
await this.stackCtrl.setActive(enteringView, direction, animated);
|
||||
this.activateEvents.emit(this.activated.instance);
|
||||
|
||||
const lastDeactivatedRef = ctrl.getLastDeactivatedRef(this.views);
|
||||
emitEvent(this.elementRef.nativeElement);
|
||||
}
|
||||
|
||||
runTransition(this.activated, lastDeactivatedRef).then(() => {
|
||||
console.log('transition end');
|
||||
this.activateEvents.emit(this.activated.instance);
|
||||
});
|
||||
canGoBack(deep = 1) {
|
||||
return this.stackCtrl.canGoBack(deep);
|
||||
}
|
||||
|
||||
pop(deep = 1) {
|
||||
return this.stackCtrl.pop(deep);
|
||||
}
|
||||
}
|
||||
|
||||
function emitEvent(el: HTMLElement) {
|
||||
console.log('ionRouterOutletActivated');
|
||||
const event = new CustomEvent('ionRouterOutletActivated', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
el.dispatchEvent(event);
|
||||
}
|
||||
|
||||
class OutletInjector implements Injector {
|
||||
constructor(
|
||||
private route: ActivatedRoute, private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector) {}
|
||||
private route: ActivatedRoute,
|
||||
private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector
|
||||
) {}
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === ActivatedRoute) {
|
||||
17
angular/src/directives/navigation/nav-delegate.ts
Normal file
17
angular/src/directives/navigation/nav-delegate.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { ComponentFactoryResolver, Directive, ElementRef, Injector, ViewContainerRef } from '@angular/core';
|
||||
import { AngularDelegate } from '../../providers/angular-delegate';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-nav',
|
||||
})
|
||||
export class NavDelegate {
|
||||
constructor(
|
||||
ref: ElementRef,
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
angularDelegate: AngularDelegate,
|
||||
location: ViewContainerRef
|
||||
) {
|
||||
ref.nativeElement.delegate = angularDelegate.create(resolver, injector, location);
|
||||
}
|
||||
}
|
||||
45
angular/src/directives/navigation/nav-params.ts
Normal file
45
angular/src/directives/navigation/nav-params.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @name NavParams
|
||||
* @description
|
||||
* NavParams are an object that exists on a page and can contain data for that particular view.
|
||||
* Similar to how data was pass to a view in V1 with `$stateParams`, NavParams offer a much more flexible
|
||||
* option with a simple `get` method.
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* import { NavParams } from '@ionic/angular';
|
||||
*
|
||||
* export class MyClass{
|
||||
*
|
||||
* constructor(navParams: NavParams){
|
||||
* // userParams is an object we have in our nav-parameters
|
||||
* navParams.get('userParams');
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class NavParams {
|
||||
|
||||
constructor(public data: {[key: string]: any} = {}) {}
|
||||
|
||||
/**
|
||||
* Get the value of a nav-parameter for the current view
|
||||
*
|
||||
* ```ts
|
||||
* import { NavParams } from 'ionic-angular';
|
||||
*
|
||||
* export class MyClass{
|
||||
* constructor(public navParams: NavParams){
|
||||
* // userParams is an object we have in our nav-parameters
|
||||
* this.navParams.get('userParams');
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {string} param Which param you want to look up
|
||||
*/
|
||||
get(param: string): any {
|
||||
return this.data[param];
|
||||
}
|
||||
}
|
||||
147
angular/src/directives/navigation/router-controller.ts
Normal file
147
angular/src/directives/navigation/router-controller.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { ComponentRef } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { NavDirection } from '@ionic/core';
|
||||
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
|
||||
export class StackController {
|
||||
|
||||
private viewsSnapshot: RouteView[] = [];
|
||||
private views: RouteView[] = [];
|
||||
|
||||
constructor(
|
||||
private stack: boolean,
|
||||
private containerEl: HTMLIonRouterOutletElement,
|
||||
private router: Router,
|
||||
private navCtrl: NavController,
|
||||
) {}
|
||||
|
||||
createView(enteringRef: ComponentRef<any>, route: ActivatedRoute): RouteView {
|
||||
return {
|
||||
ref: enteringRef,
|
||||
element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement,
|
||||
url: this.getUrl(route),
|
||||
deactivatedId: -1
|
||||
};
|
||||
}
|
||||
|
||||
getExistingView(activatedRoute: ActivatedRoute): RouteView|null {
|
||||
const activatedUrlKey = this.getUrl(activatedRoute);
|
||||
return this.views.find(vw => vw.url === activatedUrlKey);
|
||||
}
|
||||
|
||||
canGoBack(deep: number): boolean {
|
||||
return this.views.length > deep;
|
||||
}
|
||||
|
||||
async setActive(enteringView: RouteView, direction: number, animated: boolean) {
|
||||
const leavingView = this.getActive();
|
||||
this.insertView(enteringView, direction);
|
||||
await this.transition(enteringView, leavingView, direction, animated, this.canGoBack(1));
|
||||
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
pop(deep: number) {
|
||||
const view = this.views[this.views.length - deep - 1];
|
||||
this.navCtrl.goBack(view.url);
|
||||
}
|
||||
|
||||
private insertView(enteringView: RouteView, direction: number) {
|
||||
// no stack
|
||||
if (!this.stack) {
|
||||
this.views = [enteringView];
|
||||
return;
|
||||
}
|
||||
|
||||
// stack setRoot
|
||||
if (direction === 0) {
|
||||
this.views = [enteringView];
|
||||
return;
|
||||
}
|
||||
|
||||
// stack
|
||||
const index = this.views.indexOf(enteringView);
|
||||
if (index >= 0) {
|
||||
this.views = this.views.slice(0, index + 1);
|
||||
} else {
|
||||
if (direction === 1) {
|
||||
this.views.push(enteringView);
|
||||
} else {
|
||||
this.views = [enteringView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private cleanup() {
|
||||
this.viewsSnapshot
|
||||
.filter(view => !this.views.includes(view))
|
||||
.forEach(view => destroyView(view));
|
||||
|
||||
for (let i = 0; i < this.views.length - 1; i++) {
|
||||
this.views[i].element.hidden = true;
|
||||
}
|
||||
this.viewsSnapshot = this.views.slice();
|
||||
}
|
||||
|
||||
getActive(): RouteView | null {
|
||||
return this.views.length > 0 ? this.views[this.views.length - 1] : null;
|
||||
}
|
||||
|
||||
private async transition(
|
||||
enteringView: RouteView,
|
||||
leavingView: RouteView,
|
||||
direction: number,
|
||||
animated: boolean,
|
||||
showGoBack: boolean
|
||||
) {
|
||||
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', 'hide-page');
|
||||
containerEl.appendChild(enteringEl);
|
||||
|
||||
await containerEl.componentOnReady();
|
||||
await containerEl.commit(enteringEl, leavingEl, {
|
||||
duration: !animated ? 0 : undefined,
|
||||
direction: direction === 1 ? NavDirection.Forward : NavDirection.Back,
|
||||
deepWait: true,
|
||||
showGoBack
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getUrl(activatedRoute: ActivatedRoute) {
|
||||
const urlTree = this.router.createUrlTree(['.'], { relativeTo: activatedRoute });
|
||||
return this.router.serializeUrl(urlTree);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function destroyView(view: RouteView) {
|
||||
if (view) {
|
||||
// TODO lifecycle event
|
||||
view.ref.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export function getLastDeactivatedRef(views: RouteView[]) {
|
||||
if (views.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return views.sort((a, b) => {
|
||||
if (a.deactivatedId > b.deactivatedId) return -1;
|
||||
if (a.deactivatedId < b.deactivatedId) return 1;
|
||||
return 0;
|
||||
})[0].ref;
|
||||
}
|
||||
|
||||
export interface RouteView {
|
||||
url: string;
|
||||
element: HTMLElement;
|
||||
ref: ComponentRef<any>;
|
||||
deactivatedId: number;
|
||||
}
|
||||
28
angular/src/directives/navigation/router-direction.ts
Normal file
28
angular/src/directives/navigation/router-direction.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Directive, HostListener, Input } from '@angular/core';
|
||||
import { NavController, NavIntent } from '../../providers/nav-controller';
|
||||
|
||||
@Directive({
|
||||
selector: '[routerDirection]',
|
||||
})
|
||||
export class RouterDirection {
|
||||
|
||||
@Input() routerDirection: string;
|
||||
|
||||
constructor(
|
||||
private navCtrl: NavController,
|
||||
) {}
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.navCtrl.setIntent(textToIntent(this.routerDirection));
|
||||
}
|
||||
}
|
||||
|
||||
function textToIntent(direction: string) {
|
||||
switch (direction) {
|
||||
case 'forward': return NavIntent.Forward;
|
||||
case 'back': return NavIntent.Back;
|
||||
case 'root': return NavIntent.Root;
|
||||
default: return NavIntent.Auto;
|
||||
}
|
||||
}
|
||||
32
angular/src/directives/navigation/tab-delegate.ts
Normal file
32
angular/src/directives/navigation/tab-delegate.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ComponentFactoryResolver, Directive, ElementRef, HostListener, Injector, ViewContainerRef } from '@angular/core';
|
||||
import { AngularDelegate } from '../../providers/angular-delegate';
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-tab'
|
||||
})
|
||||
export class TabDelegate {
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
angularDelegate: AngularDelegate,
|
||||
location: ViewContainerRef
|
||||
) {
|
||||
elementRef.nativeElement.delegate = angularDelegate.create(resolver, injector, location);
|
||||
}
|
||||
|
||||
@HostListener('ionRouterOutletActivated', ['$event'])
|
||||
async onNavChanged() {
|
||||
const tab = this.elementRef.nativeElement as HTMLIonTabElement;
|
||||
await tab.componentOnReady();
|
||||
const tabs = tab.closest('ion-tabs');
|
||||
if (tabs) {
|
||||
await tabs.componentOnReady();
|
||||
await tabs.select(tab);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
angular/src/directives/navigation/tabs-delegate.ts
Normal file
25
angular/src/directives/navigation/tabs-delegate.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-tabs'
|
||||
})
|
||||
export class TabsDelegate {
|
||||
|
||||
constructor(
|
||||
@Optional() private router: Router,
|
||||
elementRef: ElementRef
|
||||
) {
|
||||
if (router) {
|
||||
elementRef.nativeElement.useRouter = true;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('ionTabbarClick', ['$event'])
|
||||
onTabbarClick(ev: UIEvent) {
|
||||
const tabElm: HTMLIonTabElement = ev.detail as any;
|
||||
if (this.router && tabElm && tabElm.href) {
|
||||
this.router.navigateByUrl(tabElm.href);
|
||||
}
|
||||
}
|
||||
}
|
||||
79
angular/src/directives/proxies-list.txt
Normal file
79
angular/src/directives/proxies-list.txt
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
import * as d from './proxies';
|
||||
|
||||
export const DIRECTIVES = [
|
||||
d.App,
|
||||
d.Avatar,
|
||||
d.BackButton,
|
||||
d.Badge,
|
||||
d.Button,
|
||||
d.Buttons,
|
||||
d.Card,
|
||||
d.CardContent,
|
||||
d.CardHeader,
|
||||
d.CardSubtitle,
|
||||
d.CardTitle,
|
||||
d.Checkbox,
|
||||
d.Chip,
|
||||
d.ChipButton,
|
||||
d.Col,
|
||||
d.Content,
|
||||
d.Datetime,
|
||||
d.Fab,
|
||||
d.FabButton,
|
||||
d.FabList,
|
||||
d.Footer,
|
||||
d.Grid,
|
||||
d.Header,
|
||||
d.HideWhen,
|
||||
d.InfiniteScroll,
|
||||
d.InfiniteScrollContent,
|
||||
d.Input,
|
||||
d.Item,
|
||||
d.ItemDivider,
|
||||
d.ItemGroup,
|
||||
d.ItemOption,
|
||||
d.ItemOptions,
|
||||
d.ItemSliding,
|
||||
d.Label,
|
||||
d.List,
|
||||
d.ListHeader,
|
||||
d.Menu,
|
||||
d.MenuButton,
|
||||
d.MenuToggle,
|
||||
d.Nav,
|
||||
d.NavPop,
|
||||
d.NavPush,
|
||||
d.NavSetRoot,
|
||||
d.Note,
|
||||
d.Radio,
|
||||
d.RadioGroup,
|
||||
d.Range,
|
||||
d.Refresher,
|
||||
d.RefresherContent,
|
||||
d.Reorder,
|
||||
d.ReorderGroup,
|
||||
d.RippleEffect,
|
||||
d.Row,
|
||||
d.Scroll,
|
||||
d.Searchbar,
|
||||
d.Segment,
|
||||
d.SegmentButton,
|
||||
d.Select,
|
||||
d.SelectOption,
|
||||
d.SelectPopover,
|
||||
d.ShowWhen,
|
||||
d.SkeletonText,
|
||||
d.Slide,
|
||||
d.Slides,
|
||||
d.Spinner,
|
||||
d.SplitPane,
|
||||
d.Tab,
|
||||
d.Tabs,
|
||||
d.Text,
|
||||
d.Textarea,
|
||||
d.Thumbnail,
|
||||
d.Toggle,
|
||||
d.Toolbar,
|
||||
d.ToolbarTitle
|
||||
];
|
||||
714
angular/src/directives/proxies.ts
Normal file
714
angular/src/directives/proxies.ts
Normal file
File diff suppressed because one or more lines are too long
20
angular/src/index.ts
Normal file
20
angular/src/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// export module
|
||||
export { IonicModule } from './module';
|
||||
|
||||
// export auto generated directive
|
||||
export * from './directives/proxies';
|
||||
|
||||
// export custom directives
|
||||
export * from './directives';
|
||||
|
||||
// export custom providers
|
||||
export * from './providers';
|
||||
|
||||
// ionic types
|
||||
export * from './types/interfaces';
|
||||
|
||||
// ionic oute reuse strategy
|
||||
export * from './util/ionic-router-reuse-strategy';
|
||||
|
||||
/*tslint:disable*/
|
||||
import './ionic-angular';
|
||||
32
angular/src/ionic-angular.ts
Normal file
32
angular/src/ionic-angular.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*tslint:disable*/
|
||||
import './ionic';
|
||||
import { IonicWindow } from './types/interfaces';
|
||||
|
||||
const win = (window as IonicWindow);
|
||||
const Ionic = win.Ionic;
|
||||
|
||||
if (Ionic) {
|
||||
Ionic.ael = function ngAddEventListener(elm, eventName, cb, opts) {
|
||||
if (elm.__zone_symbol__addEventListener) {
|
||||
elm.__zone_symbol__addEventListener(eventName, cb, opts);
|
||||
} else {
|
||||
elm.addEventListener(eventName, cb, opts);
|
||||
}
|
||||
};
|
||||
|
||||
Ionic.rel = function ngRemoveEventListener(elm, eventName, cb, opts) {
|
||||
if (elm.__zone_symbol__removeEventListener) {
|
||||
elm.__zone_symbol__removeEventListener(eventName, cb, opts);
|
||||
} else {
|
||||
elm.removeEventListener(eventName, cb, opts);
|
||||
}
|
||||
};
|
||||
|
||||
Ionic.raf = function ngRequestAnimationFrame(cb: any) {
|
||||
if (win.__zone_symbol__requestAnimationFrame) {
|
||||
win.__zone_symbol__requestAnimationFrame(cb);
|
||||
} else {
|
||||
win.requestAnimationFrame(cb);
|
||||
}
|
||||
};
|
||||
}
|
||||
3
angular/src/ionic.ts
Normal file
3
angular/src/ionic.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
// placeholder for ionic loader js
|
||||
// created by the stencil build process
|
||||
156
angular/src/module.ts
Normal file
156
angular/src/module.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import * as c from './directives';
|
||||
import * as d from './directives/proxies';
|
||||
import * as p from './providers';
|
||||
|
||||
|
||||
const DECLARATIONS = [
|
||||
// proxies
|
||||
d.App,
|
||||
d.Avatar,
|
||||
d.BackButton,
|
||||
d.Badge,
|
||||
d.Button,
|
||||
d.Buttons,
|
||||
d.Card,
|
||||
d.CardContent,
|
||||
d.CardHeader,
|
||||
d.CardSubtitle,
|
||||
d.CardTitle,
|
||||
d.Checkbox,
|
||||
d.Chip,
|
||||
d.ChipButton,
|
||||
d.Col,
|
||||
d.Content,
|
||||
d.Datetime,
|
||||
d.Fab,
|
||||
d.FabButton,
|
||||
d.FabList,
|
||||
d.Footer,
|
||||
d.Grid,
|
||||
d.Header,
|
||||
d.HideWhen,
|
||||
d.InfiniteScroll,
|
||||
d.InfiniteScrollContent,
|
||||
d.Input,
|
||||
d.Item,
|
||||
d.ItemDivider,
|
||||
d.ItemGroup,
|
||||
d.ItemOption,
|
||||
d.ItemOptions,
|
||||
d.ItemSliding,
|
||||
d.Label,
|
||||
d.List,
|
||||
d.ListHeader,
|
||||
d.Menu,
|
||||
d.MenuButton,
|
||||
d.MenuToggle,
|
||||
d.Nav,
|
||||
d.NavPop,
|
||||
d.NavPush,
|
||||
d.NavSetRoot,
|
||||
d.Note,
|
||||
d.Radio,
|
||||
d.RadioGroup,
|
||||
d.Range,
|
||||
d.Refresher,
|
||||
d.RefresherContent,
|
||||
d.Reorder,
|
||||
d.ReorderGroup,
|
||||
d.RippleEffect,
|
||||
d.Row,
|
||||
d.Scroll,
|
||||
d.Searchbar,
|
||||
d.Segment,
|
||||
d.SegmentButton,
|
||||
d.Select,
|
||||
d.SelectOption,
|
||||
d.SelectPopover,
|
||||
d.ShowWhen,
|
||||
d.SkeletonText,
|
||||
d.Slide,
|
||||
d.Slides,
|
||||
d.Spinner,
|
||||
d.SplitPane,
|
||||
d.Tab,
|
||||
d.Tabs,
|
||||
d.Text,
|
||||
d.Textarea,
|
||||
d.Thumbnail,
|
||||
d.Toggle,
|
||||
d.Toolbar,
|
||||
d.ToolbarTitle,
|
||||
|
||||
// custom proxy
|
||||
c.Icon,
|
||||
|
||||
// ngModel accessors
|
||||
c.BooleanValueAccessor,
|
||||
c.NumericValueAccessor,
|
||||
c.RadioValueAccessor,
|
||||
c.SelectValueAccessor,
|
||||
c.TextValueAccessor,
|
||||
|
||||
// navigation
|
||||
c.IonBackButton,
|
||||
c.IonRouterOutlet,
|
||||
c.RouterDirection,
|
||||
c.NavDelegate,
|
||||
c.TabDelegate,
|
||||
c.TabsDelegate,
|
||||
c.HrefDelegate,
|
||||
|
||||
// virtual scroll
|
||||
c.VirtualFooter,
|
||||
c.VirtualHeader,
|
||||
c.VirtualItem,
|
||||
c.VirtualScroll,
|
||||
];
|
||||
|
||||
const PROVIDERS = [
|
||||
p.ActionSheetController,
|
||||
p.AlertController,
|
||||
p.LoadingController,
|
||||
p.PickerController,
|
||||
p.ToastController,
|
||||
p.MenuController,
|
||||
p.NavController,
|
||||
p.Platform,
|
||||
p.Events,
|
||||
p.DomController,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: DECLARATIONS,
|
||||
exports: DECLARATIONS,
|
||||
providers: [
|
||||
p.AngularDelegate,
|
||||
p.ModalController,
|
||||
p.PopoverController,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
]
|
||||
})
|
||||
export class IonicModule {
|
||||
static forRoot(config?: {[key: string]: any}): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: IonicModule,
|
||||
providers: [
|
||||
// Load config with defualt values
|
||||
{ provide: ConfigToken, useValue: config },
|
||||
{ provide: p.Config, useFactory: setupConfig, deps: [ ConfigToken ] },
|
||||
|
||||
...PROVIDERS,
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const ConfigToken = new InjectionToken<any>('USERCONFIG');
|
||||
export function setupConfig(userConfig: any): p.Config {
|
||||
const config = new p.Config(userConfig);
|
||||
return config;
|
||||
}
|
||||
10
angular/src/providers/action-sheet-controller.ts
Normal file
10
angular/src/providers/action-sheet-controller.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionSheetOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@Injectable()
|
||||
export class ActionSheetController extends OverlayBaseController<ActionSheetOptions, HTMLIonActionSheetElement> {
|
||||
constructor() {
|
||||
super('ion-action-sheet-controller');
|
||||
}
|
||||
}
|
||||
10
angular/src/providers/alert-controller.ts
Normal file
10
angular/src/providers/alert-controller.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AlertOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@Injectable()
|
||||
export class AlertController extends OverlayBaseController<AlertOptions, HTMLIonAlertElement> {
|
||||
constructor() {
|
||||
super('ion-alert-controller');
|
||||
}
|
||||
}
|
||||
129
angular/src/providers/angular-delegate.ts
Normal file
129
angular/src/providers/angular-delegate.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
|
||||
import { FrameworkDelegate, ViewLifecycle } from '@ionic/core';
|
||||
import { NavParams } from '../directives/navigation/nav-params';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AngularDelegate {
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private appRef: ApplicationRef
|
||||
) {}
|
||||
|
||||
create(
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
location?: ViewContainerRef,
|
||||
) {
|
||||
return new AngularFrameworkDelegate(resolver, injector, location, this.appRef, this.zone);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
|
||||
private elRefMap = new WeakMap<HTMLElement, any>();
|
||||
|
||||
constructor(
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
private location: ViewContainerRef,
|
||||
private appRef: ApplicationRef,
|
||||
private zone: NgZone,
|
||||
) {}
|
||||
|
||||
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
this.zone.run(() => {
|
||||
const el = attachView(
|
||||
this.resolver, this.injector, this.location, this.appRef, this.elRefMap,
|
||||
container, component, params, cssClasses
|
||||
);
|
||||
resolve(el);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(_container: any, component: any): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
this.zone.run(() => {
|
||||
const componentRef = this.elRefMap.get(component);
|
||||
if (componentRef) {
|
||||
componentRef.destroy();
|
||||
this.elRefMap.delete(component);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function attachView(
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
location: ViewContainerRef|undefined,
|
||||
appRef: ApplicationRef,
|
||||
elRefMap: WeakMap<HTMLElement, any>,
|
||||
container: any, component: any, params: any, cssClasses: string[]
|
||||
) {
|
||||
const factory = resolver.resolveComponentFactory(component);
|
||||
const childInjector = Injector.create(getProviders(params), injector);
|
||||
const componentRef = (location)
|
||||
? location.createComponent(factory, location.length, childInjector)
|
||||
: factory.create(childInjector);
|
||||
|
||||
const hostElement = componentRef.location.nativeElement;
|
||||
if (params) {
|
||||
Object.assign(hostElement, params);
|
||||
}
|
||||
for (const clazz of cssClasses) {
|
||||
hostElement.classList.add(clazz);
|
||||
}
|
||||
bindLifecycleEvents(componentRef.instance, hostElement);
|
||||
container.appendChild(hostElement);
|
||||
|
||||
if (!location) {
|
||||
appRef.attachView(componentRef.hostView);
|
||||
}
|
||||
|
||||
componentRef.changeDetectorRef.reattach();
|
||||
elRefMap.set(hostElement, componentRef);
|
||||
return hostElement;
|
||||
}
|
||||
|
||||
const LIFECYCLES = [
|
||||
ViewLifecycle.WillEnter,
|
||||
ViewLifecycle.DidEnter,
|
||||
ViewLifecycle.WillLeave,
|
||||
ViewLifecycle.DidLeave,
|
||||
ViewLifecycle.WillUnload
|
||||
];
|
||||
|
||||
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
|
||||
LIFECYCLES.forEach(eventName => {
|
||||
element.addEventListener(eventName, (ev: CustomEvent) => {
|
||||
if (typeof instance[eventName] === 'function') {
|
||||
instance[eventName](ev.detail);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
|
||||
|
||||
|
||||
function getProviders(params: {[key: string]: any}) {
|
||||
return [
|
||||
{
|
||||
provide: NavParamsToken, useValue: params
|
||||
},
|
||||
{
|
||||
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function provideNavParamsInjectable(params: {[key: string]: any}) {
|
||||
return new NavParams(params);
|
||||
}
|
||||
40
angular/src/providers/config.ts
Normal file
40
angular/src/providers/config.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Config as CoreConfig } from '@ionic/core';
|
||||
|
||||
export class Config {
|
||||
|
||||
constructor(defaultConfig: {[key: string]: any}) {
|
||||
const Ionic = (window as any).Ionic;
|
||||
if (Ionic.config && Ionic.config.constructor.name !== 'Object') {
|
||||
console.error('ionic config was already initialized');
|
||||
return;
|
||||
}
|
||||
Ionic.config = {
|
||||
...Ionic.config,
|
||||
...defaultConfig
|
||||
};
|
||||
}
|
||||
|
||||
get(key: string, fallback?: any): any {
|
||||
return getConfig().get(key, fallback);
|
||||
}
|
||||
|
||||
getBoolean(key: string, fallback?: boolean): boolean {
|
||||
return getConfig().getBoolean(key, fallback);
|
||||
}
|
||||
|
||||
getNumber(key: string, fallback?: number): number {
|
||||
return getConfig().getNumber(key, fallback);
|
||||
}
|
||||
|
||||
set(key: string, value?: any) {
|
||||
getConfig().set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
function getConfig(): CoreConfig {
|
||||
const Ionic = (window as any).Ionic;
|
||||
if (Ionic && Ionic.config) {
|
||||
return Ionic.config;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
27
angular/src/providers/dom-controller.ts
Normal file
27
angular/src/providers/dom-controller.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class DomController {
|
||||
|
||||
read(cb: RafCallback) {
|
||||
getQueue().read(cb);
|
||||
}
|
||||
|
||||
write(cb: RafCallback) {
|
||||
getQueue().write(cb);
|
||||
}
|
||||
}
|
||||
|
||||
function getQueue() {
|
||||
const Ionic = (window as any).Ionic;
|
||||
if (Ionic && Ionic.queue) {
|
||||
return Ionic.queue;
|
||||
}
|
||||
|
||||
return {
|
||||
read: (cb: any) => window.requestAnimationFrame(cb),
|
||||
write: (cb: any) => window.requestAnimationFrame(cb)
|
||||
};
|
||||
}
|
||||
|
||||
export type RafCallback = { (timeStamp?: number): void };
|
||||
15
angular/src/providers/index.ts
Normal file
15
angular/src/providers/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export { AngularDelegate } from './angular-delegate';
|
||||
export { ActionSheetController } from './action-sheet-controller';
|
||||
export { AlertController } from './alert-controller';
|
||||
export { Events } from './events';
|
||||
export { LoadingController } from './loading-controller';
|
||||
export { MenuController } from './menu-controller';
|
||||
export { PickerController } from './picker-controller';
|
||||
export { ModalController } from './modal-controller';
|
||||
export { Platform } from './platform';
|
||||
export { PopoverController } from './popover-controller';
|
||||
export { ToastController } from './toast-controller';
|
||||
export { NavController } from './nav-controller';
|
||||
export { DomController } from './dom-controller';
|
||||
export { Config } from './config';
|
||||
10
angular/src/providers/loading-controller.ts
Normal file
10
angular/src/providers/loading-controller.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { LoadingOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@Injectable()
|
||||
export class LoadingController extends OverlayBaseController<LoadingOptions, HTMLIonLoadingElement> {
|
||||
constructor() {
|
||||
super('ion-loading-controller');
|
||||
}
|
||||
}
|
||||
104
angular/src/providers/menu-controller.ts
Normal file
104
angular/src/providers/menu-controller.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { proxyMethod } from '../util/util';
|
||||
|
||||
const CTRL = 'ion-menu-controller';
|
||||
@Injectable()
|
||||
export class MenuController {
|
||||
|
||||
/**
|
||||
* Programatically open the Menu.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {Promise} returns a promise when the menu is fully opened
|
||||
*/
|
||||
open(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, 'open', menuId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Programatically close the Menu. If no `menuId` is given as the first
|
||||
* argument then it'll close any menu which is open. If a `menuId`
|
||||
* is given then it'll close that exact menu.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {Promise} returns a promise when the menu is fully closed
|
||||
*/
|
||||
close(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, 'close', menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the menu. If it's closed, it will open, and if opened, it
|
||||
* will close.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {Promise} returns a promise when the menu has been toggled
|
||||
*/
|
||||
toggle(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, 'toggle', menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable or disable a menu. For example, there could be multiple
|
||||
* left menus, but only one of them should be able to be opened at the same
|
||||
* time. If there are multiple menus on the same side, then enabling one menu
|
||||
* will also automatically disable all the others that are on the same side.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, 'enable', shouldEnable, menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable or disable the ability to swipe open the menu.
|
||||
* @param {boolean} shouldEnable True if it should be swipe-able, false if not.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, 'swipeEnable', shouldEnable, menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {boolean} 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, 'isOpen', menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {boolean} Returns true if the menu is currently enabled, otherwise false.
|
||||
*/
|
||||
isEnabled(menuId?: string): Promise<boolean> {
|
||||
return proxyMethod(CTRL, 'isEnabled', menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get a menu instance. If a `menuId` is not provided then it'll
|
||||
* return the first menu found. If a `menuId` is `left` or `right`, then
|
||||
* it'll return the enabled menu on that side. Otherwise, if a `menuId` is
|
||||
* provided, then it'll try to find the menu using the menu's `id`
|
||||
* property. If a menu is not found then it'll return `null`.
|
||||
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||
* @return {HTMLIonMenuElement} Returns the instance of the menu if found, otherwise `null`.
|
||||
*/
|
||||
get(menuId?: string): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, 'get', menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Menu} Returns the instance of the menu already opened, otherwise `null`.
|
||||
*/
|
||||
getOpen(): Promise<HTMLIonMenuElement> {
|
||||
return proxyMethod(CTRL, 'getOpen');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array<HTMLIonMenuElement>} Returns an array of all menu instances.
|
||||
*/
|
||||
getMenus(): Promise<HTMLIonMenuElement[]> {
|
||||
return proxyMethod(CTRL, 'getMenus');
|
||||
}
|
||||
}
|
||||
23
angular/src/providers/modal-controller.ts
Normal file
23
angular/src/providers/modal-controller.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
import { AngularDelegate } from './angular-delegate';
|
||||
|
||||
@Injectable()
|
||||
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
|
||||
|
||||
constructor(
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
) {
|
||||
super('ion-modal-controller');
|
||||
}
|
||||
|
||||
create(opts?: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
return super.create({
|
||||
...opts,
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector)
|
||||
});
|
||||
}
|
||||
}
|
||||
85
angular/src/providers/nav-controller.ts
Normal file
85
angular/src/providers/nav-controller.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
import { NavigationExtras, Router, UrlTree } from '@angular/router';
|
||||
|
||||
export const enum NavIntent {
|
||||
Auto,
|
||||
Forward,
|
||||
Back,
|
||||
Root
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class NavController {
|
||||
|
||||
private intent: NavIntent = NavIntent.Auto;
|
||||
private animated = true;
|
||||
private stack: string[] = [];
|
||||
|
||||
constructor(
|
||||
@Optional() private router?: Router
|
||||
) {}
|
||||
|
||||
goForward(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
|
||||
this.setIntent(NavIntent.Forward, animated);
|
||||
return this.router.navigateByUrl(url, extras);
|
||||
}
|
||||
|
||||
goBack(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
|
||||
this.setIntent(NavIntent.Back, animated);
|
||||
return this.router.navigateByUrl(url, extras);
|
||||
}
|
||||
|
||||
goRoot(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
|
||||
this.setIntent(NavIntent.Root, animated);
|
||||
return this.router.navigateByUrl(url, extras);
|
||||
}
|
||||
|
||||
setIntent(intent: NavIntent, animated?: boolean) {
|
||||
this.intent = intent;
|
||||
this.animated = (animated === undefined)
|
||||
? intent !== NavIntent.Root
|
||||
: animated;
|
||||
}
|
||||
|
||||
consumeTransition() {
|
||||
const guessDirection = this.guessDirection();
|
||||
|
||||
let direction = 0;
|
||||
let animated = false;
|
||||
|
||||
if (this.intent === NavIntent.Auto) {
|
||||
direction = guessDirection;
|
||||
animated = direction !== 0;
|
||||
} else {
|
||||
animated = this.animated;
|
||||
direction = intentToDirection(this.intent);
|
||||
}
|
||||
this.intent = NavIntent.Auto;
|
||||
this.animated = true;
|
||||
|
||||
return {
|
||||
direction,
|
||||
animated
|
||||
};
|
||||
}
|
||||
|
||||
private guessDirection() {
|
||||
const index = this.stack.indexOf(document.location.href);
|
||||
if (index === -1) {
|
||||
this.stack.push(document.location.href);
|
||||
return 1;
|
||||
} else if (index < this.stack.length - 1) {
|
||||
this.stack = this.stack.slice(0, index + 1);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function intentToDirection(intent: NavIntent): number {
|
||||
switch (intent) {
|
||||
case NavIntent.Forward: return 1;
|
||||
case NavIntent.Back: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
10
angular/src/providers/picker-controller.ts
Normal file
10
angular/src/providers/picker-controller.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PickerOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@Injectable()
|
||||
export class PickerController extends OverlayBaseController<PickerOptions, HTMLIonPickerElement> {
|
||||
constructor() {
|
||||
super('ion-picker-controller');
|
||||
}
|
||||
}
|
||||
199
angular/src/providers/platform.ts
Normal file
199
angular/src/providers/platform.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { proxyEvent } from '../util/util';
|
||||
|
||||
export interface PlatformConfig {
|
||||
name: string;
|
||||
isMatch: (win: Window) => boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class Platform {
|
||||
|
||||
private _platforms: PlatformConfig[] = [];
|
||||
private _readyPromise: Promise<any>;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
backButton = new EventEmitter<Event>();
|
||||
|
||||
/**
|
||||
* The pause event emits when the native platform puts the application
|
||||
* into the background, typically when the user switches to a different
|
||||
* application. This event would emit when a Cordova app is put into
|
||||
* the background, however, it would not fire on a standard web browser.
|
||||
*/
|
||||
pause = new EventEmitter<Event>();
|
||||
|
||||
/**
|
||||
* The resume event emits when the native platform pulls the application
|
||||
* out from the background. This event would emit when a Cordova app comes
|
||||
* out from the background, however, it would not fire on a standard web browser.
|
||||
*/
|
||||
resume = new EventEmitter<Event>();
|
||||
|
||||
/**
|
||||
* The resize event emits when the browser window has changed dimensions. This
|
||||
* could be from a browser window being physically resized, or from a device
|
||||
* changing orientation.
|
||||
*/
|
||||
resize = new EventEmitter<Event>();
|
||||
|
||||
constructor() {
|
||||
|
||||
proxyEvent(this.pause, document, 'pause');
|
||||
proxyEvent(this.resume, document, 'resume');
|
||||
proxyEvent(this.backButton, document, 'backbutton');
|
||||
proxyEvent(this.resize, document, 'resize');
|
||||
|
||||
let readyResolve: Function;
|
||||
this._readyPromise = new Promise(res => { readyResolve = res; } );
|
||||
if ((window as any)['cordova']) {
|
||||
window.addEventListener('deviceready', () => {
|
||||
readyResolve();
|
||||
});
|
||||
} else {
|
||||
readyResolve();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} returns true/false based on platform.
|
||||
* @description
|
||||
* Depending on the platform the user is on, `is(platformName)` will
|
||||
* return `true` or `false`. Note that the same app can return `true`
|
||||
* for more than one platform name. For example, an app running from
|
||||
* an iPad would return `true` for the platform names: `mobile`,
|
||||
* `ios`, `ipad`, and `tablet`. Additionally, if the app was running
|
||||
* from Cordova then `cordova` would be true, and if it was running
|
||||
* from a web browser on the iPad then `mobileweb` would be `true`.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* if (this.platform.is('ios')) {
|
||||
* // This will only print when on iOS
|
||||
* console.log('I am an iOS device!');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* | Platform Name | Description |
|
||||
* |-----------------|------------------------------------|
|
||||
* | android | on a device running Android. |
|
||||
* | cordova | on a device running Cordova. |
|
||||
* | core | on a desktop device. |
|
||||
* | ios | on a device running iOS. |
|
||||
* | ipad | on an iPad device. |
|
||||
* | iphone | on an iPhone device. |
|
||||
* | mobile | on a mobile device. |
|
||||
* | mobileweb | in a browser on a mobile device. |
|
||||
* | phablet | on a phablet device. |
|
||||
* | tablet | on a tablet device. |
|
||||
* | windows | on a device running Windows. |
|
||||
* | electron | in Electron on a desktop device. |
|
||||
*
|
||||
* @param {string} platformName
|
||||
*/
|
||||
is(platformName: string): boolean {
|
||||
return this._platforms.some(p => p.name === platformName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {array} the array of platforms
|
||||
* @description
|
||||
* Depending on what device you are on, `platforms` can return multiple values.
|
||||
* Each possible value is a hierarchy of platforms. For example, on an iPhone,
|
||||
* it would return `mobile`, `ios`, and `iphone`.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* // This will print an array of the current platforms
|
||||
* console.log(this.platform.platforms());
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
platforms(): string[] {
|
||||
return this._platforms.map(platform => platform.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing version information about all of the platforms.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* // This will print an object containing
|
||||
* // all of the platforms and their versions
|
||||
* console.log(platform.versions());
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @returns {object} An object containing all of the platforms and their versions.
|
||||
*/
|
||||
versions(): PlatformConfig[] {
|
||||
return this._platforms.slice();
|
||||
}
|
||||
|
||||
|
||||
ready(): Promise<void> {
|
||||
return this._readyPromise;
|
||||
}
|
||||
|
||||
get isRTL(): boolean {
|
||||
return document.dir === 'rtl';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the query string parameter
|
||||
*/
|
||||
getQueryParam(key: string): string {
|
||||
return readQueryParam(window.location.href, key);
|
||||
}
|
||||
|
||||
isLandscape(): boolean {
|
||||
return !this.isPortrait();
|
||||
}
|
||||
|
||||
isPortrait(): boolean {
|
||||
return window.matchMedia('(orientation: portrait)').matches;
|
||||
}
|
||||
|
||||
testUserAgent(expression: string): boolean {
|
||||
return navigator.userAgent.indexOf(expression) >= 0;
|
||||
}
|
||||
|
||||
url() {
|
||||
return window.location.href;
|
||||
}
|
||||
|
||||
width() {
|
||||
return window.innerWidth;
|
||||
}
|
||||
|
||||
height(): number {
|
||||
return window.innerHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function readQueryParam(url: string, key: string) {
|
||||
key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
|
||||
const results = regex.exec(url);
|
||||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
|
||||
}
|
||||
23
angular/src/providers/popover-controller.ts
Normal file
23
angular/src/providers/popover-controller.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { PopoverOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
import { AngularDelegate } from './angular-delegate';
|
||||
|
||||
@Injectable()
|
||||
export class PopoverController extends OverlayBaseController<PopoverOptions, HTMLIonPopoverElement> {
|
||||
|
||||
constructor(
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
) {
|
||||
super('ion-popover-controller');
|
||||
}
|
||||
|
||||
create(opts?: PopoverOptions): Promise<HTMLIonPopoverElement> {
|
||||
return super.create({
|
||||
...opts,
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector)
|
||||
});
|
||||
}
|
||||
}
|
||||
10
angular/src/providers/toast-controller.ts
Normal file
10
angular/src/providers/toast-controller.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ToastOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
|
||||
@Injectable()
|
||||
export class ToastController extends OverlayBaseController<ToastOptions, HTMLIonToastElement> {
|
||||
constructor() {
|
||||
super('ion-toast-controller');
|
||||
}
|
||||
}
|
||||
28
angular/src/util/ionic-router-reuse-strategy.ts
Normal file
28
angular/src/util/ionic-router-reuse-strategy.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
import { deepEqual, objectValues } from './util';
|
||||
|
||||
export class IonicRouteStrategy implements RouteReuseStrategy {
|
||||
|
||||
shouldDetach(_route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line
|
||||
store(_route: ActivatedRouteSnapshot, _detachedTree: DetachedRouteHandle): void { }
|
||||
|
||||
shouldAttach(_route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
retrieve(_route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
|
||||
if (objectValues(future.params) && objectValues(curr.params)) {
|
||||
return deepEqual(future.params, curr.params);
|
||||
} else {
|
||||
return future.routeConfig === curr.routeConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
angular/src/util/overlay.ts
Normal file
17
angular/src/util/overlay.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { proxyMethod } from '../util/util';
|
||||
|
||||
export class OverlayBaseController<Opts, Overlay> {
|
||||
constructor(private ctrl: string) {}
|
||||
|
||||
create(opts?: Opts): Promise<Overlay> {
|
||||
return proxyMethod(this.ctrl, 'create', opts);
|
||||
}
|
||||
|
||||
dismiss(data?: any, role?: string, id = -1): Promise<void> {
|
||||
return proxyMethod(this.ctrl, 'dismiss', data, role, id);
|
||||
}
|
||||
|
||||
getTop(): Promise<Overlay> {
|
||||
return proxyMethod(this.ctrl, 'getTop');
|
||||
}
|
||||
}
|
||||
52
angular/src/util/util.ts
Normal file
52
angular/src/util/util.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ElementRef } from '@angular/core';
|
||||
|
||||
export function inputs(instance: any, el: ElementRef, props: string[]) {
|
||||
props.forEach(propName => {
|
||||
Object.defineProperty(instance, propName, {
|
||||
get: () => el.nativeElement[propName], set: (val: any) => el.nativeElement[propName] = val
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function proxyEvent(emitter: any, el: Node, eventName: string) {
|
||||
el.addEventListener(eventName, (ev) => {
|
||||
emitter.emit(ev);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function proxyMethod(ctrlName: string, methodName: string, ...args: any[]) {
|
||||
const controller = ensureElementInBody(ctrlName);
|
||||
return controller.componentOnReady()
|
||||
.then(() => (controller as any)[methodName].apply(controller, args));
|
||||
}
|
||||
|
||||
export function ensureElementInBody(elementName: string) {
|
||||
let element = document.querySelector(elementName);
|
||||
if (!element) {
|
||||
element = document.createElement(elementName);
|
||||
document.body.appendChild(element);
|
||||
}
|
||||
return element as HTMLStencilElement;
|
||||
}
|
||||
|
||||
export function objectValues(obj: any): any[] {
|
||||
return Object.keys(obj).map(key => obj[key]);
|
||||
}
|
||||
|
||||
export function deepEqual(x: any, y: any) {
|
||||
if (x === y) {
|
||||
return true;
|
||||
} else if (typeof x === 'object' && x != null && (typeof y === 'object' && y != null)) {
|
||||
if (Object.keys(x).length !== Object.keys(y).length) return false;
|
||||
|
||||
for (const prop in x) {
|
||||
if (y.hasOwnProperty(prop)) {
|
||||
if (!deepEqual(x[prop], y[prop])) return false;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
72
angular/stencil.config.js
Normal file
72
angular/stencil.config.js
Normal file
@@ -0,0 +1,72 @@
|
||||
const path = require('path');
|
||||
|
||||
// use ionic/core's stencil config
|
||||
exports.config = require('../core/stencil.config.js').config;
|
||||
|
||||
// user ionic core's tsconfig
|
||||
exports.config.tsconfig ='../core/tsconfig.json';
|
||||
|
||||
// update where to find the original ionic/core src
|
||||
exports.config.srcDir = '../core/src';
|
||||
exports.config.globalScript = '../core/src/global/ionic-global.ts';
|
||||
|
||||
// update the output targets
|
||||
exports.config.outputTargets = [
|
||||
{
|
||||
type: 'angular',
|
||||
directivesProxyFile: 'src/directives/proxies.ts',
|
||||
directivesArrayFile: 'src/directives/proxies-list.txt',
|
||||
empty: false,
|
||||
excludeComponents: [
|
||||
// overlays
|
||||
'ion-action-sheet',
|
||||
'ion-action-sheet-controller',
|
||||
'ion-alert',
|
||||
'ion-alert-controller',
|
||||
'ion-loading',
|
||||
'ion-loading-controller',
|
||||
'ion-modal',
|
||||
'ion-modal-controller',
|
||||
'ion-picker',
|
||||
'ion-picker-controller',
|
||||
'ion-popover',
|
||||
'ion-popover-controller',
|
||||
'ion-toast',
|
||||
'ion-toast-controller',
|
||||
'ion-toast',
|
||||
|
||||
// controllers
|
||||
'ion-menu-controller',
|
||||
'ion-animation-controller',
|
||||
'ion-animation-controller',
|
||||
'ion-gesture-controller',
|
||||
'ion-platform',
|
||||
'ion-cordova-platform',
|
||||
|
||||
// navigation
|
||||
'ion-router',
|
||||
'ion-route',
|
||||
'ion-route-redirect',
|
||||
'ion-router-outlet',
|
||||
'ion-anchor',
|
||||
'ion-tabbar',
|
||||
'ion-tab-button',
|
||||
|
||||
// auxiliar
|
||||
'ion-gesture',
|
||||
'ion-status-tap',
|
||||
'ion-tap-click',
|
||||
'ion-picker-column',
|
||||
'ion-range-knob',
|
||||
'ion-input-shims',
|
||||
'ion-backdrop',
|
||||
'ion-anchor',
|
||||
'ion-virtual-scroll'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
exports.devServer = {
|
||||
root: '.',
|
||||
watchGlob: ['dist/*.*', 'dist/ionic/**/**', 'src/**/*.html']
|
||||
};
|
||||
@@ -10,7 +10,11 @@
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico",
|
||||
{ "glob": "**/*", "input": "../node_modules/@ionic/core/dist", "output": "./ionic/core" }
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "../node_modules/@ionic/angular/dist/ionic",
|
||||
"output": "./ionic"
|
||||
}
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
@@ -57,5 +61,8 @@
|
||||
"defaults": {
|
||||
"styleExt": "scss",
|
||||
"component": {}
|
||||
},
|
||||
"warnings": {
|
||||
"typescriptMismatch": false
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,7 @@ module.exports = function(config) {
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
files: [
|
||||
// TODO: I have not fully worked out how this will work.
|
||||
// Perhaps just the base include with a plugin?
|
||||
{ pattern: '../node_modules/@ionic/core/dist/ionic.js', watched: false, served: false, nocache: true, included: true }
|
||||
],
|
||||
files: [],
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@ionic/angular-demo",
|
||||
"version": "0.0.0",
|
||||
"name": "@ionic/angular-test-nav",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
@@ -8,27 +9,24 @@
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"override-router": "rm -rf ./node_modules/@angular/router && mkdir ./node_modules/@angular/router && cp -R ./scripts/router ./node_modules/@angular"
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "latest",
|
||||
"@angular/common": "latest",
|
||||
"@angular/compiler": "latest",
|
||||
"@angular/core": "latest",
|
||||
"@angular/forms": "latest",
|
||||
"@angular/http": "latest",
|
||||
"@angular/platform-browser": "latest",
|
||||
"@angular/platform-browser-dynamic": "latest",
|
||||
"@angular/router": "latest",
|
||||
"@angular/animations": "^6.0.0-rc.3",
|
||||
"@angular/common": "^6.0.0-rc.3",
|
||||
"@angular/compiler": "^6.0.0-rc.3",
|
||||
"@angular/core": "^6.0.0-rc.3",
|
||||
"@angular/forms": "^6.0.0-rc.3",
|
||||
"@angular/http": "^6.0.0-rc.3",
|
||||
"@angular/platform-browser": "^6.0.0-rc.3",
|
||||
"@angular/platform-browser-dynamic": "^6.0.0-rc.3",
|
||||
"@angular/router": "^6.0.0-rc.3",
|
||||
"@ionic/angular": "next",
|
||||
"@ionic/core": "next",
|
||||
"body-parser": "^1.18.2",
|
||||
"core-js": "^2.4.1",
|
||||
"express": "^4.16.2",
|
||||
"rxjs": "^5.5.2",
|
||||
"zone.js": "^0.8.14"
|
||||
"rxjs": "^6.0.0-terrific-rc.3",
|
||||
"zone.js": "^0.8.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "latest",
|
||||
@@ -6,16 +6,14 @@ import { ActionSheetController } from '@ionic/angular';
|
||||
selector: 'app-action-sheet-page',
|
||||
template: `
|
||||
<ion-app>
|
||||
<ion-page class="show-page">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Test</ion-title>
|
||||
<ion-title>Action Sheet</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<ion-button (click)="clickMe()">Open Basic ActionSheet</ion-button>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</ion-app>
|
||||
`
|
||||
})
|
||||
@@ -25,9 +23,9 @@ export class ActionSheetPageComponent {
|
||||
|
||||
}
|
||||
|
||||
clickMe() {
|
||||
const actionSheet = this.actionSheetController.create({
|
||||
title: 'Albums',
|
||||
async clickMe() {
|
||||
const actionSheet = await this.actionSheetController.create({
|
||||
header: 'Albums',
|
||||
buttons: [{
|
||||
text: 'Delete',
|
||||
role: 'destructive',
|
||||
@@ -1,15 +1,16 @@
|
||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { ActionSheetPageComponent } from './action-sheet-page.component';
|
||||
import { ActionSheetRoutingModule } from './action-sheet-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
ActionSheetRoutingModule
|
||||
],
|
||||
declarations: [ActionSheetPageComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
declarations: [ActionSheetPageComponent]
|
||||
})
|
||||
export class ActionSheetModule { }
|
||||
@@ -6,28 +6,24 @@ import { AlertController } from '@ionic/angular';
|
||||
selector: 'app-alert-page',
|
||||
template: `
|
||||
<ion-app>
|
||||
<ion-page class="show-page">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Test</ion-title>
|
||||
<ion-title>Alert</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<ion-button (click)="clickMe()">Open Basic Alert</ion-button>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</ion-app>
|
||||
`
|
||||
})
|
||||
export class AlertPageComponent {
|
||||
|
||||
constructor(private alertController: AlertController) {
|
||||
constructor(private alertController: AlertController) {}
|
||||
|
||||
}
|
||||
|
||||
clickMe() {
|
||||
const alert = this.alertController.create({
|
||||
title: 'ohhhh snap',
|
||||
async clickMe() {
|
||||
const alert = await this.alertController.create({
|
||||
header: 'ohhhh snap',
|
||||
message: 'Ive been injected via Angular keeping the old api',
|
||||
buttons: [
|
||||
{
|
||||
@@ -45,14 +41,8 @@ export class AlertPageComponent {
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
});
|
||||
alert.present().then(() => {
|
||||
// return alert.dismiss();
|
||||
|
||||
}).then(() => {
|
||||
console.log('dismissed');
|
||||
});
|
||||
return alert.present();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { AlertPageComponent } from './alert-page.component';
|
||||
import { AlertRoutingModule } from './alert-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
AlertRoutingModule
|
||||
],
|
||||
declarations: [AlertPageComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
declarations: [AlertPageComponent]
|
||||
})
|
||||
export class AlertModule { }
|
||||
35
angular/test/nav/src/app/app-routing.module.ts
Normal file
35
angular/test/nav/src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||
{ path: 'basic-inputs', loadChildren: './basic-inputs-page/basic-inputs-page.module#BasicInputsPageModule' },
|
||||
{ path: 'show-hide-when', loadChildren: './show-hide-when/show-hide-when.module#ShowHideWhenModule' },
|
||||
{ path: 'form-sample', loadChildren: './form-sample-page/form-sample-page.module#FormSamplePageModule' },
|
||||
{ path: 'group-inputs', loadChildren: './group-inputs-page/group-inputs-page.module#GroupInputsPageModule' },
|
||||
{ path: 'home', loadChildren: './home-page/home-page.module#HomePageModule' },
|
||||
{ path: 'alert', loadChildren: './alert/alert.module#AlertModule' },
|
||||
{ path: 'actionSheet', loadChildren: './action-sheet/action-sheet.module#ActionSheetModule' },
|
||||
{ path: 'badge', loadChildren: './badge/badge.module#BadgeModule' },
|
||||
{ path: 'card', loadChildren: './card/card.module#CardModule' },
|
||||
{ path: 'content', loadChildren: './content/content.module#ContentModule' },
|
||||
{ path: 'toast', loadChildren: './toast/toast.module#ToastModule' },
|
||||
{ path: 'loading', loadChildren: './loading/loading.module#LoadingModule' },
|
||||
{ path: 'modal', loadChildren: './modal/modal.module#ModalModule' },
|
||||
{ path: 'ng-if', loadChildren: './ng-if/ng-if.module#NgIfModule' },
|
||||
{ path: 'popover', loadChildren: './popover/popover.module#PopoverModule' },
|
||||
{ path: 'segment', loadChildren: './segment/segment.module#SegmentModule' },
|
||||
{ path: 'virtual-scroll', loadChildren: './virtual-scroll/virtual-scroll.module#VirtualScrollModule' },
|
||||
|
||||
{ path: 'no-routing-nav', loadChildren: './no-routing-nav/no-routing-nav.module#NoRoutingNavModule' },
|
||||
{ path: 'simple-nav', loadChildren: './simple-nav/simple-nav.module#SimpleNavModule' },
|
||||
{ path: 'lazy-load-tabs', loadChildren: './lazy-load-tabs/tabs.module#TabsModule' },
|
||||
{ path: 'simple-tabs', loadChildren: './simple-tabs/tabs.module#TabsModule' },
|
||||
{ path: 'static-tabs', loadChildren: './static-tabs/tabs.module#TabsModule' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user