Compare commits

..

79 Commits

Author SHA1 Message Date
Liam DeBeasi
7f4d3a36df merge release-4.7.2
Release 4.7.2 merge to master
2019-08-07 12:23:40 -04:00
Liam DeBeasi
a633db1688 4.7.2 2019-08-07 12:08:11 -04:00
Liam DeBeasi
3ec9607281 chore(): disable swipe to go back e2e tests (#19024) 2019-08-07 11:25:22 -04:00
Adam Bradley
84e306c1a6 feat(ssr): add ionic angular server (#18880) 2019-08-06 12:24:42 -05:00
Manu MA
713ea8adaa fix(router): fix partial gesture (#18977)
fixes #18462
2019-08-06 17:28:29 +02:00
Manu MA
8f7853c5e9 fix(range): participate in <form> (#19008) 2019-08-06 16:51:48 +02:00
Manu MA
f94300cbb3 refactor(angular): use arrow functions (#18910) 2019-08-06 14:18:08 +02:00
Manu MA
3a22105375 fix(platform): subscribeWithPriority trigger change detection (#18962)
fixes #18959
2019-08-06 13:39:01 +02:00
Manu MA
6bbdb80871 fix(accessor): ngModel conflits with nested inputs (#18976)
fixes #18248
2019-08-06 13:34:54 +02:00
Manu MA
7cd68b59fc fix(): remove JSX array commas (#19006) 2019-08-06 13:28:30 +02:00
Manu MA
d237e808c2 fix(reorder): only move item if reorder happens (#19007) 2019-08-06 13:26:37 +02:00
Manu MA
e043ea9dae chore(): fix e2e angular (#19005) 2019-08-06 13:05:47 +02:00
Liam DeBeasi
f9579bcd1d refactor(toast): add deprecation warnings for showCloseButton and closeButtonText (#18955) 2019-08-05 09:01:19 -04:00
James Spencer
23f327ecb6 feat(toast): optionally render ion-icon from asset path if provided (#18969) 2019-08-02 08:17:43 -05:00
Brandy Carney
3e1dfc657b chore(github): update issue template to include stackblitz 2019-07-31 16:49:28 -04:00
Matthew Harris
32bb1f7230 docs(nav-set-root): fix typos (#18946)
* docs(nav-set-root): fix typo a / of

* docs(nav-set-root): fix inconsistent terminology
2019-07-30 12:23:44 -04:00
Matthew Harris
48352533ff docs(nav-pop): fix typos & terminology (#18947) 2019-07-30 12:23:16 -04:00
Adam Bradley
e3a5d1f93a chore(angular-server): init angular-server package (#18950) 2019-07-30 09:50:23 -05:00
Brandy Carney
f08ac68e0b refactor(searchbar): add deprecation warnings for showCancelButton (#18938) 2019-07-30 10:12:51 -04:00
Brandy Carney
7951289460 docs(changelog): update changelog to include Angular 8 support 2019-07-29 10:26:08 -04:00
Liam DeBeasi
9f32d0edd7 merge release-4.7.1
Hotfix 4.7.1
2019-07-26 11:48:15 -04:00
Liam DeBeasi
27a68b3f7f 4.7.1 2019-07-26 11:35:34 -04:00
Manu MA
962783bfba fix(router-outlet): change detection fires properly (#18896)
* fix(router-outlet): never detach() the entering view

fixes #18894

* add tests

* ci

* update package-lock

* circle sync runtime
2019-07-26 11:13:50 -04:00
Manu MA
e82648bda2 refactor(all): update to one (part 3) (#18874) 2019-07-25 20:22:44 +02:00
Liam DeBeasi
9b85e13493 merge release-4.7.0
Merge changes from release-4.7.0 to master
2019-07-25 11:36:30 -04:00
Liam DeBeasi
462cee5b2e merge release-4.7.0
Release 4.7.0
2019-07-25 11:29:12 -04:00
Liam DeBeasi
d792560447 4.7.0 2019-07-25 11:10:51 -04:00
Liam DeBeasi
7272d481bf chore(): update stencil to 1.2.1 (#18891) 2019-07-25 10:58:47 -04:00
Manu Mtz.-Almeida
c83edd9329 chore(): update core in react 2019-07-25 16:18:51 +02:00
Amy Marsh
a869ca0bba (fix): define top-level ARIA landmark regions to improve accessibility (#18672)
references #18671
2019-07-24 17:35:50 -04:00
tomsk
c2348f71a5 fix(vue): rename swipeEnable to swipeGesture (#17346)
fixes #16002
2019-07-24 17:25:57 -04:00
Manu MA
67ffe2f9cc chore(): update stencil to 1.2.0 (#18882)
* chore(): update stencil

* Update to @stencil/core@1.2.0
2019-07-24 15:17:04 -04:00
Romulo Cintra
2e02dc7319 refactor(utils): remove duplicated functions in react utils (#18817) 2019-07-24 14:15:01 -04:00
Vlad Topala
b7761fe353 fix(datetime): allow AM/PM to be changed (#18684)
fixes #18585
2019-07-24 12:52:36 -04:00
Stefanos Anagnostou
00891119f7 feat(virtual-scroll): adds headerHeight and footerHeight (#18851)
Currently, if you have an ion-virtual-scroll with a list of items and a search bar for filtering them, when you change the list of items, the items disappear until rendered again, causing a flicker. This could be solved for the items using the itemHeight function to provide the exact height size and bypass some calculations and be more performant etc.

However, if you had a header or footer, they would still flicker. This commit adds two more optional functions named headerHeight and footerHeight that return the exact size of the header and footer respectively and resolve the flicker.
2019-07-24 18:29:16 +02:00
Manu MA
c91819c94f fix(virtual-scroll): rebuild cells on resizing (#18878) 2019-07-24 18:15:35 +02:00
Manu MA
3ef6ecf422 fix(virtual-scroll): make virtual-scroll css more specific (#18877)
fixes #18870
2019-07-24 18:05:16 +02:00
Manu MA
7ba718c0db fix(datetime): column validation (#18875)
fixes #18793
2019-07-24 18:04:43 +02:00
Matthew Harris
e8ab0fd317 docs(select): clarify button customisation options (#18835)
closes #18834 closes ionic-team/ionic-docs#836
2019-07-24 10:43:14 -04:00
Adam Bradley
815fa2eb06 feat(hydrate): add @ionic/core/hydrate app (#18867) 2019-07-23 16:46:06 -05:00
Adam Bradley
c52b3b4997 fix(hydrate): check for client runtime method (#18866) 2019-07-23 16:11:29 -05:00
Adam Bradley
23ce6fae9e fix(hydrate): avoid window reference (#18865) 2019-07-23 15:28:20 -05:00
Adam Bradley
a8455a90ff chore(ssr): fix document.body reference (#18863) 2019-07-23 14:11:09 -05:00
Amy Marsh
798103bf63 feat(searchbar): improve accessibility (#18797) 2019-07-23 10:21:10 -05:00
Adam Bradley
bd8ca63451 chore(ionicons): update to ionicons 4.6.2 (#18861) 2019-07-23 10:05:46 -05:00
Matthew Harris
cf27063aae docs(process): tiny typos (#18855) 2019-07-23 01:36:49 +02:00
Manu MA
fb18f3ba25 feat(): support for stackblitz (#18846) 2019-07-23 01:01:36 +02:00
Manu MA
71137a2ffa fix(tap-click): ensure ripple is removed (#18854)
fixes #18836
2019-07-22 18:54:50 +02:00
Manu MA
544e550286 fix(platform): wrap event listeners around zone (#18853)
fixes #18831
2019-07-22 18:53:31 +02:00
Matthew Harris
854004cf2c docs(nav-controller): fix typos (#18848) 2019-07-22 11:00:53 -04:00
Brandy Carney
6b5a59dc43 fix(components): apply translucent if backdrop-filter is supported (#18832)
This updates the components and the docs so that translucent is only applied when backdrop filter is supported, this prevents it from being applied when viewing iOS in Chrome, for example.

closes ionic-team/ionic-docs#666
2019-07-19 11:16:10 -04:00
Ken Sodemann
fbfc07688e fix(menu-controller): add swipeGesture proxy (#18806) 2019-07-18 15:56:09 -05:00
Adam Bradley
9b075ef529 feat(transition): iOS page transition shadow (#18695)
Closes #18661
2019-07-18 14:50:56 -05:00
Manu MA
97fec92365 fix(router-outlet): attach entering view before first change detection (#18821) 2019-07-18 10:26:54 +02:00
Manu MA
26e6d6f115 fix(textarea): autogrow (#18822)
fixes #18744
2019-07-17 19:23:13 +02:00
Nico L
978cc39009 fix(hardwareBackButton): added missing import of hardware back button… (#18794) 2019-07-17 17:54:19 +02:00
Manu MA
53179c475c fix(inputs): apply ng form classes (#18820) 2019-07-17 17:46:22 +02:00
Mike Hartington
7ae9303a97 chore(): change peer deps to support ng8 (#18645) 2019-07-15 10:13:02 -05:00
Brandy Carney
045bc59b75 fix(theming): update components to use the proper colors for dark themes (#18735)
references #18713
2019-07-12 17:31:42 -04:00
Mike Hartington
08af35aad2 chore(): update vue version 2019-07-12 15:43:59 -04:00
Ely Lucas
5b932152f8 React beta 7 (#18780)
* fix(react): ion-item work for href attribute

* fix(react): route redirect bugs

* chore(react): dev version bump

* fix(package): point module to correct esm dist file

* chore(ionicons): update to ionicons 4.6.2-0

* fix(): ion-item work for href attribute

* fix(): route redirect bugs

* fix(package): point module to correct esm dist file

* chore(): removing un-needed export

* fix(react): subsequent render redirect fix

* chore(react): bump version for beta 7 release
2019-07-12 09:38:52 -06:00
Max Lynch
9993b73355 Update v3 package.json
Again trying to get github to credit us for v3 installs on the Used By feature. This time trying a new repo URL
2019-07-11 09:29:05 -05:00
Max Lynch
f1eeed1c91 Move package.json to angular directory for v3.
Per conversation with Adam, we are trying to get GitHub to properly pick up the Used By
count for Ionic 3 which is much higher than v4 today. This is a dummy package.
2019-07-10 12:47:40 -05:00
Brandy Carney
ee81907713 merge release-4.6.2 2019-07-10 13:20:37 -04:00
Brandy Carney
1f40d8fffd Revert "chore(scripts): update release script"
This reverts commit e33bfc7f1d.
2019-07-10 13:20:00 -04:00
Brandy Carney
723196a157 merge release-4.6.2 2019-07-10 13:18:32 -04:00
Manu Mtz.-Almeida
0b0dddf8ec 4.6.2 2019-07-10 19:12:11 +02:00
Brandy Carney
e33bfc7f1d chore(scripts): update release script 2019-07-10 11:02:26 -04:00
Manu MA
03c1d19e07 perf(all): minify better by using arrow functions (#18730) 2019-07-10 10:33:33 -04:00
Manu MA
8beeff2c52 fix(virtual-scroll): remove runOutsideAngular error (#18752)
fixes #18746
2019-07-10 10:21:42 -04:00
Brandy Carney
f060db5fe6 merge release-4.6.1 2019-07-09 12:41:23 -04:00
Brandy Carney
4a3ff61571 merge release-4.6.1 2019-07-09 12:41:09 -04:00
Max Lynch
292cc867a5 Create v3 package.json for proper Used By count
Github scans repos to compute the Used By, and ionic 3 has more usage which we should get credit for so this adds a dummy `package.json` file for v3
2019-07-09 10:54:16 -05:00
Mike Hartington
470615eb05 chore(): add page component 2019-07-08 20:26:39 -04:00
Simon Wicki
f56fea6a1f fix(vue): update imports for types and ionicons
Closes #18701
2019-07-08 20:25:30 -04:00
Brandy Carney
f16b118794 fix(overlays): fallback to step color if overlay background variable is unset (#18709)
fixes #18658
2019-07-05 10:52:47 -04:00
Brandy Carney
24840d4d99 fix(menu-button): hide menu button when auto hide or split pane (#18702)
- updates menu-button to use the host element
- moves menu-toggle logic to a utils file for menu button to share
- removes the dependency on menu-toggle
- adds an e2e test for an auto-hidden menu button

fixes #18666
2019-07-03 11:51:30 -04:00
Brandy Carney
876ab41ba8 fix(menu-button): move font-size to host for easier customization (#18699)
fixes #18667
2019-07-02 15:37:16 -04:00
Ely Lucas
c6bb2730a8 chore() react beta 6 release (#18588)
* fix(react) attribute data for web components fix

* fix(react) attribute data for web components fix

* wip

* putting back cause issues

* update version 0.6-6

* wip

* fix(react) - fixing flash between moving between tabs

* update version to 0.6-7

* update to core 4.6

* update to 6-9 and tab button selected fix

* wrapping react router

* beta 6 release
2019-07-02 10:08:23 -06:00
408 changed files with 5475 additions and 14680 deletions

View File

@@ -91,6 +91,23 @@ jobs:
paths:
- "*"
build-angular-server:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
command: npm install
working_directory: /tmp/workspace/packages/angular-server
- run:
command: npm run build.prod
working_directory: /tmp/workspace/packages/angular-server
- persist_to_workspace:
root: /tmp/workspace
paths:
- "*"
test-core-clean-build:
<<: *defaults
steps:
@@ -173,6 +190,9 @@ jobs:
- run:
command: npm install
working_directory: /tmp/workspace/angular/test/test-app
- run:
command: npm run sync
working_directory: /tmp/workspace/angular/test/test-app
- run:
command: npm test
working_directory: /tmp/workspace/angular/test/test-app
@@ -205,7 +225,11 @@ workflows:
- build-angular:
requires: [build-core]
- build-angular-server:
requires: [build-angular]
- test-angular-lint:
requires: [build-angular]
- test-angular-e2e:
requires: [build-angular]
requires:
- build-angular
- build-angular-server

View File

@@ -37,6 +37,7 @@ assignees: ''
A sample application via GitHub
StackBlitz (https://stackblitz.com)
Ionic Angular StackBlitz: https://stackblitz.com/edit/ionic-v4-angular-tabs
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)

6
.github/PROCESS.md vendored
View File

@@ -64,7 +64,7 @@ If the issue is a support question, the submitter should be redirected to our [f
### Incomplete Template
If the issue template has not been filled out completely, the issue should be closed and locked. The submitter should be informed top re-submit the issue making sure they fill the form out completely. Use the `ionitron: missing template` label to accomplish this.
If the issue template has not been filled out completely, the issue should be closed and locked. The submitter should be informed to re-submit the issue making sure they fill the form out completely. Use the `ionitron: missing template` label to accomplish this.
### Issues with Open Questions
@@ -77,7 +77,7 @@ NOTE: be sure to perform those actions in the order stated. If you add the comme
If there is a response to the question, the bot will remove the `needs: reply` and apply the `triage` label. The issue will then go through the triage handling again.
if there is no response within 30 days, the issue will be closed and locked.
If there is no response within 30 days, the issue will be closed and locked.
## Workflow
@@ -248,4 +248,4 @@ Hotfixes bypass `master` and should only be used for urgent fixes that can't wai
1. Rewrite the commit message to `merge release-[VERSION]` with the proper release branch. For example, if this release is for `4.5.0`, the message would be `merge release-4.5.0`.
1. Submit a pull request from the release branch into `master`. Merge this pull request using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.
1. Submit a pull request from the release branch into `master`. Merge this pull request using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.

2
.gitignore vendored
View File

@@ -58,7 +58,7 @@ prerender-static.html
# stencil
angular/css/
core/css/
core/hydrated/
core/hydrate/
core/loader/
core/www/
.stencil/

View File

@@ -258,11 +258,18 @@ function isVersionGreater(oldVersion, newVersion) {
return true;
}
function copyCDNLoader(tasks, version) {
tasks.push({
title: `Copy CDN loader`,
task: () => execa('node', ['copy-cdn-loader.js', version], { cwd: path.join(rootDir, 'core', 'scripts') }),
});
}
module.exports = {
checkGit,
isValidVersion,
isVersionGreater,
copyCDNLoader,
packages,
packagePath,
prepareDevPackage,

View File

@@ -116,6 +116,7 @@ async function preparePackages(packages, version, install) {
// update core readme with version number
updateCoreReadme(tasks, version);
common.copyCDNLoader(tasks, version);
const listr = new Listr(tasks, { showSubtasks: true });
await listr.run();
@@ -171,7 +172,6 @@ function updateCoreReadme(tasks, version) {
});
}
const SEMVER_INCREMENTS = ['patch', 'minor', 'major'];
const isValidVersionInput = input => SEMVER_INCREMENTS.indexOf(input) !== -1 || common.isValidVersion(input);

View File

@@ -38,6 +38,7 @@ async function main() {
packages.forEach(package => {
common.prepareDevPackage(tasks, package, devVersion);
});
common.copyCDNLoader(tasks, devVersion);
common.publishPackages(tasks, packages, devVersion, DIST_NPM_TAG);
const listr = new Listr(tasks);

View File

@@ -54,7 +54,7 @@ function publishGit(tasks, version, changelog) {
},
{
title: 'Push tags to remove',
task: () => execa('git', ['push', '--tags'], { cwd: common.rootDir })
task: () => execa('git', ['push', '--follow-tags'], { cwd: common.rootDir })
},
{
title: 'Publish Github release',

View File

@@ -1,3 +1,105 @@
## [4.7.2](https://github.com/ionic-team/ionic/compare/v4.7.1...v4.7.2) (2019-08-07)
### Bug Fixes
* **angular:** hardware back button subscribeWithPriority triggers change detection ([#18962](https://github.com/ionic-team/ionic/issues/18962)) ([3a22105](https://github.com/ionic-team/ionic/commit/3a22105)), closes [#18959](https://github.com/ionic-team/ionic/issues/18959)
* **angular:** nested inputs no longer conflict with each other ([#18976](https://github.com/ionic-team/ionic/issues/18976)) ([6bbdb80](https://github.com/ionic-team/ionic/commit/6bbdb80)), closes [#18248](https://github.com/ionic-team/ionic/issues/18248)
* **range:** ion-range value now submitted with form ([#19008](https://github.com/ionic-team/ionic/issues/19008)) ([8f7853c](https://github.com/ionic-team/ionic/commit/8f7853c))
* **reorder:** only move item if reorder happens ([#19007](https://github.com/ionic-team/ionic/issues/19007)) ([d237e80](https://github.com/ionic-team/ionic/commit/d237e80))
* **router:** partial swipe to go back gesture no longer breaks view([#18977](https://github.com/ionic-team/ionic/issues/18977)) ([713ea8a](https://github.com/ionic-team/ionic/commit/713ea8a)), closes [#18462](https://github.com/ionic-team/ionic/issues/18462)
* **toast:** allow loading ion-icon from asset path ([#18969](https://github.com/ionic-team/ionic/issues/18969)) ([23f327e](https://github.com/ionic-team/ionic/commit/23f327e))
* **vue:** rename swipeEnable to swipeGesture ([#17346](https://github.com/ionic-team/ionic/issues/17346)) ([c2348f7](https://github.com/ionic-team/ionic/commit/c2348f7)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
## [4.7.1](https://github.com/ionic-team/ionic/compare/v4.7.0...v4.7.1) (2019-07-26)
### Bug Fixes
* **angular:** ensure change detection fires properly ([#18896](https://github.com/ionic-team/ionic/issues/18896)) ([962783b](https://github.com/ionic-team/ionic/commit/962783b)), closes [#18894](https://github.com/ionic-team/ionic/issues/18894)
# [4.7.0 Nitrogen](https://github.com/ionic-team/ionic/compare/v4.6.2...v4.7.0) (2019-07-24)
### Angular 8 Support
With this version comes support for Angular 8! Follow the below steps to update.
1. Update `@ionic/angular` and `@ionic/angular-toolkit` to the latest releases:
```shell
$ npm install @ionic/angular@4.7.0
$ npm install @ionic/angular-toolkit@2.0.0 -D
```
1. Update `@angular/core` and `@angular/cli`:
```shell
$ npx ng update @angular/core @angular/cli
```
1. Update `@angular-devkit` dependencies:
```shell
$ npm i @angular-devkit/architect@latest @angular-devkit/build-angular@latest @angular-devkit/core@latest @angular-devkit/schematics@latest
```
View our [Angular 8 Update Guide](https://docs.google.com/document/d/1QOpQeDifPSg6F9WycDLcbQnpqjN96ew-Ap0_CB7CcCQ/edit?usp=sharing) for tips on potential issues!
### Bug Fixes
* **angular:** copy input form classes to parent ion-item ([#18820](https://github.com/ionic-team/ionic/issues/18820)) ([53179c4](https://github.com/ionic-team/ionic/commit/53179c4)), closes [#18800](https://github.com/ionic-team/ionic/issues/18800)
* **angular:** add the swipeGesture method for enabling or disabling the ability to swipe open a menu ([#18806](https://github.com/ionic-team/ionic/issues/18806)) ([fbfc076](https://github.com/ionic-team/ionic/commit/fbfc076)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
* **angular:** webview "pause", "resume", and "resize" events now trigger change detection ([#18853](https://github.com/ionic-team/ionic/issues/18853)) ([544e550](https://github.com/ionic-team/ionic/commit/544e550)), closes [#18831](https://github.com/ionic-team/ionic/issues/18831)
* **core:** apply translucent if backdrop-filter is supported ([#18832](https://github.com/ionic-team/ionic/issues/18832)) ([6b5a59d](https://github.com/ionic-team/ionic/commit/6b5a59d)), closes [ionic-team/ionic-docs#666](https://github.com/ionic-team/ionic-docs/issues/666)
* **datetime:** allow AM/PM to be changed ([#18684](https://github.com/ionic-team/ionic/issues/18684)) ([b7761fe](https://github.com/ionic-team/ionic/commit/b7761fe)), closes [#18585](https://github.com/ionic-team/ionic/issues/18585)
* **datetime:** properly apply disabled classes when updating columns ([#18875](https://github.com/ionic-team/ionic/issues/18875)) ([7ba718c](https://github.com/ionic-team/ionic/commit/7ba718c)), closes [#18793](https://github.com/ionic-team/ionic/issues/18793)
* **hardware-back-button:** hardware back button no longer erroneously restarts app ([#18794](https://github.com/ionic-team/ionic/issues/18794)) ([978cc39](https://github.com/ionic-team/ionic/commit/978cc39)), closes [#18792](https://github.com/ionic-team/ionic/issues/18792)
* **ripple-effect:** ensure ripple is removed from components after pointer release ([#18854](https://github.com/ionic-team/ionic/issues/18854)) ([71137a2](https://github.com/ionic-team/ionic/commit/71137a2)), closes [#18836](https://github.com/ionic-team/ionic/issues/18836)
* **searchbar:** add aria and role for improved accessibility ([#18797](https://github.com/ionic-team/ionic/issues/18797)) ([798103b](https://github.com/ionic-team/ionic/commit/798103b)), closes [#18796](https://github.com/ionic-team/ionic/issues/18796)
* **ssr:** avoid window reference ([#18865](https://github.com/ionic-team/ionic/issues/18865)) ([23ce6fa](https://github.com/ionic-team/ionic/commit/23ce6fa))
* **ssr:** check for client runtime method ([#18866](https://github.com/ionic-team/ionic/issues/18866)) ([c52b3b4](https://github.com/ionic-team/ionic/commit/c52b3b4))
* **textarea:** autogrow now resets textarea back to original number of rows when text is cleared ([#18822](https://github.com/ionic-team/ionic/issues/18822)) ([26e6d6f](https://github.com/ionic-team/ionic/commit/26e6d6f)), closes [#18744](https://github.com/ionic-team/ionic/issues/18744)
* **theming:** update components to use the proper colors for dark themes ([#18735](https://github.com/ionic-team/ionic/issues/18735)) ([045bc59](https://github.com/ionic-team/ionic/commit/045bc59)), closes [#18713](https://github.com/ionic-team/ionic/issues/18713)
* **virtual-scroll:** card rendering is no longer distorted ([#18877](https://github.com/ionic-team/ionic/issues/18877)) ([3ef6ecf](https://github.com/ionic-team/ionic/commit/3ef6ecf)), closes [#18870](https://github.com/ionic-team/ionic/issues/18870)
* **virtual-scroll:** element dimensions are recalculated on resize ([#18878](https://github.com/ionic-team/ionic/issues/18878)) ([c91819c](https://github.com/ionic-team/ionic/commit/c91819c))
### Features
* **core:** add support for Stackblitz ([#18846](https://github.com/ionic-team/ionic/issues/18846)) ([fb18f3b](https://github.com/ionic-team/ionic/commit/fb18f3b))
* **ssr:** add @ionic/core/hydrate app ([#18867](https://github.com/ionic-team/ionic/issues/18867)) ([815fa2e](https://github.com/ionic-team/ionic/commit/815fa2e))
* **navigation:** add experimental shadow to iOS page transitions ([#18695](https://github.com/ionic-team/ionic/issues/18695)) ([9b075ef](https://github.com/ionic-team/ionic/commit/9b075ef)), closes [#18661](https://github.com/ionic-team/ionic/issues/18661)
* **virtual-scroll:** adds headerHeight and footerHeight to help prevent flickering ([#18851](https://github.com/ionic-team/ionic/issues/18851)) ([0089111](https://github.com/ionic-team/ionic/commit/0089111)), closes [#17540](https://github.com/ionic-team/ionic/issues/17540)
### Performance
* **angular:** attach entering view before first change detection and detach leaving page ([#18821](https://github.com/ionic-team/ionic/issues/18821)) ([97fec92](https://github.com/ionic-team/ionic/commit/97fec92))
## [4.6.2](https://github.com/ionic-team/ionic/compare/v4.6.1...v4.6.2) (2019-07-10)
### Bug Fixes
* **menu-button:** hide menu button when auto hide or split pane ([#18702](https://github.com/ionic-team/ionic/issues/18702)) ([24840d4](https://github.com/ionic-team/ionic/commit/24840d4)), closes [#18666](https://github.com/ionic-team/ionic/issues/18666)
* **menu-button:** move font-size to host for easier customization ([#18699](https://github.com/ionic-team/ionic/issues/18699)) ([876ab41](https://github.com/ionic-team/ionic/commit/876ab41)), closes [#18667](https://github.com/ionic-team/ionic/issues/18667)
* **overlays:** fallback to step color if overlay background variable is unset ([#18709](https://github.com/ionic-team/ionic/issues/18709)) ([f16b118](https://github.com/ionic-team/ionic/commit/f16b118)), closes [#18658](https://github.com/ionic-team/ionic/issues/18658)
* **virtual-scroll:** remove runOutsideAngular error ([#18752](https://github.com/ionic-team/ionic/issues/18752)) ([8beeff2](https://github.com/ionic-team/ionic/commit/8beeff2)), closes [#18746](https://github.com/ionic-team/ionic/issues/18746)
* **vue:** update imports for types and ionicons ([f56fea6](https://github.com/ionic-team/ionic/commit/f56fea6)), closes [#18701](https://github.com/ionic-team/ionic/issues/18701)
### Performance Improvements
* **all:** minify better by using arrow functions ([#18730](https://github.com/ionic-team/ionic/issues/18730)) ([03c1d19](https://github.com/ionic-team/ionic/commit/03c1d19))
## [4.6.1](https://github.com/ionic-team/ionic/compare/v4.6.0...v4.6.1) (2019-07-09)

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "4.6.1",
"version": "4.7.2",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -19,6 +19,10 @@
"type": "git",
"url": "https://github.com/ionic-team/ionic.git"
},
"bugs": {
"url": "https://github.com/ionic-team/ionic/issues"
},
"homepage": "https://ionicframework.com/",
"scripts": {
"build": "npm run clean && npm run build.core && npm run build.ng && npm run clean-generated",
"build.core": "node scripts/build-core.js",
@@ -38,29 +42,29 @@
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"module": "dist/fesm5.js",
"main": "dist/fesm5.js",
"main": "dist/fesm5.cjs.js",
"types": "dist/core.d.ts",
"files": [
"dist/",
"css/"
],
"dependencies": {
"@ionic/core": "4.6.1",
"@ionic/core": "4.7.2",
"tslib": "^1.9.3"
},
"peerDependencies": {
"@angular-devkit/core": "^7.2.1",
"@angular-devkit/schematics": "^7.2.1",
"@angular/core": "^7.2.1",
"@angular/common": "^7.2.1",
"@angular/forms": "^7.2.1",
"@angular/router": "^7.2.1",
"@angular/compiler": "^7.2.1",
"@angular/compiler-cli": "^7.2.1",
"@angular/platform-browser": "^7.2.1",
"@angular/platform-browser-dynamic": "^7.2.1",
"@angular-devkit/core": "7.2.1 - 8",
"@angular-devkit/schematics": "7.2.1 - 8",
"@angular/core": "7.2.1 - 8",
"@angular/common": "7.2.1 - 8",
"@angular/forms": "7.2.1 - 8",
"@angular/router": "7.2.1 - 8",
"@angular/compiler": "7.2.1 - 8",
"@angular/compiler-cli": "7.2.1 - 8",
"@angular/platform-browser": "7.2.1 - 8",
"@angular/platform-browser-dynamic": "7.2.1 - 8",
"rxjs": ">=6.2.0",
"zone.js": "^0.8.26"
"zone.js": ">=0.8.26"
},
"devDependencies": {
"@angular-devkit/core": "^7.2.1",
@@ -75,15 +79,15 @@
"@angular/router": "^7.2.1",
"@types/node": "~12.0.12",
"fs-extra": "^7.0.0",
"glob": "^7.1.3",
"rollup": "^1.1.2",
"rollup-plugin-node-resolve": "^4.0.0",
"glob": "^7.1.4",
"rollup": "~1.17.0",
"rollup-plugin-node-resolve": "~5.2.0",
"rxjs": "^6.5.2",
"tsickle": "^0.34.0",
"tslint": "^5.12.1",
"tslint-ionic-rules": "0.0.21",
"typescript": "3.2.4",
"zone.js": "^0.8.28"
"typescript": "~3.2.2",
"zone.js": "~0.8.26"
},
"schematics": "./dist/schematics/collection.json"
}

View File

@@ -15,3 +15,7 @@
npm run build.link ../ionic-conference-app
When the command above is ran from the `angular` directory, it will build `@ionic/angular` and copy the `dist` directory to the correct location of another local project. In the example above, the end result is that it copies the `dist` directory to `../ionic-conference-app/node_modules/@ionic/angular/dist`. The path given should be relative to the root of this mono repo.
## package.json note
The `package.json` file in this directory references __Ionic 3__ and is in here to get GitHub to properly show the Used By counts on the repo. __Do not remove it!__

View File

@@ -1,12 +1,12 @@
const fs = require('fs-extra');
const path = require('path');
const ROOT_DIR = path.join(__dirname, '..');
const cleanDirs = [
'dist'
path.join(ROOT_DIR, 'dist')
];
cleanDirs.forEach(dir => {
const cleanDir = path.join(__dirname, '../', dir);
fs.removeSync(cleanDir);
fs.emptyDirSync(dir);
});

View File

@@ -0,0 +1,16 @@
{
"name": "ionic-angular",
"version": "`gulp package` generates dist/package.json from this template using the root ./package.json",
"description": "",
"keywords": [],
"repository": {
"type": "git",
"url": "https://github.com/ionic-team/ionic.git"
},
"license": "MIT",
"main": "umd/index.js",
"module": "index.js",
"es2015": "es2015/index.js",
"peerDependencies": {
}
}

View File

@@ -2,10 +2,12 @@ import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'build/es2015/core.js',
output: {
file: 'dist/fesm2015.js',
format: 'es'
},
output: [
{
file: 'dist/fesm2015.js',
format: 'es'
}
],
external: (id) => {
// anything else is external
// Windows: C:\xxxxxx\xxx

View File

@@ -4,6 +4,15 @@ const newConfig = {
...config,
input: 'build/es5/core.js',
};
newConfig.output.file = 'dist/fesm5.js';
newConfig.output = [
{
file: 'dist/fesm5.js',
format: 'es'
},
{
file: 'dist/fesm5.cjs.js',
format: 'cjs'
}
];
export { newConfig as default };

View File

@@ -3,8 +3,9 @@ import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
import { Config } from './providers/config';
import { IonicWindow } from './types/interfaces';
import { raf } from './util/util';
export function appInitialize(config: Config, doc: Document, zone: NgZone) {
export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
return (): any => {
const win: IonicWindow | undefined = doc.defaultView as any;
if (win) {
@@ -15,7 +16,7 @@ export function appInitialize(config: Config, doc: Document, zone: NgZone) {
_zoneGate: (h: any) => zone.run(h)
};
const aelFn = '__zone_symbol__addEventListener' in (document.body as any)
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
? '__zone_symbol__addEventListener'
: 'addEventListener';
@@ -23,12 +24,8 @@ export function appInitialize(config: Config, doc: Document, zone: NgZone) {
return defineCustomElements(win, {
exclude: ['ion-tabs', 'ion-tab'],
syncQueue: true,
raf,
jmp: (h: any) => zone.runOutsideAngular(h),
raf: h => {
return zone.runOutsideAngular(() => {
return (win.__zone_symbol__requestAnimationFrame) ? win.__zone_symbol__requestAnimationFrame(h) : requestAnimationFrame(h);
});
},
ael(elm, eventName, cb, opts) {
(elm as any)[aelFn](eventName, cb, opts);
},
@@ -39,4 +36,4 @@ export function appInitialize(config: Config, doc: Document, zone: NgZone) {
});
}
};
}
};

View File

@@ -25,8 +25,8 @@ export class BooleanValueAccessor extends ValueAccessor {
setIonicClasses(this.el);
}
@HostListener('ionChange', ['$event.target.checked'])
_handleIonChange(value: any) {
this.handleChangeEvent(value);
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any) {
this.handleChangeEvent(el, el.checked);
}
}

View File

@@ -20,9 +20,9 @@ export class NumericValueAccessor extends ValueAccessor {
super(el);
}
@HostListener('ionChange', ['$event.target.value'])
_handleIonChange(value: any) {
this.handleChangeEvent(value);
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any) {
this.handleChangeEvent(el, el.value);
}
registerOnChange(fn: (_: number | null) => void) {

View File

@@ -20,8 +20,8 @@ export class RadioValueAccessor extends ValueAccessor {
super(el);
}
@HostListener('ionSelect', ['$event.target.checked'])
_handleIonSelect(value: any) {
this.handleChangeEvent(value);
@HostListener('ionSelect', ['$event.target'])
_handleIonSelect(el: any) {
this.handleChangeEvent(el, el.checked);
}
}

View File

@@ -20,8 +20,8 @@ export class SelectValueAccessor extends ValueAccessor {
super(el);
}
@HostListener('ionChange', ['$event.target.value'])
_handleChangeEvent(value: any) {
this.handleChangeEvent(value);
@HostListener('ionChange', ['$event.target'])
_handleChangeEvent(el: any) {
this.handleChangeEvent(el, el.value);
}
}

View File

@@ -20,8 +20,8 @@ export class TextValueAccessor extends ValueAccessor {
super(el);
}
@HostListener('ionChange', ['$event.target.value'])
_handleInputEvent(value: any) {
this.handleChangeEvent(value);
@HostListener('ionChange', ['$event.target'])
_handleInputEvent(el: any) {
this.handleChangeEvent(el, el.value);
}
}

View File

@@ -1,6 +1,8 @@
import { ElementRef, HostListener } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
import { raf } from '../../util/util';
export class ValueAccessor implements ControlValueAccessor {
private onChange: (value: any) => void = () => {/**/};
@@ -14,18 +16,22 @@ export class ValueAccessor implements ControlValueAccessor {
setIonicClasses(this.el);
}
handleChangeEvent(value: any) {
if (value !== this.lastValue) {
this.lastValue = value;
this.onChange(value);
handleChangeEvent(el: HTMLElement, value: any) {
if (el === this.el.nativeElement) {
if (value !== this.lastValue) {
this.lastValue = value;
this.onChange(value);
}
setIonicClasses(this.el);
}
setIonicClasses(this.el);
}
@HostListener('ionBlur')
_handleBlurEvent() {
this.onTouched();
setIonicClasses(this.el);
@HostListener('ionBlur', ['$event.target'])
_handleBlurEvent(el: any) {
if (el === this.el.nativeElement) {
this.onTouched();
setIonicClasses(this.el);
}
}
registerOnChange(fn: (value: any) => void) {
@@ -41,18 +47,20 @@ export class ValueAccessor implements ControlValueAccessor {
}
}
export function setIonicClasses(element: ElementRef) {
const input = element.nativeElement as HTMLElement;
const classes = getClasses(input);
setClasses(input, classes);
export const setIonicClasses = (element: ElementRef) => {
raf(() => {
const input = element.nativeElement as HTMLElement;
const classes = getClasses(input);
setClasses(input, classes);
const item = input.closest('ion-item');
if (item) {
setClasses(item, classes);
}
}
const item = input.closest('ion-item');
if (item) {
setClasses(item, classes);
}
});
};
function getClasses(element: HTMLElement) {
const getClasses = (element: HTMLElement) => {
const classList = element.classList;
const classes = [];
for (let i = 0; i < classList.length; i++) {
@@ -62,9 +70,9 @@ function getClasses(element: HTMLElement) {
}
}
return classes;
}
};
function setClasses(element: HTMLElement, classes: string[]) {
const setClasses = (element: HTMLElement, classes: string[]) => {
const classList = element.classList;
classList.remove(
@@ -76,8 +84,8 @@ function setClasses(element: HTMLElement, classes: string[]) {
'ion-pristine'
);
classList.add(...classes);
}
};
function startsWith(input: string, search: string): boolean {
const startsWith = (input: string, search: string): boolean => {
return input.substr(0, search.length) === search;
}
};

View File

@@ -205,7 +205,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
// Calling `markForCheck` to make sure we will run the change detection when the
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
enteringView = this.stackCtrl.createView(this.activated, activatedRoute);
enteringView.ref.changeDetectorRef.detectChanges();
// Store references to the proxy by component
this.proxyMap.set(cmpRef.instance, activatedRouteProxy);

View File

@@ -31,7 +31,7 @@ export class StackController {
createView(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
const url = getUrl(this.router, activatedRoute);
const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
const unlistenEvents = bindLifecycleEvents(ref.instance, element);
const unlistenEvents = bindLifecycleEvents(this.zone, ref.instance, element);
return {
id: this.nextId++,
stackId: computeStackId(this.tabsPrefix, url),
@@ -44,7 +44,11 @@ export class StackController {
getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
const activatedUrlKey = getUrl(this.router, activatedRoute);
return this.views.find(vw => vw.url === activatedUrlKey);
const view = this.views.find(vw => vw.url === activatedUrlKey);
if (view) {
view.ref.changeDetectorRef.reattach();
}
return view;
}
setActive(enteringView: RouteView): Promise<StackEvent> {
@@ -55,6 +59,7 @@ export class StackController {
direction = 'back';
animation = undefined;
}
const viewsSnapshot = this.views.slice();
let currentNavigation;
@@ -90,16 +95,36 @@ export class StackController {
}
}
const reused = this.views.includes(enteringView);
const views = this.insertView(enteringView, direction);
return this.wait(() => {
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
.then(() => ({
enteringView,
direction,
animation,
tabSwitch
}));
// Trigger change detection before transition starts
// This will call ngOnInit() the first time too, just after the view
// was attached to the dom, but BEFORE the transition starts
if (!reused) {
enteringView.ref.changeDetectorRef.detectChanges();
}
// Wait until previous transitions finish
return this.zone.runOutsideAngular(() => {
return this.wait(() => {
// disconnect leaving page from change detection to
// reduce jank during the page transition
if (leavingView) {
leavingView.ref.changeDetectorRef.detach();
}
// In case the enteringView is the same as the leavingPage we need to reattach()
enteringView.ref.changeDetectorRef.reattach();
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
.then(() => ({
enteringView,
direction,
animation,
tabSwitch
}));
});
});
}
@@ -144,7 +169,7 @@ export class StackController {
enteringView, // entering view
leavingView, // leaving view
'back',
true,
this.canGoBack(2),
true
);
});
@@ -156,6 +181,8 @@ export class StackController {
if (shouldComplete) {
this.skipTransition = true;
this.pop(1);
} else if (this.activeView) {
cleanup(this.activeView, this.views, this.views, this.location);
}
}
@@ -196,14 +223,9 @@ export class StackController {
this.skipTransition = false;
return Promise.resolve(false);
}
if (enteringView) {
enteringView.ref.changeDetectorRef.reattach();
if (leavingView === enteringView) {
return Promise.resolve(false);
}
// TODO: disconnect leaving page from change detection to
// reduce jank during the page transition
// if (leavingView) {
// leavingView.ref.changeDetectorRef.detach();
// }
const enteringEl = enteringView ? enteringView.element : undefined;
const leavingEl = leavingView ? leavingView.element : undefined;
const containerEl = this.containerEl;
@@ -213,13 +235,15 @@ export class StackController {
containerEl.appendChild(enteringEl);
}
return this.zone.runOutsideAngular(() => containerEl.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
}));
if ((containerEl as any).commit) {
return containerEl.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
});
}
}
return Promise.resolve(false);
}
@@ -234,16 +258,19 @@ export class StackController {
}
}
function cleanupAsync(activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) {
return new Promise(resolve => {
requestAnimationFrame(() => {
cleanup(activeRoute, views, viewsSnapshot, location);
resolve();
const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
if (typeof (requestAnimationFrame as any) === 'function') {
return new Promise<any>(resolve => {
requestAnimationFrame(() => {
cleanup(activeRoute, views, viewsSnapshot, location);
resolve();
});
});
});
}
}
return Promise.resolve();
};
function cleanup(activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) {
const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
viewsSnapshot
.filter(view => !views.includes(view))
.forEach(destroyView);
@@ -268,4 +295,4 @@ function cleanup(activeRoute: RouteView, views: RouteView[], viewsSnapshot: Rout
view.ref.changeDetectorRef.detach();
}
});
}
};

View File

@@ -2,7 +2,7 @@ import { ComponentRef } from '@angular/core';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
export function insertView(views: RouteView[], view: RouteView, direction: RouterDirection) {
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
if (direction === 'root') {
return setRoot(views, view);
} else if (direction === 'forward') {
@@ -10,15 +10,15 @@ export function insertView(views: RouteView[], view: RouteView, direction: Route
} else {
return setBack(views, view);
}
}
};
function setRoot(views: RouteView[], view: RouteView) {
const setRoot = (views: RouteView[], view: RouteView) => {
views = views.filter(v => v.stackId !== view.stackId);
views.push(view);
return views;
}
};
function setForward(views: RouteView[], view: RouteView) {
const setForward = (views: RouteView[], view: RouteView) => {
const index = views.indexOf(view);
if (index >= 0) {
views = views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
@@ -26,30 +26,30 @@ function setForward(views: RouteView[], view: RouteView) {
views.push(view);
}
return views;
}
};
function setBack(views: RouteView[], view: RouteView) {
const setBack = (views: RouteView[], view: RouteView) => {
const index = views.indexOf(view);
if (index >= 0) {
return views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
} else {
return setRoot(views, view);
}
}
};
export function getUrl(router: Router, activatedRoute: ActivatedRoute) {
export const getUrl = (router: Router, activatedRoute: ActivatedRoute) => {
const urlTree = router.createUrlTree(['.'], { relativeTo: activatedRoute });
return router.serializeUrl(urlTree);
}
};
export function isTabSwitch(enteringView: RouteView, leavingView: RouteView | undefined) {
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined) => {
if (!leavingView) {
return true;
}
return enteringView.stackId !== leavingView.stackId;
}
};
export function computeStackId(prefixUrl: string[] | undefined, url: string) {
export const computeStackId = (prefixUrl: string[] | undefined, url: string) => {
if (!prefixUrl) {
return undefined;
}
@@ -63,22 +63,22 @@ export function computeStackId(prefixUrl: string[] | undefined, url: string) {
}
}
return undefined;
}
};
export function toSegments(path: string): string[] {
export const toSegments = (path: string) => {
return path
.split('/')
.map(s => s.trim())
.filter(s => s !== '');
}
};
export function destroyView(view: RouteView | undefined) {
export const destroyView = (view: RouteView | undefined) => {
if (view) {
// TODO lifecycle event
view.ref.destroy();
view.unlistenEvents();
}
}
};
export interface StackEvent {
enteringView: RouteView;

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EmbeddedViewRef, IterableDiffer, IterableDiffers, NgZone, SimpleChanges, TrackByFunction } from '@angular/core';
import { Cell, CellType, HeaderFn, ItemHeightFn } from '@ionic/core';
import { Cell, CellType, FooterHeightFn, HeaderFn, HeaderHeightFn, ItemHeightFn } from '@ionic/core';
import { proxyInputs, proxyMethods } from '../proxies-utils';
@@ -75,7 +75,7 @@ export declare interface IonVirtualScroll {
/**
* An optional function that maps each item within their height.
* When this function is provides, heavy optimizations and fast path can be taked by
* When this function is provided, heavy optimizations and fast path can be taked by
* `ion-virtual-scroll` leading to massive performance improvements.
*
* This function allows to skip all DOM reads, which can be Doing so leads
@@ -83,6 +83,16 @@ export declare interface IonVirtualScroll {
*/
itemHeight?: ItemHeightFn;
/**
* An optional function that maps each item header within their height.
*/
headerHeight?: HeaderHeightFn;
/**
* An optional function that maps each item footer within their height.
*/
footerHeight?: FooterHeightFn;
/**
* Same as `ngForTrackBy` which can be used on `ngFor`.
*/
@@ -114,6 +124,8 @@ export declare interface IonVirtualScroll {
'footerFn',
'items',
'itemHeight',
'headerHeight',
'footerHeight',
'trackBy'
]
})
@@ -128,7 +140,7 @@ export class IonVirtualScroll {
@ContentChild(VirtualFooter) ftrTmp!: VirtualFooter;
constructor(
private zone: NgZone,
private z: NgZone,
private iterableDiffers: IterableDiffers,
elementRef: ElementRef,
) {
@@ -162,7 +174,7 @@ export class IonVirtualScroll {
}
private nodeRender(el: HTMLElement | null, cell: Cell, index: number): HTMLElement {
return this.zone.run(() => {
return this.z.run(() => {
let node: EmbeddedViewRef<VirtualContext>;
if (!el) {
node = this.itmTmp.viewContainer.createEmbeddedView(
@@ -194,7 +206,7 @@ export class IonVirtualScroll {
}
}
function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement {
const getElement = (view: EmbeddedViewRef<VirtualContext>): HTMLElement => {
const rootNodes = view.rootNodes;
for (let i = 0; i < rootNodes.length; i++) {
if (rootNodes[i].nodeType === 1) {
@@ -202,7 +214,7 @@ function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement {
}
}
throw new Error('virtual element was not created');
}
};
proxyInputs(IonVirtualScroll, [
'approxItemHeight',
@@ -211,7 +223,9 @@ proxyInputs(IonVirtualScroll, [
'headerFn',
'footerFn',
'items',
'itemHeight'
'itemHeight',
'headerHeight',
'footerHeight'
]);
proxyMethods(IonVirtualScroll, [

View File

@@ -34,10 +34,10 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
) {}
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
return new Promise(resolve => {
this.zone.run(() => {
return this.zone.run(() => {
return new Promise(resolve => {
const el = attachView(
this.resolver, this.injector, this.location, this.appRef,
this.zone, this.resolver, this.injector, this.location, this.appRef,
this.elRefMap, this.elEventsMap,
container, component, params, cssClasses
);
@@ -47,8 +47,8 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
}
removeViewFromDom(_container: any, component: any): Promise<void> {
return new Promise(resolve => {
this.zone.run(() => {
return this.zone.run(() => {
return new Promise(resolve => {
const componentRef = this.elRefMap.get(component);
if (componentRef) {
componentRef.destroy();
@@ -65,7 +65,8 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
}
}
export function attachView(
export const attachView = (
zone: NgZone,
resolver: ComponentFactoryResolver,
injector: Injector,
location: ViewContainerRef | undefined,
@@ -73,7 +74,7 @@ export function attachView(
elRefMap: WeakMap<HTMLElement, any>,
elEventsMap: WeakMap<HTMLElement, () => void>,
container: any, component: any, params: any, cssClasses: string[] | undefined
) {
) => {
const factory = resolver.resolveComponentFactory(component);
const childInjector = Injector.create({
providers: getProviders(params),
@@ -93,7 +94,7 @@ export function attachView(
hostElement.classList.add(clazz);
}
}
const unbindEvents = bindLifecycleEvents(instance, hostElement);
const unbindEvents = bindLifecycleEvents(zone, instance, hostElement);
container.appendChild(hostElement);
if (!location) {
@@ -103,7 +104,7 @@ export function attachView(
elRefMap.set(hostElement, componentRef);
elEventsMap.set(hostElement, unbindEvents);
return hostElement;
}
};
const LIFECYCLES = [
LIFECYCLE_WILL_ENTER,
@@ -113,20 +114,22 @@ const LIFECYCLES = [
LIFECYCLE_WILL_UNLOAD
];
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
const unregisters = LIFECYCLES
.filter(eventName => typeof instance[eventName] === 'function')
.map(eventName => {
const handler = (ev: any) => instance[eventName](ev.detail);
element.addEventListener(eventName, handler);
return () => element.removeEventListener(eventName, handler);
});
return () => unregisters.forEach(fn => fn());
}
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
return zone.run(() => {
const unregisters = LIFECYCLES
.filter(eventName => typeof instance[eventName] === 'function')
.map(eventName => {
const handler = (ev: any) => instance[eventName](ev.detail);
element.addEventListener(eventName, handler);
return () => element.removeEventListener(eventName, handler);
});
return () => unregisters.forEach(fn => fn());
});
};
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
function getProviders(params: {[key: string]: any}) {
const getProviders = (params: {[key: string]: any}) => {
return [
{
provide: NavParamsToken, useValue: params
@@ -135,8 +138,8 @@ function getProviders(params: {[key: string]: any}) {
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
}
];
}
};
function provideNavParamsInjectable(params: {[key: string]: any}) {
const provideNavParamsInjectable = (params: {[key: string]: any}) => {
return new NavParams(params);
}
};

View File

@@ -42,7 +42,7 @@ export class Config {
export const ConfigToken = new InjectionToken<any>('USERCONFIG');
function getConfig(): CoreConfig | null {
const getConfig = (): CoreConfig | null => {
if (typeof (window as any) !== 'undefined') {
const Ionic = (window as IonicWindow).Ionic;
if (Ionic && Ionic.config) {
@@ -50,4 +50,4 @@ function getConfig(): CoreConfig | null {
}
}
return null;
}
};

View File

@@ -22,7 +22,7 @@ export class DomController {
}
}
function getQueue() {
const getQueue = () => {
const win = typeof (window as any) !== 'undefined' ? window : null as any;
if (win != null) {
@@ -41,6 +41,6 @@ function getQueue() {
read: (cb: any) => cb(),
write: (cb: any) => cb()
};
}
};
export type RafCallback = (timeStamp?: number) => void;

View File

@@ -59,9 +59,21 @@ export class MenuController {
* @param shouldEnable True if it should be swipe-able, false if not.
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
* @deprecated Use swipeGesture() instead
*/
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, this.doc, 'swipeEnable', shouldEnable, menuId);
console.warn('MenuController.swipeEnable is deprecated. Use MenuController.swipeGesture() instead');
return this.swipeGesture(shouldEnable, menuId);
}
/**
* Used to enable or disable the ability to swipe open the menu.
* @param shouldEnable True if it should be swipe-able, false if not.
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
*/
swipeGesture(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, this.doc, 'swipeGesture', shouldEnable, menuId);
}
/**

View File

@@ -50,12 +50,12 @@ export class NavController {
/**
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
* it's equivalent to call `this.router.navigateByUrl()`, but it's explicit about the **direction** of the transition.
* it's equivalent to calling `this.router.navigateByUrl()`, but it's explicit about the **direction** of the transition.
*
* Going **forward** means that a new page it's going to be pushed to the stack of the outlet (ion-router-outlet),
* Going **forward** means that a new page is going to be pushed to the stack of the outlet (ion-router-outlet),
* and that it will show a "forward" animation by default.
*
* Navigating forward can also be trigger in a declarative manner by using the `[routerDirection]` directive:
* Navigating forward can also be triggered in a declarative manner by using the `[routerDirection]` directive:
*
* ```html
* <a routerLink="/path/to/page" routerDirection="forward">Link</a>
@@ -68,17 +68,17 @@ export class NavController {
/**
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
* it's equivalent to call:
* it's equivalent to calling:
*
* ```ts
* this.navController.setDirection('back');
* this.router.navigateByUrl(path);
* ```
*
* Going **back** means that all the pages in the stack until the navigated page is found will be pop,
* Going **back** means that all the pages in the stack until the navigated page is found will be popped,
* and that it will show a "back" animation by default.
*
* Navigating back can also be trigger in a declarative manner by using the `[routerDirection]` directive:
* Navigating back can also be triggered in a declarative manner by using the `[routerDirection]` directive:
*
* ```html
* <a routerLink="/path/to/page" routerDirection="back">Link</a>
@@ -91,7 +91,7 @@ export class NavController {
/**
* This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
* it's equivalent to call:
* it's equivalent to calling:
*
* ```ts
* this.navController.setDirection('root');
@@ -101,7 +101,7 @@ export class NavController {
* Going **root** means that all existing pages in the stack will be removed,
* and the navigated page will become the single page in the stack.
*
* Navigating root can also be trigger in a declarative manner by using the `[routerDirection]` directive:
* Navigating root can also be triggered in a declarative manner by using the `[routerDirection]` directive:
*
* ```html
* <a routerLink="/path/to/page" routerDirection="root">Link</a>
@@ -114,7 +114,8 @@ export class NavController {
/**
* Same as [Location](https://angular.io/api/common/Location)'s back() method.
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation.
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation
* by default.
*/
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
this.setDirection('back', options.animated, options.animationDirection);
@@ -122,9 +123,9 @@ export class NavController {
}
/**
* This methods goes back in the context of ionic's stack navigation.
* This methods goes back in the context of Ionic's stack navigation.
*
* It recursivelly finds the top active `ion-router-outlet` and calls `pop()`.
* It recursively finds the top active `ion-router-outlet` and calls `pop()`.
* This is the recommended way to go back when you are using `ion-router-outlet`.
*/
async pop() {
@@ -140,11 +141,11 @@ export class NavController {
}
/**
* This methods specifies the direction of the next navigation performed by the angular router.
* This methods specifies the direction of the next navigation performed by the Angular router.
*
* `setDirection()` does not trigger any transition, it just sets a set of flags to be consumed by `ion-router-outlet`.
* `setDirection()` does not trigger any transition, it just sets some flags to be consumed by `ion-router-outlet`.
*
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateBack()` instead of `setDirection()`.
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
*/
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
this.direction = direction;
@@ -212,7 +213,7 @@ export class NavController {
}
}
function getAnimation(direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined {
const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
if (animated === false) {
return undefined;
}
@@ -225,7 +226,7 @@ function getAnimation(direction: RouterDirection, animated: boolean | undefined,
return 'forward';
}
return undefined;
}
};
const DEFAULT_DIRECTION = 'auto';
const DEFAULT_ANIMATED = undefined;

View File

@@ -1,5 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { Inject, Injectable, NgZone } from '@angular/core';
import { BackButtonEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
import { Subject, Subscription } from 'rxjs';
@@ -42,29 +42,30 @@ export class Platform {
*/
resize = new Subject<void>();
constructor(@Inject(DOCUMENT) private doc: any) {
this.win = doc.defaultView;
constructor(@Inject(DOCUMENT) private doc: any, zone: NgZone) {
zone.run(() => {
this.win = doc.defaultView;
this.backButton.subscribeWithPriority = function(priority, callback) {
return this.subscribe(ev => (
ev.register(priority, () => zone.run(callback))
));
};
this.backButton.subscribeWithPriority = function(priority, callback) {
return this.subscribe(ev => {
ev.register(priority, callback);
});
};
proxyEvent(this.pause, doc, 'pause');
proxyEvent(this.resume, doc, 'resume');
proxyEvent(this.backButton, doc, 'ionBackButton');
proxyEvent(this.resize, this.win, 'resize');
proxyEvent(this.pause, doc, 'pause');
proxyEvent(this.resume, doc, 'resume');
proxyEvent(this.backButton, doc, 'ionBackButton');
proxyEvent(this.resize, this.win, 'resize');
let readyResolve: (value: string) => void;
this._readyPromise = new Promise(res => { readyResolve = res; });
if (this.win && this.win['cordova']) {
doc.addEventListener('deviceready', () => {
readyResolve('cordova');
}, { once: true });
} else {
readyResolve!('dom');
}
let readyResolve: (value: string) => void;
this._readyPromise = new Promise(res => { readyResolve = res; });
if (this.win && this.win['cordova']) {
doc.addEventListener('deviceready', () => {
readyResolve('cordova');
}, { once: true });
} else {
readyResolve!('dom');
}
});
}
/**

View File

@@ -25,9 +25,6 @@ export class IonicRouteStrategy implements RouteReuseStrategy {
if (future.routeConfig !== curr.routeConfig) {
return false;
}
if (future.component !== curr.component) {
return false;
}
// checking router params
const futureParams = future.params;

View File

@@ -1,16 +1,29 @@
import { HTMLStencilElement } from '../types/interfaces';
export function proxyMethod(ctrlName: string, doc: Document, methodName: string, ...args: any[]) {
declare const __zone_symbol__requestAnimationFrame: any;
declare const requestAnimationFrame: any;
export const raf = (h: any) => {
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
return __zone_symbol__requestAnimationFrame(h);
}
if (typeof requestAnimationFrame === 'function') {
return requestAnimationFrame(h);
}
return setTimeout(h);
};
export const proxyMethod = (ctrlName: string, doc: Document, methodName: string, ...args: any[]) => {
const controller = ensureElementInBody(ctrlName, doc);
return controller.componentOnReady()
.then(() => (controller as any)[methodName].apply(controller, args));
}
};
export function ensureElementInBody(elementName: string, doc: Document) {
export const ensureElementInBody = (elementName: string, doc: Document) => {
let element = doc.querySelector(elementName);
if (!element) {
element = doc.createElement(elementName);
doc.body.appendChild(element);
}
return element as HTMLStencilElement;
}
};

View File

@@ -0,0 +1 @@
package-lock=false

View File

@@ -13,11 +13,11 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/test-app",
"outputPath": "dist/browser",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
{
@@ -31,9 +31,7 @@
"output": "./svg"
}
],
"styles": [
"src/styles.css"
],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
@@ -86,37 +84,13 @@
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.css"
],
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"styles": ["src/styles.css"],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
"assets": ["src/favicon.ico", "src/assets"]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"test-app-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
@@ -126,20 +100,39 @@
"configurations": {
"production": {
"devServerTarget": "test-app:serve:production"
},
"ci": {
"devServerTarget": "test-app:serve:ci"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
"exclude": ["**/node_modules/**"]
}
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/main.server.ts",
"tsConfig": "tsconfig.server.json"
},
"configurations": {
"production": {
"fileReplacements": [
{
"src": "src/environments/environment.ts",
"replaceWith": "src/environments/environment.prod.ts"
}
]
}
}
}
}
}
},
"defaultProject": "test-app"
}
}

View File

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -1,19 +1,22 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./**/*.e2e-spec.ts'
'./src/**/*.e2e-spec.ts'
],
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=400,1000", "--start-maximized" ]
}
'browserName': 'chrome'
},
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=400,1000", "--start-maximized" ]
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
@@ -25,8 +28,8 @@ exports.config = {
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
};

View File

@@ -4,7 +4,7 @@ import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
describe('form', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
describe('change', () => {

View File

@@ -8,7 +8,7 @@ describe('inputs', () => {
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should have default value', async () => {
@@ -60,4 +60,10 @@ describe('inputs', () => {
expect(await element(by.css('#select-note')).getText()).toEqual('playstation');
expect(await element(by.css('#range-note')).getText()).toEqual('20');
});
it('nested components should not interfere with NgModel', async () => {
expect(await element(by.css('#range-note')).getText()).toEqual('10');
await element(by.css('#nested-toggle')).click();
expect(await element(by.css('#range-note')).getText()).toEqual('10');
});
});

View File

@@ -8,7 +8,7 @@ describe('modals', () => {
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should open standalone modal and close', async () => {

View File

@@ -4,9 +4,44 @@ import { handleErrorMessages, waitTime, testStack } from './utils';
describe('navigation', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
// TODO: Fix flaky tests
xit ('should swipe and abort', async () => {
await browser.get('/router-link?ionic:mode=ios');
await waitTime(500);
await element(by.css('#routerLink')).click();
await waitTime(500);
await swipeLeft(5);
await waitTime(500);
const pageHidden = element(by.css('app-router-link'));
expect(await pageHidden.getAttribute('aria-hidden')).toEqual('true');
expect(await pageHidden.getAttribute('class')).toEqual('ion-page ion-page-hidden');
const pageVisible = element(by.css('app-router-link-page'));
expect(await pageVisible.getAttribute('aria-hidden')).toEqual(null);
expect(await pageVisible.getAttribute('class')).toEqual('ion-page can-go-back');
});
xit ('should swipe and go back', async () => {
await browser.get('/router-link?ionic:mode=ios');
await waitTime(500);
await element(by.css('#routerLink')).click();
await waitTime(500);
await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
await swipeLeft(300);
await waitTime(1000);
await testStack('ion-router-outlet', ['app-router-link']);
const page = element(by.css('app-router-link'));
expect(await page.getAttribute('aria-hidden')).toEqual(null);
expect(await page.getAttribute('class')).toEqual('ion-page');
})
it('should navigate correctly', async () => {
await browser.get('/navigation/page1');
await waitTime(2000);
@@ -22,3 +57,17 @@ describe('navigation', () => {
});
});
function swipeLeft(end: number) {
return browser.driver.touchActions()
.tapAndHold({x: 5, y: 1})
.move({x: 6, y: 1})
.move({x: 7, y: 1})
.move({x: 8, y: 1})
.move({x: 30, y: 1})
.move({x: 300, y: 1})
.move({x: end, y: 1})
.move({x: end, y: 1})
.release({x: end, y: 1})
.perform();
}

View File

@@ -4,7 +4,7 @@ import { waitTime, handleErrorMessages, goBack } from './utils';
describe('nested-outlet', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should navigate correctly', async () => {

View File

@@ -4,7 +4,7 @@ import { handleErrorMessages, waitTime } from './utils';
describe('providers', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should load all providers', async () => {
@@ -12,6 +12,9 @@ describe('providers', () => {
expect(await element(by.css('#is-loaded')).getText()).toEqual('true');
expect(await element(by.css('#is-ready')).getText()).toEqual('true');
expect(await element(by.css('#is-paused')).getText()).toEqual('true');
expect(await element(by.css('#is-resumed')).getText()).toEqual('true');
expect(await element(by.css('#is-resized')).getText()).toEqual('true');
expect(await element(by.css('#is-testing')).getText()).toEqual('false');
expect(await element(by.css('#is-desktop')).getText()).toEqual('true');
expect(await element(by.css('#is-mobile')).getText()).toEqual('false');

View File

@@ -1,5 +1,5 @@
import { browser, element, by, protractor } from 'protractor';
import { waitTime, testStack, testLifeCycle, handleErrorMessages } from './utils';
import { waitTime, testStack, testLifeCycle, handleErrorMessages, getText } from './utils';
const EC = protractor.ExpectedConditions;
@@ -9,7 +9,7 @@ describe('router-link params and fragments', () => {
const id = 'MyPageID==';
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should go to a page with properly encoded values', async () => {
@@ -23,12 +23,13 @@ describe('router-link params and fragments', () => {
it('should return to a page with preserved query param and fragment', async () => {
await browser.get('/router-link?ionic:_testing=true');
await waitTime(30);
await element(by.css('#queryParamsFragment')).click();
await waitTime(200);
await waitTime(400);
await element(by.css('#goToPage3')).click();
browser.wait(EC.urlContains('router-link-page3'), 5000);
await waitTime(200);
await waitTime(400);
await element(by.css('#goBackFromPage3')).click();
@@ -38,6 +39,7 @@ describe('router-link params and fragments', () => {
it('should preserve query param and fragment with defaultHref string', async () => {
await browser.get('/router-link-page3?ionic:_testing=true');
await waitTime(30);
await element(by.css('#goBackFromPage3')).click();
@@ -53,7 +55,7 @@ describe('router-link', () => {
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
@@ -71,18 +73,6 @@ describe('router-link', () => {
it('should go forward with ion-button[routerLink]', async () => {
await element(by.css('#routerLink')).click();
await testForward();
// test go back
await element(by.css('ion-back-button')).click();
await waitTime(500);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 2,
ionViewDidEnter: 2,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
});
it('should go forward with a[routerLink]', async () => {
@@ -140,18 +130,23 @@ describe('router-link', () => {
async function testForward() {
await waitTime(2500);
await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
await testLifeCycle('app-router-link-page', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('true');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 2,
ionViewDidEnter: 2,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
}
async function testRoot() {
@@ -163,6 +158,8 @@ async function testRoot() {
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
@@ -183,4 +180,15 @@ async function testBack() {
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
}

View File

@@ -8,7 +8,7 @@ describe('slides', () => {
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should change index on slide change', async () => {

View File

@@ -3,7 +3,7 @@ import { waitTime, testStack, handleErrorMessages } from './utils';
describe('tabs', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
describe('entry url - /tabs', () => {
beforeEach(async () => {
@@ -20,7 +20,7 @@ describe('tabs', () => {
it('should simulate stack + double tab click', async () => {
let tab = await getSelectedTab() as ElementFinder;
await tab.$('#goto-tab1-page2').click();
await testTabTitle('Tab 1 - Page 2');
await testTabTitle('Tab 1 - Page 2 (1)');
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']);
await testState(1, 'account');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
@@ -31,7 +31,7 @@ describe('tabs', () => {
await testState(2, 'contact');
await element(by.css('#tab-button-account')).click();
tab = await testTabTitle('Tab 1 - Page 2');
tab = await testTabTitle('Tab 1 - Page 2 (1)');
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
await testState(3, 'account');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
@@ -45,7 +45,7 @@ describe('tabs', () => {
it('should simulate stack + back button click', async () => {
const tab = await getSelectedTab();
await tab.$('#goto-tab1-page2').click();
await testTabTitle('Tab 1 - Page 2');
await testTabTitle('Tab 1 - Page 2 (1)');
await testState(1, 'account');
await element(by.css('#tab-button-contact')).click();
@@ -53,7 +53,7 @@ describe('tabs', () => {
await testState(2, 'contact');
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 2');
await testTabTitle('Tab 1 - Page 2 (1)');
await testState(3, 'account');
await element(by.css('ion-back-button')).click();
@@ -62,6 +62,33 @@ describe('tabs', () => {
await testState(3, 'account');
});
it('should navigate deep then go home', async () => {
let tab = await getSelectedTab();
await tab.$('#goto-tab1-page2').click();
tab = await testTabTitle('Tab 1 - Page 2 (1)');
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await element(by.css('#tab-button-contact')).click();
tab = await testTabTitle('Tab 2 - Page 1');
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 2 (2)');
await testStack('ion-tabs ion-router-outlet', [
'app-tabs-tab1',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab2'
]);
await element(by.css('#tab-button-account')).click();
await testTabTitle('Tab 1 - Page 1');
await testStack('ion-tabs ion-router-outlet', [
'app-tabs-tab1',
'app-tabs-tab2'
]);
});
it('should switch tabs and go back', async () => {
await element(by.css('#tab-button-contact')).click();
const tab = await testTabTitle('Tab 2 - Page 1');
@@ -76,7 +103,7 @@ describe('tabs', () => {
const tab = await testTabTitle('Tab 2 - Page 1');
await tab.$('#goto-tab1-page2').click();
await testTabTitle('Tab 1 - Page 2');
await testTabTitle('Tab 1 - Page 2 (1)');
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']);
});
@@ -97,14 +124,14 @@ describe('tabs', () => {
});
});
describe('entry url - /tabs/account/nested/12', () => {
describe('entry url - /tabs/account/nested/1', () => {
beforeEach(async () => {
await browser.get('/tabs/account/nested/12');
await browser.get('/tabs/account/nested/1');
await waitTime(30);
});
it('should only display the back-button when there is a page in the stack', async () => {
let tab = await testTabTitle('Tab 1 - Page 2') as ElementFinder;
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
@@ -112,9 +139,32 @@ describe('tabs', () => {
tab = await testTabTitle('Tab 1 - Page 1');
await tab.$('#goto-tab1-page2').click();
tab = await testTabTitle('Tab 1 - Page 2');
tab = await testTabTitle('Tab 1 - Page 2 (1)');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
});
it('should not reuse the same page', async () => {
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (3)');
await testStack('ion-tabs ion-router-outlet',[
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested'
]);
await tab.$('ion-back-button').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await tab.$('ion-back-button').click();
tab = await testTabTitle('Tab 1 - Page 2 (1)');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
});
});
describe('entry url - /tabs/lazy', () => {
@@ -128,7 +178,7 @@ describe('tabs', () => {
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']);
await tab.$('#goto-tab1-page2').click();
tab = await testTabTitle('Tab 1 - Page 2');
tab = await testTabTitle('Tab 1 - Page 2 (1)');
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']);
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
});

View File

@@ -37,29 +37,30 @@ export interface LifeCycleCount {
}
export function handleErrorMessages() {
browser.manage().logs().get('browser').then(function(browserLog) {
let severWarnings = false;
for (let i; i <= browserLog.length - 1; i++) {
if (browserLog[i].level.name === 'SEVERE') {
console.log('\n' + browserLog[i].level.name);
console.log('(Possibly exception) \n' + browserLog[i].message);
severWarnings = true;
}
return browser.manage().logs().get('browser').then(function (browserLog) {
for (let i = 0; i <= browserLog.length - 1; i++) {
if (browserLog[i].level.name_ === 'SEVERE') {
fail(browserLog[i].message);
}
}
expect(severWarnings).toBe(false);
});
}
export async function testLifeCycle(selector: string, expected: LifeCycleCount) {
await waitTime(50);
expect(await getText(`${selector} #ngOnInit`)).toEqual('1');
expect(await getText(`${selector} #ionViewWillEnter`)).toEqual(expected.ionViewWillEnter.toString());
expect(await getText(`${selector} #ionViewDidEnter`)).toEqual(expected.ionViewDidEnter.toString());
expect(await getText(`${selector} #ionViewWillLeave`)).toEqual(expected.ionViewWillLeave.toString());
expect(await getText(`${selector} #ionViewDidLeave`)).toEqual(expected.ionViewDidLeave.toString());
const results = await Promise.all([
getText(`${selector} #ngOnInit`),
getText(`${selector} #ionViewWillEnter`),
getText(`${selector} #ionViewDidEnter`),
getText(`${selector} #ionViewWillLeave`),
getText(`${selector} #ionViewDidLeave`),
]);
expect(results[0]).toEqual('1');
expect(results[1]).toEqual(expected.ionViewWillEnter.toString());
expect(results[2]).toEqual(expected.ionViewDidEnter.toString());
expect(results[3]).toEqual(expected.ionViewWillLeave.toString());
expect(results[4]).toEqual(expected.ionViewDidLeave.toString());
}
export async function testStack(selector: string, expected: string[]) {

View File

@@ -8,7 +8,7 @@ describe('view-child', () => {
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should get a reference to all children', async () => {

View File

@@ -0,0 +1,18 @@
import { browser, element, by } from 'protractor';
import { waitTime, handleErrorMessages } from './utils';
describe('virtual-scroll', () => {
afterEach(() => {
return handleErrorMessages();
});
beforeEach(async () => {
await browser.get('/virtual-scroll');
await waitTime(30);
});
it('should open virtual-scroll', () => {
const virtualElements = element.all(by.css('ion-virtual-scroll > *'));
expect(virtualElements.count()).toBeGreaterThan(0);
});
});

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +1,63 @@
{
"name": "test-app",
"name": "ionic-angular-test-app",
"version": "0.0.0",
"private": true,
"scripts": {
"ng": "ng",
"start": "npm run sync && ng serve",
"sync:build": "sh scripts/build-ionic.sh",
"sync": "sh scripts/sync.sh",
"build": "ng build --prod --no-progress",
"build": "npm run sync && ng build --prod --no-progress",
"test": "ng e2e --prod",
"lint": "ng lint"
"test.dev": "npm run sync && ng e2e",
"lint": "ng lint",
"postinstall": "npm run sync",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
"build:client-and-server-bundles": "npm run build && ng run test-app:server:production"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.2.1",
"@angular/common": "~7.2.1",
"@angular/compiler": "~7.2.1",
"@angular/core": "~7.2.1",
"@angular/forms": "~7.2.1",
"@angular/platform-browser": "~7.2.1",
"@angular/platform-browser-dynamic": "~7.2.1",
"@angular/router": "~7.2.1",
"@ionic/angular": "^4.5.0",
"@angular/animations": "~8.2.0",
"@angular/common": "~8.2.0",
"@angular/compiler": "~8.2.0",
"@angular/core": "~8.2.0",
"@angular/forms": "~8.2.0",
"@angular/platform-browser": "~8.2.0",
"@angular/platform-browser-dynamic": "~8.2.0",
"@angular/platform-server": "~8.2.0",
"@angular/router": "~8.2.0",
"@ionic/angular": "^4.7.0",
"@ionic/angular-server": "^0.0.2",
"@nguniversal/express-engine": "~8.1.1",
"@nguniversal/module-map-ngfactory-loader": "~8.1.1",
"core-js": "^2.6.2",
"rxjs": "~6.3.3",
"express": "^4.15.2",
"rxjs": "~6.5.2",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
"zone.js": "~0.10.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.12.2",
"@angular/cli": "~7.2.1",
"@angular/compiler-cli": "~7.2.1",
"@angular/language-service": "~7.2.1",
"@types/jasmine": "~2.8.8",
"@angular-devkit/build-angular": "~0.802.0",
"@angular/cli": "~8.2.0",
"@angular/compiler-cli": "~8.2.0",
"@angular/language-service": "~8.2.0",
"@types/jasmine": "~3.3.16",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~4.5.0",
"@types/node": "~12.6.8",
"codelyzer": "^5.0.1",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~3.1.4",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"karma": "~4.2.0",
"karma-chrome-launcher": "~3.0.0",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.2",
"protractor": "~5.4.2",
"ts-node": "~7.0.0",
"tslint": "~5.12.1",
"typescript": "~3.2.4"
"ts-loader": "^5.2.0",
"ts-node": "~8.3.0",
"tslint": "~5.18.0",
"typescript": "~3.5.3",
"webpack-cli": "^3.1.0"
}
}

View File

@@ -10,6 +10,14 @@ popd
pushd angular
npm link @ionic/core
npm run build
npm link
popd
# Build angular-server
pushd packages/angular-server
npm link @ionic/core
npm link @ionic/angular
npm run build
popd
popd

View File

@@ -1,15 +1,25 @@
# Copy angular dist
rm -rf node_modules/@ionic/angular/dist
rm -rf node_modules/@ionic/angular
mkdir node_modules/@ionic/angular
cp -a ../../dist node_modules/@ionic/angular/dist
cp -a ../../css node_modules/@ionic/angular/css
cp -a ../../package.json node_modules/@ionic/angular/package.json
# Copy core dist
rm -rf node_modules/@ionic/core/dist
rm -rf node_modules/@ionic/core/loader
# Copy angular server
rm -rf node_modules/@ionic/angular-server
mkdir node_modules/@ionic/angular-server
cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server/dist
cp -a ../../../packages/angular-server/package.json node_modules/@ionic/angular-server/package.json
# # Copy core dist
rm -rf node_modules/@ionic/core
mkdir node_modules/@ionic/core
cp -a ../../../core/css node_modules/@ionic/core/css
cp -a ../../../core/dist node_modules/@ionic/core/dist
cp -a ../../../core/hydrate node_modules/@ionic/core/hydrate
cp -a ../../../core/loader node_modules/@ionic/core/loader
cp -a ../../../core/package.json node_modules/@ionic/core/package.json
# Copy ionicons
# # Copy ionicons
rm -rf node_modules/ionicons
cp -a ../../../core/node_modules/ionicons node_modules/ionicons

View File

@@ -0,0 +1,58 @@
/**
* *** NOTE ON IMPORTING FROM ANGULAR AND NGUNIVERSAL IN THIS FILE ***
*
* If your application uses third-party dependencies, you'll need to
* either use Webpack or the Angular CLI's `bundleDependencies` feature
* in order to adequately package them for use on the server without a
* node_modules directory.
*
* However, due to the nature of the CLI's `bundleDependencies`, importing
* Angular in this file will create a different instance of Angular than
* the version in the compiled application code. This leads to unavoidable
* conflicts. Therefore, please do not explicitly import from @angular or
* @nguniversal in this file. You can export any needed resources
* from your application's main.server.ts file, as seen below with the
* import for `ngExpressEngine`.
*/
import 'zone.js/dist/zone-node';
import * as express from 'express';
import {join} from 'path';
// Express server
const app = express();
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap} = require('./dist/server/main');
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', DIST_FOLDER);
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});

View File

@@ -1,10 +1,10 @@
<ion-header>
<ion-toolbar>
<ion-title>
Modal test
Alert test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-button (click)="openAlert()" id="action-button">Open Alert</ion-button>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
</ion-content>

View File

@@ -8,10 +8,17 @@ import { NavComponent } from '../nav/nav.component';
})
export class AlertComponent {
changes = 0;
constructor(
private alertCtrl: AlertController
) { }
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
async openAlert() {
const alert = await this.alertCtrl.create({
header: 'Hello',
@@ -21,6 +28,7 @@ export class AlertComponent {
role: 'cancel',
text: 'Cancel',
handler: () => {
console.log(NgZone.isInAngularZone());
NgZone.assertInAngularZone();
}
}

View File

@@ -7,10 +7,6 @@ import { RouterLinkPageComponent } from './router-link-page/router-link-page.com
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
import { HomePageComponent } from './home-page/home-page.component';
import { TabsComponent } from './tabs/tabs.component';
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
import { NestedOutletComponent } from './nested-outlet/nested-outlet.component';
@@ -51,40 +47,7 @@ const routes: Routes = [
},
{
path: 'tabs',
component: TabsComponent,
children: [
{
path: 'account',
children: [
{
path: 'nested/:id',
component: TabsTab1NestedComponent
},
{
path: '',
component: TabsTab1Component
}
]
},
{
path: 'contact',
children: [
{
path: 'one',
component: TabsTab2Component
},
{
path: '',
redirectTo: 'one',
pathMatch: 'full'
}
]
},
{
path: 'lazy',
loadChildren: './tabs-lazy/tabs-lazy.module#TabsLazyModule'
}
]
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
},
{
path: 'nested-outlet',

View File

@@ -1,10 +1,11 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouteReuseStrategy } from '@angular/router';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { IonicModule } from '@ionic/angular';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { InputsComponent } from './inputs/inputs.component';
import { ModalComponent } from './modal/modal.component';
@@ -14,10 +15,6 @@ import { RouterLinkPageComponent } from './router-link-page/router-link-page.com
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
import { HomePageComponent } from './home-page/home-page.component';
import { TabsComponent } from './tabs/tabs.component';
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
import { VirtualScrollInnerComponent } from './virtual-scroll-inner/virtual-scroll-inner.component';
@@ -45,10 +42,6 @@ import { AlertComponent } from './alert/alert.component';
RouterLinkPage2Component,
RouterLinkPage3Component,
HomePageComponent,
TabsComponent,
TabsTab1Component,
TabsTab2Component,
TabsTab1NestedComponent,
VirtualScrollComponent,
VirtualScrollDetailComponent,
VirtualScrollInnerComponent,
@@ -66,7 +59,7 @@ import { AlertComponent } from './alert/alert.component';
AlertComponent
],
imports: [
BrowserModule,
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
@@ -76,7 +69,9 @@ import { AlertComponent } from './alert/alert.component';
ModalExampleComponent,
NavComponent
],
providers: [],
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { IonicServerModule } from '@ionic/angular-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
@NgModule({
imports: [
AppModule,
ServerModule,
ModuleMapLoaderModule,
IonicServerModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}

View File

@@ -20,7 +20,9 @@ export class FormComponent {
input2: ['Default Value'],
checkbox: [false],
range: [5, Validators.min(10)],
}, {updateOn: window.location.hash === '#blur' ? 'blur' : 'change'});
}, {
updateOn: typeof (window as any) !== 'undefined' && window.location.hash === '#blur' ? 'blur' : 'change'
});
}
onSubmit(_ev) {

View File

@@ -93,7 +93,9 @@
<ion-item color="dark">
<ion-label>Range Mirror</ion-label>
<ion-range [(ngModel)]="range"></ion-range>
<ion-range [(ngModel)]="range">
<ion-toggle slot="start" id="nested-toggle" [(ngModel)]="toggle"></ion-toggle>
</ion-range>
<ion-note slot="end">{{range}}</ion-note>
</ion-item>

View File

@@ -12,6 +12,15 @@
<p>
isReady: <span id="is-ready">{{isReady}}</span>
</p>
<p>
isResumed: <span id="is-resumed">{{isResumed}}</span>
</p>
<p>
isPaused: <span id="is-paused">{{isPaused}}</span>
</p>
<p>
isResized: <span id="is-resized">{{isResized}}</span>
</p>
<p>
isTesting: <span id="is-testing">{{isTesting}}</span>
</p>

View File

@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, NgZone } from '@angular/core';
import {
Platform, ModalController, AlertController, ActionSheetController,
PopoverController, ToastController, Events, PickerController, MenuController,
@@ -14,6 +14,9 @@ export class ProvidersComponent {
isLoaded = false;
isReady = false;
isEvent = false;
isResumed = false;
isPaused = false;
isResized = false;
isTesting: boolean = undefined;
isDesktop: boolean = undefined;
isMobile: boolean = undefined;
@@ -32,7 +35,8 @@ export class ProvidersComponent {
toastCtrl: ToastController,
navCtrl: NavController,
domCtrl: DomController,
config: Config
config: Config,
zone: NgZone
) {
// test all providers load
if (
@@ -44,15 +48,31 @@ export class ProvidersComponent {
// test platform ready()
platform.ready().then(() => {
NgZone.assertInAngularZone();
this.isReady = true;
});
platform.resume.subscribe(() => {
console.log('platform:resume');
NgZone.assertInAngularZone();
this.isResumed = true;
});
platform.pause.subscribe(() => {
console.log('platform:pause');
NgZone.assertInAngularZone();
this.isPaused = true;
});
platform.resize.subscribe(() => {
console.log('platform:resize');
NgZone.assertInAngularZone();
this.isResized = true;
});
this.isDesktop = platform.is('desktop');
this.isMobile = platform.is('mobile');
// test events
events.subscribe('topic', () => {
this.isEvent = true;
NgZone.assertInAngularZone();
});
events.publish('topic');
@@ -60,5 +80,11 @@ export class ProvidersComponent {
this.isTesting = config.getBoolean('_testing');
config.set('keyboardHeight', 12345);
this.keyboardHeight = config.getNumber('keyboardHeight');
zone.runOutsideAngular(() => {
document.dispatchEvent(new CustomEvent('pause'));
document.dispatchEvent(new CustomEvent('resume'));
window.dispatchEvent(new CustomEvent('resize'));
});
}
}

View File

@@ -9,6 +9,7 @@
<ion-content padding>
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
<p>canGoBack: <span id="canGoBack">{{canGoBack}}</span></p>
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>

View File

@@ -1,4 +1,5 @@
import { Component, OnInit, NgZone } from '@angular/core';
import { IonRouterOutlet } from '@ionic/angular';
@Component({
selector: 'app-router-link-page',
@@ -11,9 +12,15 @@ export class RouterLinkPageComponent implements OnInit {
didEnter = 0;
willLeave = 0;
didLeave = 0;
canGoBack: boolean = null;
constructor(
private ionRouterOutlet: IonRouterOutlet
) {}
ngOnInit() {
NgZone.assertInAngularZone();
this.canGoBack = this.ionRouterOutlet.canGoBack();
this.onInit++;
}
@@ -21,10 +28,16 @@ export class RouterLinkPageComponent implements OnInit {
if (this.onInit !== 1) {
throw new Error('ngOnInit was not called');
}
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
throw new Error('canGoBack() changed');
}
NgZone.assertInAngularZone();
this.willEnter++;
}
ionViewDidEnter() {
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
throw new Error('canGoBack() changed');
}
NgZone.assertInAngularZone();
this.didEnter++;
}

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
@@ -6,7 +6,7 @@ import { IonSlides } from '@ionic/angular';
templateUrl: './slides.component.html',
})
export class SlidesComponent implements AfterViewInit {
@ViewChild(IonSlides) slides: IonSlides;
@ViewChild(IonSlides, { static: true }) slides: IonSlides;
slideIndex = 0;
slideIndex2 = 0;

View File

@@ -10,6 +10,6 @@
<ion-content padding>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
</p>
</ion-content>

View File

@@ -8,7 +8,7 @@
<h1>LAZY LOADED TAB</h1>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
</p>

View File

@@ -1,6 +1,6 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 1 - Page 2</ion-title>
<ion-title>Tab 1 - Page 2 ({{id}})</ion-title>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
@@ -8,9 +8,10 @@
</ion-header>
<ion-content padding>
<h1>Welcome to NESTED PAGE</h1>
<h1>Welcome to NESTED PAGE {{id}}</h1>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
<ion-button routerLink="/tabs/contact" id="goto-tab2-page1">Go to Tab 2 - Page 1</ion-button>
<ion-button routerLink="/tabs/account/nested/{{next()}}" id="goto-next">Go to Next</ion-button>
</p>
</ion-content>

View File

@@ -1,7 +1,21 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-tabs-tab1-nested',
templateUrl: './tabs-tab1-nested.component.html',
})
export class TabsTab1NestedComponent { }
export class TabsTab1NestedComponent {
id = '';
constructor(
private route: ActivatedRoute,
) {}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
}
next() {
return parseInt(this.id, 10) + 1;
}
}

View File

@@ -1,13 +1,13 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 1 - Page 1</ion-title>
<ion-title>{{title}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Welcome to Tab1</h1>
<p>
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Page 2</ion-button>
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go to nested</ion-button>
</p>

View File

@@ -1,7 +1,17 @@
import { Component } from '@angular/core';
import { Component, NgZone } from '@angular/core';
@Component({
selector: 'app-tabs-tab1',
templateUrl: './tabs-tab1.component.html',
})
export class TabsTab1Component { }
export class TabsTab1Component {
title = 'ERROR';
ionViewWillEnter() {
NgZone.assertInAngularZone();
setTimeout(() => {
NgZone.assertInAngularZone();
this.title = 'Tab 1 - Page 1';
});
}
}

View File

@@ -1,6 +1,6 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 2 - Page 1</ion-title>
<ion-title>{{title}}</ion-title>
</ion-toolbar>
</ion-header>
@@ -8,7 +8,7 @@
<h1>Welcome to Tab 2</h1>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go to nested</ion-button>
</p>
</ion-content>

View File

@@ -1,7 +1,17 @@
import { Component } from '@angular/core';
import { Component, NgZone } from '@angular/core';
@Component({
selector: 'app-tabs-tab2',
templateUrl: './tabs-tab2.component.html',
})
export class TabsTab2Component { }
export class TabsTab2Component {
title = 'ERROR';
ngOnInit() {
NgZone.assertInAngularZone();
setTimeout(() => {
NgZone.assertInAngularZone();
this.title = 'Tab 2 - Page 1';
});
}
}

View File

@@ -0,0 +1,27 @@
import { IonicModule } from '@ionic/angular';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TabsPageRoutingModule } from './tabs.router.module';
import { TabsComponent } from './tabs.component';
import { TabsTab1Component } from '../tabs-tab1/tabs-tab1.component';
import { TabsTab2Component } from '../tabs-tab2/tabs-tab2.component';
import { TabsTab1NestedComponent } from '../tabs-tab1-nested/tabs-tab1-nested.component';
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
TabsPageRoutingModule
],
declarations: [
TabsComponent,
TabsTab1Component,
TabsTab2Component,
TabsTab1NestedComponent
]
})
export class TabsPageModule {}

View File

@@ -0,0 +1,52 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TabsComponent } from './tabs.component';
import { TabsTab1NestedComponent } from '../tabs-tab1-nested/tabs-tab1-nested.component';
import { TabsTab1Component } from '../tabs-tab1/tabs-tab1.component';
import { TabsTab2Component } from '../tabs-tab2/tabs-tab2.component';
const routes: Routes = [
{
path: '',
component: TabsComponent,
children: [
{
path: 'account',
children: [
{
path: 'nested/:id',
component: TabsTab1NestedComponent
},
{
path: '',
component: TabsTab1Component
}
]
},
{
path: 'contact',
children: [
{
path: 'one',
component: TabsTab2Component
},
{
path: '',
redirectTo: 'one',
pathMatch: 'full'
}
]
},
{
path: 'lazy',
loadChildren: () => import('../tabs-lazy/tabs-lazy.module').then(m => m.TabsLazyModule)
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class TabsPageRoutingModule {}

View File

@@ -7,11 +7,11 @@ import { IonTabs, IonButton, IonSlides, IonSlide } from '@ionic/angular';
})
export class ViewChildComponent implements AfterViewInit {
@ViewChild(IonSlides) slides: IonSlides;
@ViewChild(IonButton) button: IonButton;
@ViewChild(IonTabs) tabs: IonTabs;
@ViewChild('div') div: ElementRef;
@ViewChild('slide') slide: IonSlide;
@ViewChild(IonSlides, { static: true }) slides: IonSlides;
@ViewChild(IonButton, { static: true }) button: IonButton;
@ViewChild(IonTabs, { static: true }) tabs: IonTabs;
@ViewChild('div', { static: true }) div: ElementRef;
@ViewChild('slide', { static: true }) slide: IonSlide;
ngAfterViewInit() {
const loaded = !!(this.slides && this.button && this.tabs && this.div && this.slide);

View File

@@ -8,7 +8,7 @@ import { IonVirtualScroll } from '@ionic/angular';
})
export class VirtualScrollComponent {
@ViewChild(IonVirtualScroll) virtualScroll: IonVirtualScroll;
@ViewChild(IonVirtualScroll, { static: true }) virtualScroll: IonVirtualScroll;
items = Array.from({length: 100}, (_, i) => ({ name: `${i}`, checked: true}));

View File

@@ -1,11 +0,0 @@
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11

View File

@@ -0,0 +1,11 @@
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
export { ngExpressEngine } from '@nguniversal/express-engine';
export { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';

View File

@@ -8,5 +8,8 @@ if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
});

View File

@@ -18,57 +18,40 @@
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
**/
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/

View File

@@ -1,15 +0,0 @@
{
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictMetadataEmit" : true
},
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

View File

@@ -1,18 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts",
"polyfills.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@@ -1,17 +0,0 @@
{
"extends": "../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
]
}
}

View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app"
},
"include": ["src/**/*.ts"],
"exclude": ["src/test.ts", "src/**/*.spec.ts"]
}

View File

@@ -1,16 +1,13 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"importHelpers": true,
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "es2015",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.app.json",
"compilerOptions": {
"outDir": "../out-tsc/app-server"
},
"angularCompilerOptions": {
"entryModule": "./src/app/app.server.module#AppServerModule"
}
}

View File

@@ -0,0 +1,19 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/zone-flags.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

View File

@@ -1,36 +1,16 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"extends": "tslint:recommended",
"rulesDirectory": ["codelyzer"],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"import-blacklist": [true, "rxjs/Rx"],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [true, 140],
"member-access": false,
"member-ordering": [
true,
@@ -43,89 +23,32 @@
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-consecutive-blank-lines": false,
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-inferrable-types": [true, "ignore-params"],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"ordered-imports": false,
"quotemark": [true, "single"],
"trailing-comma": false,
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-inputs-metadata-property": true,
"no-inputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
"one-variable-per-declaration": false,
"component-class-suffix": [true, "Page", "Component"],
"directive-class-suffix": true,
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "page", "kebab-case"]
}
}

View File

@@ -0,0 +1,53 @@
// Work around for https://github.com/angular/angular-cli/issues/7200
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'none',
entry: {
// This is our Express server for Dynamic universal
server: './server.ts'
},
externals: {
'./dist/server/main': 'require("./server/main")'
},
target: 'node',
resolve: {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js']
},
optimization: {
minimize: false
},
output: {
// Puts the output at the root of the dist folder
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
{
// Mark files inside `@angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
parser: { system: true },
},
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
};

View File

@@ -29,7 +29,16 @@
"importHelpers": true,
"rootDir": "src",
"strictPropertyInitialization": false,
"target": "es2015"
"target": "es2015",
"baseUrl": ".",
"paths": {
"@ionic/core/hydrate": [
"../core/hydrate"
],
"@ionic/core": [
"../core"
]
}
},
"exclude": ["node_modules", "src/schematics"],
"files": ["src/index.ts"]

View File

@@ -18,7 +18,7 @@
"no-floating-promises": false,
"no-invalid-template-strings": true,
"ban-export-const-enum": true,
"only-arrow-functions": true,
"prefer-for-of": false
}
}

View File

@@ -23,9 +23,9 @@ The Ionic Core package contains the Web Components that make up the reusable UI
Easiest way to start using Ionic Core is by adding a script tag to the CDN:
```html
<script type="module" src="https://unpkg.com/@ionic/core@4.6.1/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://unpkg.com/@ionic/core@4.6.1/dist/ionic/ionic.js"></script>
<link href="https://unpkg.com/@ionic/core@4.6.1/css/ionic.bundle.css" rel="stylesheet">
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/dist/ionic/ionic.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@ionic/core@4.6.2/css/ionic.bundle.css" rel="stylesheet">
```
Any Ionic component added to the webpage will automatically load. This includes writing the component tag directly in HTML, or using JavaScript such as `document.createElement('ion-toggle')`.

View File

@@ -1280,7 +1280,9 @@ ion-virtual-scroll,prop,approxFooterHeight,number,30,false,false
ion-virtual-scroll,prop,approxHeaderHeight,number,30,false,false
ion-virtual-scroll,prop,approxItemHeight,number,45,false,false
ion-virtual-scroll,prop,footerFn,((item: any, index: number, items: any[]) => string | null | undefined) | undefined,undefined,false,false
ion-virtual-scroll,prop,footerHeight,((item: any, index: number) => number) | undefined,undefined,false,false
ion-virtual-scroll,prop,headerFn,((item: any, index: number, items: any[]) => string | null | undefined) | undefined,undefined,false,false
ion-virtual-scroll,prop,headerHeight,((item: any, index: number) => number) | undefined,undefined,false,false
ion-virtual-scroll,prop,itemHeight,((item: any, index: number) => number) | undefined,undefined,false,false
ion-virtual-scroll,prop,items,any[] | undefined,undefined,false,false
ion-virtual-scroll,prop,nodeRender,((el: HTMLElement | null, cell: Cell, domIndex: number) => HTMLElement) | undefined,undefined,false,false

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "4.6.1",
"version": "4.7.2",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -16,7 +16,6 @@
"pwa"
],
"main": "dist/index.js",
"unpkg": "dist/ionic/ionic.js",
"module": "dist/index.mjs",
"es2015": "dist/esm/index.mjs",
"es2017": "dist/esm/index.mjs",
@@ -27,14 +26,15 @@
"files": [
"dist/",
"css/",
"hydrate/",
"loader/"
],
"dependencies": {
"ionicons": "4.6.1",
"ionicons": "^4.6.2",
"tslib": "^1.10.0"
},
"devDependencies": {
"@stencil/core": "1.1.5",
"@stencil/core": "1.2.3",
"@stencil/sass": "1.0.0",
"@types/jest": "24.0.13",
"@types/node": "10.12.18",
@@ -43,6 +43,7 @@
"aws-sdk": "^2.320.0",
"chromedriver": "^2.38.3",
"clean-css-cli": "^4.1.11",
"domino": "^2.1.3",
"fs-extra": "^8.0.1",
"jest": "24.8.0",
"jest-cli": "24.8.0",
@@ -61,13 +62,14 @@
"tslint-react": "^3.6.0"
},
"scripts": {
"build": "npm run clean && npm run build.css && npm run build.vendor && stencil build --docs",
"build": "npm run clean && npm run build.css && npm run build.vendor && stencil build --docs && npm run cdnloader",
"build.vendor": "rollup --config ./scripts/swiper.rollup.config.js",
"build.css": "npm run css.sass && npm run css.minify",
"build.debug": "npm run clean && stencil build --debug",
"build.docs.json": "stencil build --docs-json dist/docs.json",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"clean": "node scripts/clean.js",
"cdnloader": "node scripts/copy-cdn-loader.js",
"css.minify": "cleancss -O2 -o ./css/ionic.bundle.css ./css/ionic.bundle.css",
"css.sass": "sass src/css:./css",
"lint": "npm run lint.ts && npm run lint.sass",
@@ -77,7 +79,7 @@
"lint.ts": "tslint --project .",
"lint.ts.fix": "tslint --project . --fix",
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
"prerender.e2e": "node scripts/testing/prerender-e2e.js",
"prerender.e2e": "node scripts/testing/prerender.js",
"start": "npm run build.css && stencil build --dev --watch --serve",
"test": "stencil test --spec --e2e",
"test.spec": "stencil test --spec",
@@ -98,7 +100,7 @@
"bugs": {
"url": "https://github.com/ionic-team/ionic/issues"
},
"homepage": "https://github.com/ionic-team/ionic#readme",
"homepage": "https://ionicframework.com/",
"jest": {
"preset": "@stencil/core/testing"
}

View File

@@ -0,0 +1,30 @@
exports.applyPolyfills = function() { return Promise.resolve() };
exports.defineCustomElements = function(_, opts) {
return new Promise(function(resolve, reject) {
if (typeof document !== 'undefined') {
opts = opts || {};
var mod = document.createElement('script');
mod.setAttribute('type', 'module');
mod['data-opts'] = opts;
mod.src = '__CDN_LOADER_URL__/dist/ionic/ionic.esm.js';
var legacy = document.createElement('script');
legacy.setAttribute('nomodule', '');
legacy['data-opts'] = opts;
legacy.src = '__CDN_LOADER_URL__/dist/ionic/ionic.js';
mod.onload = resolve;
mod.onerror = reject;
legacy.onload = resolve;
legacy.onerror = reject;
document.head.appendChild(mod);
document.head.appendChild(legacy);
} else {
resolve();
}
});
}

Some files were not shown because too many files have changed in this diff Show More