mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Merge branch '2.0' into pr/6203
This commit is contained in:
104
CHANGELOG.md
104
CHANGELOG.md
@@ -1,3 +1,107 @@
|
||||
<a name="2.0.0-beta.6"></a>
|
||||
# [2.0.0-beta.6](https://github.com/driftyco/ionic/compare/v2.0.0-beta.5...v2.0.0-beta.6) (2016-04-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **nav:** tabs should not dereg child navs ([f3ddb0b](https://github.com/driftyco/ionic/commit/f3ddb0b)), closes [#6267](https://github.com/driftyco/ionic/issues/6267)
|
||||
* **sass:** fix sass errors ([219059c](https://github.com/driftyco/ionic/commit/219059c))
|
||||
* **toast:** create unique toast id ([e07f0ae](https://github.com/driftyco/ionic/commit/e07f0ae))
|
||||
* **toast:** remove default duration, allow close button click when bd disabled ([d6589e1](https://github.com/driftyco/ionic/commit/d6589e1))
|
||||
* **toast:** remove unused options ([f9ea2d8](https://github.com/driftyco/ionic/commit/f9ea2d8))
|
||||
|
||||
### Features
|
||||
|
||||
* **toast:** add toast component ([3fb79cf](https://github.com/driftyco/ionic/commit/3fb79cf))
|
||||
* **toast:** display the toast even on page change unless `dismissOnPageChange` is passed ([0264532](https://github.com/driftyco/ionic/commit/0264532)), closes [#5582](https://github.com/driftyco/ionic/issues/5582)
|
||||
|
||||
|
||||
|
||||
<a name="2.0.0-beta.5"></a>
|
||||
# [2.0.0-beta.5](https://github.com/driftyco/ionic/compare/v2.0.0-beta.4...v2.0.0-beta.5) (2016-04-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** remove justify content from buttons in an alert ([9412a7c](https://github.com/driftyco/ionic/commit/9412a7c))
|
||||
* **app:** add iOS status bar padding to each mode ([5a1c441](https://github.com/driftyco/ionic/commit/5a1c441)), closes [#5924](https://github.com/driftyco/ionic/issues/5924)
|
||||
* **button:** add a category to buttons so they won't get the button styles ([35dd0ed](https://github.com/driftyco/ionic/commit/35dd0ed)), closes [#6237](https://github.com/driftyco/ionic/issues/6237)
|
||||
* **button:** buttons don't get activated when ion-label contains exotic elements ([0521ce2](https://github.com/driftyco/ionic/commit/0521ce2))
|
||||
* **button:** remove classes from buttons with categories ([5f8edc2](https://github.com/driftyco/ionic/commit/5f8edc2))
|
||||
* **checkbox:** add `type="button"` to button tag ([7583ebf](https://github.com/driftyco/ionic/commit/7583ebf))
|
||||
* **content:** fix padding/margin attributes so all work on scroll-content ([9020d52](https://github.com/driftyco/ionic/commit/9020d52))
|
||||
* **cordova:** add status bar padding for content for all modes ([f45ddf9](https://github.com/driftyco/ionic/commit/f45ddf9)), closes [#5934](https://github.com/driftyco/ionic/issues/5934)
|
||||
* **cordova:** only target navbar section when it has the statusbar-padding ([422c983](https://github.com/driftyco/ionic/commit/422c983))
|
||||
* **focus:** improve input focus control ([e27452b](https://github.com/driftyco/ionic/commit/e27452b)), closes [#5536](https://github.com/driftyco/ionic/issues/5536)
|
||||
* **input:** add 'type="button"' to button tag ([f17f517](https://github.com/driftyco/ionic/commit/f17f517))
|
||||
* **input:** blur when tapping outside input on iOS ([f9b46c2](https://github.com/driftyco/ionic/commit/f9b46c2)), closes [#5020](https://github.com/driftyco/ionic/issues/5020)
|
||||
* **input:** move nested function outside of if statment so as to fix issue related to strict ([c8e58e5](https://github.com/driftyco/ionic/commit/c8e58e5))
|
||||
* **keyboard:** remove content padding after input blur ([e21c4d5](https://github.com/driftyco/ionic/commit/e21c4d5)), closes [#5800](https://github.com/driftyco/ionic/issues/5800)
|
||||
* **label:** remove flex-basis to fix floating/stacked labels on iOS/Safari ([cd62a4c](https://github.com/driftyco/ionic/commit/cd62a4c)), closes [#6109](https://github.com/driftyco/ionic/issues/6109)
|
||||
* **loading:** present loading from root nav controller ([f972908](https://github.com/driftyco/ionic/commit/f972908)), closes [#6121](https://github.com/driftyco/ionic/issues/6121)
|
||||
* **platform:** fire cordova platform.ready using zone ([ba5624b](https://github.com/driftyco/ionic/commit/ba5624b)), closes [#6186](https://github.com/driftyco/ionic/issues/6186)
|
||||
* **platform:** run zone after cordova deviceready ([e082bd1](https://github.com/driftyco/ionic/commit/e082bd1)), closes [#6087](https://github.com/driftyco/ionic/issues/6087)
|
||||
* **sass:** move the `@at-root` font import to the components file ([8f08de1](https://github.com/driftyco/ionic/commit/8f08de1)), closes [#5931](https://github.com/driftyco/ionic/issues/5931)
|
||||
* **searchbar:** only show clear icon when focused on the searchbar ([ecf9302](https://github.com/driftyco/ionic/commit/ecf9302)), closes [#5922](https://github.com/driftyco/ionic/issues/5922)
|
||||
* **showHideWhen:** remove hidden attribute on directives and use classes ([5692abe](https://github.com/driftyco/ionic/commit/5692abe)), closes [#5836](https://github.com/driftyco/ionic/issues/5836)
|
||||
* **slides:** add id to the slide component to grab the correct pagination ([7263728](https://github.com/driftyco/ionic/commit/7263728)), closes [#5745](https://github.com/driftyco/ionic/issues/5745) [#5508](https://github.com/driftyco/ionic/issues/5508)
|
||||
* **tabs:** do not init w/ tab that is hidden or disabled ([8d8cc4c](https://github.com/driftyco/ionic/commit/8d8cc4c)), closes [#6226](https://github.com/driftyco/ionic/issues/6226)
|
||||
* **tabs:** remove tabbarIcons and fix windows styling to use tabbarLayout ([81dd1cc](https://github.com/driftyco/ionic/commit/81dd1cc)), closes [#6126](https://github.com/driftyco/ionic/issues/6126)
|
||||
* **toolbar:** add border-top when toolbar is positioned to the bottom ([29e6242](https://github.com/driftyco/ionic/commit/29e6242)), closes [#5967](https://github.com/driftyco/ionic/issues/5967)
|
||||
* **virtualScroll:** load async data ([16a283e](https://github.com/driftyco/ionic/commit/16a283e)), closes [#6124](https://github.com/driftyco/ionic/issues/6124)
|
||||
|
||||
### Features
|
||||
|
||||
* **app:** getActiveNav() method ([7777237](https://github.com/driftyco/ionic/commit/7777237))
|
||||
* **backbutton:** add hardware back button ([68278b0](https://github.com/driftyco/ionic/commit/68278b0)), closes [#5071](https://github.com/driftyco/ionic/issues/5071)
|
||||
* **changeDetection:** detach Tabs when not active ([0c4171e](https://github.com/driftyco/ionic/commit/0c4171e))
|
||||
* **changeDetection:** detach ViewControllers when not active ([b282e90](https://github.com/driftyco/ionic/commit/b282e90))
|
||||
* **config:** create a method to access the global app injector which contains references the ([17a9e6d](https://github.com/driftyco/ionic/commit/17a9e6d)), closes [#5973](https://github.com/driftyco/ionic/issues/5973)
|
||||
* **content:** add scrollToBottom ([bef4a67](https://github.com/driftyco/ionic/commit/bef4a67))
|
||||
* **directives:** auto provide IONIC_DIRECTIVES to all components ([0a83f2f](https://github.com/driftyco/ionic/commit/0a83f2f)), closes [#6092](https://github.com/driftyco/ionic/issues/6092)
|
||||
* **platform:** add backbutton event ([156fdc3](https://github.com/driftyco/ionic/commit/156fdc3))
|
||||
* **platform:** default desktop to use material design ([51032d2](https://github.com/driftyco/ionic/commit/51032d2)), closes [#6003](https://github.com/driftyco/ionic/issues/6003)
|
||||
* **select:** fallback to alert interface when more than 6 opts ([1c67b02](https://github.com/driftyco/ionic/commit/1c67b02))
|
||||
* **select:** using action-sheet as ion-select interface ([81096f1](https://github.com/driftyco/ionic/commit/81096f1))
|
||||
* **slides:** add ability to slide to specific index ([a6091bd](https://github.com/driftyco/ionic/commit/a6091bd))
|
||||
* **slides:** add method to get previous index ([a54361c](https://github.com/driftyco/ionic/commit/a54361c))
|
||||
* **statusbarPadding:** add statusbar-padding css to content ([98c2aab](https://github.com/driftyco/ionic/commit/98c2aab))
|
||||
* **statusbarPadding:** add statusbar-padding css to toolbars ([44403d1](https://github.com/driftyco/ionic/commit/44403d1))
|
||||
* **tabs:** enabled and show inputs ([1b085e3](https://github.com/driftyco/ionic/commit/1b085e3)), closes [#5768](https://github.com/driftyco/ionic/issues/5768)
|
||||
* **toggle:** add animation for windows mode toggle ([f841bef](https://github.com/driftyco/ionic/commit/f841bef)), closes [#5981](https://github.com/driftyco/ionic/issues/5981)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **img:** do not reuse img elements ([b744275](https://github.com/driftyco/ionic/commit/b744275)), closes [#6112](https://github.com/driftyco/ionic/issues/6112)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **tabs:** `tabbarIcons` is officially removed, please use `tabbarLayout` instead. View the [Tabs API docs](http://ionicframework.com/docs/v2/api/components/tabs/Tabs/) for more information.
|
||||
* **slides:** The Slides component has been refactored. Many methods and events were
|
||||
renamed.
|
||||
|
||||
The following events have been renamed:
|
||||
|
||||
- `slideChangeStart` has been renamed `willChange`
|
||||
- `change` has been renamed `didChange`
|
||||
|
||||
The following methods have been renamed:
|
||||
|
||||
- `next()` has been renamed to `slideNext()`
|
||||
- `prev()` has been renamed to `slidePrev()`
|
||||
- `getIndex()` has been renamed to `getActiveIndex()`
|
||||
- `getNumSlides()` has been renamed to `length()`
|
||||
- `isAtEnd()` has been renamed to `isEnd()`
|
||||
- `isAtBeginning()` has been renamed to `isBeginning()`
|
||||
- `getSliderWidget()` has been renamed to `getSlider()`
|
||||
|
||||
All methods have been documented in the API docs:
|
||||
http://ionicframework.com/docs/v2/api/components/slides/Slides/
|
||||
|
||||
* **platform:** `platform.versions()` no longer accepts an optional parameter for platform name
|
||||
and now returns only an object containing all of the platforms and their versions.
|
||||
|
||||
<a name="2.0.0-beta.4"></a>
|
||||
# [2.0.0-beta.4](https://github.com/driftyco/ionic/compare/v2.0.0-beta.3...v2.0.0-beta.4) (2016-04-07)
|
||||
|
||||
|
||||
187
CONTRIBUTING.md
187
CONTRIBUTING.md
@@ -1,118 +1,115 @@
|
||||
### Creating an Issue
|
||||
# Contributing
|
||||
|
||||
If you have a question on how something works, or its expected functionality, you might want to visit the [Ionic Forum](http://forum.ionicframework.com/) first.
|
||||
|
||||
If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/driftyco/ionic/issues?state=open). You can search through existing issues to see if someone's reported one similar to yours.
|
||||
|
||||
Next [create a new issue](https://github.com/driftyco/ionic/issues/new) that thoroughly explains the problem, how to reproduce the issue, and provide any additional information such as code examples and error logs.
|
||||
|
||||
### Issue Etiquette Guidelines
|
||||
|
||||
Poor attitude, ranting, name-calling, bullying, being a jerk, complaining, or spamming are fruitless and unacceptable. Issues that violate the open source spirit of this community, or any of the guidelines listed here, may result in your Issue being deleted or reposted to our Forum, a better place for debate and discussion. If you wish to contribute, either make your response respectful or do not bother to respond. You’ll find it’s pretty ineffective.
|
||||
|
||||
Simply put: be respectful and act like an adult. Critiques are better made on the Forum. If you can’t do that, this isn’t a community for you.
|
||||
|
||||
See our [Code of Conduct](./CODE_OF_CONDUCT.md) for more info.
|
||||
Thanks for your interest in contributing to the Ionic Framework! :tada:
|
||||
|
||||
|
||||
### Pull Request Guidelines
|
||||
## Contributing Etiquette
|
||||
|
||||
Please use [Commitizen](https://github.com/commitizen/cz-cli#installing-the-command-line-tool) to commit to this repository. This ensures your commits will match our git conventions. It can be installed by running the following command (add sudo if on OSX/Linux):
|
||||
|
||||
```
|
||||
npm install -g commitizen
|
||||
```
|
||||
|
||||
Then, when you want to commit, instead of writing `git commit` you will write:
|
||||
|
||||
```
|
||||
git cz
|
||||
```
|
||||
|
||||
This will prompt you with some questions.
|
||||
|
||||
When in doubt, keep your pull requests small. To give a PR the best chance of getting accepted, do not bundle more than one "feature" or bug fix per PR. Doing so makes it very hard to accept it if one of the fixes has issues.
|
||||
|
||||
It's always best to create two smaller PRs than one big one.
|
||||
|
||||
### Style
|
||||
|
||||
Always use two spaces, no tabs. This goes for any HTML, CSS, or Javascript.
|
||||
|
||||
#### Sass Guidelines
|
||||
|
||||
##### Sass Linter
|
||||
|
||||
Run [Sass Linter](https://github.com/brigade/scss-lint) to ensure the css/sass matches our conventions (requires Ruby)
|
||||
|
||||
1. Install the linter: `gem install scss_lint`
|
||||
2. Make sure to run the linter at the root of the repository where the `.scss-lint.yml` file is located
|
||||
3. For all component Sass files: `scss-lint ionic/**/**/*.scss`
|
||||
4. For a specific Sass file: `scss-lint ionic/components/toolbar/toolbar.ios.scss`
|
||||
Please see our [Contributor Code of Conduct](./CODE_OF_CONDUCT.md) for information on our rules of conduct.
|
||||
|
||||
|
||||
##### Variable Naming Conventions
|
||||
## Creating an Issue
|
||||
|
||||
The Sass variable should start with the component name:
|
||||
If you have a question about using the framework, please ask on the [Ionic Forum](http://forum.ionicframework.com/) or in the [Ionic Worldwide Slack](http://ionicworldwide.herokuapp.com/) group.
|
||||
|
||||
```
|
||||
$alert
|
||||
$action-sheet
|
||||
$badge
|
||||
$toolbar
|
||||
```
|
||||
If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/driftyco/ionic/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution.
|
||||
|
||||
Then it should use the mode abbreviation (ios, md, wp):
|
||||
Next, [create a new issue](https://github.com/driftyco/ionic/issues/new) that thoroughly explains the problem. Please fill out the populated issue form before submitting the issue.
|
||||
|
||||
```
|
||||
$alert-md
|
||||
$action-sheet-ios
|
||||
$badge-md
|
||||
$toolbar-wp
|
||||
```
|
||||
|
||||
Next should be the css property it is affecting, for example:
|
||||
## Creating a Pull Request
|
||||
|
||||
```
|
||||
$alert-md-max-width
|
||||
$action-sheet-ios-background
|
||||
$badge-md-border-radius
|
||||
$toolbar-wp-padding
|
||||
```
|
||||
We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort.
|
||||
|
||||
If it is affecting a component inside of the top level component, that should come next instead of the css property:
|
||||
Looking for an issue to fix? Make sure to look through our issues with the [help wanted](https://github.com/driftyco/ionic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label!
|
||||
|
||||
```
|
||||
$alert-md-title
|
||||
$alert-md-sub-title
|
||||
$alert-md-message
|
||||
$action-sheet-ios-title
|
||||
$action-sheet-ios-button
|
||||
```
|
||||
### Setup
|
||||
|
||||
Followed by the css property of that component:
|
||||
1. Fork the repo.
|
||||
2. Clone your fork.
|
||||
3. Make a branch for your change.
|
||||
4. Run `npm install` (make sure you have [node](https://nodejs.org/en/) and [npm](http://blog.npmjs.org/post/85484771375/how-to-install-npm) installed first)
|
||||
|
||||
```
|
||||
$alert-md-title-font-size
|
||||
$alert-md-sub-title-font-size
|
||||
$alert-md-message-padding
|
||||
$action-sheet-ios-title-color
|
||||
$action-sheet-ios-button-background
|
||||
```
|
||||
|
||||
If the variable only applies to a specific state, that should come last (hover, focused, activated, etc):
|
||||
### Modifying Components
|
||||
|
||||
```
|
||||
$action-sheet-ios-button-background-activated
|
||||
$alert-md-input-border-width-focused
|
||||
```
|
||||
1. Make any changes to the component.
|
||||
2. Modify the e2e test in the `test/` directory under the component directory, if possible. If the test does not exist and it is possible to show the change, please create a new test in a directory called `basic/`.
|
||||
|
||||
**Should I use `background` or `bg`?**
|
||||
`background`
|
||||
#### TypeScript Changes
|
||||
|
||||
**Should I use `background` or `background-color`?**
|
||||
`background` so users can override backgrounds in Sass variables using images and etc
|
||||
1. If there is a `*.spec.ts` file located in the `test/` folder, update it to include a karma test for your change, if needed. If this file doesn't exist, please notify us.
|
||||
2. Run `gulp karma` to make sure all tests are working, regardless if a test was added.
|
||||
3. Run `gulp tslint` and fix any linter errors.
|
||||
|
||||
### License
|
||||
#### Sass Changes
|
||||
|
||||
1. If the css property is something that the user may want to override and it won't break the component layout, it should be given a Sass variable. See our [doc on naming Sass variables](https://docs.google.com/document/d/1OyOyrRE5lpB_9mdkF0HWVQLV97fHma450N8XqE4mjZQ/edit?usp=sharing).
|
||||
2. After any changes to the Sass files run the [Sass Linter](https://github.com/brigade/scss-lint), and fix any linter errors:
|
||||
- Requires [Ruby](https://www.ruby-lang.org/en/documentation/installation/). **Skip this step entirely if you are unable to install Ruby.**
|
||||
- Install the linter: `gem install scss_lint`
|
||||
- Make sure to run the linter at the root of the repository.
|
||||
- To check all component Sass files: `scss-lint ionic/**/**/*.scss`
|
||||
- To check a specific Sass file: `scss-lint ionic/components/toolbar/toolbar.ios.scss`
|
||||
|
||||
|
||||
#### Viewing Changes
|
||||
|
||||
1. Run the gulp watch task for e2e tests: `gulp watch.e2e`
|
||||
2. Launch your browser and navigate to `http://localhost:8000/dist/e2e`
|
||||
3. From here, navigate to the component you are changing.
|
||||
4. Any changes to the e2e tests in the `test/` directory will show here.
|
||||
5. If your changes look good, you're ready to [commit](#committing)!
|
||||
|
||||
|
||||
#### Adding Documentation
|
||||
|
||||
1. To add or modify API Documentation for a component, it should be added/changed in the component's TypeScript (`*.ts`) file, prior to the Class definition. For example, `Badge` looks similar to this:
|
||||
|
||||
```
|
||||
/**
|
||||
* @name Badge
|
||||
* @module ionic
|
||||
* @description
|
||||
* Badges are simple components in Ionic containing numbers or text.
|
||||
*
|
||||
* @see {@link /docs/v2/components/#badges Badges Component Docs}
|
||||
* @demo /docs/v2/demos/badge/
|
||||
**/
|
||||
```
|
||||
|
||||
where `@name` is the Class name, `@description` is the description displayed on the documentation page, `@see` links to any related pages, and `@demo` links to the API demo located in the `demos` folder.
|
||||
2. In order to run API documentation locally, you will need to clone the `ionic-site` repo as a sibling to the `ionic` repo and then run it: https://github.com/driftyco/ionic-site#local-build
|
||||
3. Then, run `gulp docs` in the `ionic` repo every time you make a change and the site will update.
|
||||
4. If the change affects the component documentation, create an issue on the `ionic-site` repo: https://github.com/driftyco/ionic-site/issues
|
||||
|
||||
|
||||
#### Adding Demos
|
||||
|
||||
1. Create or modify the demo in the `demos/` folder.
|
||||
2. If it is new, link to the demo in the component's TypeScript (`*.ts`) file (under `ionic/components`) by adding a link to it in the documentation using `@demo`, for example:
|
||||
|
||||
```
|
||||
/**
|
||||
* @name Badge
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* @demo /docs/v2/demos/badge/
|
||||
**/
|
||||
```
|
||||
3. Run `gulp watch.demos` to watch for changes to the demo
|
||||
4. Navigate to `http://localhost:8000/dist/demos/` and then to your component's demo to view it.
|
||||
5. If the change affects the component demos, create an issue on the `ionic-site` repo: https://github.com/driftyco/ionic-site/issues
|
||||
|
||||
### Committing
|
||||
|
||||
1. Install [Commitizen](https://github.com/commitizen/cz-cli#installing-the-command-line-tool) (add sudo if on OSX/Linux): `npm install -g commitizen`
|
||||
2. Use commitizen to commit instead of `git commit`: `git cz`
|
||||
3. This will prompt you with questions and commit when you are finished.
|
||||
4. Submit the Pull Request!
|
||||
|
||||
|
||||
## License
|
||||
|
||||
By contributing your code to the driftyco/ionic GitHub Repository, you agree to license your contribution under the MIT license.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 517 KiB |
@@ -1,6 +0,0 @@
|
||||
import {App} from 'ionic-angular';
|
||||
|
||||
@App({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class ApiDemoApp {}
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
<ion-toolbar>
|
||||
<ion-title>Blur</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
<ion-content>
|
||||
<div class="blur-content">
|
||||
<ion-card blur class="blur-card">
|
||||
<ion-card-header>
|
||||
Card
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
This card will blur the content behind it.
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
<style>
|
||||
.blur-content {
|
||||
position: absolute;
|
||||
text-align:center;
|
||||
background: url('bg.jpg') no-repeat transparent;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.blur-card,
|
||||
.blur-card ion-card-header {
|
||||
background: transparent;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
@@ -6,12 +6,28 @@
|
||||
<h5 margin>Hide Icon Per Platform</h5>
|
||||
<p margin>In this example we're using the <code>hideWhen</code> directive to decide whether to hide an icon based on the platform.</p>
|
||||
|
||||
<ion-row text-center>
|
||||
<ion-col>
|
||||
<ion-icon name="logo-android" hideWhen="ios"></ion-icon>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-apple" hideWhen="android,windows"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-icon name="logo-apple" hideWhen="android"></ion-icon>
|
||||
<code> <ion-icon name="logo-apple" hideWhen="android,windows"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-android" hideWhen="ios,windows"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<code> <ion-icon name="logo-android" hideWhen="ios,windows"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-windows" hideWhen="ios,android"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<code> <ion-icon name="logo-windows" hideWhen="ios,android"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-content>
|
||||
@@ -20,7 +36,10 @@
|
||||
.hide-when-demo ion-col {
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #ddd;
|
||||
margin: 5px;
|
||||
margin: 1%;
|
||||
max-width: 48%;
|
||||
flex: 0 0 48%;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.hide-when-demo code {
|
||||
@@ -28,6 +47,6 @@
|
||||
}
|
||||
|
||||
.hide-when-demo ion-icon {
|
||||
font-size: 200px;
|
||||
font-size: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,12 +7,10 @@ class ApiDemoApp {
|
||||
isIos: boolean;
|
||||
isAndroid: boolean;
|
||||
isWindows: boolean;
|
||||
userAgent: string;
|
||||
|
||||
constructor(platform: Platform) {
|
||||
this.isIos = platform.is('ios');
|
||||
this.isAndroid = platform.is('android');
|
||||
this.isWindows = platform.is('windows');
|
||||
this.userAgent = platform.userAgent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,6 @@
|
||||
<ion-col><b>Name</b></ion-col>
|
||||
<ion-col><b>Value</b></ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<pre>platform.is('android')</pre>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<pre [ngClass]="isAndroid ? 'platform-true' : 'platform-false'">{{isAndroid}}</pre>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<pre>platform.is('ios')</pre>
|
||||
@@ -27,18 +19,18 @@
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<pre>platform.is('windows')</pre>
|
||||
<pre>platform.is('android')</pre>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<pre [ngClass]="isWindows ? 'platform-true' : 'platform-false'">{{isWindows}}</pre>
|
||||
<pre [ngClass]="isAndroid ? 'platform-true' : 'platform-false'">{{isAndroid}}</pre>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<pre>platform.userAgent()</pre>
|
||||
<pre>platform.is('windows')</pre>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<pre class="platform-normal">{{userAgent}}</pre>
|
||||
<pre [ngClass]="isWindows ? 'platform-true' : 'platform-false'">{{isWindows}}</pre>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
|
||||
@@ -6,12 +6,28 @@
|
||||
<h5 margin>Show Icon Per Platform</h5>
|
||||
<p margin>In this example we're using the <code>showWhen</code> directive to decide whether to show an icon based on the platform.</p>
|
||||
|
||||
<ion-row text-center>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-apple" showWhen="ios"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<code> <ion-icon name="logo-apple" showWhen="ios"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-android" showWhen="android"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-icon name="logo-apple" showWhen="ios"></ion-icon>
|
||||
<code> <ion-icon name="logo-android" showWhen="android"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col text-center>
|
||||
<ion-icon name="logo-windows" showWhen="windows"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<code> <ion-icon name="logo-windows" showWhen="windows"></ion-icon> </code>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-content>
|
||||
@@ -20,7 +36,10 @@
|
||||
.show-when-demo ion-col {
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #ddd;
|
||||
margin: 5px;
|
||||
margin: 1%;
|
||||
max-width: 48%;
|
||||
flex: 0 0 48%;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.show-when-demo code {
|
||||
@@ -28,6 +47,6 @@
|
||||
}
|
||||
|
||||
.show-when-demo ion-icon {
|
||||
font-size: 200px;
|
||||
font-size: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
59
demos/toast/index.ts
Normal file
59
demos/toast/index.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import {App, Page, Toast, NavController} from 'ionic-angular';
|
||||
|
||||
@Page({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class ApiPage {
|
||||
constructor(private nav: NavController) { }
|
||||
|
||||
showToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'User was created successfully',
|
||||
});
|
||||
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
showLongToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.',
|
||||
});
|
||||
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
showDismissDurationToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'I am dismissed after 1.5 seconds',
|
||||
duration: 1500
|
||||
});
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
showToastWithCloseButton() {
|
||||
const toast = Toast.create({
|
||||
message: 'Your internet connection appears to be offline. Data integrity is not guaranteed.',
|
||||
showCloseButton: true,
|
||||
closeButtonText: 'Ok'
|
||||
});
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
private dismissHandler(toast: Toast) {
|
||||
console.info('Toast onDismiss()');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@App({
|
||||
template: '<ion-nav [root]="root"></ion-nav>'
|
||||
})
|
||||
class ApiDemoApp {
|
||||
root = ApiPage;
|
||||
constructor() { }
|
||||
}
|
||||
11
demos/toast/main.html
Normal file
11
demos/toast/main.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<ion-toolbar>
|
||||
<ion-title>Toast</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
<ion-content padding>
|
||||
<button block (click)="showToast()">Show Toast</button>
|
||||
<button block margin-bottom (click)="showLongToast()">Show Long Toast</button>
|
||||
|
||||
<button block (click)="showDismissDurationToast()">Show Custom Duration Toast</button>
|
||||
<button block (click)="showToastWithCloseButton()">Show Close Button Toast</button>
|
||||
</ion-content>
|
||||
@@ -29,8 +29,5 @@
|
||||
"components/virtual-scroll/virtual-scroll";
|
||||
|
||||
|
||||
// Ionicons (to be replaced with SVGs)
|
||||
$ionicons: true !default;
|
||||
@if ($ionicons) {
|
||||
@import "fonts/ionicons";
|
||||
}
|
||||
// Ionicons
|
||||
@import "fonts/ionicons";
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"components/select/select.ios",
|
||||
"components/tabs/tabs.ios",
|
||||
"components/toggle/toggle.ios",
|
||||
"components/toast/toast.ios",
|
||||
"components/toolbar/toolbar.ios";
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"components/select/select.md",
|
||||
"components/tabs/tabs.md",
|
||||
"components/toggle/toggle.md",
|
||||
"components/toast/toast.md",
|
||||
"components/toolbar/toolbar.md";
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ export * from './components/app/id'
|
||||
export * from './components/action-sheet/action-sheet'
|
||||
export * from './components/alert/alert'
|
||||
export * from './components/badge/badge'
|
||||
export * from './components/blur/blur'
|
||||
export * from './components/button/button'
|
||||
export * from './components/checkbox/checkbox'
|
||||
export * from './components/content/content'
|
||||
@@ -47,5 +46,6 @@ export * from './components/tabs/tabs'
|
||||
export * from './components/tabs/tab'
|
||||
export * from './components/tap-click/tap-click'
|
||||
export * from './components/toggle/toggle'
|
||||
export * from './components/toast/toast'
|
||||
export * from './components/toolbar/toolbar'
|
||||
export * from './components/virtual-scroll/virtual-scroll'
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"components/select/select.wp",
|
||||
"components/tabs/tabs.wp",
|
||||
"components/toggle/toggle.wp",
|
||||
"components/toast/toast.wp",
|
||||
"components/toolbar/toolbar.wp";
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ ion-action-sheet {
|
||||
|
||||
.action-sheet-selected {
|
||||
font-weight: bold;
|
||||
background: white;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.action-sheet-destructive {
|
||||
|
||||
@@ -70,6 +70,10 @@ $action-sheet-md-icon-margin: 0 28px 0 0 !default;
|
||||
&:last-child .action-sheet-button {
|
||||
margin-bottom: $action-sheet-md-group-margin-bottom;
|
||||
}
|
||||
|
||||
.button-inner {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.action-sheet-selected {
|
||||
|
||||
@@ -75,6 +75,62 @@ import {ViewController} from '../nav/view-controller';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Dismissing And Async Navigation
|
||||
*
|
||||
* After an action sheet has been dismissed, the app may need to also transition
|
||||
* to another page depending on the handler's logic. However, because multiple
|
||||
* transitions were fired at roughly the same time, it's difficult for the
|
||||
* nav controller to cleanly animate multiple transitions that may
|
||||
* have been kicked off asynchronously. This is further described in the
|
||||
* [`Nav Transition Promises`](../../nav/NavController) section. For action sheets,
|
||||
* this means it's best to wait for the action sheet to finish its transition
|
||||
* out before starting a new transition on the same nav controller.
|
||||
*
|
||||
* In the example below, after the button has been clicked, its handler
|
||||
* waits on async operation to complete, *then* it uses `pop` to navigate
|
||||
* back a page in the same stack. The potential problem is that the async operation
|
||||
* may have been completed before the action sheet has even finished its transition
|
||||
* out. In this case, it's best to ensure the action sheet has finished its transition
|
||||
* out first, *then* start the next transition.
|
||||
*
|
||||
* ```ts
|
||||
* let actionSheet = ActionSheet.create({
|
||||
* title: 'Hello',
|
||||
* buttons: [{
|
||||
* text: 'Ok',
|
||||
* handler: () => {
|
||||
* // user has clicked the action sheet button
|
||||
* // begin the action sheet's dimiss transition
|
||||
* let navTransition = actionSheet.dismiss();
|
||||
*
|
||||
* // start some async method
|
||||
* someAsyncOperation().then(() => {
|
||||
* // once the async operation has completed
|
||||
* // then run the next nav transition after the
|
||||
* // first transition has finished animating out
|
||||
*
|
||||
* navTransition.then(() => {
|
||||
* this.nav.pop();
|
||||
* });
|
||||
* });
|
||||
* return false;
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
*
|
||||
* this.nav.present(actionSheet);
|
||||
* ```
|
||||
*
|
||||
* It's important to note that the handler returns `false`. A feature of
|
||||
* button handlers is that they automatically dismiss the action sheet when their button
|
||||
* was clicked, however, we'll need more control regarding the transition. Because
|
||||
* the handler returns `false`, then the action sheet does not automatically dismiss
|
||||
* itself. Instead, you now have complete control of when the action sheet has finished
|
||||
* transitioning, and the ability to wait for the action sheet to finish transitioning
|
||||
* out before starting a new transition.
|
||||
*
|
||||
*
|
||||
* @demo /docs/v2/demos/action-sheet/
|
||||
* @see {@link /docs/v2/components#action-sheets ActionSheet Component Docs}
|
||||
*/
|
||||
@@ -166,14 +222,14 @@ export class ActionSheet extends ViewController {
|
||||
'<div class="action-sheet-group">' +
|
||||
'<div class="action-sheet-title" id="{{hdrId}}" *ngIf="d.title">{{d.title}}</div>' +
|
||||
'<div class="action-sheet-sub-title" id="{{descId}}" *ngIf="d.subTitle">{{d.subTitle}}</div>' +
|
||||
'<button (click)="click(b)" *ngFor="#b of d.buttons" class="action-sheet-button disable-hover" [ngClass]="b.cssClass">' +
|
||||
'<button category="action-sheet-button" (click)="click(b)" *ngFor="#b of d.buttons" class="disable-hover" [ngClass]="b.cssClass">' +
|
||||
'<ion-icon [name]="b.icon" *ngIf="b.icon" class="action-sheet-icon"></ion-icon> ' +
|
||||
'{{b.text}}' +
|
||||
'<ion-button-effect></ion-button-effect>' +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'<div class="action-sheet-group" *ngIf="d.cancelButton">' +
|
||||
'<button (click)="click(d.cancelButton)" class="action-sheet-button action-sheet-cancel disable-hover" [ngClass]="d.cancelButton.cssClass">' +
|
||||
'<button category="action-sheet-button" (click)="click(d.cancelButton)" class="action-sheet-cancel disable-hover" [ngClass]="d.cancelButton.cssClass">' +
|
||||
'<ion-icon [name]="d.cancelButton.icon" *ngIf="d.cancelButton.icon" class="action-sheet-icon"></ion-icon> ' +
|
||||
'{{d.cancelButton.text}}' +
|
||||
'<ion-button-effect></ion-button-effect>' +
|
||||
@@ -234,7 +290,7 @@ class ActionSheetCmp {
|
||||
|
||||
// deprecated warning
|
||||
if (button.style) {
|
||||
console.warn('Alert "style" property has been renamed to "role"');
|
||||
console.warn('Action sheet "style" property has been renamed to "role"');
|
||||
button.role = button.style;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,10 @@ $action-sheet-wp-icon-margin: 0 16px 0 0 !default;
|
||||
&:last-child .action-sheet-button {
|
||||
margin-bottom: $action-sheet-wp-group-margin-bottom;
|
||||
}
|
||||
|
||||
.button-inner {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.action-sheet-selected {
|
||||
|
||||
@@ -58,7 +58,7 @@ $alert-ios-radio-label-padding: 13px !default;
|
||||
|
||||
$alert-ios-radio-min-width: 30px !default;
|
||||
|
||||
$alert-ios-radio-icon-top: 13px !default;
|
||||
$alert-ios-radio-icon-top: -7px !default;
|
||||
$alert-ios-radio-icon-left: 7px !default;
|
||||
$alert-ios-radio-icon-width: 6px !default;
|
||||
$alert-ios-radio-icon-height: 12px !default;
|
||||
|
||||
@@ -57,7 +57,7 @@ $alert-md-list-border-bottom: $alert-md-list-border-top !default
|
||||
|
||||
$alert-md-radio-label-padding: 13px 26px !default;
|
||||
|
||||
$alert-md-radio-top: 13px !default;
|
||||
$alert-md-radio-top: 0 !default;
|
||||
$alert-md-radio-left: 13px !default;
|
||||
$alert-md-radio-width: 16px !default;
|
||||
$alert-md-radio-height: 16px !default;
|
||||
@@ -78,7 +78,7 @@ $alert-md-radio-icon-transition: transform 280ms cubic-bezier(.4, 0
|
||||
|
||||
$alert-md-checkbox-label-padding: 13px 26px !default;
|
||||
|
||||
$alert-md-checkbox-top: 13px !default;
|
||||
$alert-md-checkbox-top: 0 !default;
|
||||
$alert-md-checkbox-left: 13px !default;
|
||||
$alert-md-checkbox-width: 16px !default;
|
||||
$alert-md-checkbox-height: 16px !default;
|
||||
@@ -337,4 +337,8 @@ $alert-md-checkbox-icon-transform: rotate(45deg) !default;
|
||||
&.activated {
|
||||
background-color: $alert-md-button-background-color-activated;
|
||||
}
|
||||
|
||||
.button-inner {
|
||||
justify-content: $alert-md-button-group-justify-content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,62 @@ import {ViewController} from '../nav/view-controller';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Dismissing And Async Navigation
|
||||
*
|
||||
* After an alert has been dismissed, the app may need to also transition
|
||||
* to another page depending on the handler's logic. However, because multiple
|
||||
* transitions were fired at roughly the same time, it's difficult for the
|
||||
* nav controller to cleanly animate multiple transitions that may
|
||||
* have been kicked off asynchronously. This is further described in the
|
||||
* [`Nav Transition Promises`](../../nav/NavController) section. For alerts,
|
||||
* this means it's best to wait for the alert to finish its transition
|
||||
* out before starting a new transition on the same nav controller.
|
||||
*
|
||||
* In the example below, after the alert button has been clicked, its handler
|
||||
* waits on async operation to complete, *then* it uses `pop` to navigate
|
||||
* back a page in the same stack. The potential problem is that the async operation
|
||||
* may have been completed before the alert has even finished its transition
|
||||
* out. In this case, it's best to ensure the alert has finished its transition
|
||||
* out first, *then* start the next transition.
|
||||
*
|
||||
* ```ts
|
||||
* let alert = Alert.create({
|
||||
* title: 'Hello',
|
||||
* buttons: [{
|
||||
* text: 'Ok',
|
||||
* handler: () => {
|
||||
* // user has clicked the alert button
|
||||
* // begin the alert's dimiss transition
|
||||
* let navTransition = alert.dismiss();
|
||||
*
|
||||
* // start some async method
|
||||
* someAsyncOperation().then(() => {
|
||||
* // once the async operation has completed
|
||||
* // then run the next nav transition after the
|
||||
* // first transition has finished animating out
|
||||
*
|
||||
* navTransition.then(() => {
|
||||
* this.nav.pop();
|
||||
* });
|
||||
* });
|
||||
* return false;
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
*
|
||||
* this.nav.present(alert);
|
||||
* ```
|
||||
*
|
||||
* It's important to note that the handler returns `false`. A feature of
|
||||
* button handlers is that they automatically dismiss the alert when their button
|
||||
* was clicked, however, we'll need more control regarding the transition. Because
|
||||
* the handler returns `false`, then the alert does not automatically dismiss
|
||||
* itself. Instead, you now have complete control of when the alert has finished
|
||||
* transitioning, and the ability to wait for the alert to finish transitioning
|
||||
* out before starting a new transition.
|
||||
*
|
||||
*
|
||||
* @demo /docs/v2/demos/alert/
|
||||
*/
|
||||
export class Alert extends ViewController {
|
||||
@@ -242,7 +298,7 @@ export class Alert extends ViewController {
|
||||
* | cssClass | `string` | An additional CSS class for the button |
|
||||
* | role | `string` | The buttons role, null or `cancel` |
|
||||
*
|
||||
* @param {object} opts Alert. See the tabel above
|
||||
* @param {object} opts Alert. See the table above
|
||||
*/
|
||||
static create(opts: AlertOptions = {}) {
|
||||
return new Alert(opts);
|
||||
@@ -267,7 +323,7 @@ export class Alert extends ViewController {
|
||||
|
||||
'<template ngSwitchWhen="radio">' +
|
||||
'<div class="alert-radio-group" role="radiogroup" [attr.aria-labelledby]="hdrId" [attr.aria-activedescendant]="activeId">' +
|
||||
'<button *ngFor="#i of d.inputs" (click)="rbClick(i)" [attr.aria-checked]="i.checked" [attr.id]="i.id" class="alert-tappable alert-radio" role="radio">' +
|
||||
'<button category="alert-radio-button" *ngFor="#i of d.inputs" (click)="rbClick(i)" [attr.aria-checked]="i.checked" [attr.id]="i.id" class="alert-tappable alert-radio" role="radio">' +
|
||||
'<div class="alert-radio-icon"><div class="alert-radio-inner"></div></div>' +
|
||||
'<div class="alert-radio-label">' +
|
||||
'{{i.label}}' +
|
||||
@@ -278,7 +334,7 @@ export class Alert extends ViewController {
|
||||
|
||||
'<template ngSwitchWhen="checkbox">' +
|
||||
'<div class="alert-checkbox-group">' +
|
||||
'<button *ngFor="#i of d.inputs" (click)="cbClick(i)" [attr.aria-checked]="i.checked" class="alert-tappable alert-checkbox" role="checkbox">' +
|
||||
'<button category="alert-checkbox-button" *ngFor="#i of d.inputs" (click)="cbClick(i)" [attr.aria-checked]="i.checked" class="alert-tappable alert-checkbox" role="checkbox">' +
|
||||
'<div class="alert-checkbox-icon"><div class="alert-checkbox-inner"></div></div>' +
|
||||
'<div class="alert-checkbox-label">' +
|
||||
'{{i.label}}' +
|
||||
@@ -297,7 +353,7 @@ export class Alert extends ViewController {
|
||||
|
||||
'</div>' +
|
||||
'<div class="alert-button-group" [ngClass]="{vertical: d.buttons.length>2}">' +
|
||||
'<button *ngFor="#b of d.buttons" (click)="btnClick(b)" [ngClass]="b.cssClass" class="alert-button">' +
|
||||
'<button category="alert-button" *ngFor="#b of d.buttons" (click)="btnClick(b)" [ngClass]="b.cssClass">' +
|
||||
'{{b.text}}' +
|
||||
'<ion-button-effect></ion-button-effect>' +
|
||||
'</button>' +
|
||||
|
||||
@@ -59,7 +59,7 @@ $alert-wp-radio-border-color: $input-wp-border-color !default;
|
||||
|
||||
$alert-wp-radio-label-padding: 13px 26px !default;
|
||||
|
||||
$alert-wp-radio-top: 13px !default;
|
||||
$alert-wp-radio-top: 0 !default;
|
||||
$alert-wp-radio-left: 13px !default;
|
||||
$alert-wp-radio-width: 16px !default;
|
||||
$alert-wp-radio-height: 16px !default;
|
||||
@@ -76,7 +76,7 @@ $alert-wp-radio-icon-border-radius: $alert-wp-radio-border-radius !de
|
||||
|
||||
$alert-wp-checkbox-label-padding: 13px 26px !default;
|
||||
|
||||
$alert-wp-checkbox-top: 13px !default;
|
||||
$alert-wp-checkbox-top: 0 !default;
|
||||
$alert-wp-checkbox-left: 13px !default;
|
||||
$alert-wp-checkbox-width: 16px !default;
|
||||
$alert-wp-checkbox-height: 16px !default;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Alert, NavController, App, Page } from 'ionic-angular/index';
|
||||
import { Alert, Loading, NavController, App, Page } from 'ionic-angular/index';
|
||||
import { FORM_DIRECTIVES, FormBuilder, ControlGroup, Validators } from 'angular2/common';
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ export class E2EPage {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<p>
|
||||
<button block (click)="doFastPop()">Fast Loading Dismiss, Nav Pop</button>
|
||||
</p>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
@@ -107,6 +110,46 @@ class AnotherPage {
|
||||
this.nav.present(alert);
|
||||
}
|
||||
|
||||
doFastPop() {
|
||||
let alert = Alert.create({
|
||||
title: 'Async Nav Transition',
|
||||
message: 'This is an example of dismissing an alert, then quickly starting another transition on the same nav controller.',
|
||||
buttons: [{
|
||||
text: 'Ok',
|
||||
handler: () => {
|
||||
// present a loading indicator
|
||||
let loading = Loading.create({
|
||||
content: 'Loading...'
|
||||
});
|
||||
this.nav.present(loading);
|
||||
|
||||
// start an async operation
|
||||
setTimeout(() => {
|
||||
// the async operation has completed
|
||||
// dismiss the loading indicator
|
||||
loading.dismiss();
|
||||
|
||||
// begin dismissing the alert
|
||||
alert.dismiss().then(() => {
|
||||
// after the alert has been dismissed
|
||||
// then you can do another nav transition
|
||||
this.nav.pop();
|
||||
});
|
||||
}, 100);
|
||||
|
||||
// return false so the alert doesn't automatically
|
||||
// dismissed itself. Instead we're manually
|
||||
// handling the dismiss logic above so that we
|
||||
// can wait for the alert to finish it's dismiss
|
||||
// transition before starting another nav transition
|
||||
// on the same nav controller
|
||||
return false;
|
||||
}
|
||||
}]
|
||||
});
|
||||
this.nav.present(alert);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {Injectable, Injector} from 'angular2/core';
|
||||
import {Title} from 'angular2/platform/browser';
|
||||
|
||||
import {Config} from '../../config/config';
|
||||
@@ -19,6 +19,7 @@ export class IonicApp {
|
||||
private _titleSrv: Title = new Title();
|
||||
private _isProd: boolean = false;
|
||||
private _rootNav: any = null;
|
||||
private _appInjector: Injector;
|
||||
|
||||
constructor(
|
||||
private _config: Config,
|
||||
@@ -199,4 +200,19 @@ export class IonicApp {
|
||||
return this._cmps[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global app injector that contains references to all of the instantiated providers
|
||||
* @param injector
|
||||
*/
|
||||
setAppInjector(injector: Injector) {
|
||||
this._appInjector = injector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the global app injector that contains references to all of the instantiated providers
|
||||
* @returns {Injector}
|
||||
*/
|
||||
getAppInjector(): Injector {
|
||||
return this._appInjector;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {AppViewManager, ElementRef, Directive, Renderer, Input} from 'angular2/c
|
||||
import {IonicApp} from './app';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @name Id
|
||||
* @description
|
||||
* The `id` attribute is an easy way to identify unique components in an app and access them
|
||||
|
||||
6
ionic/components/app/normalize.scss
vendored
6
ionic/components/app/normalize.scss
vendored
@@ -151,6 +151,12 @@ textarea {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
a ion-label,
|
||||
button ion-label,
|
||||
[tappable] ion-label {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
button {
|
||||
border: 0;
|
||||
font-family: inherit;
|
||||
|
||||
@@ -89,9 +89,10 @@ describe('IonicApp', () => {
|
||||
var app: IonicApp;
|
||||
var config: Config;
|
||||
var platform: Platform;
|
||||
var _cd: any;
|
||||
|
||||
function mockNav(): Nav {
|
||||
return new Nav(null,null,null,config,null,null,null,null,null,null);
|
||||
return new Nav(null, null, null, config, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
function mockTabs(): Tabs {
|
||||
@@ -99,13 +100,17 @@ describe('IonicApp', () => {
|
||||
}
|
||||
|
||||
function mockTab(parentTabs: Tabs): Tab {
|
||||
return new Tab(parentTabs,null,config,null,null,null,null,null,null);
|
||||
return new Tab(parentTabs, app, config, null, null, null, null, null, null, _cd);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
config = new Config();
|
||||
platform = new Platform();
|
||||
app = new IonicApp(config, null, platform);
|
||||
_cd = {
|
||||
reattach: function(){},
|
||||
detach: function(){}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import {Directive, Renderer, ElementRef} from 'angular2/core';
|
||||
|
||||
|
||||
/**
|
||||
* @name Blur
|
||||
* @description
|
||||
* The blur attribute applies the CSS blur attribute to an element. Safari only.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <ion-card blur>
|
||||
* This card will blur the content behind it.
|
||||
* </ion-card>
|
||||
* ```
|
||||
*
|
||||
* @demo /docs/v2/demos/blur/
|
||||
* @private
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[blur]'
|
||||
})
|
||||
export class Blur {
|
||||
constructor(private _elementRef: ElementRef, private _renderer: Renderer) {
|
||||
_renderer.setElementStyle(_elementRef.nativeElement, '-webkit-backdrop-filter', 'blur(10px)');
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 517 KiB |
@@ -1,10 +0,0 @@
|
||||
import {App} from 'ionic-angular';
|
||||
|
||||
|
||||
@App({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class E2EApp {
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
<ion-toolbar>
|
||||
<ion-title>Blur</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
<ion-content>
|
||||
<div class="blur-content">
|
||||
<ion-card blur class="blur-card">
|
||||
<ion-card-header>
|
||||
Card
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
This card will blur the content behind it.
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
<style>
|
||||
.blur-content {
|
||||
position: absolute;
|
||||
text-align:center;
|
||||
background: url('bg.jpg') no-repeat transparent;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.blur-card,
|
||||
.blur-card ion-card-header {
|
||||
background: transparent;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
@@ -58,6 +58,11 @@ export class Button {
|
||||
*/
|
||||
isItem: boolean;
|
||||
|
||||
/**
|
||||
* @input {string} The category of the button.
|
||||
*/
|
||||
@Input() category: string;
|
||||
|
||||
/**
|
||||
* @input {string} Large button.
|
||||
*/
|
||||
@@ -185,6 +190,16 @@ export class Button {
|
||||
this._readAttrs(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngOnInit() {
|
||||
// If the button has a role applied to it
|
||||
if (this.category) {
|
||||
this.setRole(this.category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -55,6 +55,7 @@ const CHECKBOX_VALUE_ACCESSOR = new Provider(
|
||||
'</div>' +
|
||||
'<button role="checkbox" ' +
|
||||
'type="button" ' +
|
||||
'category="item-cover" ' +
|
||||
'[id]="id" ' +
|
||||
'[attr.aria-checked]="_checked" ' +
|
||||
'[attr.aria-labelledby]="_labelId" ' +
|
||||
|
||||
@@ -268,7 +268,7 @@ export class Content extends Ion {
|
||||
* @returns {Promise} Returns a promise which is resolved when the scroll has completed.
|
||||
*/
|
||||
scrollToTop(duration: number = 300) {
|
||||
return this.scrollTo(0, 0, duration);
|
||||
return this._scroll.scrollToTop(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,6 +287,15 @@ export class Content extends Ion {
|
||||
this._scroll.setTop(top);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the bottom of the content component.
|
||||
* @param {number} [duration] Duration of the scroll animation in milliseconds. Defaults to `300`.
|
||||
* @returns {Promise} Returns a promise which is resolved when the scroll has completed.
|
||||
*/
|
||||
scrollToBottom(duration: number = 300) {
|
||||
return this._scroll.scrollToBottom(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -434,7 +434,7 @@ export class InputBase {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Angular2 Forms API method called by the the view (NgControl) to register
|
||||
* Angular2 Forms API method called by the view (NgControl) to register
|
||||
* the onTouched event handler that marks model (Control) as touched.
|
||||
* @param {Function} fn onTouched event handler.
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,7 @@ export class NativeInput {
|
||||
function docTouchEnd(ev) {
|
||||
var tapped: HTMLElement = ev.target;
|
||||
if (tapped && self.element()) {
|
||||
if (tapped.tagName !== "INPUT" && tapped.tagName !== "TEXTAREA" && !tapped.classList.contains('input-cover')) {
|
||||
if (tapped.tagName !== 'INPUT' && tapped.tagName !== 'TEXTAREA' && !tapped.classList.contains('input-cover')) {
|
||||
self.element().blur();
|
||||
}
|
||||
}
|
||||
@@ -211,4 +211,4 @@ export class NextInput {
|
||||
this.focused.emit(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,18 @@
|
||||
<button outline item-right (click)="testClick($event)">View</button>
|
||||
</ion-item>
|
||||
|
||||
<button ion-item *ngFor="#data of [0,1,2,3,4]; #i = index" [class.activated]="i == 1">
|
||||
<button ion-item *ngFor="#data of [0,1,2,3,4]; #i = index" [class.activated]="i == 1" (click)="testClick($event)">
|
||||
<ion-avatar item-left>
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||
</ion-avatar>
|
||||
<h3>ng-for {{i}}</h3>
|
||||
<ion-badge item-right>260k</ion-badge>
|
||||
</button>
|
||||
|
||||
</ion-content>
|
||||
|
||||
<style>
|
||||
img {
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,9 +7,9 @@ import {Directive, ElementRef, Renderer, Input, Optional, Attribute} from 'angul
|
||||
* Labels are placed inside of an `ion-item` element and can be used
|
||||
* to describe an `ion-input`, `ion-toggle`, `ion-checkbox`, and more.
|
||||
*
|
||||
* @property [fixed] - a persistant label that sits next the the input
|
||||
* @property [floating] - a label that will float about the input if the input is empty of looses focus
|
||||
* @property [stacked] - A stacked label will always appear on top of the input
|
||||
* @property [fixed] - A persistant label that sits next the input.
|
||||
* @property [floating] - A label that will float about the input if the input is empty of looses focus.
|
||||
* @property [stacked] - A stacked label will always appear on top of the input.
|
||||
|
||||
*
|
||||
* @usage
|
||||
|
||||
@@ -52,11 +52,12 @@ export class List extends Ion {
|
||||
* Enable sliding items if your page has them
|
||||
*
|
||||
* ```ts
|
||||
* import {Page, List} from 'ionic-angular';
|
||||
* import {ViewChild} from 'angular2/core';
|
||||
* @Page...
|
||||
* export class MyClass {
|
||||
* constructor(app: IonicApp){
|
||||
* this.app = app;
|
||||
* this.list = this.app.getComponent('my-list');
|
||||
* }
|
||||
* @ViewChild(List) list: List;
|
||||
* constructor(){}
|
||||
* stopSliding(){
|
||||
* this.list.enableSlidingItems(false);
|
||||
* }
|
||||
@@ -86,13 +87,12 @@ export class List extends Ion {
|
||||
* Enable sliding items if your page has
|
||||
*
|
||||
* ```ts
|
||||
* import {Page, List} from 'ionic-angular';
|
||||
* import {ViewChild} from 'angular2/core';
|
||||
* @Page...
|
||||
* export class MyClass {
|
||||
* constructor(app: IonicApp){
|
||||
* this.app = app;
|
||||
* this.list = this.app.getComponent('my-list');
|
||||
* }
|
||||
* // Here we have some method that will close the items
|
||||
* // when called
|
||||
* @ViewChild(List) list: List;
|
||||
* constructor(){}
|
||||
* closeItmes(){
|
||||
* this.list.closeSlidingItems();
|
||||
* }
|
||||
|
||||
@@ -36,7 +36,9 @@ import {ViewController} from '../nav/view-controller';
|
||||
* the `duration` of the loading options. By default the loading indicator
|
||||
* will show even during page changes, but this can be disabled by setting
|
||||
* `dismissOnPageChange` to `true`. To dismiss the loading indicator after
|
||||
* creation, call the `dismiss()` method on the Loading instance.
|
||||
* creation, call the `dismiss()` method on the Loading instance. The
|
||||
* `onDismiss` function can be called to perform an action after the loading
|
||||
* indicator is dismissed.
|
||||
*
|
||||
* ### Limitations
|
||||
* The element is styled to appear on top of other content by setting its
|
||||
@@ -71,6 +73,10 @@ import {ViewController} from '../nav/view-controller';
|
||||
* duration: 5000
|
||||
* });
|
||||
*
|
||||
* loading.onDismiss(() => {
|
||||
* console.log('Dismissed loading');
|
||||
* });
|
||||
*
|
||||
* this.nav.present(loading);
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -13,6 +13,10 @@ class E2EPage {
|
||||
duration: 1000
|
||||
});
|
||||
|
||||
loading.onDismiss(() => {
|
||||
console.log('Dismissed loading');
|
||||
});
|
||||
|
||||
this.nav.present(loading);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import {ViewController} from './view-controller';
|
||||
* specific NavController, most times you will inject and use a reference to the
|
||||
* nearest NavController to manipulate the navigation stack.
|
||||
*
|
||||
* <h3 id="injecting_nav_controller">Injecting NavController</h3>
|
||||
* ### Injecting NavController
|
||||
* Injecting NavController will always get you an instance of the nearest
|
||||
* NavController, regardless of whether it is a Tab or a Nav.
|
||||
*
|
||||
@@ -58,7 +58,8 @@ import {ViewController} from './view-controller';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* <h2 id="creating_pages">Page creation</h2>
|
||||
*
|
||||
* ## Page creation
|
||||
* _For more information on the `@Page` decorator see the [@Page API
|
||||
* reference](../../../decorators/Page/)._
|
||||
*
|
||||
@@ -73,7 +74,7 @@ import {ViewController} from './view-controller';
|
||||
* [pop()](#pop) or [setRoot()](#setRoot)).
|
||||
*
|
||||
*
|
||||
* <h2 id="Lifecycle">Lifecycle events</h2>
|
||||
* ## Lifecycle events
|
||||
* Lifecycle events are fired during various stages of navigation. They can be
|
||||
* defined in any `@Page` decorated component class.
|
||||
*
|
||||
@@ -91,15 +92,53 @@ import {ViewController} from './view-controller';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* | Page Event | Description |
|
||||
* |--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
* | `onPageLoaded` | Runs when the page has loaded. This event only happens once per page being created and added to the DOM. If a page leaves but is cached, then this event will not fire again on a subsequent viewing. The `onPageLoaded` event is good place to put your setup code for the page. |
|
||||
* | `onPageWillEnter` | Runs when the page is about to enter and become the active page. |
|
||||
* | `onPageDidEnter` | Runs when the page has fully entered and is now the active page. This event will fire, whether it was the first load or a cached page. |
|
||||
* | `onPageWillLeave` | Runs when the page is about to leave and no longer be the active page. |
|
||||
* | `onPageDidLeave` | Runs when the page has finished leaving and is no longer the active page. |
|
||||
* | `onPageWillUnload` | Runs when the page is about to be destroyed and have its elements removed. |
|
||||
* | `onPageDidUnload` | Runs after the page has been destroyed and its elements have been removed.
|
||||
*
|
||||
*
|
||||
* - `onPageLoaded` - Runs when the page has loaded. This event only happens once per page being created and added to the DOM. If a page leaves but is cached, then this event will not fire again on a subsequent viewing. The `onPageLoaded` event is good place to put your setup code for the page.
|
||||
* - `onPageWillEnter` - Runs when the page is about to enter and become the active page.
|
||||
* - `onPageDidEnter` - Runs when the page has fully entered and is now the active page. This event will fire, whether it was the first load or a cached page.
|
||||
* - `onPageWillLeave` - Runs when the page is about to leave and no longer be the active page.
|
||||
* - `onPageDidLeave` - Runs when the page has finished leaving and is no longer the active page.
|
||||
* - `onPageWillUnload` - Runs when the page is about to be destroyed and have its elements removed.
|
||||
* - `onPageDidUnload` - Runs after the page has been destroyed and its elements have been removed.
|
||||
* ## Nav Transition Promises
|
||||
*
|
||||
* Navigation transitions are asynchronous, meaning they take a few moments to finish, and
|
||||
* the duration of a transition could be any number. In most cases the async nature of a
|
||||
* transition doesn't cause any problems and the nav controller is pretty good about handling
|
||||
* which transition was the most recent when multiple transitions have been kicked off.
|
||||
* However, when an app begins firing off many transitions, on the same stack at
|
||||
* *roughly* the same time, the nav controller can start to get lost as to which transition
|
||||
* should be finishing, and which transitions should not be animated.
|
||||
*
|
||||
* In cases where an app's navigation can be altered by other async tasks, which may or
|
||||
* may not take a long time, it's best to rely on each nav transition's returned
|
||||
* promise. So instead of firing and forgetting multiple `push` or `pop` nav transitions,
|
||||
* it's better to fire the next nav transition when the previous one has finished.
|
||||
*
|
||||
* In the example below, after the async operation has completed, we then want to transition
|
||||
* to another page. Where the potential problem comes in, is that if the async operation
|
||||
* completed 100ms after the first transition started, then kicking off another transition
|
||||
* halfway through the first transition ends up with a janky animation. Instead, it's best
|
||||
* to always ensure the first transition has already finished before starting the next.
|
||||
*
|
||||
* ```ts
|
||||
* // begin the first transition
|
||||
* let navTransition = this.nav.push(SomePage);
|
||||
*
|
||||
* // start an async call, we're not sure how long it'll take
|
||||
* someAsyncOperation().then(() => {
|
||||
* // incase the async operation completed faster than the time
|
||||
* // it took to finish the first transition, this logic should
|
||||
* // always ensure that the previous transition has resolved
|
||||
* // first before kicking off the next transition
|
||||
* navTransition.then(() => {
|
||||
* this.nav.push(AnotherPage);
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @see {@link /docs/v2/components#navigation Navigation Component Docs}
|
||||
*/
|
||||
@@ -178,6 +217,9 @@ export class NavController extends Ion {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setPortal(val: Portal) {
|
||||
this._portal = val;
|
||||
}
|
||||
@@ -1357,7 +1399,7 @@ export class NavController extends Ion {
|
||||
}
|
||||
this._views.length = 0;
|
||||
|
||||
if (this.parent) {
|
||||
if (this.parent && this.parent.unregisterChildNav) {
|
||||
this.parent.unregisterChildNav(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {Component, Type, ViewChild} from 'angular2/core';
|
||||
import {App, NavController, Alert, Content} from 'ionic-angular';
|
||||
import {Page, Config, IonicApp} from 'ionic-angular';
|
||||
import {NavParams, ViewController, IONIC_DIRECTIVES} from 'ionic-angular';;
|
||||
import {NavParams, ViewController} from 'ionic-angular';;
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'my-cmp',
|
||||
template: `<p>My Custom Component Test <ion-icon name="star"></ion-icon></p>`,
|
||||
directives: [IONIC_DIRECTIVES]
|
||||
template: `<p>My Custom Component Test <ion-icon name="star"></ion-icon></p>`
|
||||
})
|
||||
class MyCmpTest{}
|
||||
|
||||
@@ -49,6 +48,7 @@ class MyCmpTest{}
|
||||
<button ion-item (click)="quickPush()">New push during transition</button>
|
||||
<button ion-item (click)="quickPop()">New pop during transition</button>
|
||||
<button ion-item (click)="reload()">Reload</button>
|
||||
<button ion-item (click)="scrollToBottom()">Scroll to bottom</button>
|
||||
<button *ngFor="#i of pages" ion-item (click)="pushPrimaryHeaderPage()">Page {{i}}</button>
|
||||
<button ion-item (click)="content.scrollToTop()">Scroll to top</button>
|
||||
</ion-list>
|
||||
@@ -122,6 +122,10 @@ class FirstPage {
|
||||
scrollToTop() {
|
||||
this.content.scrollToTop();
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
this.content.scrollToBottom(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class ToolbarBackground {
|
||||
selector: 'ion-navbar',
|
||||
template:
|
||||
'<div class="toolbar-background"></div>' +
|
||||
'<button class="back-button bar-button bar-button-default" [hidden]="_hideBb">' +
|
||||
'<button category="bar-button" class="back-button" [hidden]="_hideBb">' +
|
||||
'<span class="button-inner">' +
|
||||
'<ion-icon class="back-button-icon" [name]="_bbIcon"></ion-icon>' +
|
||||
'<span class="back-button-text">' +
|
||||
|
||||
@@ -37,6 +37,7 @@ import {RadioGroup} from './radio-group';
|
||||
'</div>' +
|
||||
'<button role="radio" ' +
|
||||
'type="button" ' +
|
||||
'category="item-cover" ' +
|
||||
'[id]="id" ' +
|
||||
'[attr.aria-checked]="_checked" ' +
|
||||
'[attr.aria-labelledby]="_labelId" ' +
|
||||
|
||||
@@ -65,7 +65,7 @@ const SELECT_VALUE_ACCESSOR = new Provider(
|
||||
* <ion-option>Pepperoni</ion-option>
|
||||
* <ion-option>Sausage</ion-option>
|
||||
* </ion-select>
|
||||
* <ion-item>
|
||||
* </ion-item>
|
||||
* ```
|
||||
*
|
||||
* ### Alert Buttons
|
||||
@@ -109,6 +109,7 @@ const SELECT_VALUE_ACCESSOR = new Provider(
|
||||
'</div>' +
|
||||
'<button aria-haspopup="true" ' +
|
||||
'[id]="id" ' +
|
||||
'category="item-cover" ' +
|
||||
'[attr.aria-labelledby]="_labelId" ' +
|
||||
'[attr.aria-disabled]="_disabled" ' +
|
||||
'class="item-cover">' +
|
||||
@@ -255,7 +256,7 @@ export class Select {
|
||||
this.onChange(input.value);
|
||||
this.change.emit(input.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}));
|
||||
alertOptions.cssClass = 'select-action-sheet';
|
||||
|
||||
@@ -273,7 +274,7 @@ export class Select {
|
||||
label: input.text,
|
||||
value: input.value,
|
||||
checked: input.checked
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// create the alert instance from our built up alertOptions
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
// Applied by the showWhen directive
|
||||
.hidden-show-when {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// Applied by the hideWhen directive
|
||||
.hidden-hide-when {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,15 @@ export class DisplayWhen {
|
||||
* @description
|
||||
* The `showWhen` attribute takes a string that represents a platform or screen orientation.
|
||||
* The element the attribute is added to will only be shown when that platform or screen orientation is active.
|
||||
* Complements the [hideWhen attribute](../HideWhen).
|
||||
*
|
||||
* Complements the [hideWhen attribute](../HideWhen). If the `showWhen` attribute is used on an
|
||||
* element that also has the `hideWhen` attribute, the element will not show if `hideWhen` evaluates
|
||||
* to `true` or `showWhen` evaluates to `false`. If the `hidden` attribute is also added, the element
|
||||
* will not show if `hidden` evaluates to `true`.
|
||||
*
|
||||
* View the [Platform API docs](../../../platform/Platform) for more information on the different
|
||||
* platforms you can use.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <div showWhen="android">
|
||||
@@ -87,6 +95,7 @@ export class DisplayWhen {
|
||||
* ```
|
||||
* @demo /docs/v2/demos/show-when/
|
||||
* @see {@link ../HideWhen HideWhen API Docs}
|
||||
* @see {@link ../../../platform/Platform Platform API Docs}
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[showWhen]',
|
||||
@@ -111,7 +120,15 @@ export class ShowWhen extends DisplayWhen {
|
||||
* @description
|
||||
* The `hideWhen` attribute takes a string that represents a plaform or screen orientation.
|
||||
* The element the attribute is added to will only be hidden when that platform or screen orientation is active.
|
||||
* Complements the [showWhen attribute](../ShowWhen).
|
||||
*
|
||||
* Complements the [showWhen attribute](../ShowWhen). If the `hideWhen` attribute is used on an
|
||||
* element that also has the `showWhen` attribute, the element will not show if `hideWhen` evaluates
|
||||
* to `true` or `showWhen` evaluates to `false`. If the `hidden` attribute is also added, the element
|
||||
* will not show if `hidden` evaluates to `true`.
|
||||
*
|
||||
* View the [Platform API docs](../../../platform/Platform) for more information on the different
|
||||
* platforms you can use.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <div hideWhen="android">
|
||||
@@ -137,7 +154,8 @@ export class ShowWhen extends DisplayWhen {
|
||||
*
|
||||
* @demo /docs/v2/demos/hide-when/
|
||||
* @see {@link ../ShowWhen ShowWhen API Docs}
|
||||
*/
|
||||
* @see {@link ../../../platform/Platform Platform API Docs}
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[hideWhen]',
|
||||
host: {
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
|
||||
<ion-toolbar><ion-title>Show/Hide When</ion-title></ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-title>Show/Hide When</ion-title>
|
||||
<ion-buttons end>
|
||||
<button showWhen="ios">iOS</button>
|
||||
<button showWhen="windows">Windows</button>
|
||||
<button showWhen="android">Android</button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
||||
|
||||
<ion-content padding>
|
||||
<button showWhen="ios">iOS</button>
|
||||
<button showWhen="windows">Windows</button>
|
||||
<button showWhen="android">Android</button>
|
||||
|
||||
<p showWhen="ios" style="background:blue; color:white">
|
||||
showWhen="ios"
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
@import "../../globals.core";
|
||||
|
||||
ion-swipe-slides {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swiper 3.1.2
|
||||
|
||||
@@ -7,7 +7,7 @@ import {Gesture} from '../../gestures/gesture';
|
||||
import {DragGesture} from '../../gestures/drag-gesture';
|
||||
import {dom} from '../../util';
|
||||
import {CSS} from '../../util/dom';
|
||||
import {debounce, isTrueProperty, defaults} from '../../util/util';
|
||||
import {debounce, isTrueProperty, isPresent, defaults} from '../../util/util';
|
||||
|
||||
import {Swiper} from './swiper-widget';
|
||||
import {Scroll} from '../scroll/scroll';
|
||||
@@ -16,38 +16,159 @@ import {Scroll} from '../scroll/scroll';
|
||||
/**
|
||||
* @name Slides
|
||||
* @description
|
||||
* Slides is a slide box implementation based on Swiper.js
|
||||
* The Slides component is a multi-section container. Each section can be swiped
|
||||
* or dragged between. It contains any number of [Slide](../Slide) components.
|
||||
*
|
||||
*
|
||||
* ### Creating
|
||||
* You should use a template to create slides and listen to slide events. The template
|
||||
* should contain the slide container, an `<ion-slides>` element, and any number of
|
||||
* [Slide](../Slide) components, written as `<ion-slide>`. Any configuration of the
|
||||
* slides should be passed in the `options` property of the `<ion-slides>` element.
|
||||
* You can listen to events such as the slide changing by placing the event on the
|
||||
* `<ion-slides>` element. See [Usage](#usage) below for more information on
|
||||
* creating slides.
|
||||
*
|
||||
*
|
||||
* ### Configuring
|
||||
* There are several configuration options that can be passed to Slides. These should
|
||||
* be passed in the `options` property of the `<ion-slides>` element upon creation.
|
||||
* You can allow the slides to loop around from the last to the first, set autoplay
|
||||
* on the slides so it will automatically switch between them, and more.
|
||||
*
|
||||
* Properties to pass in options:
|
||||
*
|
||||
* | Property | Type | Default | Description |
|
||||
* |-----------------------|-----------|----------------|--------------------------------------------------------------------------------------------|
|
||||
* | autoplay | `number` | - | Delay between transitions (in ms). If this parameter is not passed, autoplay is disabled. |
|
||||
* | direction | `string` | 'horizontal' | Swipe direction: 'horizontal' or 'vertical'. |
|
||||
* | initialSlide | `number` | 0 | Index number of initial slide |
|
||||
* | loop | `boolean` | false | Whether to continuously loop from the last slide to the first slide. |
|
||||
* | pager | `boolean` | false | Show the pagination bullets. |
|
||||
* | speed | `number` | 300 | Duration of transition between slides (in ms). |
|
||||
*
|
||||
* See [Usage](#usage) below for more information on configuring slides.
|
||||
*
|
||||
*
|
||||
* ### Navigating
|
||||
* After creating and configuring the slides, you can navigate between them
|
||||
* by swiping or calling methods on the `Slides` instance. You can call `slideTo()` to
|
||||
* navigate to a specific slide, or `slideNext()` to change to the slide that follows
|
||||
* the active slide. All of the [methods](#instance-members) provided by the `Slides`
|
||||
* instance are listed below. See [Usage](#usage) below for more information on
|
||||
* navigating between slides.
|
||||
*
|
||||
*
|
||||
* ### Limitations
|
||||
* The Slides component wraps the [Swiper](http://www.idangero.us/swiper/) component
|
||||
* built by iDangero.us. This means that all of the Swiper API isn't exposed on the
|
||||
* Slides component. See the [`getSlider()`](#getSlider) method for information on
|
||||
* getting the `Swiper` instance and using its methods directly.
|
||||
*
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* @Page({
|
||||
* template: `
|
||||
* <ion-slides pager (change)="onSlideChanged($event)" (move)="onSlideMove($event)">
|
||||
* <ion-slide>
|
||||
* <h3>Thank you for choosing the Awesome App!</h3>
|
||||
* <p>
|
||||
* The number one app for everything awesome.
|
||||
* </p>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <h3>Using Awesome</h3>
|
||||
* <div id="list">
|
||||
* <h5>Just three steps:</h5>
|
||||
* <ol>
|
||||
* <li>Be awesome</li>
|
||||
* <li>Stay awesome</li>
|
||||
* <li>There is no step 3</li>
|
||||
* </ol>
|
||||
* </div>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <h3>Any questions?</h3>
|
||||
* </ion-slide>
|
||||
* </ion-slides>
|
||||
* `
|
||||
*})
|
||||
*
|
||||
*```
|
||||
* You can add slides to a `@Page` using the following template:
|
||||
*
|
||||
* ```html
|
||||
* <ion-slides>
|
||||
* <ion-slide>
|
||||
* <h1>Slide 1</h1>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <h1>Slide 2</h1>
|
||||
* </ion-slide>
|
||||
* <ion-slide>
|
||||
* <h1>Slide 3</h1>
|
||||
* </ion-slide>
|
||||
* </ion-slides>
|
||||
* ```
|
||||
*
|
||||
* To add [options](#configuring), we will define them in `mySlideOptions` in our class `MyPage`:
|
||||
*
|
||||
* ```ts
|
||||
* import {Page, Slides} from 'ionic-angular';
|
||||
*
|
||||
* @Page({
|
||||
* templateUrl: 'my-page.html'
|
||||
* })
|
||||
* class MyPage {
|
||||
* mySlideOptions = {
|
||||
* initialSlide: 1,
|
||||
* loop: true
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This is setting the second slide as the initial slide on load, since
|
||||
* the `initialSlide` begins at `0`. We are also setting `loop` to true which
|
||||
* allows us to swipe from the last slide to the first continuously. Then,
|
||||
* we will pass `mySlideOptions` in the `options` property of the `<ion-slides>`
|
||||
* element. We are using [property binding](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#property-binding)
|
||||
* on `options` because `mySlideOptions` is an expression:
|
||||
*
|
||||
* ```html
|
||||
* <ion-slides [options]="mySlideOptions">
|
||||
* ```
|
||||
*
|
||||
* To grab a reference to the Slides, we will add a [local template variable](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#local-vars)
|
||||
* to `<ion-slides>` called `mySlider`:
|
||||
*
|
||||
* ```html
|
||||
* <ion-slides #mySlider [options]="mySlideOptions">
|
||||
* ```
|
||||
*
|
||||
* Next, we can use `ViewChild` to assign the Slides instance to `slider`:
|
||||
*
|
||||
* ```ts
|
||||
* import {ViewChild} from 'angular2/core';
|
||||
*
|
||||
* class MyPage {
|
||||
* @ViewChild('mySlider') slider: Slides;
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Now we can call any of the `Slider` [methods]((#instance-members)),
|
||||
* for example we can use the Slider's `slideTo()` method in order to
|
||||
* navigate to a specific slide on a button click. Below we call the
|
||||
* `goToSlide()` method and it navigates to the 3rd slide:
|
||||
*
|
||||
* ```ts
|
||||
* class MyPage {
|
||||
* ...
|
||||
*
|
||||
* goToSlide() {
|
||||
* this.slider.slideTo(2, 500);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* We can also add events to listen to on the `<ion-slides>` element.
|
||||
* Let's add the `didChange` event and call a method when the slide changes:
|
||||
*
|
||||
* ```html
|
||||
* <ion-slides #mySlider (didChange)="onSlideChanged()" [options]="mySlideOptions">
|
||||
* ```
|
||||
*
|
||||
* In our class, we add the `onSlideChanged()` method which gets the active
|
||||
* index and prints it:
|
||||
*
|
||||
* ```ts
|
||||
* class MyPage {
|
||||
* ...
|
||||
*
|
||||
* onSlideChanged() {
|
||||
* let currentIndex = this.slider.getActiveIndex();
|
||||
* console.log("Current index is", currentIndex);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* For all of the methods you can call on the `Slider` instance, see the
|
||||
* [Instance Members](#instance-members).
|
||||
*
|
||||
* @demo /docs/v2/demos/slides/
|
||||
* @see {@link /docs/v2/components#slides Slides Component Docs}
|
||||
*
|
||||
@@ -72,6 +193,9 @@ import {Scroll} from '../scroll/scroll';
|
||||
'<div [class.hide]="!showPager" class="swiper-pagination"></div>' +
|
||||
'</div>',
|
||||
directives: [NgClass],
|
||||
host: {
|
||||
'[class]': 'slideId'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
@@ -82,6 +206,16 @@ export class Slides extends Ion {
|
||||
*/
|
||||
public rapidUpdate: Function;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
private id: number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
private slideId: string;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -156,54 +290,64 @@ export class Slides extends Ion {
|
||||
};
|
||||
|
||||
/**
|
||||
* @input {boolean} Whether the slide should show the pager or not
|
||||
*/
|
||||
@Input() pager: any;
|
||||
|
||||
/**
|
||||
* @input {any} Any slider options you want to configure, see swiper parameters: http://www.idangero.us/swiper/api/
|
||||
* @input {Object} Any configuration for the slides
|
||||
*/
|
||||
@Input() options: any;
|
||||
|
||||
/**
|
||||
* @input {number} Whether or not the slider can zoom in or out
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Input() pager: any;
|
||||
|
||||
/**
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Input() zoom: any;
|
||||
|
||||
/**
|
||||
* @input {number} how long it should take to zoom a slide
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Input() zoomDuration: any;
|
||||
|
||||
/**
|
||||
* @input {number} the max scale an slide can be zoomed
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Input() zoomMax: any;
|
||||
|
||||
/**
|
||||
* @output {any} expression to evaluate when a slide has been changed
|
||||
*/
|
||||
@Output() change: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @output {any} expression to evaluate when a slide change starts
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Output() slideChangeStart: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @output {any} expression to evaluate when a slide moves
|
||||
* @private Deprecated
|
||||
*/
|
||||
@Output() change: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @output {any} Expression to evaluate when a slide change starts.
|
||||
*/
|
||||
@Output() willChange: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @output {any} Expression to evaluate when a slide change ends.
|
||||
*/
|
||||
@Output() didChange: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @output {any} Expression to evaluate when a slide moves.
|
||||
*/
|
||||
@Output() move: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {ElementRef} elementRef TODO
|
||||
*/
|
||||
|
||||
constructor(elementRef: ElementRef) {
|
||||
super(elementRef);
|
||||
this.rapidUpdate = debounce(() => {
|
||||
this.update();
|
||||
}, 10);
|
||||
|
||||
this.id = ++slidesId;
|
||||
this.slideId = 'slides-' + this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,10 +358,32 @@ export class Slides extends Ion {
|
||||
this.options = {};
|
||||
}
|
||||
|
||||
this.showPager = isTrueProperty(this.pager);
|
||||
if (isPresent(this.pager)) {
|
||||
// beta.5 2016-04-18 deprecated warning
|
||||
// Pager should be passed as an option
|
||||
console.warn('The "pager" attribute has been deprecated. Please pass it in options.');
|
||||
// Remove this with the deprecation warning
|
||||
this.showPager = isTrueProperty(this.pager);
|
||||
}
|
||||
|
||||
if (isPresent(this.zoom)) {
|
||||
// beta.5 2016-04-18 deprecated warning
|
||||
// Zoom should be passed as an option
|
||||
console.warn('The "zoom" attribute has been deprecated. Please pass it in options.');
|
||||
}
|
||||
|
||||
// Deprecated 04-18 beta.5
|
||||
console.warn('The "slideChangeStart" event has been deprecated. Please use "willChange" instead. Ignore this if you aren\'t using it.');
|
||||
console.warn('The "change" event has been deprecated. Please use "didChange" instead. Ignore this if you aren\'t using it.');
|
||||
|
||||
if (isPresent(this.options.pager)) {
|
||||
this.showPager = isTrueProperty(this.options.pager);
|
||||
}
|
||||
|
||||
let paginationId = '.' + this.slideId + ' .swiper-pagination';
|
||||
|
||||
var options = defaults({
|
||||
pagination: '.swiper-pagination',
|
||||
pagination: paginationId
|
||||
}, this.options);
|
||||
|
||||
options.onTap = (swiper, e) => {
|
||||
@@ -241,11 +407,17 @@ export class Slides extends Ion {
|
||||
return this.options.onTransitionEnd && this.options.onTransitionEnd(swiper, e);
|
||||
};
|
||||
options.onSlideChangeStart = (swiper) => {
|
||||
// TODO deprecated 2016-04-18
|
||||
this.slideChangeStart.emit(swiper);
|
||||
|
||||
this.willChange.emit(swiper);
|
||||
return this.options.onSlideChangeStart && this.options.onSlideChangeStart(swiper);
|
||||
};
|
||||
options.onSlideChangeEnd = (swiper) => {
|
||||
// TODO deprecated 2016-04-18
|
||||
this.change.emit(swiper);
|
||||
|
||||
this.didChange.emit(swiper);
|
||||
return this.options.onSlideChangeEnd && this.options.onSlideChangeEnd(swiper);
|
||||
};
|
||||
options.onLazyImageLoad = (swiper, slide, img) => {
|
||||
@@ -259,6 +431,7 @@ export class Slides extends Ion {
|
||||
return this.options.onSliderMove && this.options.onSliderMove(swiper, e);
|
||||
};
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
var swiper = new Swiper(this.getNativeElement().children[0], options);
|
||||
this.slider = swiper;
|
||||
@@ -266,7 +439,7 @@ export class Slides extends Ion {
|
||||
|
||||
/*
|
||||
* TODO: Finish this
|
||||
if (util.isTrueProperty(this.zoom)) {
|
||||
if (isTrueProperty(this.zoom)) {
|
||||
this.enableZoom = true;
|
||||
setTimeout(() => {
|
||||
this.initZoom();
|
||||
@@ -290,7 +463,6 @@ export class Slides extends Ion {
|
||||
* @private
|
||||
*/
|
||||
onDoubleTap(swiper, e) {
|
||||
|
||||
this.toggleZoom(swiper, e);
|
||||
}
|
||||
/**
|
||||
@@ -602,58 +774,98 @@ export class Slides extends Ion {
|
||||
this.slider.update();
|
||||
|
||||
// Don't allow pager to show with > 10 slides
|
||||
if (this.slider.slides.length > 10) {
|
||||
if (this.length() > 10) {
|
||||
this.showPager = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Transition to the specified slide.
|
||||
*
|
||||
* @param {number} index The index number of the slide.
|
||||
* @param {number} speed Transition duration (in ms). Optional.
|
||||
* @param {boolean} runCallbacks Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
|
||||
*/
|
||||
next() {
|
||||
this.slider.slideNext();
|
||||
slideTo(index: number, speed: number, runCallbacks: boolean) {
|
||||
this.slider.slideTo(index, speed, runCallbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Transition to the next slide.
|
||||
*
|
||||
* @param {number} speed Transition duration (in ms). Optional.
|
||||
* @param {boolean} runCallbacks Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
|
||||
*/
|
||||
prev() {
|
||||
this.slider.slidePrev();
|
||||
slideNext(speed: number, runCallbacks: boolean) {
|
||||
this.slider.slideNext(runCallbacks, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Transition to the previous slide.
|
||||
*
|
||||
* @param {number} speed Transition duration (in ms). Optional.
|
||||
* @param {boolean} runCallbacks Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
|
||||
*/
|
||||
getIndex(): number {
|
||||
slidePrev(speed: number, runCallbacks: boolean) {
|
||||
this.slider.slidePrev(runCallbacks, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the active slide.
|
||||
*
|
||||
* @returns {number} The index number of the current slide.
|
||||
*/
|
||||
getActiveIndex(): number {
|
||||
return this.slider.activeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Get the index of the previous slide.
|
||||
*
|
||||
* @returns {number} The index number of the previous slide.
|
||||
*/
|
||||
getNumSlides(): number {
|
||||
getPreviousIndex(): number {
|
||||
return this.slider.previousIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of slides.
|
||||
*
|
||||
* @returns {number} The total number of slides.
|
||||
*/
|
||||
length(): number {
|
||||
return this.slider.slides.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Get whether or not the current slide is the last slide.
|
||||
*
|
||||
* @returns {boolean} If the slide is the last slide or not.
|
||||
*/
|
||||
isAtEnd(): boolean {
|
||||
isEnd(): boolean {
|
||||
return this.slider.isEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Get whether or not the current slide is the first slide.
|
||||
*
|
||||
* @returns {boolean} If the slide is the first slide or not.
|
||||
*/
|
||||
isAtBeginning(): boolean {
|
||||
isBeginning(): boolean {
|
||||
return this.slider.isBeginning;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Get the `Swiper` instance.
|
||||
*
|
||||
* The Slides component wraps the `Swiper` component built by iDangero.us. See the
|
||||
* [Swiper API Docs](http://idangero.us/swiper/api/) for information on using
|
||||
* the `Swiper` instance directly.
|
||||
*
|
||||
* @returns {Swiper}
|
||||
*/
|
||||
getSliderWidget() {
|
||||
getSlider() {
|
||||
return this.slider;
|
||||
}
|
||||
}
|
||||
@@ -661,7 +873,11 @@ export class Slides extends Ion {
|
||||
/**
|
||||
* @name Slide
|
||||
* @description
|
||||
* `ion-slide` is a child component of `ion-slides` and is where all your individule slide content will be rendered too.
|
||||
* The Slide component is a child component of [Slides](../Slides). The template
|
||||
* should be written as `ion-slide`. Any slide content should be written
|
||||
* in this component and it should be used in conjunction with [Slides](../Slides).
|
||||
*
|
||||
* See the [Slides API Docs](../Slides) for more usage information.
|
||||
*
|
||||
* @demo /docs/v2/demos/slides/
|
||||
* @see {@link /docs/v2/api/components/slides/Slides/ Slides API Docs}
|
||||
@@ -706,3 +922,5 @@ export class Slide {
|
||||
}
|
||||
})
|
||||
export class SlideLazy {}
|
||||
|
||||
let slidesId = -1;
|
||||
|
||||
6
ionic/components/slides/swiper-widget.d.ts
vendored
6
ionic/components/slides/swiper-widget.d.ts
vendored
@@ -3,9 +3,11 @@ export declare class Swiper {
|
||||
constructor(container: HTMLElement, params: any);
|
||||
slides: Array<HTMLElement>;
|
||||
activeIndex: number;
|
||||
previousIndex: number;
|
||||
isEnd: boolean;
|
||||
isBeginning: boolean;
|
||||
update(): any;
|
||||
slideNext(): any;
|
||||
slidePrev(): any;
|
||||
slideNext(runCallbacks: boolean, speed: number);
|
||||
slidePrev(runCallbacks: boolean, speed: number);
|
||||
slideTo(slideIndex: number, speed: number, runCallbacks: boolean);
|
||||
}
|
||||
|
||||
53
ionic/components/slides/test/controller/index.ts
Normal file
53
ionic/components/slides/test/controller/index.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {ViewChild} from 'angular2/core';
|
||||
import {App, Page, Slides} from 'ionic-angular';
|
||||
|
||||
|
||||
@App({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class MyPage {
|
||||
@ViewChild('mySlider') slider: Slides;
|
||||
mySlideOptions = {
|
||||
initialSlide: 1,
|
||||
loop: false
|
||||
};
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
}
|
||||
|
||||
onSlideChanged() {
|
||||
let previousIndex = this.slider.getPreviousIndex();
|
||||
let currentIndex = this.slider.getActiveIndex();
|
||||
console.log("Previous index is", previousIndex, "Current index is", currentIndex);
|
||||
}
|
||||
|
||||
goToPrevSlide() {
|
||||
this.slider.slidePrev();
|
||||
}
|
||||
|
||||
goToNextSlide() {
|
||||
this.slider.slideNext();
|
||||
}
|
||||
|
||||
goToSlide(index) {
|
||||
this.slider.slideTo(index);
|
||||
}
|
||||
|
||||
getIndex() {
|
||||
let index = this.slider.getActiveIndex();
|
||||
console.log("Current Index is", index);
|
||||
}
|
||||
|
||||
getLength() {
|
||||
let length = this.slider.length();
|
||||
console.log("Current Length is", length);
|
||||
}
|
||||
}
|
||||
|
||||
@App({
|
||||
template: `<ion-nav [root]="root"></ion-nav>`
|
||||
})
|
||||
class E2EApp {
|
||||
root: Page = MyPage;
|
||||
}
|
||||
23
ionic/components/slides/test/controller/main.html
Normal file
23
ionic/components/slides/test/controller/main.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<ion-slides #mySlider [options]="mySlideOptions" (didChange)="onSlideChanged()">
|
||||
<ion-slide padding>
|
||||
<h1>Slide 1</h1>
|
||||
<button block (click)="goToPrevSlide()">Navigate Back</button>
|
||||
<button block (click)="goToNextSlide()">Navigate Forward</button>
|
||||
<button block (click)="goToSlide(2)">Navigate to 3rd Slide</button>
|
||||
<button block (click)="getLength()">Get Slide Length</button>
|
||||
<button block (click)="getIndex()">Get Index</button>
|
||||
</ion-slide>
|
||||
<ion-slide padding>
|
||||
<h1>Slide 2</h1>
|
||||
<button block (click)="goToPrevSlide()">Navigate Back</button>
|
||||
<button block (click)="goToNextSlide()">Navigate Forward</button>
|
||||
<button block (click)="goToSlide(2)">Navigate to 3rd Slide</button>
|
||||
<button block (click)="getIndex()">Get Index</button>
|
||||
</ion-slide>
|
||||
<ion-slide padding>
|
||||
<h1>Slide 3</h1>
|
||||
<button block (click)="goToPrevSlide()">Navigate Back</button>
|
||||
<button block (click)="goToNextSlide()">Navigate Forward</button>
|
||||
<button block (click)="getIndex()">Get Index</button>
|
||||
</ion-slide>
|
||||
</ion-slides>
|
||||
@@ -8,7 +8,7 @@
|
||||
</ion-navbar>
|
||||
|
||||
<ion-content>
|
||||
<ion-slides pager [options]="mySlideOptions" (change)="onSlideChanged($event)" (slideChangeStart)="onSlideChangeStart($event)" (move)="onSlideMove($event)">
|
||||
<ion-slides pager [options]="mySlideOptions" (didChange)="onSlideChanged($event)" (willChange)="onSlideChangeStart($event)" (move)="onSlideMove($event)">
|
||||
<ion-slide>
|
||||
<h3>Thank you for choosing the Awesome App!</h3>
|
||||
<div id="logo">
|
||||
|
||||
@@ -35,7 +35,10 @@ class MyApp {
|
||||
|
||||
onSlideChanged(slider: Slides) {
|
||||
console.log('Slide changed', slider);
|
||||
console.log("active index", slider.activeIndex);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
console.log(this.loopSlider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="slides-div">
|
||||
<ion-slides [options]="myTopSlideOptions" #loopSlider (change)="onSlideChanged($event)" pager>
|
||||
<ion-slides [options]="myTopSlideOptions" #loopSlider (didChange)="onSlideChanged($event)" pager>
|
||||
<ion-slide *ngFor="#slide of slides" [ngClass]="slide.class">
|
||||
Loop {{ slide.name }}
|
||||
</ion-slide>
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
<div class="slides-div">
|
||||
<ion-slides (change)="onSlideChanged($event)" pager>
|
||||
<ion-slides (didChange)="onSlideChanged($event)" pager>
|
||||
<ion-slide *ngFor="#slide of slides" [ngClass]="slide.class">
|
||||
Don't Loop {{ slide.name }}
|
||||
</ion-slide>
|
||||
|
||||
@@ -90,7 +90,7 @@ tabbar {
|
||||
ion-badge,
|
||||
ion-icon,
|
||||
span {
|
||||
opacity: 0.4;
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -287,9 +287,30 @@ export class Tabs extends Ion {
|
||||
* @private
|
||||
*/
|
||||
ngAfterContentInit() {
|
||||
let preloadTabs = (isBlank(this.preloadTabs) ? this._config.getBoolean('preloadTabs') : isTrueProperty(this.preloadTabs));
|
||||
|
||||
// get the selected index
|
||||
let selectedIndex = this.selectedIndex ? parseInt(this.selectedIndex, 10) : 0;
|
||||
|
||||
let preloadTabs = (isBlank(this.preloadTabs) ? this._config.getBoolean('preloadTabs') : isTrueProperty(this.preloadTabs));
|
||||
// ensure the selectedIndex isn't a hidden or disabled tab
|
||||
// also find the first available index incase we need it later
|
||||
let availableIndex = -1;
|
||||
this._tabs.forEach((tab, index) => {
|
||||
if (tab.enabled && tab.show && availableIndex < 0) {
|
||||
// we know this tab index is safe to show
|
||||
availableIndex = index;
|
||||
}
|
||||
|
||||
if (index === selectedIndex && (!tab.enabled || !tab.show)) {
|
||||
// the selectedIndex is not safe to show
|
||||
selectedIndex = -1;
|
||||
}
|
||||
});
|
||||
if (selectedIndex < 0) {
|
||||
// the selected index wasn't safe to show
|
||||
// instead use an available index found to be safe to show
|
||||
selectedIndex = availableIndex;
|
||||
}
|
||||
|
||||
this._tabs.forEach((tab, index) => {
|
||||
if (index === selectedIndex) {
|
||||
|
||||
@@ -81,7 +81,7 @@ tabbar {
|
||||
// Windows Tabbar Color Mixin
|
||||
// --------------------------------------------------
|
||||
|
||||
@mixin tabbar-wp($color-name, $color-base) {
|
||||
@mixin tabbar-wp($color-name, $color-base, $color-contrast) {
|
||||
|
||||
ion-tabs[#{$color-name}] tabbar {
|
||||
background-color: $color-base;
|
||||
@@ -104,5 +104,5 @@ tabbar {
|
||||
// --------------------------------------------------
|
||||
|
||||
@each $color-name, $color-base, $color-contrast in get-colors($colors-wp) {
|
||||
@include tabbar-wp($color-name, $color-base);
|
||||
@include tabbar-wp($color-name, $color-base, $color-contrast);
|
||||
}
|
||||
|
||||
8
ionic/components/toast/test/basic/e2e.ts
Normal file
8
ionic/components/toast/test/basic/e2e.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
it('should open toast', function() {
|
||||
element(by.css('.e2eOpenToast')).click();
|
||||
});
|
||||
|
||||
it('should close with backdrop click', function() {
|
||||
element(by.css('.backdrop')).click();
|
||||
});
|
||||
84
ionic/components/toast/test/basic/index.ts
Normal file
84
ionic/components/toast/test/basic/index.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import {App, Page, Toast, NavController} from 'ionic-angular';
|
||||
|
||||
@Page({
|
||||
template: `
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Another Page</ion-title>
|
||||
</ion-navbar>
|
||||
<ion-content padding>
|
||||
<p>This is another page to show that the toast stays.</p>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
class AnotherPage {
|
||||
|
||||
}
|
||||
|
||||
@Page({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class E2EPage {
|
||||
|
||||
constructor(private nav: NavController) { }
|
||||
|
||||
showToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'User was created successfully',
|
||||
showCloseButton: true,
|
||||
enableBackdropDismiss: false
|
||||
});
|
||||
|
||||
toast.onDismiss(() => {
|
||||
console.log('Dismissed toast');
|
||||
});
|
||||
|
||||
this.nav.present(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
this.nav.push(AnotherPage);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
showLongToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.',
|
||||
});
|
||||
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
showDismissDurationToast() {
|
||||
const toast = Toast.create({
|
||||
message: 'I am dismissed after 1.5 seconds',
|
||||
duration: 1500
|
||||
});
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
showToastWithCloseButton() {
|
||||
const toast = Toast.create({
|
||||
message: 'Your internet connection appears to be offline. Data integrity is not gauranteed.',
|
||||
showCloseButton: true,
|
||||
closeButtonText: 'Ok'
|
||||
});
|
||||
toast.onDismiss(this.dismissHandler);
|
||||
this.nav.present(toast);
|
||||
}
|
||||
|
||||
private dismissHandler(toast: Toast) {
|
||||
console.info('Toast onDismiss()');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@App({
|
||||
template: '<ion-nav [root]="root"></ion-nav>'
|
||||
})
|
||||
class E2EApp {
|
||||
root = E2EPage;
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
23
ionic/components/toast/test/basic/main.html
Normal file
23
ionic/components/toast/test/basic/main.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Toasts</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
<ion-content padding>
|
||||
<button block (click)="showToast()">Show Toast and Navigate</button>
|
||||
<button block (click)="showLongToast()">Show Long Toast</button>
|
||||
<br />
|
||||
<button block (click)="showDismissDurationToast()">Custom (1.5s) Duration</button>
|
||||
<button block (click)="showToastWithCloseButton()" class="e2eOpenToast">With closeButtonText</button>
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lacinia purus ac turpis fermentum, nec accumsan nulla rutrum. Aenean lorem est, luctus id iaculis ac, ultricies quis odio. Aenean imperdiet imperdiet ex et vehicula. Suspendisse vulputate turpis quis ultricies porttitor. Proin malesuada tortor at libero laoreet, eu eleifend enim pulvinar. Nulla facilisi. Fusce sit amet mauris mauris. Mauris consequat libero sed egestas tincidunt.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In felis augue, sagittis id dui ac, tempor luctus turpis. Vestibulum nec urna vitae nisl malesuada lacinia ut sit amet orci. Suspendisse sed mauris vitae mauris porttitor pulvinar. Donec quis ante id dui cursus malesuada ut nec magna. Vestibulum venenatis efficitur urna, quis tempus quam. Curabitur id elementum eros, at euismod nisl. Aliquam ultricies imperdiet arcu id consequat. Aliquam erat volutpat. Nam quis laoreet dui. Donec eget neque non leo porta scelerisque. In blandit placerat nibh, ut viverra nisi feugiat a. Pellentesque semper, ligula et tincidunt egestas, urna arcu pellentesque massa, vitae accumsan ligula velit vitae sem. Nulla porta est id ligula viverra, ut placerat quam auctor. Morbi eget efficitur nibh.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Aenean viverra commodo enim eget interdum. Donec condimentum tincidunt sollicitudin. Curabitur malesuada est elementum lectus sodales, vitae eleifend massa dignissim. Pellentesque nec diam dapibus purus vulputate pharetra at id nunc. Vivamus dapibus sed turpis in facilisis. Nulla sollicitudin lacus sem, vel fringilla neque accumsan non. Suspendisse non congue turpis, id mattis ex. Nam sit amet diam quis neque convallis aliquet quis et lorem. Donec sit amet libero sit amet nisl mollis vehicula nec id eros. Curabitur rutrum condimentum porta. Donec pellentesque consectetur lacus. Etiam maximus ante vitae varius eleifend. Integer ac justo sem. Morbi iaculis vel urna in tempus. Aenean at rhoncus nulla.
|
||||
</p>
|
||||
</ion-content>
|
||||
52
ionic/components/toast/toast.ios.scss
Normal file
52
ionic/components/toast/toast.ios.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
@import "../../globals.ios";
|
||||
@import "./toast";
|
||||
|
||||
// iOS Toast
|
||||
// --------------------------------------------------
|
||||
|
||||
$toast-ios-text-align: left !default;
|
||||
$toast-ios-background: rgba(0, 0, 0, .9) !default;
|
||||
$toast-ios-border-radius: .65rem !default;
|
||||
|
||||
$toast-ios-title-color: #fff !default;
|
||||
$toast-ios-title-font-size: 1.4rem !default;
|
||||
$toast-ios-title-padding: 1.5rem !default;
|
||||
|
||||
|
||||
ion-toast {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay;
|
||||
display: block;
|
||||
|
||||
width: $toast-width;
|
||||
height: $toast-width;
|
||||
}
|
||||
|
||||
.toast-wrapper {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
z-index: $z-index-overlay-wrapper;
|
||||
display: block;
|
||||
|
||||
margin: auto;
|
||||
|
||||
max-width: $toast-max-width;
|
||||
|
||||
border-radius: $toast-ios-border-radius;
|
||||
|
||||
background: $toast-ios-background;
|
||||
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
padding: $toast-ios-title-padding;
|
||||
|
||||
font-size: $toast-ios-title-font-size;
|
||||
|
||||
color: $toast-ios-title-color;
|
||||
}
|
||||
51
ionic/components/toast/toast.md.scss
Normal file
51
ionic/components/toast/toast.md.scss
Normal file
@@ -0,0 +1,51 @@
|
||||
@import "../../globals.md";
|
||||
@import "./toast";
|
||||
|
||||
// Material Design Toast
|
||||
// --------------------------------------------------
|
||||
|
||||
$toast-md-text-align: left !default;
|
||||
$toast-md-background: #333 !default;
|
||||
$toast-md-group-margin-bottom: 8px !default;
|
||||
|
||||
$toast-md-title-color: #fff !default;
|
||||
$toast-md-title-font-size: 1.5rem !default;
|
||||
$toast-md-title-padding: 19px 16px 17px !default;
|
||||
|
||||
|
||||
ion-toast {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay;
|
||||
display: block;
|
||||
|
||||
width: $toast-width;
|
||||
height: $toast-width;
|
||||
}
|
||||
|
||||
.toast-wrapper {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay-wrapper;
|
||||
display: block;
|
||||
|
||||
margin: auto;
|
||||
|
||||
width: $toast-width;
|
||||
max-width: $toast-max-width;
|
||||
|
||||
background: $toast-md-background;
|
||||
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
padding: $toast-md-title-padding;
|
||||
|
||||
font-size: $toast-md-title-font-size;
|
||||
|
||||
color: $toast-md-title-color;
|
||||
}
|
||||
52
ionic/components/toast/toast.scss
Normal file
52
ionic/components/toast/toast.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
@import "../../globals.core";
|
||||
|
||||
|
||||
// Toast
|
||||
// --------------------------------------------------
|
||||
|
||||
$toast-width: 100% !default;
|
||||
$toast-max-width: 700px !default;
|
||||
|
||||
|
||||
ion-toast {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay;
|
||||
|
||||
display: block;
|
||||
|
||||
width: $toast-width;
|
||||
height: $toast-width;
|
||||
}
|
||||
|
||||
.toast-container {
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
padding: 19px 16px 17px;
|
||||
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toast-wrapper {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay-wrapper;
|
||||
display: block;
|
||||
|
||||
margin: auto;
|
||||
|
||||
max-width: $toast-max-width;
|
||||
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
322
ionic/components/toast/toast.ts
Normal file
322
ionic/components/toast/toast.ts
Normal file
@@ -0,0 +1,322 @@
|
||||
import {Component, ElementRef, Renderer, Output, EventEmitter} from 'angular2/core';
|
||||
import {NgClass, NgIf, NgFor} from 'angular2/common';
|
||||
|
||||
import {Button} from '../button/button';
|
||||
import {Icon} from '../icon/icon';
|
||||
import {ActionSheet, ActionSheetOptions} from '../action-sheet/action-sheet';
|
||||
import {Animation} from '../../animations/animation';
|
||||
import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
|
||||
import {Config} from '../../config/config';
|
||||
import {isPresent} from '../../util/util';
|
||||
import {NavParams} from '../nav/nav-params';
|
||||
import {NavController} from '../nav/nav-controller';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
|
||||
/**
|
||||
* @name Toast
|
||||
* @description
|
||||
* A Toast is a subtle notification that appears at the bottom of the
|
||||
* screen. It can be used to provide feedback about an operation or to
|
||||
* display a system message. The toast appears on top of the app's content,
|
||||
* and can be dismissed by the app to resume user interaction with
|
||||
* the app. It includes a backdrop, which can optionally be clicked to
|
||||
* dismiss the toast.
|
||||
*
|
||||
* ### Creating
|
||||
* All of the toast options should be passed in the first argument of
|
||||
* the create method: `Toast.create(opts)`. The message to display should be
|
||||
* passed in the `message` property. The `showCloseButton` option can be set to
|
||||
* true in order to display a close button on the toast. See the [create](#create)
|
||||
* method below for all available options.
|
||||
*
|
||||
* ### Dismissing
|
||||
* The toast can be dismissed automatically after a specific amount of time
|
||||
* by passing the number of milliseconds to display it in the `duration` of
|
||||
* the toast options. It can also be dismissed by clicking on the backdrop,
|
||||
* unless `enableBackdropDismiss` is set to `false` upon creation. If `showCloseButton`
|
||||
* is set to true, then the close button will dismiss the toast. To dismiss
|
||||
* the toast after creation, call the `dismiss()` method on the Toast instance.
|
||||
* The `onDismiss` function can be called to perform an action after the toast
|
||||
* is dismissed.
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* constructor(nav: NavController) {
|
||||
* this.nav = nav;
|
||||
* }
|
||||
*
|
||||
* presentToast() {
|
||||
* let toast = Toast.create({
|
||||
* message: 'User was added successfully',
|
||||
* duration: 3000
|
||||
* });
|
||||
*
|
||||
* toast.onDismiss(() => {
|
||||
* console.log('Dismissed toast');
|
||||
* });
|
||||
*
|
||||
* this.nav.present(toast);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @demo /docs/v2/demos/toast/
|
||||
*/
|
||||
export class Toast extends ViewController {
|
||||
|
||||
constructor(opts: ToastOptions = {}) {
|
||||
opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? !!opts.enableBackdropDismiss : true;
|
||||
opts.dismissOnPageChange = isPresent(opts.dismissOnPageChange) ? !!opts.dismissOnPageChange : false;
|
||||
|
||||
super(ToastCmp, opts);
|
||||
this.viewType = 'toast';
|
||||
this.isOverlay = true;
|
||||
this.usePortal = true;
|
||||
|
||||
// by default, toasts should not fire lifecycle events of other views
|
||||
// for example, when an toast enters, the current active view should
|
||||
// not fire its lifecycle events because it's not conceptually leaving
|
||||
this.fireOtherLifecycles = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getTransitionName(direction: string) {
|
||||
let key = 'toast' + (direction === 'back' ? 'Leave' : 'Enter');
|
||||
return this._nav && this._nav.config.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message Toast message content
|
||||
*/
|
||||
setMessage(message: string) {
|
||||
this.data.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Toast options
|
||||
*
|
||||
* | Property | Type | Default | Description |
|
||||
* |-----------------------|-----------|-----------------|---------------------------------------------------------------------------------------------------------------|
|
||||
* | message | `string` | - | The message for the toast. Long strings will wrap and the toast container will expand. |
|
||||
* | duration | `number` | - | How many milliseconds to wait before hiding the toast. By default, it will show until `dismiss()` is called. |
|
||||
* | cssClass | `string` | - | Any additional class for custom styles. |
|
||||
* | showCloseButton | `boolean` | false | Whether or not to show a button to close the toast. |
|
||||
* | closeButtonText | `string` | "Close" | Text to display in the close button. |
|
||||
* | enableBackdropDismiss | `boolean` | true | Whether the toast should be dismissed by tapping the backdrop. |
|
||||
* | dismissOnPageChange | `boolean` | false | Whether to dismiss the toast when navigating to a new page. |
|
||||
*
|
||||
* @param {object} opts Toast options. See the above table for available options.
|
||||
*/
|
||||
static create(opts: ToastOptions = {}) {
|
||||
return new Toast(opts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-toast',
|
||||
template: `
|
||||
<div (click)="bdClick()" tappable disable-activated class="backdrop" role="presentation"></div>
|
||||
<div class="toast-wrapper">
|
||||
<div class="toast-container">
|
||||
<div class="toast-message" id="{{hdrId}}" *ngIf="d.message">{{d.message}}</div>
|
||||
<button clear class="toast-button" *ngIf="d.showCloseButton" (click)="cbClick()">
|
||||
{{ d.closeButtonText || 'Close' }}
|
||||
<ion-button-effect></ion-button-effect>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
host: {
|
||||
'role': 'dialog',
|
||||
'[attr.aria-labelledby]': 'hdrId',
|
||||
'[attr.aria-describedby]': 'descId'
|
||||
},
|
||||
directives: [NgIf, Icon, Button]
|
||||
})
|
||||
class ToastCmp {
|
||||
private d: any;
|
||||
private descId: string;
|
||||
private hdrId: string;
|
||||
private created: number;
|
||||
private id: number;
|
||||
private dismissTimeout: number = undefined;
|
||||
|
||||
constructor(
|
||||
private _nav: NavController,
|
||||
private _viewCtrl: ViewController,
|
||||
private _config: Config,
|
||||
private _elementRef: ElementRef,
|
||||
params: NavParams,
|
||||
renderer: Renderer
|
||||
) {
|
||||
|
||||
this.d = params.data;
|
||||
this.created = Date.now();
|
||||
|
||||
if (this.d.cssClass) {
|
||||
renderer.setElementClass(_elementRef.nativeElement, this.d.cssClass, true);
|
||||
}
|
||||
|
||||
this.id = (++toastIds);
|
||||
if (this.d.message) {
|
||||
this.hdrId = 'toast-hdr-' + this.id;
|
||||
}
|
||||
}
|
||||
|
||||
onPageDidEnter() {
|
||||
const { activeElement }: any = document;
|
||||
if (activeElement) {
|
||||
activeElement.blur();
|
||||
}
|
||||
|
||||
let focusableEle = this._elementRef.nativeElement.querySelector('button');
|
||||
|
||||
if (focusableEle) {
|
||||
focusableEle.focus();
|
||||
}
|
||||
|
||||
// if there's a `duration` set, automatically dismiss.
|
||||
if (this.d.duration) {
|
||||
this.dismissTimeout =
|
||||
setTimeout(() => {
|
||||
this.dismiss('backdrop');
|
||||
}, this.d.duration);
|
||||
}
|
||||
}
|
||||
|
||||
bdClick() {
|
||||
if (this.isEnabled() && this.d.enableBackdropDismiss) {
|
||||
this.dismiss('backdrop');
|
||||
}
|
||||
}
|
||||
|
||||
cbClick() {
|
||||
if (this.isEnabled()) {
|
||||
this.dismiss('close');
|
||||
}
|
||||
}
|
||||
|
||||
dismiss(role): Promise<any> {
|
||||
clearTimeout(this.dismissTimeout);
|
||||
this.dismissTimeout = undefined;
|
||||
return this._viewCtrl.dismiss(null, role);
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
let tm = this._config.getNumber('overlayCreatedDiff', 750);
|
||||
return (this.created + tm < Date.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface ToastOptions {
|
||||
message?: string;
|
||||
cssClass?: string;
|
||||
duration?: number;
|
||||
showCloseButton?: boolean;
|
||||
closeButtonText?: string;
|
||||
enableBackdropDismiss?: boolean;
|
||||
dismissOnPageChange?: boolean;
|
||||
}
|
||||
|
||||
class ToastSlideIn extends Transition {
|
||||
constructor(enteringView, leavingView, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = enteringView.pageRef().nativeElement;
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
|
||||
wrapper.fromTo('translateY', '120%', '0%');
|
||||
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
class ToastSlideOut extends Transition {
|
||||
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = leavingView.pageRef().nativeElement;
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
|
||||
wrapper.fromTo('translateY', '0%', '120%');
|
||||
this.easing('cubic-bezier(.36,.66,.04,1)').duration(300).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
class ToastMdSlideIn extends Transition {
|
||||
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = enteringView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
|
||||
backdrop.fromTo('opacity', 0, 0);
|
||||
wrapper.fromTo('translateY', '120%', '0%');
|
||||
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(backdrop).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
class ToastMdSlideOut extends Transition {
|
||||
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = leavingView.pageRef().nativeElement;
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
|
||||
wrapper.fromTo('translateY', '0%', '120%');
|
||||
backdrop.fromTo('opacity', 0, 0);
|
||||
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add(backdrop).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
class ToastWpPopIn extends Transition {
|
||||
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = enteringView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.3', '1');
|
||||
backdrop.fromTo('opacity', 0, 0);
|
||||
|
||||
this.easing('cubic-bezier(0,0 0.05,1)').duration(200).add(backdrop).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
class ToastWpPopOut extends Transition {
|
||||
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
|
||||
super(opts);
|
||||
|
||||
let ele = leavingView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.toast-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '1.3');
|
||||
backdrop.fromTo('opacity', 0, 0);
|
||||
|
||||
this.easing('ease-out').duration(150).add(backdrop).add(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Transition.register('toast-slide-in', ToastSlideIn);
|
||||
Transition.register('toast-slide-out', ToastSlideOut);
|
||||
Transition.register('toast-md-slide-in', ToastMdSlideIn);
|
||||
Transition.register('toast-md-slide-out', ToastMdSlideOut);
|
||||
Transition.register('toast-wp-slide-out', ToastWpPopOut);
|
||||
Transition.register('toast-wp-slide-in', ToastWpPopIn);
|
||||
|
||||
let toastIds = -1;
|
||||
44
ionic/components/toast/toast.wp.scss
Normal file
44
ionic/components/toast/toast.wp.scss
Normal file
@@ -0,0 +1,44 @@
|
||||
@import "../../globals.wp";
|
||||
@import "./toast";
|
||||
|
||||
// Windows Phone Toast
|
||||
// --------------------------------------------------
|
||||
|
||||
$toast-wp-text-align: left !default;
|
||||
$toast-wp-background: rgba(0, 0, 0, 1) !default;
|
||||
$toast-wp-border-radius: 0 !default;
|
||||
$toast-wp-button-color: #fff !default;
|
||||
|
||||
$toast-wp-title-color: #fff !default;
|
||||
$toast-wp-title-font-size: 1.4rem !default;
|
||||
$toast-wp-title-padding: 1.5rem !default;
|
||||
|
||||
|
||||
.toast-wrapper {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: $z-index-overlay-wrapper;
|
||||
display: block;
|
||||
|
||||
margin: auto;
|
||||
|
||||
max-width: $toast-max-width;
|
||||
|
||||
border-radius: $toast-wp-border-radius;
|
||||
background: $toast-wp-background;
|
||||
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
padding: $toast-wp-title-padding;
|
||||
|
||||
font-size: $toast-wp-title-font-size;
|
||||
|
||||
color: $toast-wp-title-color;
|
||||
}
|
||||
|
||||
.toast-button {
|
||||
color: $toast-wp-button-color;
|
||||
}
|
||||
@@ -58,6 +58,7 @@ const TOGGLE_VALUE_ACCESSOR = new Provider(
|
||||
'</div>' +
|
||||
'<button role="checkbox" ' +
|
||||
'type="button" ' +
|
||||
'category="item-cover" ' +
|
||||
'[id]="id" ' +
|
||||
'[attr.aria-checked]="_checked" ' +
|
||||
'[attr.aria-labelledby]="_labelId" ' +
|
||||
|
||||
@@ -128,7 +128,7 @@ ion-toggle {
|
||||
// Windows Color Mixin
|
||||
// --------------------------------------------------
|
||||
|
||||
@mixin toggle-theme-wp($color-name, $color-base) {
|
||||
@mixin toggle-theme-wp($color-name, $color-base, $color-contrast) {
|
||||
|
||||
ion-toggle[#{$color-name}] {
|
||||
|
||||
@@ -151,6 +151,6 @@ ion-toggle {
|
||||
|
||||
@each $color-name, $color-base, $color-contrast in get-colors($colors-wp) {
|
||||
|
||||
@include toggle-theme-wp($color-name, $color-base);
|
||||
@include toggle-theme-wp($color-name, $color-base, $color-contrast);
|
||||
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export function postBootstrap(appRef: ComponentRef, prodMode: boolean) {
|
||||
platform.setZone(appRef.injector.get(NgZone));
|
||||
platform.prepareReady();
|
||||
app.setProd(prodMode);
|
||||
app.setAppInjector(appRef.injector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import {MenuToggle} from '../components/menu/menu-toggle';
|
||||
import {MenuClose} from '../components/menu/menu-close';
|
||||
import {Badge} from '../components/badge/badge';
|
||||
import {Button} from '../components/button/button';
|
||||
import {Blur} from '../components/blur/blur';
|
||||
import {Content} from '../components/content/content';
|
||||
import {Img} from '../components/img/img';
|
||||
import {Scroll} from '../components/scroll/scroll';
|
||||
@@ -44,79 +43,102 @@ import {ShowWhen, HideWhen} from '../components/show-hide-when/show-hide-when';
|
||||
|
||||
/**
|
||||
* @name IONIC_DIRECTIVES
|
||||
* @private
|
||||
* @description
|
||||
* The core Ionic directives as well as Angular's CORE_DIRECTIVES and
|
||||
* FORM_DIRECTIVES. Automatically available in every [@Page](../Page/) template.
|
||||
* The core Ionic directives as well as Angular's `CORE_DIRECTIVES` and `FORM_DIRECTIVES` are
|
||||
* avaialbe automatically when you bootstrap your app with the `@App` decorator. This means
|
||||
* if you are using custom components you no longer need to import `IONIC_DIRECTIVES` as they
|
||||
* are part of the `@App`s default directives.
|
||||
*
|
||||
* **Angular**
|
||||
* If you would like to **not** have them included by default, you would need to bootstrap
|
||||
* the app differently.
|
||||
*
|
||||
* Instead of starting your app like so:
|
||||
*
|
||||
* ```typescript
|
||||
* @App({
|
||||
* template: "<ion-nav></ion-nav>"
|
||||
* })
|
||||
*
|
||||
* export class MyApp{
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* We would use Angulars default way of bootstrap an app, import `IONIC_DIRECTIVES` and `ionicProviders`, then
|
||||
* declare `ionicProviders` as a dependencey.
|
||||
*
|
||||
* ```typescript
|
||||
* import {IONIC_DIRECTIVES, ionicProviders} from 'ionic-angular';
|
||||
* import {bootstrap} from 'angular2/platform/browser';
|
||||
*
|
||||
* @Component({
|
||||
* //default selector, and theme.
|
||||
* directives: [IONIC_DIRECTIVES]
|
||||
* })
|
||||
* class App {}
|
||||
*
|
||||
* bootstrap(App,ionicProviders())
|
||||
* ```
|
||||
*
|
||||
*
|
||||
*
|
||||
* #### Angular
|
||||
* - CORE_DIRECTIVES
|
||||
* - FORM_DIRECTIVES
|
||||
*
|
||||
* **Content**
|
||||
* - Menu
|
||||
* - MenuToggle
|
||||
* - MenuClose
|
||||
*
|
||||
* - Button
|
||||
* - Blur
|
||||
* - Content
|
||||
* - Scroll
|
||||
* - InfiniteScroll
|
||||
* - InfiniteScrollContent
|
||||
* - Refresher
|
||||
* - RefresherContent
|
||||
*
|
||||
* **Lists**
|
||||
* - List
|
||||
* - ListHeader
|
||||
* - Item
|
||||
* - ItemSliding
|
||||
* - VirtualScroll
|
||||
* - VirtualFor
|
||||
*
|
||||
* **Slides**
|
||||
* - Slides
|
||||
* - Slide
|
||||
* - SlideLazy
|
||||
*
|
||||
* **Tabs**
|
||||
* - Tabs
|
||||
* - Tab
|
||||
*
|
||||
* **Toolbar**
|
||||
* - Toolbar
|
||||
* - ToolbarTitle
|
||||
* - ToolbarItem
|
||||
*
|
||||
* **Media**
|
||||
* - Icon
|
||||
* - Spinner
|
||||
*
|
||||
* **Forms**
|
||||
* - Searchbar
|
||||
* - Segment
|
||||
* - SegmentButton
|
||||
* - Checkbox
|
||||
* - RadioGroup
|
||||
* - RadioButton
|
||||
* - Select
|
||||
* - Option
|
||||
* - Toggle
|
||||
* - TextInput
|
||||
* - Label
|
||||
*
|
||||
* **Nav**
|
||||
* - Nav
|
||||
* - NavbarTemplate
|
||||
* - Navbar
|
||||
* - NavPush
|
||||
* - NavPop
|
||||
* - NavRouter
|
||||
* - IdRef
|
||||
*
|
||||
* - ShowWhen
|
||||
* - HideWhen
|
||||
* #### Ionic
|
||||
* - Menu
|
||||
* - MenuToggle
|
||||
* - MenuClose
|
||||
* - Badge
|
||||
* - Button
|
||||
* - Content
|
||||
* - Scroll
|
||||
* - InfiniteScroll
|
||||
* - InfiniteScrollContent
|
||||
* - Refresher
|
||||
* - RefresherContent
|
||||
* - Img
|
||||
* - List
|
||||
* - ListHeader
|
||||
* - Item
|
||||
* - ItemSliding
|
||||
* - VirtualScroll
|
||||
* - VirtualItem
|
||||
* - VirtualHeader
|
||||
* - VirtualFooter
|
||||
* - Slides
|
||||
* - Slide
|
||||
* - SlideLazy
|
||||
* - Tabs
|
||||
* - Tab
|
||||
* - Toolbar
|
||||
* - ToolbarTitle
|
||||
* - ToolbarItem
|
||||
* - Icon
|
||||
* - Spinner
|
||||
* - Searchbar
|
||||
* - SearchbarInput
|
||||
* - Segment
|
||||
* - SegmentButton
|
||||
* - Checkbox
|
||||
* - RadioGroup
|
||||
* - RadioButton
|
||||
* - Select
|
||||
* - Option
|
||||
* - Toggle
|
||||
* - TextArea
|
||||
* - TextInput
|
||||
* - Label
|
||||
* - Nav
|
||||
* - NavbarTemplate
|
||||
* - Navbar
|
||||
* - NavPush
|
||||
* - NavPop
|
||||
* - NavRouter
|
||||
* - IdRef
|
||||
* - ShowWhen
|
||||
* - HideWhen
|
||||
*/
|
||||
export const IONIC_DIRECTIVES = [
|
||||
// Angular
|
||||
@@ -130,7 +152,6 @@ export const IONIC_DIRECTIVES = [
|
||||
|
||||
Badge,
|
||||
Button,
|
||||
Blur,
|
||||
Content,
|
||||
Scroll,
|
||||
InfiniteScroll,
|
||||
|
||||
@@ -9,6 +9,9 @@ Config.setModeConfig('ios', {
|
||||
actionSheetEnter: 'action-sheet-slide-in',
|
||||
actionSheetLeave: 'action-sheet-slide-out',
|
||||
|
||||
toastEnter: 'toast-slide-in',
|
||||
toastLeave: 'toast-slide-out',
|
||||
|
||||
alertEnter: 'alert-pop-in',
|
||||
alertLeave: 'alert-pop-out',
|
||||
|
||||
@@ -41,6 +44,9 @@ Config.setModeConfig('md', {
|
||||
actionSheetEnter: 'action-sheet-md-slide-in',
|
||||
actionSheetLeave: 'action-sheet-md-slide-out',
|
||||
|
||||
toastEnter: 'toast-md-slide-in',
|
||||
toastLeave: 'toast-md-slide-out',
|
||||
|
||||
alertEnter: 'alert-md-pop-in',
|
||||
alertLeave: 'alert-md-pop-out',
|
||||
|
||||
@@ -76,6 +82,9 @@ Config.setModeConfig('wp', {
|
||||
actionSheetEnter: 'action-sheet-wp-slide-in',
|
||||
actionSheetLeave: 'action-sheet-wp-slide-out',
|
||||
|
||||
toastEnter: 'toast-wp-slide-in',
|
||||
toastLeave: 'toast-wp-slide-out',
|
||||
|
||||
alertEnter: 'alert-wp-pop-in',
|
||||
alertLeave: 'alert-wp-pop-out',
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, ChangeDetectionStrategy, ViewEncapsulation, enableProdMode, Type} from 'angular2/core';
|
||||
import {Component, ChangeDetectionStrategy, ViewEncapsulation, enableProdMode, Type, provide, PLATFORM_DIRECTIVES} from 'angular2/core';
|
||||
import {bootstrap} from 'angular2/platform/browser';
|
||||
import {ionicProviders, postBootstrap} from '../config/bootstrap';
|
||||
import {IONIC_DIRECTIVES} from '../config/directives';
|
||||
@@ -41,6 +41,9 @@ export interface AppMetadata {
|
||||
* property that has an inline template, or a `templateUrl` property that points
|
||||
* to an external html template. The `@App` decorator runs the Angular bootstrapping
|
||||
* process automatically, however you can bootstrap your app separately if you prefer.
|
||||
* Additionally, `@App` will automatically bootstrap with all of Ionic's
|
||||
* core components, meaning they won't all have to be individually imported and added
|
||||
* to each component's `directives` property.
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
@@ -71,9 +74,6 @@ export function App(args: AppMetadata = {}) {
|
||||
|
||||
args.selector = 'ion-app';
|
||||
|
||||
// auto add Ionic directives
|
||||
args.directives = args.directives ? args.directives.concat(IONIC_DIRECTIVES) : IONIC_DIRECTIVES;
|
||||
|
||||
// if no template was provided, default so it has a root <ion-nav>
|
||||
if (!args.templateUrl && !args.template) {
|
||||
args.template = '<ion-nav></ion-nav>';
|
||||
@@ -88,6 +88,12 @@ export function App(args: AppMetadata = {}) {
|
||||
// define array of bootstrap providers
|
||||
let providers = ionicProviders(args).concat(args.providers || []);
|
||||
|
||||
// auto add Ionic directives
|
||||
let directives = args.directives ? args.directives.concat(IONIC_DIRECTIVES) : IONIC_DIRECTIVES;
|
||||
|
||||
// automatically provide all of Ionic's directives to every component
|
||||
providers.push(provide(PLATFORM_DIRECTIVES, {useValue: [directives], multi: true}));
|
||||
|
||||
if (args.prodMode) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Component, ChangeDetectionStrategy, ViewEncapsulation, Type} from 'angular2/core';
|
||||
import {IONIC_DIRECTIVES} from '../config/directives';
|
||||
|
||||
const _reflect: any = Reflect;
|
||||
|
||||
@@ -33,12 +32,15 @@ export interface PageMetadata {
|
||||
* @description
|
||||
*
|
||||
* The Page decorator indicates that the decorated class is an Ionic
|
||||
* navigation component, meaning it can be navigated to using a NavController.
|
||||
* navigation component, meaning it can be navigated to using a
|
||||
* [NavController](../../nav/NavController).
|
||||
*
|
||||
* Pages have all `IONIC_DIRECTIVES`, which include all Ionic components and directives,
|
||||
* as well as Angular's [CORE_DIRECTIVES](https://angular.io/docs/js/latest/api/core/CORE_DIRECTIVES-const.html)
|
||||
* and [FORM_DIRECTIVES](https://angular.io/docs/js/latest/api/core/FORM_DIRECTIVES-const.html),
|
||||
* already provided to them, so you only need to supply custom components and directives to your pages:
|
||||
* Since the app has already been bootstrapped with Ionic's core directives, it
|
||||
* is not needed to include `IONIC_DIRECTIVES` in the directives property. Additionally,
|
||||
* Angular's [CORE_DIRECTIVES](https://angular.io/docs/ts/latest/api/common/CORE_DIRECTIVES-let.html)
|
||||
* and [FORM_DIRECTIVES](https://angular.io/docs/ts/latest/api/common/FORM_DIRECTIVES-let.html),
|
||||
* are also already provided, so you only need to supply any custom components and directives
|
||||
* to your pages:
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
@@ -53,44 +55,7 @@ export interface PageMetadata {
|
||||
* class MyPage {}
|
||||
* ```
|
||||
*
|
||||
* Here [Content](../../../components/content/Content/) will load because
|
||||
* it is in `IONIC_DIRECTIVES`, so there is no need to add a `directives` array.
|
||||
*
|
||||
*
|
||||
* Say you built a custom component that uses the already existing Ionic component.
|
||||
* In this case, you would add `IONIC_DIRECTIVES` to your directives array.
|
||||
*
|
||||
* ```ts
|
||||
* import {IONIC_DIRECTIVES} from 'ionic-angular';
|
||||
* @Component({
|
||||
* selector: 'my-component'
|
||||
* template: `<div class="my-style">
|
||||
* <ion-checkbox></ion-checkbox>
|
||||
* </div>`,
|
||||
* directives: [IONIC_DIRECTIVES]
|
||||
* })
|
||||
* class MyCustomCheckbox {}
|
||||
*```
|
||||
|
||||
* Alternatively, you could:
|
||||
*
|
||||
* ```ts
|
||||
* import {Checkbox, Icon} from 'ionic-angular'
|
||||
* ```
|
||||
*
|
||||
* along with any other components and add them individually:
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* ...
|
||||
* directives: [Checkbox, Icon]
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* However, using IONIC_DIRECTIVES will always *Just Work* with no
|
||||
* performance overhead, so there is really no reason to not always use it.
|
||||
*
|
||||
* Pages have their content automatically wrapped in `<ion-view>`, so although
|
||||
* Pages have their content automatically wrapped in `<ion-page>`, so although
|
||||
* you may see these tags if you inspect your markup, you don't need to include
|
||||
* them in your templates.
|
||||
*
|
||||
@@ -99,7 +64,6 @@ export interface PageMetadata {
|
||||
export function Page(config: PageMetadata) {
|
||||
return function(cls) {
|
||||
config.selector = 'ion-page';
|
||||
config.directives = config.directives ? config.directives.concat(IONIC_DIRECTIVES) : IONIC_DIRECTIVES;
|
||||
config.host = config.host || {};
|
||||
config.host['[hidden]'] = '_hidden';
|
||||
config.host['[class.tab-subpage]'] = '_tabSubPage';
|
||||
|
||||
@@ -152,9 +152,7 @@ export class Platform {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {string} [platformName] optional platformName
|
||||
* @returns {object} An object with various platform info
|
||||
*
|
||||
* @returns {object} An object containing all of the platforms and their versions.
|
||||
*/
|
||||
versions(): {[name: string]: PlatformVersion} {
|
||||
// get all the platforms that have a valid parsed version
|
||||
|
||||
@@ -104,6 +104,18 @@ export class ScrollView {
|
||||
});
|
||||
}
|
||||
|
||||
scrollToTop(duration: number): Promise<any> {
|
||||
return this.scrollTo(0, 0, duration);
|
||||
}
|
||||
|
||||
scrollToBottom(duration: number): Promise<any> {
|
||||
let y = 0;
|
||||
if (this._el) {
|
||||
y = this._el.scrollHeight - this._el.clientHeight;
|
||||
}
|
||||
return this.scrollTo(0, y, duration);
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": "true",
|
||||
"name": "ionic2",
|
||||
"version": "2.0.0-beta.4",
|
||||
"version": "2.0.0-beta.6",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -23,7 +23,7 @@
|
||||
"q": "1.4.1",
|
||||
"reflect-metadata": "0.1.2",
|
||||
"rxjs": "5.0.0-beta.2",
|
||||
"zone.js": "^0.6.10"
|
||||
"zone.js": "^0.6.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"canonical-path": "0.0.2",
|
||||
@@ -91,4 +91,4 @@
|
||||
"path": "node_modules/ionic-cz-conventional-changelog"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,9 @@ To remove the linked version of `ionic-angular` do `npm rm ionic-angular`, and t
|
||||
|
||||
1. `gulp karma`
|
||||
|
||||
### Running Sass Linter
|
||||
|
||||
1. See the [Sass Guidelines](https://github.com/driftyco/ionic/blob/2.0/CONTRIBUTING.md#sass-guidelines) for editing Sass and running the linter.
|
||||
|
||||
# Releasing
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ function run {
|
||||
./node_modules/.bin/gulp demos --production=true
|
||||
|
||||
# process new docs
|
||||
rm -R $DOCS_DEST/api
|
||||
if [ -d "$DOCS_DEST/api" ]; then
|
||||
rm -R $DOCS_DEST/api
|
||||
fi
|
||||
./node_modules/.bin/gulp docs --doc-version="$VERSION_NAME"
|
||||
|
||||
# compile sass vars json for ionic-site docs
|
||||
|
||||
@@ -12,6 +12,12 @@ module.exports = function collectInputsOutputs() {
|
||||
|
||||
memberLoop:
|
||||
for (var i in doc.members) {
|
||||
|
||||
// identify properties to differentiate from methods
|
||||
if (typeof doc.members[i].parameters == 'undefined') {
|
||||
doc.members[i].isProperty = true;
|
||||
}
|
||||
|
||||
if (doc.members[i].decorators && doc.members[i].decorators.length) {
|
||||
|
||||
decoratorLoop:
|
||||
|
||||
10
scripts/docs/templates/common.template.html
vendored
10
scripts/docs/templates/common.template.html
vendored
@@ -128,11 +128,11 @@ angular_controller: APIDemoCtrl <@ endif @>
|
||||
|
||||
<@- macro functionSyntax(fn) @>
|
||||
<@- set sep = joiner(', ') -@>
|
||||
<code><$ fn.name $>(<@- for param in fn.params @><$ sep() $>
|
||||
<code><$ fn.name $><@- if not fn.isProperty @>(<@ endif -@><@- for param in fn.params @><$ sep() $>
|
||||
<@- if param.type.optional @>[<@ endif -@>
|
||||
<$ param.name $>
|
||||
<@- if param.type.optional @>]<@ endif -@>
|
||||
<@ endfor @>)</code>
|
||||
<@ endfor @><@- if not fn.isProperty @>)<@ endif -@></code>
|
||||
<@ if fn.alias @><small>(alias: <$ fn.alias $>)</small><@ endif @>
|
||||
<@ endmacro -@>
|
||||
|
||||
@@ -142,7 +142,7 @@ angular_controller: APIDemoCtrl <@ endif @>
|
||||
<@- endmacro -@>
|
||||
|
||||
<@- macro typeInfo(fn) -@>
|
||||
<$ typeList(fn.typeList) $> <$ fn.description $>
|
||||
<$ typeList(fn.typeList) $> <$ fn.description | marked $>
|
||||
<@- endmacro -@>
|
||||
|
||||
<@ block body @>
|
||||
@@ -249,7 +249,7 @@ Improve this doc
|
||||
|
||||
|
||||
<@- if doc.statics.length -@>
|
||||
<h2><a class="anchor" name="static-methods" href="#static-methods"></a>Static Methods</h2>
|
||||
<h2><a class="anchor" name="static-members" href="#static-members"></a>Static Members</h2>
|
||||
<@- for method in doc.statics @><@ if not method.internal @>
|
||||
<div id="<$ method.name $>"></div>
|
||||
<h3><a class="anchor" name="<$ method.name $>" href="#<$ method.name $>"></a><$ functionSyntax(method) $></h3>
|
||||
@@ -283,7 +283,7 @@ Improve this doc
|
||||
<!-- instance methods on the class -->
|
||||
<@- if doc.members and doc.members.length @>
|
||||
|
||||
<h2><a class="anchor" name="instance-methods" href="#instance-methods"></a>Instance Methods</h2>
|
||||
<h2><a class="anchor" name="instance-members" href="#instance-members"></a>Instance Members</h2>
|
||||
<@- for method in doc.members @>
|
||||
|
||||
<div id="<$ method.name $>"></div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Component} from 'angular2/core';
|
||||
import {IONIC_DIRECTIVES} from 'ionic-angular';
|
||||
|
||||
/*
|
||||
Generated class for the <%= jsClassName %> component.
|
||||
@@ -9,8 +8,7 @@ import {IONIC_DIRECTIVES} from 'ionic-angular';
|
||||
*/
|
||||
@Component({
|
||||
selector: '<%= fileName %>',
|
||||
templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html',
|
||||
directives: [IONIC_DIRECTIVES] // makes all Ionic directives available to your component
|
||||
templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html'
|
||||
})
|
||||
export class <%= jsClassName %> {
|
||||
constructor() {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Component} from 'angular2/core';
|
||||
import {IONIC_DIRECTIVES} from 'ionic-angular';
|
||||
|
||||
/*
|
||||
Generated class for the <%= jsClassName %> component.
|
||||
@@ -9,8 +8,7 @@ import {IONIC_DIRECTIVES} from 'ionic-angular';
|
||||
*/
|
||||
@Component({
|
||||
selector: '<%= fileName %>',
|
||||
templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html',
|
||||
directives: [IONIC_DIRECTIVES] // makes all Ionic directives available to your component
|
||||
templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html'
|
||||
})
|
||||
export class <%= jsClassName %> {
|
||||
constructor() {
|
||||
|
||||
@@ -10,7 +10,5 @@ import {Page, NavController} from 'ionic-angular';
|
||||
templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html',
|
||||
})
|
||||
export class <%= jsClassName %> {
|
||||
constructor(public nav: NavController) {
|
||||
this.nav = nav;
|
||||
}
|
||||
constructor(public nav: NavController) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user