Compare commits

..

291 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
Brandy Carney
908f36f574 4.6.1 2019-07-09 12:28:12 -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
Manu Mtz.-Almeida
ab20bf472d revert disconnecting page on leaving page 2019-07-09 10:32:46 +02: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
7fda509333 test(e2e): increase wait time 2019-07-08 13:16:17 -04:00
Brandy Carney
0031ab82b7 style(lint): fix lint issues 2019-07-08 11:11:49 -04:00
Manu Mtz.-Almeida
e059fc8048 perf(angular): skip zone 2019-07-06 19:33:34 +02:00
Manu Mtz.-Almeida
7953088418 fix(angular): fix linting issues 2019-07-05 20:32:42 +02:00
Manu Mtz.-Almeida
1add112be6 chore(): update stencil 2019-07-05 19:33:22 +02: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
Liam DeBeasi
d71c1cd6b0 Revert "fix(angular): use baseURI has base path"
This reverts commit 4038e0a60c.

revert
2019-07-03 14:11:53 -04:00
Liam DeBeasi
ccd46028f2 chore(): update stencil to 1.1.4 2019-07-03 13:29:25 -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
Liam DeBeasi
a656dadf4b Merge branch '4.6.1-hotfix' of https://github.com/ionic-team/ionic into 4.6.1-hotfix
merge
2019-07-02 16:06:06 -04:00
Adam Bradley
03c834c647 fix(tabs): do not emit tab change if selectedTab undefined 2019-07-02 15:04:46 -05: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
Brandy Carney
dfa2b13c3a fix(item): do not disable entire item if there are multiple inputs (#18696)
references #18655
fixes #18670
2019-07-02 14:45:24 -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
Liam DeBeasi
08daaeb1a3 Merge branch '4.6.1-hotfix' of https://github.com/ionic-team/ionic into 4.6.1-hotfix
update
2019-07-01 11:39:16 -04:00
Brandy Carney
1f51ab27c4 fix(router-link): add missing target prop (#18659)
references #18655
2019-07-01 11:23:41 -04:00
Manu Mtz.-Almeida
36a58df181 fix(): copy all scss files 2019-07-01 17:12:44 +02:00
Manu Mtz.-Almeida
4038e0a60c fix(angular): use baseURI has base path 2019-07-01 17:01:14 +02:00
Brandy Carney
6042b39313 fix(fab-button): set opacity on disabled fab button (#18685)
fixes #18682
2019-07-01 10:54:02 -04:00
Liam DeBeasi
dc04a4b8a9 Merge branch '4.6.1-hotfix' of https://github.com/ionic-team/ionic into 4.6.1-hotfix
merg
2019-07-01 10:51:26 -04:00
Manu Mtz.-Almeida
98499acff9 chore(): update ionicons 2019-06-28 22:59:33 +02:00
Liam DeBeasi
2417d32316 a# the commit.
merge
2019-06-28 16:33:35 -04:00
Liam DeBeasi
735280168f Merge branch '4.6.x' of https://github.com/ionic-team/ionic into 4.6.x
merge
2019-06-28 16:33:08 -04:00
Manu Mtz.-Almeida
ef10f190cd fix(): copy theme scss 2019-06-28 22:26:23 +02:00
Manu Mtz.-Almeida
b9b60df0a4 chore(): update stencil 2019-06-28 22:26:17 +02:00
Manu Mtz.-Almeida
b69fb69a1a fix(router-outlet): fix swipe to go back 2019-06-27 17:51:03 +02:00
Kelvin Dart
92e0f98633 fix(datetime): datetime no longer reports having a value if none is set (#18541)
fixes #17979 
fixes #18540
2019-06-27 17:51:03 +02:00
Manu Mtz.-Almeida
0d58101edc fix(infinite-scroll): fix scroll listener 2019-06-27 17:50:13 +02:00
Manu Mtz.-Almeida
44c88ad908 fix(): overlay create opts are optional 2019-06-27 17:36:26 +02:00
Kelvin Dart
45b82dc466 fix(datetime): datetime no longer reports having a value if none is set (#18541)
fixes #17979 
fixes #18540
2019-06-27 10:48:09 -04:00
Brandy Carney
22ac160021 merge release-4.6.0 2019-06-26 14:15:46 -04:00
Brandy Carney
b46a025576 merge release-4.6.0
Release 4.6.0
2019-06-26 14:12:51 -04:00
Brandy Carney
7d5477cf22 4.6.0 2019-06-26 13:53:29 -04:00
Bengt Weiße
f48dc3dd1a fix(button): default opacity for disabled clear buttons (#18560)
fixes #18555
2019-06-26 12:29:24 -04:00
Manu MA
301b0fc1d1 chore(): update to stencil 1.1 (#18609) 2019-06-26 17:17:48 +02:00
Brandy Carney
d4c7b036fc feat(router-link): add router-link and deprecate anchor (#18620) 2019-06-25 18:06:51 -04:00
Brandy Carney
8a88dd25b6 feat(item): add hover and focused states (#18606)
references #18279 references #17624
2019-06-25 17:29:14 -04:00
Brandy Carney
ad00679da9 feat(fab-button): add hover state using tint colors (#18536)
- fixes a bug where backdrop filter was not applied on translucent buttons and checks for support first

references #17624
2019-06-25 17:26:29 -04:00
Adam Bradley
598a13ecc0 chore(test): remove unused preview tests (#18608) 2019-06-24 17:15:57 -05:00
Manu MA
34dfc3ce98 refactor(all): updating to newest stencil apis (#18578)
* chore(): update ionicons

* refactor(all): updating to newest stencil apis

* fix lint issues

* more changes

* moreee

* fix treeshaking

* fix config

* fix checkbox

* fix stuff

* chore(): update ionicons

* fix linting errors
2019-06-23 11:26:42 +02:00
Brandy Carney
78e477b2a7 fix(segment): apply hover properly for segment with color (#18549) 2019-06-21 16:17:09 -04:00
Brandy Carney
832306cf6e fix(segment): default ripple to currentColor (#18547)
this fixes an issue with themed toolbars so that it doesn't use the default primary color
2019-06-21 15:45:24 -04:00
Brandy Carney
73599c22aa docs(components): document what start and end mean for CSS variables (#18538) 2019-06-21 15:11:07 -04:00
Brandy Carney
26ecf2b10f fix(button): update solid buttons to use tint and shade colors (#18537) 2019-06-21 11:31:41 -04:00
Ely Lucas
1e014f0b14 fix(react) router refactor and fixes
* wip

* wip

* wip

* cleanup

* stable ver of ionic/core dependency

* update version
2019-06-20 09:28:20 -06:00
Manu MA
b40f7d36d5 fix(): update to Stencil One 🎉🎊 2019-06-19 21:33:50 +02:00
Liam DeBeasi
7f1829eb21 docs(): add iOS only note to translucent props (#18529)
* docs(): add ios-only note to translucency

* change wording slightly

* update ios only verbiage
2019-06-13 16:04:40 -04:00
Liam DeBeasi
eb9bad7a31 chore(): revise process doc (#18530) 2019-06-12 16:20:51 -04:00
Liam DeBeasi
5bdd16404e docs(toolbar): remove no-border reference (#18528) 2019-06-12 15:30:24 -04:00
Amy Marsh
9e4346bb44 fix(menu): change ARIA role from complementary to navigation (#18330)
fixes #18318
2019-06-12 14:34:53 -04:00
Brandy Carney
eca4121dc6 feat(components): add missing button/a props to components that render them (#17883)
Adds the following properties to the components listed under them:

`rel`, `download`, `target`:
- anchor
- button
- card
- fab-button
- item-option
- item
- tab-button

`disabled`:
- back-button
- menu-button

`type`:
- back-button
- item-option
- menu-button
- segment-button

fixes #16848 closes #16889


Co-authored-by: bitflower <matthias.max@bitflower.net>
2019-06-12 14:06:29 -04:00
Liam DeBeasi
828eaaf3d3 merge release-4.5.0
Release 4.5.0
2019-06-12 13:12:28 -04:00
Liam DeBeasi
335e02aa44 merge release-4.5.0
Release 4.5.0
2019-06-12 13:06:52 -04:00
Liam DeBeasi
0f242fd956 4.5.0 2019-06-12 12:43:33 -04:00
Liam DeBeasi
8b8bbb8a8d chore(): run linter 2019-06-12 12:24:08 -04:00
Liam DeBeasi
36fd78281c fix(test): avoid more race conditions 2019-06-12 12:16:52 -04:00
Liam DeBeasi
b85b7c6b9d fix(test): rsolve race conditions with toast and item 2019-06-12 11:41:26 -04:00
Iván Navarro
320719b904 fix(button): set opacity on the host for disabled button (#18509)
allows for customization of the disabled button opacity

fixes #16965
2019-06-11 17:56:13 -04:00
Liam DeBeasi
4ad078a975 feat(searchbar): add cancel button visibility options (#18507)
Resolves #18399

Co-authored-by: aballet <adrien.ballet@student.uclouvain.be>
2019-06-11 17:42:13 -04:00
Brandy Carney
d075b2c6e2 Merge branch 'master' into feat-searchbar-options 2019-06-11 17:13:34 -04:00
Liam DeBeasi
64460b8efc remove extra utils file 2019-06-11 17:05:03 -04:00
scrp
a583902f30 fix(textarea): inherit white-space for better customization (#18508)
fixes #18495
2019-06-11 14:47:37 -04:00
Liam DeBeasi
aac60b1390 default to never 2019-06-11 14:01:12 -04:00
Liam DeBeasi
500edddcb1 Merge branch 'master' into feat-searchbar-options 2019-06-11 12:49:33 -04:00
Liam DeBeasi
43ed2b0d1d fix some comments 2019-06-11 12:40:46 -04:00
Liam DeBeasi
267e733109 fix typo 2019-06-11 12:35:13 -04:00
Liam DeBeasi
05a407196f Merge branch 'feat-searchbar-options' of https://github.com/ionic-team/ionic into feat-searchbar-options
merge.
2019-06-11 12:34:26 -04:00
Liam DeBeasi
bba311653d add utils, fix css bug on md 2019-06-11 12:33:33 -04:00
Liam DeBeasi
b8b8d697f4 Update core/src/components/searchbar/searchbar.tsx
Co-Authored-By: Manu MA <manu.valladolid@gmail.com>
2019-06-11 12:05:44 -04:00
Liam DeBeasi
577318be15 Small styling fix 2019-06-11 11:31:22 -04:00
Liam DeBeasi
0b78a00afb update usage docs 2019-06-11 11:28:15 -04:00
Brandy Carney
ef29b5fb04 docs(item-sliding): fix extra paren 2019-06-11 11:27:53 -04:00
Liam DeBeasi
b959e0b5ec feat(searchbar): add cancel button options 2019-06-11 11:17:48 -04:00
Walt Woods
20c146e1e5 fix(virtual-scroll): don't crash with an empty cell list (#17799) 2019-06-11 11:00:25 -04:00
Brandy Carney
8d2a47e881 fix(item): inherit overflow to allow better customization (#18502)
fixes #17670


Co-authored-by: Stefanos Anagnostou <anagstef@gmail.com>
2019-06-11 10:34:41 -04:00
Brandy Carney
055e12570d fix(button): use correct border-radius on menu & back button (#18501)
- adds hover and focused state to menu button

references #17624
2019-06-10 17:58:04 -04:00
Albert
35c143a036 feat(item-divider): add inner padding CSS variables (#18490)
fixes #18484
2019-06-10 17:06:50 -04:00
Vlad Topala
a3e23fc9fa fix(button): use correct size on a dynamic button in an item (#18395)
fixes ##18085
2019-06-10 16:47:32 -04:00
Brandy Carney
58672fb221 feat(back-button): add variables and support for focused and hover states (#18451)
- updates MD spacing for back button text
- also adds e2e tests and adds them to screenshot

references #18279 references #17624 fixes #18465
2019-06-10 15:23:42 -04:00
Brandy Carney
5c5934bc24 feat(button): add variables for customizing hover state (#18499)
resolves #17974
2019-06-10 13:38:50 -04:00
Mark Levy
7610787e09 fix(angular): ensure all NavigationExtras values are preserved when navigating (#18468)
fixes #18469
2019-06-10 11:45:36 -04:00
Cezary Kluczyński
54bdb367c2 fix(platform): prevent error with Platform.is on Android 4.4 (#18387) 2019-06-10 10:47:23 -04:00
Max Lynch
10de1da948 Change default zoom option on Swiper options to false. Fixes #18035 2019-06-03 17:11:56 -05:00
Max Lynch
4a0de23cab Vue 0.0.8
Simpler vue components

Adding back Vue suffix
2019-06-03 16:52:13 -05:00
Marc
be8dd55c21 docs(reorder-group): update doReorder method (#18425)
* docs(reorder-group): update doReorder method

* chore: run docs build
2019-06-03 16:11:19 -04:00
Max Lynch
3a4f475889 Vue 0.0.5-test 2019-06-03 15:07:21 -05:00
Ibby Hadeed
49eba77c37 style(action-sheet): remove extra parentheses (#18447) 2019-06-03 16:07:18 -04:00
Brandy Carney
1899c13385 fix(item): use a step color if the activated background is not set (#18450)
fixes #18449
2019-06-03 16:06:21 -04:00
Max Lynch
aac7a23fd5 Vue inputs and v-model support. #14912 2019-06-03 14:46:57 -05:00
Brandy Carney
5ba0aa9aac feat(menu-button): add variables for hover and focused states (#18434)
references #18279
2019-05-31 11:31:34 -04:00
Liam DeBeasi
c8104a29ec feat(toast): allow html content (#18423) 2019-05-30 12:36:54 -04:00
Brandy Carney
17ad73ace2 docs(readme): move usages from readme to usage folder (#18384)
closes ionic-team/ionic-docs#664
closes ionic-team/ionic-docs#550
closes ionic-team/ionic-docs#148
2019-05-29 17:19:42 -04:00
Cody Sand
b2290a6420 fix(content): prevent ion-searchbar from receiving padding adjustment (#18008)
* Fixes #18007 - check for fixed containing element and don't adjust ion-content padding.

* fix lint issue

* searchbar does not receive padding fix

* remove fixed slot check
2019-05-29 15:35:07 -04:00
Liam DeBeasi
fbb76e63ad test(): remove external images (#18413)
* chore(test): replace img in favor of datauri

* remove external images
2019-05-29 15:01:46 -04:00
Robert Rhoades
d53e7aa51c fix(card): remove white space from bottom of card (#18328)
When using a card with the button attribute the `<button>` element is
set to display: inline-block in chrome. This causes an undesirable line
of white space at the bottom of the card. This is most noticeable when
using an image inside the card where the bottom of the `<img>` tag won't
reach the bottom of the card.

Setting the button to have `display: block` ignores this white space
allowing the content to reach the end of the card.
2019-05-29 10:18:25 -04:00
Liam DeBeasi
11cde99e20 fix(tabs): allow selection on enter and spacebar press (#18381)
fixes #18363
2019-05-29 08:42:02 -04:00
Max Lynch
0fd3e5d4c5 fix(react): ensure element exists in controller before dismissing it 2019-05-26 14:38:41 -05:00
Brandy Carney
f0af70736b fix(item): align stacked and floating items start (#18379)
fixes #16375
2019-05-24 17:47:29 -04:00
Liam DeBeasi
292b24ad8f fix(datetime): recalculate time columns on change (#18380) 2019-05-24 14:35:55 -04:00
Liam DeBeasi
6ddde3aa98 test(angular): add queryparam and fragment tests (#18372)
* add queryparam and fragment tests

* reorder imports
2019-05-24 11:29:56 -04:00
Brandy Carney
4bba540311 fix(label): include the ion-text-wrap class styles for larger font (#18374)
- updates all e2e tests to use the CSS classes instead of attributes
2019-05-24 11:18:28 -04:00
Brandy Carney
454510092e fix(item-sliding): use the correct gesture direction and side for rtl (#18366)
references #17012
2019-05-23 15:10:34 -04:00
Liam DeBeasi
7ab9479f2c 4.4.2
4.4.2
2019-05-22 20:05:22 -04:00
Liam DeBeasi
017febed96 merge release-4.4.2
Release 4.4.2
2019-05-22 19:55:09 -04:00
Liam DeBeasi
f7d174f2f8 4.4.2 2019-05-22 19:26:51 -04:00
Liam DeBeasi
b79f68a776 fix(angular): account for query params and fragments within a string (#18356)
* account for defaultHref, switch to serializer

* bug fix
2019-05-22 19:20:23 -04:00
Brandy Carney
62abb972e9 merge release-4.4.1 2019-05-22 15:44:39 -04:00
Brandy Carney
53720dfcc7 merge release-4.4.1 2019-05-22 15:42:11 -04:00
Liam DeBeasi
55fc424835 remove react changelog 2019-05-22 13:33:47 -04:00
Liam DeBeasi
7c7c6e47a9 4.4.1 2019-05-22 13:30:57 -04:00
Liam DeBeasi
5d8b6a5a70 Merge branch 'stable' into release-4.4.1 2019-05-22 12:34:42 -04:00
Liam DeBeasi
4be8d7e622 tests(): add missing test statements (#18346) 2019-05-22 12:31:04 -04:00
Brandy Carney
d13983451a fix(button): only apply has-icon-only if icon has the slot for icon-only (#18343)
fixes #18329
2019-05-22 11:28:06 -04:00
Abdelaziz Bennouna
788a56c5e9 fix(picker): update the column positions in rtl (#18339)
references #17012
2019-05-22 09:20:01 -04:00
Abdelaziz Bennouna
17345efb14 fix(datetime): update label direction in rtl (#18340) 2019-05-22 09:18:41 -04:00
Brandy Carney
805b225876 fix(segment): update segment border for rtl (#18326)
references #17012
2019-05-21 17:46:14 -04:00
Brandy Carney
845def82f5 fix(rtl): updates searchbar, fab and toggle icon positioning in rtl (#18325)
- fixes tab badge (in Chrome)
- fixes searchbar buttons
- fixes fab positioning
- fixes toggle

references #17012
2019-05-21 17:20:45 -04:00
Liam DeBeasi
4339ec3aa9 fix(angular): preserve special characters encoding when going back (#18323) 2019-05-21 16:06:31 -04:00
Brandy Carney
48553511be fix(range): update border-radius on range pin for rtl (#18321)
references #17012
2019-05-21 15:24:20 -04:00
Liam DeBeasi
82a63a972d docs(datetime): add note about timezones, fix typo (#18289) 2019-05-21 15:08:27 -04:00
Liam DeBeasi
adaaf89737 chore(): remove debug and log statements (#18245)
fixes #18190
2019-05-21 14:55:41 -04:00
Brandy Carney
00a27dc37b fix(css): update rtl function to prepend selectors with host-context properly (#18315)
references #17012
2019-05-21 14:42:57 -04:00
Brandy Carney
6252458d49 test(components): add rtl tests and remove skips (#18319)
references #17012
2019-05-21 13:16:07 -04:00
Sarah
04a0e41e67 docs(toast-controller): fix description typo (#18312)
Fix typo in component description text.
2019-05-20 14:23:25 -04:00
Liam DeBeasi
b8d4961483 fix(angular): ensure active page is not removed from change detection (#18299)
fixes #18293
2019-05-20 12:08:19 -04:00
Liam DeBeasi
bdd5109dbe fix(angular): preserve queryParams and fragment when going back (#18298)
fixes #16744
2019-05-20 11:56:02 -04:00
Brandy Carney
da38647478 fix(tabs): initialize select in the willLoad before the select call is made (#18300)
#17957
2019-05-20 11:26:46 -04:00
Brandy Carney
fa87e35a05 fix(toolbar): update md toolbar button spacing and padding to match spec (#17537)
- Removes the padding from the main toolbar and individually style the components inside of it
- Adds a `has-icon-only` class to button, this is used to switch between `unbounded` and `bounded` ripples on buttons in a toolbar. If the button is clear and only has an icon, we use the unbounded "circular" ripple effect, otherwise still use the bounded one. This matches the MD spec, without making the other buttons look off.
- Using the class above, style the button differently to match the MD spec
- Updates the back button and menu button to use the proper size / icon size
- Removes the opacity on an activated back button, it should use the ripple for activated
- Moves the margin to the slots in a toolbar by grabbing the "first" and "last" slot and applying a class to them
- Makes the segment in a toolbar use the min height from the toolbar
- Updates the back button so that it matches the MD spec
- Updates the header box shadow to use the old v3 datauri 

fixes #16950 fixes #14444
2019-05-17 14:54:21 -04:00
Chris
a8f9dfe0e1 fix(slides): disable swiper touch preventDefault (#16728)
* fix(slides): disable swiper touch preventDefault

* fix(slides): update Swiper types

* add screenshots to test

* add screenshot descriptions
2019-05-15 15:12:30 -04:00
Paul Stelzer
875d56363c fix(overlay): hide scrollbars on non-scrollable content (#16767)
fixes #14178
2019-05-15 10:33:33 -04:00
Brandy Carney
051198928e fix(buttons): use theme/color toolbar colors for buttons (#18191)
- Updates the iOS buttons in a toolbar to use the proper global theming variables
- Updates the iOS segment to use the correct background variable when checked
- Updates the iOS back button and menu button to use the proper color in a toolbar
- Updates the iOS buttons in a toolbar w/ color to use the proper contrast colors (background, borders, text, hover, focus), mostly solid and outline buttons were affected
- Updates the CSS that applies the global toolbar variables so that it won't affect toolbars w/ a color

fixes #18184, fixes #17840
2019-05-14 18:02:30 -04:00
Ely Lucas
578108d586 fix(react): making children prop optional on overlay components (#18243) 2019-05-14 15:40:03 -05:00
Ely Lucas
3d04417a05 fix(react): defaultHref fixes (#18278)
* fix(react): making children prop optional on overlay components

* fix(react): passing in defaultHref so it can be used if there is no prev view
2019-05-14 15:08:47 -05:00
Brandy Carney
a3644a5420 test(theming): update theming tests 2019-05-14 14:51:08 -04:00
Liam DeBeasi
d788a8eac6 fix(tab-button): apply background-focused when tabbing into tab button (#17502)
fixes #17042
2019-05-14 12:04:41 -04:00
Matt
3cad7787c2 fix(input): keep entire input in view when scrolling with keyboard open (#18253)
fixes #17457
2019-05-14 11:41:58 -04:00
Liam DeBeasi
ba0def3a38 bug(security): allow name and slot attributes when sanitizing (#18246)
* allow name attribute

* also add slot
2019-05-14 11:28:31 -04:00
Brandy Carney
394cf8d28f fix(icon): remove stroke and move fill to host element (#18241)
This removes the weird border around custom SVGs used in an ion-icon.

fixes #16483
2019-05-10 11:55:35 -04:00
Liam DeBeasi
a6cb5f218e fix(loading): allow html content (#18242)
fixes #18135
2019-05-09 16:03:38 -04:00
Ely Lucas
7bb6a8e8b1 fix(react): Support for adding css classes via className in Ionic React components (#18231)
* fix(react): adding classname to react props

* fix(react): updating rtl to latest to fix ts error

* fix(react): changes to support className
2019-05-08 15:53:33 -05:00
Liam DeBeasi
9c65d5d65a chore(): resolve conflicts from older hotifx
* Release 4.3.1 (#18152)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* merge release-4.4.0

* docs(process): update release process

* docs(fab-list): update the activated description (#18026)

* docs(breaking): add ionDrag event arguments change (#17989)

* docs(slides): add swiper prefix in animation usage (#18073)

* feat(searchbar): add disabled property (#17935)

closes #17921

* fix(reorder-group): remove required parameter for the complete method (#18084)

also updates documentation surrounding the reorder & infinite scroll

fixes #16302

* docs(components): update method and parameter descriptions (#18075)

* fix(datetime): default to current date when value is null (#18105)

fixes #18099

* docs(toolbar): fix end slot documentation (#18092)

* fix(item): use the global activated background for md ripple color (#16752)

fixes #16585

* fix(textarea): reposition textarea when keybard appears (#18098)

fixes #17847

* fix(button): apply round property to button sizes in iOS (#18125)

fixes #18108

* fix(): add prefixed transform for older versions of chrome (#18128)

fixes #17729

* fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)

fixes #17069

* fix(): sanitize components using innerHTML (#18083)

fixes #18065

* Release 4.3.1 (#18152) (#18154)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* doc(loading): remove mention of undefined "content" property (#18126)

* feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)

- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161

* fix(toast): allow button-color CSS variable to be overridden (#18133)

fixes #18127

* fix(label): use primary color on focus for md input labels (#18183)

fixes #15602

* feat(item-sliding): add open method (#17964)

resolves #17899

* feat(menu-button): add css variables for padding (#18188)

fixes #18187

* feat(card): add button functionality (#17997)

closes #17773

* feat(textarea): add option to expand textarea as value changes (#16916)

* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px

* feat(refresher): add pullFactor property to control speed (#16697)

closes #15425

* fix(input): clear on edit from inside native input (#17115)

fixes #17055

* test(angular): increase timeout for tab switch (#18221)

* 4.4.0

* chore(): resolve merge conflicts from older hotfix

* docs(process): update release process

* docs(fab-list): update the activated description (#18026)

* docs(breaking): add ionDrag event arguments change (#17989)

* docs(slides): add swiper prefix in animation usage (#18073)

* feat(searchbar): add disabled property (#17935)

closes #17921

* fix(reorder-group): remove required parameter for the complete method (#18084)

also updates documentation surrounding the reorder & infinite scroll

fixes #16302

* docs(components): update method and parameter descriptions (#18075)

* fix(datetime): default to current date when value is null (#18105)

fixes #18099

* docs(toolbar): fix end slot documentation (#18092)

* fix(item): use the global activated background for md ripple color (#16752)

fixes #16585

* fix(textarea): reposition textarea when keybard appears (#18098)

fixes #17847

* fix(button): apply round property to button sizes in iOS (#18125)

fixes #18108

* fix(): add prefixed transform for older versions of chrome (#18128)

fixes #17729

* fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)

fixes #17069

* fix(): sanitize components using innerHTML (#18083)

fixes #18065

* Release 4.3.1 (#18152) (#18154)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* doc(loading): remove mention of undefined "content" property (#18126)

* feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)

- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161

* fix(toast): allow button-color CSS variable to be overridden (#18133)

fixes #18127

* fix(label): use primary color on focus for md input labels (#18183)

fixes #15602

* feat(item-sliding): add open method (#17964)

resolves #17899

* feat(menu-button): add css variables for padding (#18188)

fixes #18187

* feat(card): add button functionality (#17997)

closes #17773

* feat(textarea): add option to expand textarea as value changes (#16916)

* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px

* feat(refresher): add pullFactor property to control speed (#16697)

closes #15425

* fix(input): clear on edit from inside native input (#17115)

fixes #17055

* test(angular): increase timeout for tab switch (#18221)

* fix other merge conflict
2019-05-08 14:15:12 -04:00
Liam DeBeasi
2c24df2578 4.4.0
* Release 4.3.1 (#18152)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* merge release-4.4.0

* docs(process): update release process

* docs(fab-list): update the activated description (#18026)

* docs(breaking): add ionDrag event arguments change (#17989)

* docs(slides): add swiper prefix in animation usage (#18073)

* feat(searchbar): add disabled property (#17935)

closes #17921

* fix(reorder-group): remove required parameter for the complete method (#18084)

also updates documentation surrounding the reorder & infinite scroll

fixes #16302

* docs(components): update method and parameter descriptions (#18075)

* fix(datetime): default to current date when value is null (#18105)

fixes #18099

* docs(toolbar): fix end slot documentation (#18092)

* fix(item): use the global activated background for md ripple color (#16752)

fixes #16585

* fix(textarea): reposition textarea when keybard appears (#18098)

fixes #17847

* fix(button): apply round property to button sizes in iOS (#18125)

fixes #18108

* fix(): add prefixed transform for older versions of chrome (#18128)

fixes #17729

* fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)

fixes #17069

* fix(): sanitize components using innerHTML (#18083)

fixes #18065

* Release 4.3.1 (#18152) (#18154)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* doc(loading): remove mention of undefined "content" property (#18126)

* feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)

- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161

* fix(toast): allow button-color CSS variable to be overridden (#18133)

fixes #18127

* fix(label): use primary color on focus for md input labels (#18183)

fixes #15602

* feat(item-sliding): add open method (#17964)

resolves #17899

* feat(menu-button): add css variables for padding (#18188)

fixes #18187

* feat(card): add button functionality (#17997)

closes #17773

* feat(textarea): add option to expand textarea as value changes (#16916)

* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px

* feat(refresher): add pullFactor property to control speed (#16697)

closes #15425

* fix(input): clear on edit from inside native input (#17115)

fixes #17055

* test(angular): increase timeout for tab switch (#18221)

* 4.4.0

* fix other merge conflict
2019-05-08 14:13:05 -04:00
Liam DeBeasi
71d540023b chore(): resolve merge conflicts from older hotfix
* docs(process): update release process

* docs(fab-list): update the activated description (#18026)

* docs(breaking): add ionDrag event arguments change (#17989)

* docs(slides): add swiper prefix in animation usage (#18073)

* feat(searchbar): add disabled property (#17935)

closes #17921

* fix(reorder-group): remove required parameter for the complete method (#18084)

also updates documentation surrounding the reorder & infinite scroll

fixes #16302

* docs(components): update method and parameter descriptions (#18075)

* fix(datetime): default to current date when value is null (#18105)

fixes #18099

* docs(toolbar): fix end slot documentation (#18092)

* fix(item): use the global activated background for md ripple color (#16752)

fixes #16585

* fix(textarea): reposition textarea when keybard appears (#18098)

fixes #17847

* fix(button): apply round property to button sizes in iOS (#18125)

fixes #18108

* fix(): add prefixed transform for older versions of chrome (#18128)

fixes #17729

* fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)

fixes #17069

* fix(): sanitize components using innerHTML (#18083)

fixes #18065

* Release 4.3.1 (#18152) (#18154)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* doc(loading): remove mention of undefined "content" property (#18126)

* feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)

- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161

* fix(toast): allow button-color CSS variable to be overridden (#18133)

fixes #18127

* fix(label): use primary color on focus for md input labels (#18183)

fixes #15602

* feat(item-sliding): add open method (#17964)

resolves #17899

* feat(menu-button): add css variables for padding (#18188)

fixes #18187

* feat(card): add button functionality (#17997)

closes #17773

* feat(textarea): add option to expand textarea as value changes (#16916)

* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px

* feat(refresher): add pullFactor property to control speed (#16697)

closes #15425

* fix(input): clear on edit from inside native input (#17115)

fixes #17055

* test(angular): increase timeout for tab switch (#18221)

* fix other merge conflict
2019-05-08 14:03:31 -04:00
Liam DeBeasi
5eb942f680 merge release-4.4.0
* docs(process): update release process

* docs(fab-list): update the activated description (#18026)

* docs(breaking): add ionDrag event arguments change (#17989)

* docs(slides): add swiper prefix in animation usage (#18073)

* feat(searchbar): add disabled property (#17935)

closes #17921

* fix(reorder-group): remove required parameter for the complete method (#18084)

also updates documentation surrounding the reorder & infinite scroll

fixes #16302

* docs(components): update method and parameter descriptions (#18075)

* fix(datetime): default to current date when value is null (#18105)

fixes #18099

* docs(toolbar): fix end slot documentation (#18092)

* fix(item): use the global activated background for md ripple color (#16752)

fixes #16585

* fix(textarea): reposition textarea when keybard appears (#18098)

fixes #17847

* fix(button): apply round property to button sizes in iOS (#18125)

fixes #18108

* fix(): add prefixed transform for older versions of chrome (#18128)

fixes #17729

* fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)

fixes #17069

* fix(): sanitize components using innerHTML (#18083)

fixes #18065

* Release 4.3.1 (#18152) (#18154)

* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)

* doc(loading): remove mention of undefined "content" property (#18126)

* feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)

- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161

* fix(toast): allow button-color CSS variable to be overridden (#18133)

fixes #18127

* fix(label): use primary color on focus for md input labels (#18183)

fixes #15602

* feat(item-sliding): add open method (#17964)

resolves #17899

* feat(menu-button): add css variables for padding (#18188)

fixes #18187

* feat(card): add button functionality (#17997)

closes #17773

* feat(textarea): add option to expand textarea as value changes (#16916)

* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px

* feat(refresher): add pullFactor property to control speed (#16697)

closes #15425

* fix(input): clear on edit from inside native input (#17115)

fixes #17055

* test(angular): increase timeout for tab switch (#18221)

* 4.4.0
2019-05-08 13:10:56 -04:00
Liam DeBeasi
bb6ae9924c test(angular): increase timeout for tab switch (#18221) 2019-05-08 12:27:34 -04:00
Paul Stelzer
85093d6352 fix(input): clear on edit from inside native input (#17115)
fixes #17055
2019-05-07 17:55:42 -04:00
Paul Stelzer
9030dcc111 feat(refresher): add pullFactor property to control speed (#16697)
closes #15425
2019-05-07 17:21:32 -04:00
Adam LaCombe
cc8678ad58 feat(textarea): add option to expand textarea as value changes (#16916)
* feat(textarea): add autoGrow - set height to scrollHeight

* change 1px to inherit, remove additional 4px
2019-05-07 16:52:24 -04:00
Josh Beard
669ec0da3d feat(card): add button functionality (#17997)
closes #17773
2019-05-07 15:12:28 -04:00
JustDoItSascha
ef989779b0 feat(menu-button): add css variables for padding (#18188)
fixes #18187
2019-05-07 12:13:56 -04:00
shreeshbhat
f912206af8 feat(item-sliding): add open method (#17964)
resolves #17899
2019-05-07 11:43:19 -04:00
Brandy Carney
ddb8ef82f0 fix(label): use primary color on focus for md input labels (#18183)
fixes #15602
2019-05-07 10:26:14 -04:00
Liam DeBeasi
0c83fd3f1a fix(toast): allow button-color CSS variable to be overridden (#18133)
fixes #18127
2019-05-06 11:14:43 -04:00
Vladimir Hinić
38ffb98421 feat(img): add ionImgWillLoad event and emit ionImgDidLoad when image is loaded (#18159)
- Adds `ionImgWillLoad` event that emits when the img src is set
- Moves the `ionImgDidLoad` event emit so that it happens when the image actually finishes loading

fixes #17652 closes #18161
2019-05-01 16:03:16 -04:00
Ken Sodemann
0e4726b62a doc(loading): remove mention of undefined "content" property (#18126) 2019-04-29 10:54:41 -04:00
Liam DeBeasi
9c2cd31b1c Release 4.3.1 (#18152) (#18154)
* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)
2019-04-26 15:52:30 -04:00
Liam DeBeasi
ed69d24013 Release 4.3.1 (#18152)
* fix(angular): support replaceUrl with angular <7.2 (#18106)

* fix(angular): support replaceUrl with angular <7.2

* run linter

* fix(): sanitize components using innerHTML (#18146)

* 4.3.1 (#18150)
2019-04-26 15:35:41 -04:00
Liam DeBeasi
d12757f975 fix(): sanitize components using innerHTML (#18083)
fixes #18065
2019-04-26 11:56:37 -04:00
Santosh Yadav
0fa645b8cc fix(segment): decrease icon size on ios and stretch segment buttons to fill height (#17751)
fixes #17069
2019-04-25 12:46:34 -04:00
Liam DeBeasi
2457a23e95 fix(): add prefixed transform for older versions of chrome (#18128)
fixes #17729
2019-04-25 11:57:25 -04:00
Abdelaziz Bennouna
ae0ecccd2e fix(button): apply round property to button sizes in iOS (#18125)
fixes #18108
2019-04-25 11:32:23 -04:00
Brandy Carney
3cdab10aa0 fix(textarea): reposition textarea when keybard appears (#18098)
fixes #17847
2019-04-24 12:33:22 -04:00
Brandy Carney
95945c05a5 fix(item): use the global activated background for md ripple color (#16752)
fixes #16585
2019-04-24 11:36:12 -04:00
obedm503
33acd78469 docs(toolbar): fix end slot documentation (#18092) 2019-04-23 23:30:12 -04:00
Liam DeBeasi
ca233b547a fix(datetime): default to current date when value is null (#18105)
fixes #18099
2019-04-23 13:12:17 -04:00
Brandy Carney
464ec3b70a docs(components): update method and parameter descriptions (#18075) 2019-04-23 12:59:25 -04:00
Brandy Carney
bd96491d03 fix(reorder-group): remove required parameter for the complete method (#18084)
also updates documentation surrounding the reorder & infinite scroll

fixes #16302
2019-04-22 18:16:23 -04:00
KyDenZ
a5b9066fee feat(searchbar): add disabled property (#17935)
closes #17921
2019-04-22 11:37:58 -04:00
Liam DeBeasi
c178236e32 docs(slides): add swiper prefix in animation usage (#18073) 2019-04-18 09:51:09 -04:00
Michael Asimakopoulos
f6524cf8c3 docs(breaking): add ionDrag event arguments change (#17989) 2019-04-17 17:13:41 -04:00
Nikhil Maheshwari
8d59d44431 docs(fab-list): update the activated description (#18026) 2019-04-17 16:47:10 -04:00
Brandy Carney
8097f578f4 docs(process): update release process 2019-04-17 15:59:01 -04:00
Brandy Carney
446fe29b15 merge release-4.3.0 2019-04-17 15:55:33 -04:00
Brandy Carney
6fbb90896b merge release-4.3.0 2019-04-17 15:42:04 -04:00
Brandy Carney
73e2123ce8 4.3.0 2019-04-17 15:27:06 -04:00
Brandy Carney
70db7080b1 test(toast): remove the safe area to enable clicks on all buttons 2019-04-17 15:06:55 -04:00
Brandy Carney
9e63947e3c fix(action-sheet): default buttons to empty array
fixes an error with the timing of the buttons being added
2019-04-17 12:56:32 -04:00
Brandy Carney
0dd2f34dfa Merge branch 'stable' into release-4.3.0 2019-04-17 12:26:52 -04:00
Tomasz Nicieja
07e739a364 feat(toast): add variables to change position start/end of toast (#17961)
closes #17854
2019-04-16 18:13:14 -04:00
Brandy Carney
e5c8c10029 fix(components): include mode classes on components for use in shadow (#17838)
- removes mode-less component classes from the internal CSS, use element instead
- adds mode specific classes `md` or `ios` for styling inside of shadow components
- adds e2e test that verifies mode classes exist on all ionic components, plus checks for specific classes that the components need for internal styling

fixes #17608
2019-04-16 17:28:21 -04:00
Brandy Carney
38ae3620a2 fix(textarea): update label alignment for inputs and textareas (#18042)
- aligns label and textarea to baseline
- updates floating and stacked labels in items to align closer to the md spec

fixes #16187
2019-04-16 14:57:32 -04:00
Brandy Carney
72be80cb58 fix(item): use the correct input highlight for an inset line item (#18052)
fixes #18051
2019-04-16 13:14:26 -04:00
Liam DeBeasi
cc60b60135 fix(datetime): date strings no longer revert to previous day (#18018)
fixes #17977
2019-04-16 12:34:35 -04:00
Liam DeBeasi
447497427e fix(slides): expose interface to provide custom animations (#17959)
fixes #16616

Co-Authored-By: CFT-Chris <mail@chrislo.ca>
2019-04-16 12:02:47 -04:00
Liam DeBeasi
18b347b4e9 fix(slides): allow zoom to work
fixes #17981
2019-04-16 10:51:23 -04:00
konnectappdev
29bb4fcb05 fix(input): prevent input from losing focus when tapping clear button (#18004)
fixes #18002
2019-04-16 10:01:56 -04:00
Jason
11aa48c83c chore(reorder-group): correct typo in ReorderGroupState enum (#18017)
fixes #18016
2019-04-16 09:39:58 -04:00
Michael Asimakopoulos
f13722cc20 fix(item-sliding): hide opposite side options when other side is open (#17986)
* fix(item-sliding): hide opposite side options

* Fix padding issue

* add visibility hidden for item options
2019-04-15 17:20:15 -04:00
Liam DeBeasi
983382c327 fix(toast): update toast interface to include buttons 2019-04-15 17:09:00 -04:00
Liam DeBeasi
1b16e1f378 chore(): add rtl label to appropriate tests 2019-04-15 16:50:03 -04:00
Brandy Carney
494991e9fb fix(textarea): float label when a value is changed async (#18024)
emits styles to the parent item on value change so that the item will get the proper class to float the label

fixes #17555 fixes #17559
2019-04-12 13:23:04 -04:00
Liam DeBeasi
1199c53437 test(): remove custom screenshot names (#18022)
* test(): remove custom screenshot names

* update test names
2019-04-12 13:02:03 -04:00
Zachary Keeton
6e1a8f1df2 feat(toast): add header and additional custom toast buttons (#17147)
Adds a `header` and `buttons` property to toast. This allows for a toast header to be passed and multiple buttons including action buttons and icon only buttons which matches the Material Design spec. Adds hover states to the button to match the spec. Updates usage section to recommend the new way of passing a close button using the buttons array and `cancel` role. If a button is passed using the cancel role default the color to match the spec. Buttons will default to the `end` side but have the option of being placed on the `start` side.

Co-authored-by: Simon Hänisch <simonhaenisch@users.noreply.github.com>
Co-authored-by: Brandy Carney <brandy@ionic.io>

closes #16791 closes #16237 closes #17611
2019-04-11 11:46:10 -04:00
Liam DeBeasi
52e5a8d3e3 fix(angular): back button goes back to proper tab (#18005)
fixes #17278 
fixes #15216
2019-04-10 16:18:59 -04:00
Liam DeBeasi
0d17e05edc chore(docs): update PR wording 2019-04-09 11:13:35 -04:00
Michael Tintiuc
fa1317359a fix(vue): use direction type from core (#17901) 2019-04-08 14:59:09 -04:00
Brandy Carney
d87170db3a docs(github): update pull request template 2019-04-08 12:07:51 -04:00
Stefanos Anagnostou
5756789b42 docs(breaking): add ion-button shape attribute (#17985) 2019-04-08 11:01:22 -04:00
Matt Netkow
b081ca4dd0 docs(modal): update Angular usage code (#17978)
closes ionic-team/ionic-docs#620
2019-04-06 12:13:50 -04:00
Liam DeBeasi
77c980b032 chore(): add label for capacitor issues
chore(): add label for capacitor issues
2019-04-05 14:03:30 -04:00
Liam DeBeasi
05eb5ddaf8 Merge branch 'master' into ionitron-capacitor 2019-04-05 13:34:14 -04:00
Liam DeBeasi
9de09bd4f5 docs(modal): add lazy loading usage
docs(modal): add lazy loading usage
2019-04-05 13:33:52 -04:00
Liam DeBeasi
2f34f52536 move lazy loading to angular usage 2019-04-05 12:32:52 -04:00
Liam DeBeasi
ec3e19e66c Merge branch 'master' into modal-lazy-loading-docs 2019-04-05 12:14:19 -04:00
Liam DeBeasi
a512287e4b chore(): add label for capacitor issues 2019-04-05 08:51:15 -04:00
Brandy Carney
48814ab134 chore(github): update issue template title 2019-04-04 16:29:30 -04:00
Brandy Carney
28249924a8 chore(github): update issue template title 2019-04-04 16:28:27 -04:00
Brandy Carney
e620d813b3 chore(github): update issue template title 2019-04-04 16:26:49 -04:00
Liam DeBeasi
0db905a871 chore(): update release process to document version branches
chore(): update release process to document version branches
2019-04-04 10:00:20 -04:00
Liam DeBeasi
c87e26131a docs(modal): add lazy loading usage 2019-04-03 12:44:00 -04:00
Liam DeBeasi
06c4233a54 change I to lowercase 2019-04-03 12:16:48 -04:00
Liam DeBeasi
9585723dda chore(): update release process to document version branches 2019-04-03 12:13:35 -04:00
Liam DeBeasi
046ca8f732 merge release-4.2.0
Release 4.2.0
2019-04-03 10:50:26 -04:00
Liam DeBeasi
fdd2978774 merge release-4.2.0
Release 4.2.0
2019-04-03 10:49:11 -04:00
1014 changed files with 31800 additions and 35169 deletions

View File

@@ -60,7 +60,7 @@ jobs:
working_directory: /tmp/workspace/core
- save_cache: *save-cache-core
- run:
command: npm run build -- --max-workers 1
command: npm run build -- --ci
working_directory: /tmp/workspace/core
- save_cache: *save-cache-core-stencil
- persist_to_workspace:
@@ -91,6 +91,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:
@@ -119,7 +136,7 @@ jobs:
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run test.spec
command: npm run test.spec --ci
working_directory: /tmp/workspace/core
test-core-treeshake:
@@ -129,7 +146,7 @@ jobs:
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run test.treeshake
command: npm run test.treeshake --ci
working_directory: /tmp/workspace/core
test-core-screenshot:
@@ -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

@@ -1,7 +1,7 @@
---
name: Bug Report
about: Create a report to help us improve
title: ''
title: 'bug: '
labels: ''
assignees: ''
---
@@ -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)

View File

@@ -1,7 +1,7 @@
---
name: Feature Request
about: Suggest an idea for this project
title: ''
title: 'feat: '
labels: ''
assignees: ''
---

View File

@@ -1,7 +1,7 @@
---
name: Support Question
about: Question on how to use this project
title: ''
title: 'support: '
labels: 'ionitron: support'
assignees: ''
---

33
.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
@@ -140,6 +140,14 @@ Once the release is ready to ship, it will get merged into `stable` and `master`
See the [steps for releasing](#releasing) below for detailed information on how to publish a release.
### Version Branches
Once a release has shipped and the release branch has been merged into `stable` and `master` it should also be merged into its corrsponding version branch. These version branches allow us to ship updates for specific versions of the framework (i.e. Lets us ship a bug fix that only affects 4.2.x).
Patch releases should be merged into their corresponding version branches. For example, a `release-4.1.1` branch should be merged into the `4.1.x` version branch and a `release-5.0.1` branch should be merged into the `5.0.x` version branch.
When releasing a major version such as `5.0.0 ` or a minor version such as `4.1.0` , the version branch will not exist. The version branch should be created once the release branch has been merged into `stable` and `master`. For example, when releasing `4.1.0`, the `release-4.1.0` release branch should be merged into `stable` and `master` and then the `4.1.x` version branch should be created off the latest `stable`.
### Hotfix Branches
@@ -213,20 +221,31 @@ Hotfixes bypass `master` and should only be used for urgent fixes that can't wai
## Releasing
1. Create the release branch from `master`, for example: `release-4.1.0`.
1. Submit a pull request from the release branch into `stable`. Do not merge this pull request yet.
1. Create the release branch from `master`, for example: `release-4.5.0`.
1. For major or minor releases, create a version branch based off the latest version branch. For example, if releasing 4.5.0, create a branch called `4.5.x` based off `4.4.x`.
1. Submit a pull request from the release branch into the version branch. Do not merge this pull request yet.
1. Verify all tests are passing, fix any bugs if needed and make sure no undesired commits are in.
1. Navigate to the root of the repository while on the release branch.
1. Run `npm i` if it hasn't already been done.
1. Run `npm run release.prepare`
- Select the version based on the type of commits and the [Ionic Versioning](https://ionicframework.com/docs/intro/versioning)
- After the process completes, verify the version number in all packages (`core`, `docs`, `angular`)
- Verify the changelog commits are accurate and follow the [proper format]((https://github.com/ionic-team/ionic/blob/master/.github/CONTRIBUTING.md#commit-message-format))
- Commit these changes with the version number as the message, e.g. `git commit -m "4.1.0"`
- For major or minor releases, ensure that the version number has an associated title (for example: `4.5.0 Boron`)
- Commit these changes with the version number as the message, e.g. `git commit -m "4.5.0"`
1. Run `npm run release`
1. Click **Merge pull request**. Use the dropdown to select this option if necessary.
<img width="191" alt="Merge pull request button" src="https://user-images.githubusercontent.com/236501/47032669-8be1b980-d138-11e8-9a90-d1518c223184.png">
1. Rewrite the commit message to `merge release-4.1.0` with the proper release branch.
1. Create a pull request and merge the release branch back into `master` using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.
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.

View File

@@ -1,12 +1,51 @@
#### Short description of what this resolves:
<!-- Please refer to our contributing documentation for any questions on submitting a pull request, or let us know here if you need any help: https://ionicframework.com/docs/building/contributing -->
## Pull request checklist
Please check if your PR fulfills the following requirements:
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been reviewed and added / updated if needed (for bug fixes / features)
- [ ] Build (`npm run build`) was run locally and any changes were pushed
- [ ] Lint (`npm run lint`) has passed locally and any fixes were made for failures
#### Changes proposed in this pull request:
## Pull request type
<!-- Please do not submit updates to dependencies unless it fixes an issue. -->
<!-- Please try to limit your pull request to one type, submit multiple pull requests if needed. -->
Please check the type of change your PR introduces:
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
Issue Number: N/A
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by this PR. -->
-
-
-
**Ionic Version**:
## Does this introduce a breaking change?
**Fixes**: #
- [ ] Yes
- [ ] No
<!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. -->

View File

@@ -118,6 +118,15 @@ labelPullRequest:
wrongRepo:
repos:
- label: "ionitron: capacitor"
repo: capacitor
message: >
Thanks for the issue! We use this issue tracker exclusively for bug reports and feature requests
associated with the Ionic Framework. It appears that this issue is associated with Capacitor.
I am moving this issue to the Capacitor repository. Please track this issue over there.
Thank you for using Ionic!
- label: "ionitron: v3"
repo: ionic-v3
message: >

7
.gitignore vendored
View File

@@ -15,6 +15,7 @@ log.txt
coverage/
collection/
dist/
dist-transpiled/
node_modules/
tmp/
temp/
@@ -49,10 +50,16 @@ demos/src/**/*.ngfactory.ts
demos/src/**/*.d.ts
demos/src/**/*.metadata.json
demos/src/**/*.css.shim.ts
prerender.html
prerender-domino.html
prerender-hydrated.html
prerender-static.html
# stencil
angular/css/
core/css/
core/hydrate/
core/loader/
core/www/
.stencil/
angular/build/

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

@@ -7,6 +7,7 @@ const fs = require('fs-extra');
const common = require('./common');
const DIST_NPM_TAG = 'dev';
const DIST_TAG = 'dev';
async function main() {
@@ -37,7 +38,8 @@ async function main() {
packages.forEach(package => {
common.prepareDevPackage(tasks, package, devVersion);
});
common.publishPackages(tasks, packages, devVersion, DIST_TAG);
common.copyCDNLoader(tasks, devVersion);
common.publishPackages(tasks, packages, devVersion, DIST_NPM_TAG);
const listr = new Listr(tasks);
await listr.run();

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,4 +1,297 @@
# [4.2.0](https://github.com/ionic-team/ionic/compare/v4.1.2...v4.2.0) (2019-04-03)
## [4.7.2](https://github.com/ionic-team/ionic/compare/v4.7.1...v4.7.2) (2019-08-07)
### Bug Fixes
* **angular:** hardware back button subscribeWithPriority triggers change detection ([#18962](https://github.com/ionic-team/ionic/issues/18962)) ([3a22105](https://github.com/ionic-team/ionic/commit/3a22105)), closes [#18959](https://github.com/ionic-team/ionic/issues/18959)
* **angular:** nested inputs no longer conflict with each other ([#18976](https://github.com/ionic-team/ionic/issues/18976)) ([6bbdb80](https://github.com/ionic-team/ionic/commit/6bbdb80)), closes [#18248](https://github.com/ionic-team/ionic/issues/18248)
* **range:** ion-range value now submitted with form ([#19008](https://github.com/ionic-team/ionic/issues/19008)) ([8f7853c](https://github.com/ionic-team/ionic/commit/8f7853c))
* **reorder:** only move item if reorder happens ([#19007](https://github.com/ionic-team/ionic/issues/19007)) ([d237e80](https://github.com/ionic-team/ionic/commit/d237e80))
* **router:** partial swipe to go back gesture no longer breaks view([#18977](https://github.com/ionic-team/ionic/issues/18977)) ([713ea8a](https://github.com/ionic-team/ionic/commit/713ea8a)), closes [#18462](https://github.com/ionic-team/ionic/issues/18462)
* **toast:** allow loading ion-icon from asset path ([#18969](https://github.com/ionic-team/ionic/issues/18969)) ([23f327e](https://github.com/ionic-team/ionic/commit/23f327e))
* **vue:** rename swipeEnable to swipeGesture ([#17346](https://github.com/ionic-team/ionic/issues/17346)) ([c2348f7](https://github.com/ionic-team/ionic/commit/c2348f7)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
## [4.7.1](https://github.com/ionic-team/ionic/compare/v4.7.0...v4.7.1) (2019-07-26)
### Bug Fixes
* **angular:** ensure change detection fires properly ([#18896](https://github.com/ionic-team/ionic/issues/18896)) ([962783b](https://github.com/ionic-team/ionic/commit/962783b)), closes [#18894](https://github.com/ionic-team/ionic/issues/18894)
# [4.7.0 Nitrogen](https://github.com/ionic-team/ionic/compare/v4.6.2...v4.7.0) (2019-07-24)
### Angular 8 Support
With this version comes support for Angular 8! Follow the below steps to update.
1. Update `@ionic/angular` and `@ionic/angular-toolkit` to the latest releases:
```shell
$ npm install @ionic/angular@4.7.0
$ npm install @ionic/angular-toolkit@2.0.0 -D
```
1. Update `@angular/core` and `@angular/cli`:
```shell
$ npx ng update @angular/core @angular/cli
```
1. Update `@angular-devkit` dependencies:
```shell
$ npm i @angular-devkit/architect@latest @angular-devkit/build-angular@latest @angular-devkit/core@latest @angular-devkit/schematics@latest
```
View our [Angular 8 Update Guide](https://docs.google.com/document/d/1QOpQeDifPSg6F9WycDLcbQnpqjN96ew-Ap0_CB7CcCQ/edit?usp=sharing) for tips on potential issues!
### Bug Fixes
* **angular:** copy input form classes to parent ion-item ([#18820](https://github.com/ionic-team/ionic/issues/18820)) ([53179c4](https://github.com/ionic-team/ionic/commit/53179c4)), closes [#18800](https://github.com/ionic-team/ionic/issues/18800)
* **angular:** add the swipeGesture method for enabling or disabling the ability to swipe open a menu ([#18806](https://github.com/ionic-team/ionic/issues/18806)) ([fbfc076](https://github.com/ionic-team/ionic/commit/fbfc076)), closes [#16002](https://github.com/ionic-team/ionic/issues/16002)
* **angular:** webview "pause", "resume", and "resize" events now trigger change detection ([#18853](https://github.com/ionic-team/ionic/issues/18853)) ([544e550](https://github.com/ionic-team/ionic/commit/544e550)), closes [#18831](https://github.com/ionic-team/ionic/issues/18831)
* **core:** apply translucent if backdrop-filter is supported ([#18832](https://github.com/ionic-team/ionic/issues/18832)) ([6b5a59d](https://github.com/ionic-team/ionic/commit/6b5a59d)), closes [ionic-team/ionic-docs#666](https://github.com/ionic-team/ionic-docs/issues/666)
* **datetime:** allow AM/PM to be changed ([#18684](https://github.com/ionic-team/ionic/issues/18684)) ([b7761fe](https://github.com/ionic-team/ionic/commit/b7761fe)), closes [#18585](https://github.com/ionic-team/ionic/issues/18585)
* **datetime:** properly apply disabled classes when updating columns ([#18875](https://github.com/ionic-team/ionic/issues/18875)) ([7ba718c](https://github.com/ionic-team/ionic/commit/7ba718c)), closes [#18793](https://github.com/ionic-team/ionic/issues/18793)
* **hardware-back-button:** hardware back button no longer erroneously restarts app ([#18794](https://github.com/ionic-team/ionic/issues/18794)) ([978cc39](https://github.com/ionic-team/ionic/commit/978cc39)), closes [#18792](https://github.com/ionic-team/ionic/issues/18792)
* **ripple-effect:** ensure ripple is removed from components after pointer release ([#18854](https://github.com/ionic-team/ionic/issues/18854)) ([71137a2](https://github.com/ionic-team/ionic/commit/71137a2)), closes [#18836](https://github.com/ionic-team/ionic/issues/18836)
* **searchbar:** add aria and role for improved accessibility ([#18797](https://github.com/ionic-team/ionic/issues/18797)) ([798103b](https://github.com/ionic-team/ionic/commit/798103b)), closes [#18796](https://github.com/ionic-team/ionic/issues/18796)
* **ssr:** avoid window reference ([#18865](https://github.com/ionic-team/ionic/issues/18865)) ([23ce6fa](https://github.com/ionic-team/ionic/commit/23ce6fa))
* **ssr:** check for client runtime method ([#18866](https://github.com/ionic-team/ionic/issues/18866)) ([c52b3b4](https://github.com/ionic-team/ionic/commit/c52b3b4))
* **textarea:** autogrow now resets textarea back to original number of rows when text is cleared ([#18822](https://github.com/ionic-team/ionic/issues/18822)) ([26e6d6f](https://github.com/ionic-team/ionic/commit/26e6d6f)), closes [#18744](https://github.com/ionic-team/ionic/issues/18744)
* **theming:** update components to use the proper colors for dark themes ([#18735](https://github.com/ionic-team/ionic/issues/18735)) ([045bc59](https://github.com/ionic-team/ionic/commit/045bc59)), closes [#18713](https://github.com/ionic-team/ionic/issues/18713)
* **virtual-scroll:** card rendering is no longer distorted ([#18877](https://github.com/ionic-team/ionic/issues/18877)) ([3ef6ecf](https://github.com/ionic-team/ionic/commit/3ef6ecf)), closes [#18870](https://github.com/ionic-team/ionic/issues/18870)
* **virtual-scroll:** element dimensions are recalculated on resize ([#18878](https://github.com/ionic-team/ionic/issues/18878)) ([c91819c](https://github.com/ionic-team/ionic/commit/c91819c))
### Features
* **core:** add support for Stackblitz ([#18846](https://github.com/ionic-team/ionic/issues/18846)) ([fb18f3b](https://github.com/ionic-team/ionic/commit/fb18f3b))
* **ssr:** add @ionic/core/hydrate app ([#18867](https://github.com/ionic-team/ionic/issues/18867)) ([815fa2e](https://github.com/ionic-team/ionic/commit/815fa2e))
* **navigation:** add experimental shadow to iOS page transitions ([#18695](https://github.com/ionic-team/ionic/issues/18695)) ([9b075ef](https://github.com/ionic-team/ionic/commit/9b075ef)), closes [#18661](https://github.com/ionic-team/ionic/issues/18661)
* **virtual-scroll:** adds headerHeight and footerHeight to help prevent flickering ([#18851](https://github.com/ionic-team/ionic/issues/18851)) ([0089111](https://github.com/ionic-team/ionic/commit/0089111)), closes [#17540](https://github.com/ionic-team/ionic/issues/17540)
### Performance
* **angular:** attach entering view before first change detection and detach leaving page ([#18821](https://github.com/ionic-team/ionic/issues/18821)) ([97fec92](https://github.com/ionic-team/ionic/commit/97fec92))
## [4.6.2](https://github.com/ionic-team/ionic/compare/v4.6.1...v4.6.2) (2019-07-10)
### Bug Fixes
* **menu-button:** hide menu button when auto hide or split pane ([#18702](https://github.com/ionic-team/ionic/issues/18702)) ([24840d4](https://github.com/ionic-team/ionic/commit/24840d4)), closes [#18666](https://github.com/ionic-team/ionic/issues/18666)
* **menu-button:** move font-size to host for easier customization ([#18699](https://github.com/ionic-team/ionic/issues/18699)) ([876ab41](https://github.com/ionic-team/ionic/commit/876ab41)), closes [#18667](https://github.com/ionic-team/ionic/issues/18667)
* **overlays:** fallback to step color if overlay background variable is unset ([#18709](https://github.com/ionic-team/ionic/issues/18709)) ([f16b118](https://github.com/ionic-team/ionic/commit/f16b118)), closes [#18658](https://github.com/ionic-team/ionic/issues/18658)
* **virtual-scroll:** remove runOutsideAngular error ([#18752](https://github.com/ionic-team/ionic/issues/18752)) ([8beeff2](https://github.com/ionic-team/ionic/commit/8beeff2)), closes [#18746](https://github.com/ionic-team/ionic/issues/18746)
* **vue:** update imports for types and ionicons ([f56fea6](https://github.com/ionic-team/ionic/commit/f56fea6)), closes [#18701](https://github.com/ionic-team/ionic/issues/18701)
### Performance Improvements
* **all:** minify better by using arrow functions ([#18730](https://github.com/ionic-team/ionic/issues/18730)) ([03c1d19](https://github.com/ionic-team/ionic/commit/03c1d19))
## [4.6.1](https://github.com/ionic-team/ionic/compare/v4.6.0...v4.6.1) (2019-07-09)
### Bug Fixes
* **app:** add hydrated to hide white screen with multiple ionic dependencies ([#18649](https://github.com/ionic-team/ionic/issues/18649))
* **datetime:** datetime no longer reports having a value if none is set ([#18541](https://github.com/ionic-team/ionic/issues/18541)) ([92e0f98](https://github.com/ionic-team/ionic/commit/92e0f98)), closes [#17979](https://github.com/ionic-team/ionic/issues/17979) [#18540](https://github.com/ionic-team/ionic/issues/18540)
* **fab-button:** set opacity on disabled fab button ([#18685](https://github.com/ionic-team/ionic/issues/18685)) ([6042b39](https://github.com/ionic-team/ionic/commit/6042b39)), closes [#18682](https://github.com/ionic-team/ionic/issues/18682)
* **icon:** load icons properly with baseHref ([#18650](https://github.com/ionic-team/ionic/issues/18650)), ([#18637](https://github.com/ionic-team/ionic/issues/18637))
* **icon:** bind icon name properly ([#18707](https://github.com/ionic-team/ionic/issues/18707))
* **infinite-scroll:** fix scroll listener ([0d58101](https://github.com/ionic-team/ionic/commit/0d58101))
* **item:** do not disable entire item if there are multiple inputs ([#18696](https://github.com/ionic-team/ionic/issues/18696)) ([dfa2b13](https://github.com/ionic-team/ionic/commit/dfa2b13)), closes [#18655](https://github.com/ionic-team/ionic/issues/18655) [#18670](https://github.com/ionic-team/ionic/issues/18670)
* **router-link:** add missing target prop ([#18659](https://github.com/ionic-team/ionic/issues/18659)) ([1f51ab2](https://github.com/ionic-team/ionic/commit/1f51ab2)), closes [#18655](https://github.com/ionic-team/ionic/issues/18655)
* **router-outlet:** fix swipe to go back ([b69fb69](https://github.com/ionic-team/ionic/commit/b69fb69))
* **scss:** copy all scss files ([36a58df](https://github.com/ionic-team/ionic/commit/36a58df))
* **searchbar:** proper styling after navigating ([#18642](https://github.com/ionic-team/ionic/issues/18642))
* **slides:** use correct order for pushing slides dynamically ([#18633](https://github.com/ionic-team/ionic/issues/18633))
* **tabs:** select proper tab by default and do not emit tab change if selectedTab is undefined ([03c834c](https://github.com/ionic-team/ionic/commit/03c834c))
* **overlay:** make create opts optional ([44c88ad](https://github.com/ionic-team/ionic/commit/44c88ad))
### Performance Improvements
* **angular:** skip zone ([e059fc8](https://github.com/ionic-team/ionic/commit/e059fc8))
# [4.6.0 Carbon](https://github.com/ionic-team/ionic/compare/v4.5.0...v4.6.0) (2019-06-26)
### Bug Fixes
* **button:** default opacity for disabled clear buttons ([#18560](https://github.com/ionic-team/ionic/issues/18560)) ([f48dc3d](https://github.com/ionic-team/ionic/commit/f48dc3d)), closes [#18555](https://github.com/ionic-team/ionic/issues/18555)
* **button:** update solid buttons to use tint and shade colors ([#18537](https://github.com/ionic-team/ionic/issues/18537)) ([26ecf2b](https://github.com/ionic-team/ionic/commit/26ecf2b))
* **menu:** change ARIA role from complementary to navigation ([#18330](https://github.com/ionic-team/ionic/issues/18330)) ([9e4346b](https://github.com/ionic-team/ionic/commit/9e4346b)), closes [#18318](https://github.com/ionic-team/ionic/issues/18318)
* **segment:** apply hover properly for segment with color ([#18549](https://github.com/ionic-team/ionic/issues/18549)) ([78e477b](https://github.com/ionic-team/ionic/commit/78e477b))
* **segment:** default ripple to currentColor ([#18547](https://github.com/ionic-team/ionic/issues/18547)) ([832306c](https://github.com/ionic-team/ionic/commit/832306c))
### Features
* **components:** add missing button/a props to components that render them ([#17883](https://github.com/ionic-team/ionic/issues/17883)) ([eca4121](https://github.com/ionic-team/ionic/commit/eca4121)), closes [#16848](https://github.com/ionic-team/ionic/issues/16848) [#16889](https://github.com/ionic-team/ionic/issues/16889)
* **fab-button:** add hover state using tint colors ([#18536](https://github.com/ionic-team/ionic/issues/18536)) ([ad00679](https://github.com/ionic-team/ionic/commit/ad00679)), closes [#17624](https://github.com/ionic-team/ionic/issues/17624)
* **item:** add hover and focused states ([#18606](https://github.com/ionic-team/ionic/issues/18606)) ([8a88dd2](https://github.com/ionic-team/ionic/commit/8a88dd2)), closes [#18279](https://github.com/ionic-team/ionic/issues/18279) [#17624](https://github.com/ionic-team/ionic/issues/17624)
* **router-link:** add router-link and deprecate anchor ([#18620](https://github.com/ionic-team/ionic/issues/18620)) ([d4c7b03](https://github.com/ionic-team/ionic/commit/d4c7b03))
### Enhancements
* **stencil:** update to Stencil One to improve app performance 🎉🎊 ([b40f7d3](https://github.com/ionic-team/ionic/commit/b40f7d3))
# [4.5.0 Boron](https://github.com/ionic-team/ionic/compare/v4.4.2...v4.5.0) (2019-06-12)
### Bug Fixes
* **angular:** ensure all NavigationExtras values are preserved when navigating ([#18468](https://github.com/ionic-team/ionic/issues/18468)) ([7610787](https://github.com/ionic-team/ionic/commit/7610787)), closes [#18469](https://github.com/ionic-team/ionic/issues/18469)
* **button:** set opacity on the host element for disabled button ([#18509](https://github.com/ionic-team/ionic/issues/18509)) ([320719b](https://github.com/ionic-team/ionic/commit/320719b)), closes [#16965](https://github.com/ionic-team/ionic/issues/16965)
* **button:** use correct border-radius on menu and back button ([#18501](https://github.com/ionic-team/ionic/issues/18501)) ([055e125](https://github.com/ionic-team/ionic/commit/055e125)), closes [#17624](https://github.com/ionic-team/ionic/issues/17624)
* **button:** use correct size on a dynamic button in an item ([#18395](https://github.com/ionic-team/ionic/issues/18395)) ([a3e23fc](https://github.com/ionic-team/ionic/commit/a3e23fc)), closes [#18085](https://github.com/ionic-team/ionic/issues/18085)
* **card:** remove white space from bottom of card ([#18328](https://github.com/ionic-team/ionic/issues/18328)) ([d53e7aa](https://github.com/ionic-team/ionic/commit/d53e7aa))
* **content:** prevent ion-searchbar from receiving padding adjustment when keyboard is open ([#18008](https://github.com/ionic-team/ionic/issues/18008)) ([b2290a6](https://github.com/ionic-team/ionic/commit/b2290a6)), closes [#18007](https://github.com/ionic-team/ionic/issues/18007)
* **datetime:** recalculate time columns on change ([#18380](https://github.com/ionic-team/ionic/issues/18380)) ([292b24a](https://github.com/ionic-team/ionic/commit/292b24a))
* **item:** start align the content under stacked and floating labels ([#18379](https://github.com/ionic-team/ionic/issues/18379)) ([f0af707](https://github.com/ionic-team/ionic/commit/f0af707)), closes [#16375](https://github.com/ionic-team/ionic/issues/16375)
* **item:** inherit overflow to allow better customization ([#18502](https://github.com/ionic-team/ionic/issues/18502)) ([8d2a47e](https://github.com/ionic-team/ionic/commit/8d2a47e)), closes [#17670](https://github.com/ionic-team/ionic/issues/17670)
* **item:** use a step color if the activated background is not set ([#18450](https://github.com/ionic-team/ionic/issues/18450)) ([1899c13](https://github.com/ionic-team/ionic/commit/1899c13)), closes [#18449](https://github.com/ionic-team/ionic/issues/18449)
* **item-sliding:** use the correct gesture direction and side for rtl ([#18366](https://github.com/ionic-team/ionic/issues/18366)) ([4545100](https://github.com/ionic-team/ionic/commit/4545100)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **label:** include the ion-text-wrap class styles for larger font ([#18374](https://github.com/ionic-team/ionic/issues/18374)) ([4bba540](https://github.com/ionic-team/ionic/commit/4bba540))
* **platform:** prevent error with Platform.is on Android 4.4 ([#18387](https://github.com/ionic-team/ionic/issues/18387)) ([54bdb36](https://github.com/ionic-team/ionic/commit/54bdb36))
* **react:** ensure element exists in controller before dismissing it ([0fd3e5d](https://github.com/ionic-team/ionic/commit/0fd3e5d))
* **slides:** resolve issue where double tap to zoom was enabled by default ([10de1da](https://github.com/ionic-team/ionic/commit/10de1da)), closes [#18035](https://github.com/ionic-team/ionic/issues/18035)
* **tabs:** allow selection on enter and spacebar press ([#18381](https://github.com/ionic-team/ionic/issues/18381)) ([11cde99](https://github.com/ionic-team/ionic/commit/11cde99)), closes [#18363](https://github.com/ionic-team/ionic/issues/18363)
* **textarea:** inherit white-space for better customization ([#18508](https://github.com/ionic-team/ionic/issues/18508)) ([a583902](https://github.com/ionic-team/ionic/commit/a583902)), closes [#18495](https://github.com/ionic-team/ionic/issues/18495)
* **virtual-scroll:** do not crash with an empty cell list ([#17799](https://github.com/ionic-team/ionic/issues/17799)) ([20c146e](https://github.com/ionic-team/ionic/commit/20c146e))
### Features
* **back-button:** add variables and support for focused and hover states ([#18451](https://github.com/ionic-team/ionic/issues/18451)) ([58672fb](https://github.com/ionic-team/ionic/commit/58672fb)), closes [#18465](https://github.com/ionic-team/ionic/issues/18465)
* **button:** add variables for customizing hover state ([#18499](https://github.com/ionic-team/ionic/issues/18499)) ([5c5934b](https://github.com/ionic-team/ionic/commit/5c5934b)), closes [#17974](https://github.com/ionic-team/ionic/issues/17974)
* **item-divider:** add inner padding CSS variables ([#18490](https://github.com/ionic-team/ionic/issues/18490)) ([35c143a](https://github.com/ionic-team/ionic/commit/35c143a)), closes [#18484](https://github.com/ionic-team/ionic/issues/18484)
* **menu-button:** add variables for hover and focused states ([#18434](https://github.com/ionic-team/ionic/issues/18434)) ([5ba0aa9](https://github.com/ionic-team/ionic/commit/5ba0aa9)), closes [#18279](https://github.com/ionic-team/ionic/issues/18279)
* **searchbar:** add cancel button options ([b959e0b](https://github.com/ionic-team/ionic/commit/b959e0b))
* **toast:** allow html content ([#18423](https://github.com/ionic-team/ionic/issues/18423)) ([c8104a2](https://github.com/ionic-team/ionic/commit/c8104a2))
## [4.4.2](https://github.com/ionic-team/ionic/compare/v4.4.1...v4.4.2) (2019-05-22)
### Bug Fixes
* **angular:** account for query params and fragments within a string when navigating ([#18356](https://github.com/ionic-team/ionic/issues/18356)) ([b79f68a](https://github.com/ionic-team/ionic/commit/b79f68a))
## [4.4.1](https://github.com/ionic-team/ionic/compare/v4.4.0...v4.4.1) (2019-05-22)
### Bug Fixes
* **angular:** ensure active page is not removed from change detection ([#18299](https://github.com/ionic-team/ionic/issues/18299)) ([b8d4961](https://github.com/ionic-team/ionic/commit/b8d4961)), closes [#18293](https://github.com/ionic-team/ionic/issues/18293)
* **angular:** preserve queryParams and fragment when going back ([#18298](https://github.com/ionic-team/ionic/issues/18298)) ([bdd5109](https://github.com/ionic-team/ionic/commit/bdd5109)), closes [#16744](https://github.com/ionic-team/ionic/issues/16744)
* **buttons:** use theme/color toolbar colors for buttons ([#18191](https://github.com/ionic-team/ionic/issues/18191)) ([0511989](https://github.com/ionic-team/ionic/commit/0511989)), closes [#18184](https://github.com/ionic-team/ionic/issues/18184) [#17840](https://github.com/ionic-team/ionic/issues/17840)
* **datetime:** update label direction in RTL ([#18340](https://github.com/ionic-team/ionic/issues/18340)) ([17345ef](https://github.com/ionic-team/ionic/commit/17345ef))
* **fab:** position fab buttons properly in RTL ([#18325](https://github.com/ionic-team/ionic/issues/18325)) ([845def8](https://github.com/ionic-team/ionic/commit/845def8)), references [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **icon:** remove stroke and move fill to host element ([#18241](https://github.com/ionic-team/ionic/issues/18241)) ([394cf8d](https://github.com/ionic-team/ionic/commit/394cf8d)), closes [#16483](https://github.com/ionic-team/ionic/issues/16483)
* **input:** keep entire input in view when scrolling with keyboard open ([#18253](https://github.com/ionic-team/ionic/issues/18253)) ([3cad778](https://github.com/ionic-team/ionic/commit/3cad778)), closes [#17457](https://github.com/ionic-team/ionic/issues/17457)
* **label:** position floating/stacked labels properly in RTL ([#18315](https://github.com/ionic-team/ionic/issues/18315)) ([00a27dc](https://github.com/ionic-team/ionic/commit/00a27dc)), references [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **loading:** allow html content ([#18242](https://github.com/ionic-team/ionic/issues/18242)) ([a6cb5f2](https://github.com/ionic-team/ionic/commit/a6cb5f2)), closes [#18135](https://github.com/ionic-team/ionic/issues/18135)
* **overlay:** hide scrollbars on non-scrollable content ([#16767](https://github.com/ionic-team/ionic/issues/16767)) ([875d563](https://github.com/ionic-team/ionic/commit/875d563)), closes [#14178](https://github.com/ionic-team/ionic/issues/14178)
* **picker:** update the column positions in RTL ([#18339](https://github.com/ionic-team/ionic/issues/18339)) ([788a56c](https://github.com/ionic-team/ionic/commit/788a56c)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **range:** update border-radius on range pin for RTL ([#18321](https://github.com/ionic-team/ionic/issues/18321)) ([4855351](https://github.com/ionic-team/ionic/commit/4855351)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **searchbar:** position buttons properly in RTL ([#18325](https://github.com/ionic-team/ionic/issues/18325)) ([845def8](https://github.com/ionic-team/ionic/commit/845def8)), references [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **segment:** update segment border for RTL ([#18326](https://github.com/ionic-team/ionic/issues/18326)) ([805b225](https://github.com/ionic-team/ionic/commit/805b225)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **slides:** allow clicks to propagate to buttons ([#16728](https://github.com/ionic-team/ionic/issues/16728)) ([a8f9dfe](https://github.com/ionic-team/ionic/commit/a8f9dfe))
* **tab-button:** apply background-focused when tabbing into tab button ([#17502](https://github.com/ionic-team/ionic/issues/17502)) ([d788a8e](https://github.com/ionic-team/ionic/commit/d788a8e)), closes [#17042](https://github.com/ionic-team/ionic/issues/17042)
* **tabs:** position badge properly in RTL (only in Chrome) ([#18325](https://github.com/ionic-team/ionic/issues/18325)) ([845def8](https://github.com/ionic-team/ionic/commit/845def8)), references [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **tabs:** select the tab called by the select method after initialization ([#18300](https://github.com/ionic-team/ionic/issues/18300)) ([da38647](https://github.com/ionic-team/ionic/commit/da38647)), closes [#17957](https://github.com/ionic-team/ionic/issues/17957)
* **toggle:** position toggle icon properly in RTL ([#18325](https://github.com/ionic-team/ionic/issues/18325)) ([845def8](https://github.com/ionic-team/ionic/commit/845def8)), references [#17012](https://github.com/ionic-team/ionic/issues/17012)
* **toolbar:** update md toolbar button spacing and padding to match spec ([#17537](https://github.com/ionic-team/ionic/issues/17537)) ([fa87e35](https://github.com/ionic-team/ionic/commit/fa87e35)), closes [#16950](https://github.com/ionic-team/ionic/issues/16950) [#14444](https://github.com/ionic-team/ionic/issues/14444)
# [4.4.0 Beryllium](https://github.com/ionic-team/ionic/compare/v4.3.1...v4.4.0) (2019-05-08)
### Bug Fixes
* **button:** apply round property to button sizes in iOS ([#18125](https://github.com/ionic-team/ionic/issues/18125)) ([ae0eccc](https://github.com/ionic-team/ionic/commit/ae0eccc)), closes [#18108](https://github.com/ionic-team/ionic/issues/18108)
* **datetime:** default to current date when value is null ([#18105](https://github.com/ionic-team/ionic/issues/18105)) ([ca233b5](https://github.com/ionic-team/ionic/commit/ca233b5)), closes [#18099](https://github.com/ionic-team/ionic/issues/18099)
* **input:** clear on edit from inside native input ([#17115](https://github.com/ionic-team/ionic/issues/17115)) ([85093d6](https://github.com/ionic-team/ionic/commit/85093d6)), closes [#17055](https://github.com/ionic-team/ionic/issues/17055)
* **item:** use the global activated background for md ripple color ([#16752](https://github.com/ionic-team/ionic/issues/16752)) ([95945c0](https://github.com/ionic-team/ionic/commit/95945c0)), closes [#16585](https://github.com/ionic-team/ionic/issues/16585)
* **label:** use primary color on focus for md input labels ([#18183](https://github.com/ionic-team/ionic/issues/18183)) ([ddb8ef8](https://github.com/ionic-team/ionic/commit/ddb8ef8)), closes [#15602](https://github.com/ionic-team/ionic/issues/15602)
* **menu** add prefixed transform for side menu animation ([#18128](https://github.com/ionic-team/ionic/issues/18128)) ([2457a23](https://github.com/ionic-team/ionic/commit/2457a23)), closes [#17729](https://github.com/ionic-team/ionic/issues/17729)
* **reorder-group:** remove required parameter for the complete method ([#18084](https://github.com/ionic-team/ionic/issues/18084)) ([bd96491](https://github.com/ionic-team/ionic/commit/bd96491)), closes [#16302](https://github.com/ionic-team/ionic/issues/16302)
* **segment:** decrease icon size on ios and stretch segment buttons to fill height ([#17751](https://github.com/ionic-team/ionic/issues/17751)) ([0fa645b](https://github.com/ionic-team/ionic/commit/0fa645b)), closes [#17069](https://github.com/ionic-team/ionic/issues/17069)
* **textarea:** reposition textarea when keyboard appears ([#18098](https://github.com/ionic-team/ionic/issues/18098)) ([3cdab10](https://github.com/ionic-team/ionic/commit/3cdab10)), closes [#17847](https://github.com/ionic-team/ionic/issues/17847)
* **toast:** allow button-color CSS variable to be overridden ([#18133](https://github.com/ionic-team/ionic/issues/18133)) ([0c83fd3](https://github.com/ionic-team/ionic/commit/0c83fd3)), closes [#18127](https://github.com/ionic-team/ionic/issues/18127)
### Features
* **card:** add button functionality ([#17997](https://github.com/ionic-team/ionic/issues/17997)) ([669ec0d](https://github.com/ionic-team/ionic/commit/669ec0d)), closes [#17773](https://github.com/ionic-team/ionic/issues/17773)
* **img:** add ionImgWillLoad event and emit ionImgDidLoad when image is loaded ([#18159](https://github.com/ionic-team/ionic/issues/18159)) ([38ffb98](https://github.com/ionic-team/ionic/commit/38ffb98)), closes [#17652](https://github.com/ionic-team/ionic/issues/17652) [#18161](https://github.com/ionic-team/ionic/issues/18161)
* **item-sliding:** add open method ([#17964](https://github.com/ionic-team/ionic/issues/17964)) ([f912206](https://github.com/ionic-team/ionic/commit/f912206)), closes [#17899](https://github.com/ionic-team/ionic/issues/17899)
* **menu-button:** add css variables for padding ([#18188](https://github.com/ionic-team/ionic/issues/18188)) ([ef98977](https://github.com/ionic-team/ionic/commit/ef98977)), closes [#18187](https://github.com/ionic-team/ionic/issues/18187)
* **refresher:** add pullFactor property to control speed ([#16697](https://github.com/ionic-team/ionic/issues/16697)) ([9030dcc](https://github.com/ionic-team/ionic/commit/9030dcc)), closes [#15425](https://github.com/ionic-team/ionic/issues/15425)
* **searchbar:** add disabled property ([#17935](https://github.com/ionic-team/ionic/issues/17935)) ([a5b9066](https://github.com/ionic-team/ionic/commit/a5b9066)), closes [#17921](https://github.com/ionic-team/ionic/issues/17921)
* **textarea:** add option to expand textarea as value changes ([#16916](https://github.com/ionic-team/ionic/issues/16916)) ([cc8678a](https://github.com/ionic-team/ionic/commit/cc8678a))
## [4.3.1](https://github.com/ionic-team/ionic/compare/v4.3.0...v4.3.1) (2019-04-26)
### Bug Fixes
* **angular:** support replaceUrl with angular <7.2 ([#18106](https://github.com/ionic-team/ionic/issues/18106)) ([eb3cbe4](https://github.com/ionic-team/ionic/commit/eb3cbe4))
* **security:** sanitize components using innerHTML ([#18146](https://github.com/ionic-team/ionic/issues/18146)) ([b839e6f](https://github.com/ionic-team/ionic/commit/b839e6f))
# [4.3.0 Lithium](https://github.com/ionic-team/ionic/compare/v4.2.0...v4.3.0) (2019-04-17)
### Bug Fixes
* **action-sheet:** default buttons to empty array ([9e63947](https://github.com/ionic-team/ionic/commit/9e63947))
* **angular:** back button correctly goes back to proper tab ([#18005](https://github.com/ionic-team/ionic/issues/18005)) ([52e5a8d](https://github.com/ionic-team/ionic/commit/52e5a8d)), closes [#17278](https://github.com/ionic-team/ionic/issues/17278) [#15216](https://github.com/ionic-team/ionic/issues/15216)
* **components:** add mode classes to components for use in shadow elements ([#17838](https://github.com/ionic-team/ionic/issues/17838)) ([e5c8c10](https://github.com/ionic-team/ionic/commit/e5c8c10)), closes [#17608](https://github.com/ionic-team/ionic/issues/17608)
* **datetime:** date strings no longer revert to previous day ([#18018](https://github.com/ionic-team/ionic/issues/18018)) ([cc60b60](https://github.com/ionic-team/ionic/commit/cc60b60)), closes [#17977](https://github.com/ionic-team/ionic/issues/17977)
* **input:** prevent input from losing focus when tapping clear button ([#18004](https://github.com/ionic-team/ionic/issues/18004)) ([29bb4fc](https://github.com/ionic-team/ionic/commit/29bb4fc)), closes [#18002](https://github.com/ionic-team/ionic/issues/18002)
* **item:** use the correct input highlight for an inset line item ([#18052](https://github.com/ionic-team/ionic/issues/18052)) ([72be80c](https://github.com/ionic-team/ionic/commit/72be80c)), closes [#18051](https://github.com/ionic-team/ionic/issues/18051)
* **item-sliding:** hide closed side options while dragging side options open ([#17986](https://github.com/ionic-team/ionic/issues/17986)) ([f13722c](https://github.com/ionic-team/ionic/commit/f13722c)), closes [#17822](https://github.com/ionic-team/ionic/issues/17822)
* **slides:** allow zoom to work ([18b347b](https://github.com/ionic-team/ionic/commit/18b347b)), closes [#17981](https://github.com/ionic-team/ionic/issues/17981)
* **slides:** expose interface to provide custom animations ([#17959](https://github.com/ionic-team/ionic/issues/17959)) ([4474974](https://github.com/ionic-team/ionic/commit/4474974)), closes [#16616](https://github.com/ionic-team/ionic/issues/16616)
* **textarea:** float label when a value is changed async ([#18024](https://github.com/ionic-team/ionic/issues/18024)) ([494991e](https://github.com/ionic-team/ionic/commit/494991e)), closes [#17555](https://github.com/ionic-team/ionic/issues/17555) [#17559](https://github.com/ionic-team/ionic/issues/17559)
* **textarea:** update label alignment for inputs and textareas ([#18042](https://github.com/ionic-team/ionic/issues/18042)) ([38ae362](https://github.com/ionic-team/ionic/commit/38ae362)), closes [#16187](https://github.com/ionic-team/ionic/issues/16187)
* **vue:** use direction type from core ([#17901](https://github.com/ionic-team/ionic/issues/17901)) ([fa13173](https://github.com/ionic-team/ionic/commit/fa13173))
### Features
* **toast:** add header and additional custom toast buttons ([#17147](https://github.com/ionic-team/ionic/issues/17147)) ([6e1a8f1](https://github.com/ionic-team/ionic/commit/6e1a8f1)), closes [#16791](https://github.com/ionic-team/ionic/issues/16791) [#16237](https://github.com/ionic-team/ionic/issues/16237) [#17611](https://github.com/ionic-team/ionic/issues/17611)
* **toast:** add variables to change position start/end of toast ([#17961](https://github.com/ionic-team/ionic/issues/17961)) ([07e739a](https://github.com/ionic-team/ionic/commit/07e739a)), closes [#17854](https://github.com/ionic-team/ionic/issues/17854)
# [4.2.0 Helium](https://github.com/ionic-team/ionic/compare/v4.1.2...v4.2.0) (2019-04-03)
### Bug Fixes

View File

@@ -182,13 +182,14 @@ These have been renamed to the following, and moved from the button element to t
In addition, several sets of mutually exclusive boolean attributes have been combined into a single string attribute.
The `small` and `large` attributes are now combined under the `size` attribute. The `clear`, `outline`, and `solid` attributes have been combined under `fill`. And, lastly, the `full` and `block` attributes have been combined under `expand`.
The `small` and `large` attributes are now combined under the `size` attribute. The `clear`, `outline`, and `solid` attributes have been combined under `fill`. The `full` and `block` attributes have been combined under `expand`. And, lastly, the `round` attribute is now used under `shape`.
| Old Property | New Property | Property Behavior |
| --------------------------- | ------------ | --------------------------- |
| `small`, `large` | `size` | Sets the button size. |
| `clear`, `outline`, `solid` | `fill` | Sets the button fill style. |
| `full`, `block`             | `expand` | Sets the button width. |
| `round`             | `shape` | Sets the button shape. |
**Old Usage Example:**
@@ -225,6 +226,10 @@ The `small` and `large` attributes are now combined under the `size` attribute.
<ion-button full>
Full-width Button
</ion-button>
<ion-button round>
Round Button
</ion-button>
```
**New Usage Example:**
@@ -251,6 +256,10 @@ The `small` and `large` attributes are now combined under the `size` attribute.
<ion-button expand="full">
Full-width Button
</ion-button>
<ion-button shape="round">
Round Button
</ion-button>
```
@@ -774,6 +783,26 @@ The option component should now be written as an `ion-item-option`. Previously i
The `getSlidingPercent` method has been renamed to `getSlidingRatio` since the function is returning a ratio of the open amount of the item compared to the width of the options.
### Arguments Changed
The `ionDrag` event no longer gets the sliding item as an argument. It now takes an event with a property `details` which contains two properties `amount` and `ratio` reflecting the absolute and ratio values of the sliding action respectively.
**Old Usage Example:**
```typescript
dragged(item: ItemSliding) {
console.log(item.getSlidingPercent());
console.log(item.getOpenAmount());
}
```
**New Usage Example:**
```typescript
dragged(ev: { details: { amount: number, ratio: number } }) {
console.log(ev.details.ratio);
console.log(ev.details.amount);
}
```
## Label
@@ -1065,11 +1094,11 @@ async openLoading() {
let loading = this.loadingCtrl.create({
content: 'Loading...'
});
await loading.present();
const { role, data } = await loading.onDidDismiss();
console.log('Loading dismissed!');
}
```

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "4.2.0",
"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.2.0",
"@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",
@@ -73,17 +77,17 @@
"@angular/platform-browser": "^7.2.1",
"@angular/platform-browser-dynamic": "^7.2.1",
"@angular/router": "^7.2.1",
"@types/node": "~10.12.0",
"@types/node": "~12.0.12",
"fs-extra": "^7.0.0",
"glob": "^7.1.3",
"rollup": "^1.1.2",
"rollup-plugin-node-resolve": "^4.0.0",
"rxjs": "^6.2.0",
"glob": "^7.1.4",
"rollup": "~1.17.0",
"rollup-plugin-node-resolve": "~5.2.0",
"rxjs": "^6.5.2",
"tsickle": "^0.34.0",
"tslint": "^5.12.1",
"tslint-ionic-rules": "0.0.21",
"typescript": "3.2.4",
"zone.js": "^0.8.28"
"typescript": "~3.2.2",
"zone.js": "~0.8.26"
},
"schematics": "./dist/schematics/collection.json"
}

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,15 +2,13 @@ import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'build/es2015/core.js',
output: {
file: 'dist/fesm2015.js',
format: 'es'
},
external: (id) => {
// inline @ionic/core deps
if (id === '@ionic/core') {
return false;
output: [
{
file: 'dist/fesm2015.js',
format: 'es'
}
],
external: (id) => {
// anything else is external
// Windows: C:\xxxxxx\xxx
const colonPosition = 1;

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

@@ -1,55 +1,39 @@
import { defineCustomElements } from '@ionic/core/loader';
import { NgZone } from '@angular/core';
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
import { Config } from './providers/config';
import { IonicWindow } from './types/interfaces';
import { raf } from './util/util';
export function appInitialize(config: Config, doc: Document) {
export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
return (): any => {
const win: IonicWindow | undefined = doc.defaultView as any;
if (win) {
const Ionic = win.Ionic = win.Ionic || {};
Ionic.config = config;
Ionic.asyncQueue = false;
Ionic.ael = (elm, eventName, cb, opts) => {
if (elm.__zone_symbol__addEventListener && skipZone(eventName)) {
elm.__zone_symbol__addEventListener(eventName, cb, opts);
} else {
elm.addEventListener(eventName, cb, opts);
}
Ionic.config = {
...config,
_zoneGate: (h: any) => zone.run(h)
};
Ionic.rel = (elm, eventName, cb, opts) => {
if (elm.__zone_symbol__removeEventListener && skipZone(eventName)) {
elm.__zone_symbol__removeEventListener(eventName, cb, opts);
} else {
elm.removeEventListener(eventName, cb, opts);
}
};
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
? '__zone_symbol__addEventListener'
: 'addEventListener';
return defineCustomElements(win, {
exclude: ['ion-tabs', 'ion-tab']
return applyPolyfills().then(() => {
return defineCustomElements(win, {
exclude: ['ion-tabs', 'ion-tab'],
syncQueue: true,
raf,
jmp: (h: any) => zone.runOutsideAngular(h),
ael(elm, eventName, cb, opts) {
(elm as any)[aelFn](eventName, cb, opts);
},
rel(elm, eventName, cb, opts) {
elm.removeEventListener(eventName, cb, opts);
}
});
});
}
};
}
const SKIP_ZONE = [
'scroll',
'resize',
'touchstart',
'touchmove',
'touchend',
'mousedown',
'mousemove',
'mouseup',
'ionStyle',
];
function skipZone(eventName: string) {
return SKIP_ZONE.indexOf(eventName) >= 0;
}
};

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,8 +47,8 @@ export class ValueAccessor implements ControlValueAccessor {
}
}
export function setIonicClasses(element: ElementRef) {
requestAnimationFrame(() => {
export const setIonicClasses = (element: ElementRef) => {
raf(() => {
const input = element.nativeElement as HTMLElement;
const classes = getClasses(input);
setClasses(input, classes);
@@ -52,9 +58,9 @@ export function setIonicClasses(element: ElementRef) {
setClasses(item, classes);
}
});
}
};
function getClasses(element: HTMLElement) {
const getClasses = (element: HTMLElement) => {
const classList = element.classList;
const classes = [];
for (let i = 0; i < classList.length; i++) {
@@ -64,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(
@@ -78,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

@@ -1,4 +1,5 @@
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
import { Location } from '@angular/common';
import { Attribute, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
@@ -56,9 +57,9 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
private resolver: ComponentFactoryResolver,
@Attribute('name') name: string,
@Optional() @Attribute('tabs') tabs: string,
private changeDetector: ChangeDetectorRef,
private config: Config,
private navCtrl: NavController,
commonLocation: Location,
elementRef: ElementRef,
router: Router,
zone: NgZone,
@@ -68,7 +69,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
this.nativeEl = elementRef.nativeElement;
this.name = name || PRIMARY_OUTLET;
this.tabsPrefix = tabs === 'true' ? getUrl(router, activatedRoute) : undefined;
this.stackCtrl = new StackController(this.tabsPrefix, this.nativeEl, router, navCtrl, zone);
this.stackCtrl = new StackController(this.tabsPrefix, this.nativeEl, router, navCtrl, zone, commonLocation);
parentContexts.onChildOutletCreated(this.name, this as any);
}
@@ -92,7 +93,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
if ((this.nativeEl as any).componentOnReady) {
this.nativeEl.componentOnReady().then(() => {
if (this._swipeGesture === undefined) {
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', this.nativeEl.mode === 'ios');
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
}
});
}
@@ -141,6 +142,20 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
if (this.activated) {
if (this.activatedView) {
this.activatedView.savedData = new Map(this.getContext()!.children['contexts']);
/**
* Ensure we are saving the NavigationExtras
* data otherwise it will be lost
*/
this.activatedView.savedExtras = {};
const context = this.getContext()!;
if (context.route) {
const contextSnapshot = context.route.snapshot;
this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams;
this.activatedView.savedExtras.fragment = contextSnapshot.fragment;
}
}
const c = this.component;
this.activatedView = null;
@@ -194,8 +209,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
// Store references to the proxy by component
this.proxyMap.set(cmpRef.instance, activatedRouteProxy);
this.currentActivatedRoute$.next({ component: cmpRef.instance, activatedRoute });
this.changeDetector.markForCheck();
}
this.activatedView = enteringView;

View File

@@ -1,3 +1,4 @@
import { Location } from '@angular/common';
import { ComponentRef, NgZone } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterDirection } from '@ionic/core';
@@ -22,6 +23,7 @@ export class StackController {
private router: Router,
private navCtrl: NavController,
private zone: NgZone,
private location: Location
) {
this.tabsPrefix = tabsPrefix !== undefined ? toSegments(tabsPrefix) : undefined;
}
@@ -29,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),
@@ -57,9 +59,25 @@ export class StackController {
direction = 'back';
animation = undefined;
}
const viewsSnapshot = this.views.slice();
const currentNavigation = this.router.getCurrentNavigation();
let currentNavigation;
const router = (this.router as any);
// Angular >= 7.2.0
if (router.getCurrentNavigation) {
currentNavigation = router.getCurrentNavigation();
// Angular < 7.2.0
} else if (
router.navigations &&
router.navigations.value
) {
currentNavigation = router.navigations.value;
}
/**
* If the navigation action
* sets `replaceUrl: true`
@@ -77,16 +95,36 @@ export class StackController {
}
}
const reused = this.views.includes(enteringView);
const views = this.insertView(enteringView, direction);
return this.wait(async () => {
await this.transition(enteringView, leavingView, animation, this.canGoBack(1), false);
await cleanupAsync(enteringView, views, viewsSnapshot);
return {
enteringView,
direction,
animation,
tabSwitch
};
// Trigger change detection before transition starts
// This will call ngOnInit() the first time too, just after the view
// was attached to the dom, but BEFORE the transition starts
if (!reused) {
enteringView.ref.changeDetectorRef.detectChanges();
}
// Wait until previous transitions finish
return this.zone.runOutsideAngular(() => {
return this.wait(() => {
// disconnect leaving page from change detection to
// reduce jank during the page transition
if (leavingView) {
leavingView.ref.changeDetectorRef.detach();
}
// In case the enteringView is the same as the leavingPage we need to reattach()
enteringView.ref.changeDetectorRef.reattach();
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
.then(() => ({
enteringView,
direction,
animation,
tabSwitch
}));
});
});
}
@@ -101,32 +139,50 @@ export class StackController {
return Promise.resolve(false);
}
const view = views[views.length - deep - 1];
return this.navCtrl.navigateBack(view.url).then(() => true);
let url = view.url;
const viewSavedData = view.savedData;
if (viewSavedData) {
const primaryOutlet = viewSavedData.get('primary');
if (
primaryOutlet &&
primaryOutlet.route &&
primaryOutlet.route._routerState &&
primaryOutlet.route._routerState.snapshot &&
primaryOutlet.route._routerState.snapshot.url
) {
url = primaryOutlet.route._routerState.snapshot.url;
}
}
return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true);
});
}
async startBackTransition() {
startBackTransition() {
const leavingView = this.activeView;
if (leavingView) {
const views = this.getStack(leavingView.stackId);
const enteringView = views[views.length - 2];
enteringView.ref.changeDetectorRef.reattach();
await this.wait(() => {
return this.wait(() => {
return this.transition(
enteringView, // entering view
leavingView, // leaving view
'back',
true,
this.canGoBack(2),
true
);
});
}
return Promise.resolve();
}
endBackTransition(shouldComplete: boolean) {
if (shouldComplete) {
this.skipTransition = true;
this.pop(1);
} else if (this.activeView) {
cleanup(this.activeView, this.views, this.views, this.location);
}
}
@@ -156,7 +212,7 @@ export class StackController {
return this.views.slice();
}
private async transition(
private transition(
enteringView: RouteView | undefined,
leavingView: RouteView | undefined,
direction: 'forward' | 'back' | undefined,
@@ -165,7 +221,10 @@ export class StackController {
) {
if (this.skipTransition) {
this.skipTransition = false;
return;
return Promise.resolve(false);
}
if (leavingView === enteringView) {
return Promise.resolve(false);
}
const enteringEl = enteringView ? enteringView.element : undefined;
const leavingEl = leavingView ? leavingView.element : undefined;
@@ -176,15 +235,17 @@ export class StackController {
containerEl.appendChild(enteringEl);
}
await containerEl.componentOnReady();
await containerEl.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
});
if ((containerEl as any).commit) {
return containerEl.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
});
}
}
return Promise.resolve(false);
}
private async wait<T>(task: () => Promise<T>): Promise<T> {
@@ -197,26 +258,41 @@ export class StackController {
}
}
function cleanupAsync(activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[]) {
return new Promise(resolve => {
requestAnimationFrame(() => {
cleanup(activeRoute, views, viewsSnapshot);
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[]) {
const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
viewsSnapshot
.filter(view => !views.includes(view))
.forEach(destroyView);
views.forEach(view => {
if (view !== activeRoute) {
/**
* In the event that a user navigated multiple
* times in rapid succession, we want to make sure
* we don't pre-emptively detach a view while
* it is in mid-transition.
*
* In this instance we also do not care about query
* params or fragments as it will be the same view regardless
*/
const locationWithoutParams = location.path().split('?')[0];
const locationWithoutFragment = locationWithoutParams.split('#')[0];
if (view !== activeRoute && view.url !== locationWithoutFragment) {
const element = view.element;
element.setAttribute('aria-hidden', 'true');
element.classList.add('ion-page-hidden');
view.ref.changeDetectorRef.detach();
}
});
}
};

View File

@@ -1,8 +1,8 @@
import { ComponentRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
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;
@@ -94,5 +94,6 @@ export interface RouteView {
element: HTMLElement;
ref: ComponentRef<any>;
savedData?: any;
savedExtras?: NavigationExtras;
unlistenEvents: () => void;
}

View File

@@ -6,7 +6,9 @@ export function proxyInputs(Cmp: any, inputs: string[]) {
inputs.forEach(item => {
Object.defineProperty(Prototype, item, {
get() { return this.el[item]; },
set(val: any) { this.el[item] = val; },
set(val: any) {
this.z.runOutsideAngular(() => this.el[item] = val);
},
});
});
}
@@ -16,7 +18,7 @@ export function proxyMethods(Cmp: any, methods: string[]) {
methods.forEach(methodName => {
Prototype[methodName] = function() {
const args = arguments;
return this.el.componentOnReady().then((el: any) => el[methodName].apply(el, args));
return this.z.runOutsideAngular(() => this.el[methodName].apply(this.el, args));
};
});
}

View File

File diff suppressed because it is too large Load Diff

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

@@ -1,5 +1,5 @@
import { CommonModule, DOCUMENT } from '@angular/common';
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
import { APP_INITIALIZER, ModuleWithProviders, NgModule, NgZone } from '@angular/core';
import { IonicConfig } from '@ionic/core';
import { appInitialize } from './app-initialize';
@@ -142,7 +142,8 @@ export class IonicModule {
multi: true,
deps: [
ConfigToken,
DOCUMENT
DOCUMENT,
NgZone
]
}
]

View File

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { ActionSheetOptions } from '@ionic/core';
import { Injectable } from '@angular/core';
import { ActionSheetOptions, actionSheetController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
providedIn: 'root',
})
export class ActionSheetController extends OverlayBaseController<ActionSheetOptions, HTMLIonActionSheetElement> {
constructor(@Inject(DOCUMENT) doc: any) {
super('ion-action-sheet-controller', doc);
constructor() {
super(actionSheetController);
}
}

View File

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { AlertOptions } from '@ionic/core';
import { Injectable } from '@angular/core';
import { AlertOptions, alertController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
providedIn: 'root',
})
export class AlertController extends OverlayBaseController<AlertOptions, HTMLIonAlertElement> {
constructor(@Inject(DOCUMENT) doc: any) {
super('ion-alert-controller', doc);
constructor() {
super(alertController);
}
}

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,26 +114,22 @@ const LIFECYCLES = [
LIFECYCLE_WILL_UNLOAD
];
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
const unregisters = LIFECYCLES.map(eventName => {
const handler = (ev: any) => {
if (typeof instance[eventName] === 'function') {
instance[eventName](ev.detail);
}
};
element.addEventListener(eventName, handler);
return () => {
element.removeEventListener(eventName, handler);
};
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
return zone.run(() => {
const unregisters = LIFECYCLES
.filter(eventName => typeof instance[eventName] === 'function')
.map(eventName => {
const handler = (ev: any) => instance[eventName](ev.detail);
element.addEventListener(eventName, handler);
return () => element.removeEventListener(eventName, handler);
});
return () => unregisters.forEach(fn => fn());
});
return () => {
unregisters.forEach(fn => fn());
};
}
};
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
function getProviders(params: {[key: string]: any}) {
const getProviders = (params: {[key: string]: any}) => {
return [
{
provide: NavParamsToken, useValue: params
@@ -141,8 +138,8 @@ function getProviders(params: {[key: string]: any}) {
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
}
];
}
};
function provideNavParamsInjectable(params: {[key: string]: any}) {
const provideNavParamsInjectable = (params: {[key: string]: any}) => {
return new NavParams(params);
}
};

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

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { LoadingOptions } from '@ionic/core';
import { Injectable } from '@angular/core';
import { LoadingOptions, loadingController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
providedIn: 'root',
})
export class LoadingController extends OverlayBaseController<LoadingOptions, HTMLIonLoadingElement> {
constructor(@Inject(DOCUMENT) doc: any) {
super('ion-loading-controller', doc);
constructor() {
super(loadingController);
}
}

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

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { ComponentFactoryResolver, Inject, Injectable, Injector } from '@angular/core';
import { ModalOptions } from '@ionic/core';
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { ModalOptions, modalController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -13,9 +12,8 @@ export class ModalController extends OverlayBaseController<ModalOptions, HTMLIon
private angularDelegate: AngularDelegate,
private resolver: ComponentFactoryResolver,
private injector: Injector,
@Inject(DOCUMENT) doc: any
) {
super('ion-modal-controller', doc);
super(modalController);
}
create(opts: ModalOptions): Promise<HTMLIonModalElement> {

View File

@@ -1,6 +1,6 @@
import { Location } from '@angular/common';
import { Injectable, Optional } from '@angular/core';
import { NavigationExtras, NavigationStart, Router, UrlTree } from '@angular/router';
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
@@ -29,6 +29,7 @@ export class NavController {
constructor(
platform: Platform,
private location: Location,
private serializer: UrlSerializer,
@Optional() private router?: Router,
) {
// Subscribe to router events to detect direction
@@ -49,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>
@@ -67,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>
@@ -90,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');
@@ -100,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>
@@ -113,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);
@@ -121,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() {
@@ -139,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;
@@ -184,12 +186,34 @@ export class NavController {
if (Array.isArray(url)) {
return this.router!.navigate(url, options);
} else {
return this.router!.navigateByUrl(url, options);
/**
* navigateByUrl ignores any properties that
* would change the url, so things like queryParams
* would be ignored unless we create a url tree
* More Info: https://github.com/angular/angular/issues/18798
*/
const urlTree = this.serializer.parse(url.toString());
if (options.queryParams !== undefined) {
urlTree.queryParams = { ...options.queryParams };
}
if (options.fragment !== undefined) {
urlTree.fragment = options.fragment;
}
/**
* `navigateByUrl` will still apply `NavigationExtras` properties
* that do not modify the url, such as `replaceUrl` which is why
* `options` is passed in here.
*/
return this.router!.navigateByUrl(urlTree, options);
}
}
}
function getAnimation(direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined {
const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
if (animated === false) {
return undefined;
}
@@ -202,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,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { PickerOptions } from '@ionic/core';
import { Injectable } from '@angular/core';
import { PickerOptions, pickerController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
providedIn: 'root',
})
export class PickerController extends OverlayBaseController<PickerOptions, HTMLIonPickerElement> {
constructor(@Inject(DOCUMENT) doc: any) {
super('ion-picker-controller', doc);
constructor() {
super(pickerController);
}
}

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

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { ComponentFactoryResolver, Inject, Injectable, Injector } from '@angular/core';
import { PopoverOptions } from '@ionic/core';
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { PopoverOptions, popoverController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -13,9 +12,8 @@ export class PopoverController extends OverlayBaseController<PopoverOptions, HTM
private angularDelegate: AngularDelegate,
private resolver: ComponentFactoryResolver,
private injector: Injector,
@Inject(DOCUMENT) doc: any
) {
super('ion-popover-controller', doc);
super(popoverController);
}
create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {

View File

@@ -1,6 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { ToastOptions } from '@ionic/core';
import { Injectable } from '@angular/core';
import { ToastOptions, toastController } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@@ -8,7 +7,7 @@ import { OverlayBaseController } from '../util/overlay';
providedIn: 'root',
})
export class ToastController extends OverlayBaseController<ToastOptions, HTMLIonToastElement> {
constructor(@Inject(DOCUMENT) doc: any) {
super('ion-toast-controller', doc);
constructor() {
super(toastController);
}
}

View File

@@ -1,13 +1,15 @@
export interface IonicGlobal {
config?: any;
ael?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
raf?: (ts: number) => void;
rel?: (elm: any, eventName: string, cb: (ev: Event) => void, opts: any) => void;
asyncQueue?: boolean;
}
export interface IonicWindow extends Window {
Ionic: IonicGlobal;
__zone_symbol__requestAnimationFrame: (ts: number) => void;
__zone_symbol__requestAnimationFrame?: (ts: FrameRequestCallback) => number;
}
export interface HTMLStencilElement extends HTMLElement {
componentOnReady(): Promise<this>;
forceUpdate(): void;
}

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,26 +1,32 @@
import { proxyMethod } from './util';
export class OverlayBaseController<Opts, Overlay> {
constructor(private ctrl: string, private doc: Document) {}
interface ControllerShape<Opts, HTMLElm> {
create(options: Opts): Promise<HTMLElm>;
dismiss(data?: any, role?: string, id?: string): Promise<boolean>;
getTop(): Promise<HTMLElm | undefined>;
}
export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opts, Overlay> {
constructor(private ctrl: ControllerShape<Opts, Overlay>) {}
/**
* Creates a new overlay
*/
create(opts?: Opts): Promise<Overlay> {
return proxyMethod(this.ctrl, this.doc, 'create', opts);
create(opts?: Opts) {
// TODO: next major release opts is not optional
return this.ctrl.create((opts || {}) as any);
}
/**
* When `id` is not provided, it dismisses the top overlay.
*/
dismiss(data?: any, role?: string, id?: string): Promise<void> {
return proxyMethod(this.ctrl, this.doc, 'dismiss', data, role, id);
dismiss(data?: any, role?: string, id?: string) {
return this.ctrl.dismiss(data, role, id);
}
/**
* Returns the top overlay.
*/
getTop(): Promise<Overlay | undefined> {
return proxyMethod(this.ctrl, this.doc, 'getTop');
getTop() {
return this.ctrl.getTop();
}
}

View File

@@ -1,15 +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,18 +13,25 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/test-app",
"outputPath": "dist/browser",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
{
"glob": "**/*",
"input": "src/assets",
"output": "assets"
},
{
"glob": "**/*.svg",
"input": "node_modules/ionicons/dist/ionicons/svg",
"output": "./svg"
}
],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
@@ -77,37 +84,13 @@
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.css"
],
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"styles": ["src/styles.css"],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
"assets": ["src/favicon.ico", "src/assets"]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"test-app-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
@@ -117,20 +100,39 @@
"configurations": {
"production": {
"devServerTarget": "test-app:serve:production"
},
"ci": {
"devServerTarget": "test-app:serve:ci"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
"exclude": ["**/node_modules/**"]
}
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/main.server.ts",
"tsConfig": "tsconfig.server.json"
},
"configurations": {
"production": {
"fileReplacements": [
{
"src": "src/environments/environment.ts",
"replaceWith": "src/environments/environment.prod.ts"
}
]
}
}
}
}
}
},
"defaultProject": "test-app"
}
}

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,12 +4,13 @@ import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
describe('form', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
describe('change', () => {
beforeEach(async () => {
await browser.get('/form');
await waitTime(30);
});
it('should have default values', async () => {
@@ -81,6 +82,7 @@ describe('form', () => {
describe('blur', () => {
beforeEach(async () => {
await browser.get('/form#blur');
await waitTime(30);
});
it('ion-toggle should change only after blur', async () => {

View File

@@ -1,13 +1,14 @@
import { browser, element, by } from 'protractor';
import { getProperty, setProperty, handleErrorMessages } from './utils';
import { getProperty, setProperty, handleErrorMessages, waitTime } from './utils';
describe('inputs', () => {
beforeEach(async () => {
await browser.get('/inputs');
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should have default value', async () => {
@@ -59,4 +60,10 @@ describe('inputs', () => {
expect(await element(by.css('#select-note')).getText()).toEqual('playstation');
expect(await element(by.css('#range-note')).getText()).toEqual('20');
});
it('nested components should not interfere with NgModel', async () => {
expect(await element(by.css('#range-note')).getText()).toEqual('10');
await element(by.css('#nested-toggle')).click();
expect(await element(by.css('#range-note')).getText()).toEqual('10');
});
});

View File

@@ -5,9 +5,10 @@ describe('modals', () => {
beforeEach(async () => {
await browser.get('/modals');
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should open standalone modal and close', async () => {

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,13 +1,61 @@
import { browser, element, by } from 'protractor';
import { waitTime, testStack, testLifeCycle, handleErrorMessages } from './utils';
import { browser, element, by, protractor } from 'protractor';
import { waitTime, testStack, testLifeCycle, handleErrorMessages, getText } from './utils';
const EC = protractor.ExpectedConditions;
describe('router-link params and fragments', () => {
const queryParam = 'A&=#Y';
const fragment = 'myDiv1';
const id = 'MyPageID==';
afterEach(() => {
return handleErrorMessages();
});
it('should go to a page with properly encoded values', async () => {
await browser.get('/router-link?ionic:_testing=true');
await element(by.css('#queryParamsFragment')).click();
const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
browser.wait(EC.urlContains(expectedRoute), 5000);
});
it('should return to a page with preserved query param and fragment', async () => {
await browser.get('/router-link?ionic:_testing=true');
await waitTime(30);
await element(by.css('#queryParamsFragment')).click();
await waitTime(400);
await element(by.css('#goToPage3')).click();
browser.wait(EC.urlContains('router-link-page3'), 5000);
await waitTime(400);
await element(by.css('#goBackFromPage3')).click();
const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
browser.wait(EC.urlContains(expectedRoute), 5000);
});
it('should preserve query param and fragment with defaultHref string', async () => {
await browser.get('/router-link-page3?ionic:_testing=true');
await waitTime(30);
await element(by.css('#goBackFromPage3')).click();
const expectedRoute = '?token=ABC#fragment';
browser.wait(EC.urlContains(expectedRoute), 5000);
});
});
describe('router-link', () => {
beforeEach(async () => {
await browser.get('/router-link');
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
@@ -25,18 +73,6 @@ describe('router-link', () => {
it('should go forward with ion-button[routerLink]', async () => {
await element(by.css('#routerLink')).click();
await testForward();
// test go back
await element(by.css('ion-back-button')).click();
await waitTime(500);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 2,
ionViewDidEnter: 2,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
});
it('should go forward with a[routerLink]', async () => {
@@ -77,7 +113,6 @@ describe('router-link', () => {
it('should go back with ion-button[routerLink][routerDirection=back]', async () => {
await element(by.css('#routerLink-back')).click();
await testBack();
});
it('should go back with a[routerLink][routerDirection=back]', async () => {
@@ -93,21 +128,25 @@ describe('router-link', () => {
});
async function testForward() {
await waitTime(500);
await waitTime(2500);
await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
await testLifeCycle('app-router-link-page', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('true');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 2,
ionViewDidEnter: 2,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
}
async function testRoot() {
@@ -119,6 +158,17 @@ async function testRoot() {
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
}
async function testBack() {
@@ -130,4 +180,15 @@ async function testBack() {
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
await browser.navigate().back();
await waitTime(100);
await testStack('ion-router-outlet', ['app-router-link']);
await testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
}

View File

@@ -5,9 +5,10 @@ describe('slides', () => {
beforeEach(async () => {
await browser.get('/slides');
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should change index on slide change', async () => {

View File

@@ -3,11 +3,12 @@ import { waitTime, testStack, handleErrorMessages } from './utils';
describe('tabs', () => {
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
describe('entry url - /tabs', () => {
beforeEach(async () => {
await browser.get('/tabs');
await waitTime(30);
});
it('should redirect and load tab-account', async () => {
@@ -19,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);
@@ -30,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);
@@ -44,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();
@@ -52,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();
@@ -61,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');
@@ -75,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']);
});
@@ -96,13 +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);
@@ -110,14 +139,38 @@ describe('tabs', () => {
tab = await testTabTitle('Tab 1 - Page 1');
await tab.$('#goto-tab1-page2').click();
tab = await testTabTitle('Tab 1 - Page 2');
tab = await testTabTitle('Tab 1 - Page 2 (1)');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
});
it('should not reuse the same page', async () => {
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await tab.$('#goto-next').click();
tab = await testTabTitle('Tab 1 - Page 2 (3)');
await testStack('ion-tabs ion-router-outlet',[
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested'
]);
await tab.$('ion-back-button').click();
tab = await testTabTitle('Tab 1 - Page 2 (2)');
await tab.$('ion-back-button').click();
tab = await testTabTitle('Tab 1 - Page 2 (1)');
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
});
});
describe('entry url - /tabs/lazy', () => {
beforeEach(async () => {
await browser.get('/tabs/lazy');
await waitTime(30);
});
it('should not display the back-button if coming from a different stack', async () => {
@@ -125,11 +178,32 @@ 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);
});
});
describe('enter url - /tabs/contact/one', () => {
beforeEach(async () => {
await browser.get('/tabs/contact/one');
await waitTime(30);
});
it('should return to correct tab after going to page in different outlet', async () => {
const tab = await getSelectedTab();
await tab.$('#goto-nested-page1').click();
await waitTime(600);
await testStack('app-nested-outlet ion-router-outlet', ['app-nested-outlet-page']);
const nestedOutlet = await element(by.css('app-nested-outlet'));
const backButton = await nestedOutlet.$('ion-back-button');
await backButton.click();
await testTabTitle('Tab 2 - Page 1');
});
})
});
async function testState(count: number, tab: string) {
@@ -137,7 +211,7 @@ async function testState(count: number, tab: string) {
}
async function testTabTitle(title: string) {
await waitTime(600);
await waitTime(1000);
const tab = await getSelectedTab();
expect(await tab.$('ion-title').getText()).toEqual(title);
return tab;

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

@@ -1,13 +1,14 @@
import { browser, element, by } from 'protractor';
import { handleErrorMessages } from './utils';
import { handleErrorMessages, waitTime } from './utils';
describe('view-child', () => {
beforeEach(async () => {
await browser.get('/view-child');
await waitTime(30);
});
afterEach(() => {
handleErrorMessages();
return handleErrorMessages();
});
it('should get a reference to all children', async () => {

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,51 +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",
"test.dev": "npm run sync && ng e2e",
"lint": "ng lint",
"postinstall": "npm run sync"
"postinstall": "npm run sync",
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
"build:client-and-server-bundles": "npm run build && ng run test-app:server:production"
},
"private": true,
"dependencies": {
"@angular/animations": "~7.2.1",
"@angular/common": "~7.2.1",
"@angular/compiler": "~7.2.1",
"@angular/core": "~7.2.1",
"@angular/forms": "~7.2.1",
"@angular/platform-browser": "~7.2.1",
"@angular/platform-browser-dynamic": "~7.2.1",
"@angular/router": "~7.2.1",
"@ionic/angular": "^4.0.0-rc.1",
"@angular/animations": "~8.2.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/node": "~8.9.4",
"@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",
"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,14 +1,25 @@
# Copy angular dist
rm -rf node_modules/@ionic/angular/dist
rm -rf node_modules/@ionic/angular
mkdir node_modules/@ionic/angular
cp -a ../../dist node_modules/@ionic/angular/dist
cp -a ../../css node_modules/@ionic/angular/css
cp -a ../../package.json node_modules/@ionic/angular/package.json
# Copy core dist
rm -rf node_modules/@ionic/core/dist
# Copy angular server
rm -rf node_modules/@ionic/angular-server
mkdir node_modules/@ionic/angular-server
cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server/dist
cp -a ../../../packages/angular-server/package.json node_modules/@ionic/angular-server/package.json
# # Copy core dist
rm -rf node_modules/@ionic/core
mkdir node_modules/@ionic/core
cp -a ../../../core/css node_modules/@ionic/core/css
cp -a ../../../core/dist node_modules/@ionic/core/dist
cp -a ../../../core/hydrate node_modules/@ionic/core/hydrate
cp -a ../../../core/loader node_modules/@ionic/core/loader
cp -a ../../../core/package.json node_modules/@ionic/core/package.json
# Copy ionicons
# # Copy ionicons
rm -rf node_modules/ionicons
cp -a ../../../core/node_modules/ionicons node_modules/ionicons

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

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

View File

@@ -0,0 +1,39 @@
import { Component, NgZone } from '@angular/core';
import { AlertController } from '@ionic/angular';
import { NavComponent } from '../nav/nav.component';
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
})
export class AlertComponent {
changes = 0;
constructor(
private alertCtrl: AlertController
) { }
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
async openAlert() {
const alert = await this.alertCtrl.create({
header: 'Hello',
message: 'Some text',
buttons: [
{
role: 'cancel',
text: 'Cancel',
handler: () => {
console.log(NgZone.isInAngularZone());
NgZone.assertInAngularZone();
}
}
]
});
await alert.present();
}
}

View File

@@ -4,11 +4,9 @@ import { InputsComponent } from './inputs/inputs.component';
import { ModalComponent } from './modal/modal.component';
import { RouterLinkComponent } from './router-link/router-link.component';
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
import { HomePageComponent } from './home-page/home-page.component';
import { TabsComponent } from './tabs/tabs.component';
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
import { NestedOutletComponent } from './nested-outlet/nested-outlet.component';
@@ -21,9 +19,11 @@ import { FormComponent } from './form/form.component';
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
import { AlertComponent } from './alert/alert.component';
const routes: Routes = [
{ path: '', component: HomePageComponent },
{ path: 'alerts', component: AlertComponent },
{ path: 'inputs', component: InputsComponent },
{ path: 'form', component: FormComponent },
{ path: 'modals', component: ModalComponent },
@@ -31,6 +31,8 @@ const routes: Routes = [
{ path: 'providers', component: ProvidersComponent },
{ path: 'router-link', component: RouterLinkComponent },
{ path: 'router-link-page', component: RouterLinkPageComponent },
{ path: 'router-link-page2/:id', component: RouterLinkPage2Component },
{ path: 'router-link-page3', component: RouterLinkPage3Component },
{ path: 'slides', component: SlidesComponent },
{ path: 'virtual-scroll', component: VirtualScrollComponent },
{ path: 'virtual-scroll-detail/:itemId', component: VirtualScrollDetailComponent },
@@ -45,40 +47,7 @@ const routes: Routes = [
},
{
path: 'tabs',
component: TabsComponent,
children: [
{
path: 'account',
children: [
{
path: 'nested/:id',
component: TabsTab1NestedComponent
},
{
path: '',
component: TabsTab1Component
}
]
},
{
path: 'contact',
children: [
{
path: 'one',
component: TabsTab2Component
},
{
path: '',
redirectTo: 'one',
pathMatch: 'full'
}
]
},
{
path: 'lazy',
loadChildren: './tabs-lazy/tabs-lazy.module#TabsLazyModule'
}
]
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
},
{
path: 'nested-outlet',

View File

@@ -1,21 +1,20 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouteReuseStrategy } from '@angular/router';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { IonicModule } from '@ionic/angular';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { InputsComponent } from './inputs/inputs.component';
import { ModalComponent } from './modal/modal.component';
import { ModalExampleComponent } from './modal-example/modal-example.component';
import { RouterLinkComponent } from './router-link/router-link.component';
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
import { HomePageComponent } from './home-page/home-page.component';
import { TabsComponent } from './tabs/tabs.component';
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
import { VirtualScrollInnerComponent } from './virtual-scroll-inner/virtual-scroll-inner.component';
@@ -30,6 +29,7 @@ import { FormComponent } from './form/form.component';
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
import { AlertComponent } from './alert/alert.component';
@NgModule({
declarations: [
@@ -39,11 +39,9 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
ModalExampleComponent,
RouterLinkComponent,
RouterLinkPageComponent,
RouterLinkPage2Component,
RouterLinkPage3Component,
HomePageComponent,
TabsComponent,
TabsTab1Component,
TabsTab2Component,
TabsTab1NestedComponent,
VirtualScrollComponent,
VirtualScrollDetailComponent,
VirtualScrollInnerComponent,
@@ -57,10 +55,11 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
FormComponent,
NavigationPage1Component,
NavigationPage2Component,
NavigationPage3Component
NavigationPage3Component,
AlertComponent
],
imports: [
BrowserModule,
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
@@ -70,7 +69,9 @@ import { NavigationPage3Component } from './navigation-page3/navigation-page3.co
ModalExampleComponent,
NavComponent
],
providers: [],
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
],
bootstrap: [AppComponent]
})
export class AppModule { }

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

@@ -7,6 +7,11 @@
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/alerts">
<ion-label>
Alerts test
</ion-label>
</ion-item>
<ion-item routerLink="/inputs">
<ion-label>
Inputs test

View File

@@ -6,6 +6,7 @@
</ion-toolbar>
</ion-header>
<ion-content>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
<ion-list>
<ion-item>
@@ -89,10 +90,12 @@
<ion-range [(ngModel)]="range"></ion-range>
<ion-note slot="end" id="range-note">{{range}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Range Mirror</ion-label>
<ion-range [(ngModel)]="range"></ion-range>
<ion-range [(ngModel)]="range">
<ion-toggle slot="start" id="nested-toggle" [(ngModel)]="toggle"></ion-toggle>
</ion-range>
<ion-note slot="end">{{range}}</ion-note>
</ion-item>

View File

@@ -12,6 +12,7 @@ export class InputsComponent {
toggle = true;
select = 'nes';
range = 10;
changes = 0;
setValues() {
console.log('set values');
@@ -32,4 +33,8 @@ export class InputsComponent {
this.select = undefined;
this.range = undefined;
}
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
}

View File

@@ -1,5 +1,8 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
NESTED OUTLET
</ion-title>

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

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

@@ -0,0 +1,12 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Router Page 2</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-button routerLink="/router-link-page3" id="goToPage3">Go to Page 3</ion-button>
</ion-content>

View File

@@ -0,0 +1,14 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-router-link-page2',
templateUrl: './router-link-page2.component.html'
})
export class RouterLinkPage2Component implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@@ -0,0 +1,12 @@
<ion-header>
<ion-toolbar color="dark">
<ion-buttons slot="start">
<ion-back-button defaultHref="/?token=ABC#fragment" id="goBackFromPage3"></ion-back-button>
</ion-buttons>
<ion-title>Router Page 3</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
Page 3
</ion-content>

View File

@@ -0,0 +1,14 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-router-link-page3',
templateUrl: './router-link-page3.component.html'
})
export class RouterLinkPage3Component implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@@ -11,6 +11,7 @@
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
<p>
<ion-button routerLink="/router-link-page" expand="block" color="dark" id="routerLink">ion-button[routerLink]</ion-button>
@@ -27,4 +28,6 @@
<p><button (click)="navigateRoot()" id="button-root">navigateForward</button></p>
<p><button (click)="navigateBack()" id="button-back">navigateBack</button></p>
<p><button id="queryParamsFragment" routerLink="/router-link-page2/MyPageID==" [queryParams]="{ token: 'A&=#Y' }" fragment="myDiv1">Query Params and Fragment</button></p>
</ion-content>

View File

@@ -13,6 +13,7 @@ export class RouterLinkComponent implements OnInit {
didEnter = 0;
willLeave = 0;
didLeave = 0;
changes = 0;
constructor(
private navCtrl: NavController,
@@ -35,6 +36,11 @@ export class RouterLinkComponent implements OnInit {
this.navCtrl.navigateRoot('/router-link-page');
}
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
ngOnInit() {
NgZone.assertInAngularZone();
this.onInit++;

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>

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