Compare commits

..

1 Commits

Author SHA1 Message Date
Brandy Carney
c36b1fd2dc @ionic/core 0.1.4-1 2018-03-07 17:59:13 -05:00
1288 changed files with 10352 additions and 8105 deletions

4
.gitignore vendored
View File

@@ -18,8 +18,8 @@ dist/
node_modules/
tmp/
temp/
core/theme-builder/
core/test-components/
packages/core/theme-builder/
packages/core/test-components/
$RECYCLE.BIN/
.DS_Store

View File

@@ -8,8 +8,8 @@ Ionic is based on [Web Components](https://www.webcomponents.org/introduction) a
# Packages
- [Core](core/README.md)
- [Ionic Angular](angular/README.md)
- [Core](packages/core/README.md)
- [Ionic Angular](packages/ionic-angular/README.md)
### Getting Started
@@ -46,8 +46,3 @@ As Ionic components migrate to the web component standard, a goal of ours is to
The source code for Ionic V1 has been moved to [ionic-team/ionic-v1](https://github.com/ionic-team/ionic-v1).
Please open any issues and pull requests related to Ionic V1 on that repository.
### Ionic V3
The source code for Ionic V3 has been moved to the [v3 branch](https://github.com/ionic-team/ionic/tree/v3).

View File

@@ -1,16 +0,0 @@
# npm link local development
`npm link` doesn't work as expected due to the `devDependency` on `@angular/core`. This is the work around...
npm run build.link ../ionic-conference-app
When the command above is ran from the `angular` directory, it will build `@ionic/angular` and copy the `dist` directory to the correct location of another local project. In the example above, the end result is that it copies the `dist` directory to `../ionic-conference-app/node_modules/@ionic/angular/dist`. The path given should be relative to the root of this mono repo.
# Deploy
1. `npm run prepare.deploy`
2. Review/update changelog
3. Commit updates using the package name and version number as the commit message.
4. `npm run deploy`
5. :tada:

View File

@@ -1,10 +0,0 @@
import { Injectable } from '@angular/core';
import { ActionSheetOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@Injectable()
export class ActionSheetController extends OverlayBaseController<ActionSheetOptions, HTMLIonActionSheetElement> {
constructor() {
super('ion-action-sheet-controller');
}
}

View File

@@ -1,10 +0,0 @@
import { Injectable } from '@angular/core';
import { AlertOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@Injectable()
export class AlertController extends OverlayBaseController<AlertOptions, HTMLIonAlertElement> {
constructor() {
super('ion-alert-controller');
}
}

View File

@@ -1,64 +0,0 @@
import {
ApplicationRef,
ComponentFactoryResolver,
Injectable,
Injector,
} from '@angular/core';
import { FrameworkDelegate } from '@ionic/core';
@Injectable()
export class AngularDelegate {
constructor(
private appRef: ApplicationRef
) {}
create(cfr: ComponentFactoryResolver, injector: Injector) {
return new AngularFrameworkDelegate(cfr, injector, this.appRef);
}
}
export class AngularFrameworkDelegate implements FrameworkDelegate {
private elRefMap = new WeakMap<HTMLElement, any>();
constructor(
private cfr: ComponentFactoryResolver,
private injector: Injector,
private appRef: ApplicationRef
) {}
attachViewToDom(container: any, component: any, data?: any, cssClasses?: string[]): Promise<any> {
const componentFactory = this.cfr.resolveComponentFactory(component);
const hostElement = document.createElement(componentFactory.selector);
if (data) {
Object.assign(hostElement, data);
}
const childInjector = Injector.create([], this.injector);
const componentRef = componentFactory.create(childInjector, [], hostElement);
for (const clazz of cssClasses) {
hostElement.classList.add(clazz);
}
container.appendChild(hostElement);
this.appRef.attachView(componentRef.hostView);
this.elRefMap.set(hostElement, componentRef);
return Promise.resolve(hostElement);
}
removeViewFromDom(_container: any, component: any): Promise<void> {
const mountingData = this.elRefMap.get(component);
if (mountingData) {
mountingData.componentRef.destroy();
this.elRefMap.delete(component);
}
return Promise.resolve();
}
}

View File

@@ -1,10 +0,0 @@
import { Injectable } from '@angular/core';
import { LoadingOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@Injectable()
export class LoadingController extends OverlayBaseController<LoadingOptions, HTMLIonLoadingElement> {
constructor() {
super('ion-loading-controller');
}
}

View File

@@ -1,104 +0,0 @@
import { Injectable } from '@angular/core';
import { proxyMethod } from '../util/util';
const CTRL = 'ion-menu-controller';
@Injectable()
export class MenuController {
/**
* Programatically open the Menu.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu is fully opened
*/
open(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'open', menuId);
}
/**
* Programatically close the Menu. If no `menuId` is given as the first
* argument then it'll close any menu which is open. If a `menuId`
* is given then it'll close that exact menu.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu is fully closed
*/
close(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'close', menuId);
}
/**
* Toggle the menu. If it's closed, it will open, and if opened, it
* will close.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu has been toggled
*/
toggle(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'toggle', menuId);
}
/**
* Used to enable or disable a menu. For example, there could be multiple
* left menus, but only one of them should be able to be opened at the same
* time. If there are multiple menus on the same side, then enabling one menu
* will also automatically disable all the others that are on the same side.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
*/
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'enable', shouldEnable, menuId);
}
/**
* Used to enable or disable the ability to swipe open the menu.
* @param {boolean} shouldEnable True if it should be swipe-able, false if not.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
*/
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'swipeEnable', shouldEnable, menuId);
}
/**
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {boolean} Returns true if the specified menu is currently open, otherwise false.
* If the menuId is not specified, it returns true if ANY menu is currenly open.
*/
isOpen(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'isOpen', menuId);
}
/**
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {boolean} Returns true if the menu is currently enabled, otherwise false.
*/
isEnabled(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'isEnabled', menuId);
}
/**
* Used to get a menu instance. If a `menuId` is not provided then it'll
* return the first menu found. If a `menuId` is `left` or `right`, then
* it'll return the enabled menu on that side. Otherwise, if a `menuId` is
* provided, then it'll try to find the menu using the menu's `id`
* property. If a menu is not found then it'll return `null`.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu if found, otherwise `null`.
*/
get(menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'get', menuId);
}
/**
* @return {Menu} Returns the instance of the menu already opened, otherwise `null`.
*/
getOpen(): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'getOpen');
}
/**
* @return {Array<HTMLIonMenuElement>} Returns an array of all menu instances.
*/
getMenus(): Promise<HTMLIonMenuElement[]> {
return proxyMethod(CTRL, 'getMenus');
}
}

View File

@@ -1,22 +0,0 @@
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { ModalOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
import { AngularDelegate } from './angular-delegate';
@Injectable()
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
constructor(
private cfr: ComponentFactoryResolver,
private injector: Injector,
private angularDelegate: AngularDelegate,
) {
super('ion-modal-controller');
}
create(opts?: ModalOptions): Promise<HTMLIonModalElement> {
return super.create({
...opts,
delegate: this.angularDelegate.create(this.cfr, this.injector)
});
}
}

View File

@@ -1,10 +0,0 @@
import { Injectable } from '@angular/core';
import { PickerOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@Injectable()
export class PickerController extends OverlayBaseController<PickerOptions, HTMLIonPickerElement> {
constructor() {
super('ion-picker-controller');
}
}

View File

@@ -1,22 +0,0 @@
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { PopoverOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
import { AngularDelegate } from './angular-delegate';
@Injectable()
export class PopoverController extends OverlayBaseController<PopoverOptions, HTMLIonPopoverElement> {
constructor(
private cfr: ComponentFactoryResolver,
private injector: Injector,
private angularDelegate: AngularDelegate,
) {
super('ion-popover-controller');
}
create(opts?: PopoverOptions): Promise<HTMLIonPopoverElement> {
return super.create({
...opts,
delegate: this.angularDelegate.create(this.cfr, this.injector)
});
}
}

View File

@@ -1,10 +0,0 @@
import { Injectable } from '@angular/core';
import { ToastOptions } from '@ionic/core';
import { OverlayBaseController } from '../util/overlay';
@Injectable()
export class ToastController extends OverlayBaseController<ToastOptions, HTMLIonToastElement> {
constructor() {
super('ion-toast-controller');
}
}

View File

@@ -1,17 +0,0 @@
import { proxyMethod } from '../util/util';
export class OverlayBaseController<Opts, Overlay> {
constructor(private ctrl: string) {}
create(opts?: Opts): Promise<Overlay> {
return proxyMethod(this.ctrl, 'create', opts);
}
dismiss(data?: any, role?: string, id = -1): Promise<void> {
return proxyMethod(this.ctrl, 'dismiss', data, role, id);
}
getTop(): Promise<Overlay> {
return proxyMethod(this.ctrl, 'getTop');
}
}

View File

@@ -1,15 +0,0 @@
export function proxyMethod(ctrlName: string, methodName: string, ...args: any[]) {
const controller = ensureElementInBody(ctrlName);
return controller.componentOnReady()
.then(() => (controller as any)[methodName].apply(controller, args));
}
export function ensureElementInBody(elementName: string) {
let element = document.querySelector(elementName);
if (!element) {
element = document.createElement(elementName);
document.body.appendChild(element);
}
return element as HTMLStencilElement;
}

View File

@@ -3,30 +3,45 @@ jobs:
build:
working_directory: ~/ionic/
docker:
- image: node:8
- image: node:7
branches:
# ignore:
# - core
ignore:
- core
steps:
- checkout
- restore_cache:
key: ionic-site
- run:
name: Prepare ionic-site repo
command: ./packages/ionic-angular/scripts/docs/prepare.sh
- save_cache:
key: ionic-site
paths:
- ~/ionic-site/
- restore_cache:
key: node_modules_{{ checksum "package.json" }}
- run:
name: Install monorepo node modules
name: Install node modules
command: npm i
- save_cache:
key: node_modules_{{ checksum "package.json" }}
paths:
- ~/ionic/node_modules/
- restore_cache:
key: node_modules_{{ checksum "core/package.json" }}
- run:
name: Install core node modules
command: npm --prefix core/ i
- save_cache:
key: node_modules_{{ checksum "core/package.json" }}
paths:
- ~/ionic/core/node_modules/
name: Run tslint
command: ./node_modules/.bin/gulp lint.ts
- run:
name: Validate Core
command: npm --prefix core/ run validate
name: Build Demos
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
./node_modules/.bin/gulp demos.prod --production=true --batch=$CIRCLE_NODE_INDEX --batches=$CIRCLE_NODE_TOTAL
fi
- add_ssh_keys
- deploy:
name: Update docs
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
./packages/ionic-angular/scripts/ci/deploy.sh
else
echo "We are on ${CIRCLE_BRANCH} branch, not going to update docs."
fi

View File

@@ -1,178 +0,0 @@
<a name="0.1.4-6"></a>
## [0.1.4-6](https://github.com/ionic-team/ionic/compare/v0.1.4-5...v0.1.4-6) (2018-03-15)
### Bug Fixes
* **alert:** backdrop calls cancel handler ([de22eca](https://github.com/ionic-team/ionic/commit/de22eca))
* **alert:** set input value ([6e2a9c9](https://github.com/ionic-team/ionic/commit/6e2a9c9))
* **angular:** create angular delegate ([3b5f758](https://github.com/ionic-team/ionic/commit/3b5f758))
* **angular:** fix overlays ([cc4fecc](https://github.com/ionic-team/ionic/commit/cc4fecc))
* **angular:** modal and popover support ([9a0755a](https://github.com/ionic-team/ionic/commit/9a0755a))
* **demos:** fixes angular ([f398b3a](https://github.com/ionic-team/ionic/commit/f398b3a))
* **overlay:** using hostData for zIndex ([64f0866](https://github.com/ionic-team/ionic/commit/64f0866))
* **overlay:** wrong stencil import ([22f6a34](https://github.com/ionic-team/ionic/commit/22f6a34))
* **overlays:** OverlayController interface ([6e2ca85](https://github.com/ionic-team/ionic/commit/6e2ca85))
* **popover:** lifecycles ([b56c2a8](https://github.com/ionic-team/ionic/commit/b56c2a8))
* **router:** ambiguous routes ([b4f46ee](https://github.com/ionic-team/ionic/commit/b4f46ee))
* **router:** fix selection ([207f416](https://github.com/ionic-team/ionic/commit/207f416))
* **router:** rename API to match stencil-router ([e729610](https://github.com/ionic-team/ionic/commit/e729610))
* **router:** retuning string path ([f48d817](https://github.com/ionic-team/ionic/commit/f48d817))
* **toggle:** ios shadow ([7df023a](https://github.com/ionic-team/ionic/commit/7df023a))
### Features
* **ion-router:** dynamic routes ([7c3cba0](https://github.com/ionic-team/ionic/commit/7c3cba0))
* **overlay:** adds lifecycle events ([0b099ce](https://github.com/ionic-team/ionic/commit/0b099ce))
* **overlays:** adds onDidDismiss and onWillDismiss ([7dcf8a5](https://github.com/ionic-team/ionic/commit/7dcf8a5))
### Performance Improvements
* **scss:** optimize multi dir ([#14156](https://github.com/ionic-team/ionic/issues/14156)) ([ba63d01](https://github.com/ionic-team/ionic/commit/ba63d01))
<a name="0.1.4-5"></a>
## [0.1.4-5](https://github.com/ionic-team/ionic/compare/v0.1.4-4...v0.1.4-5) (2018-03-09)
### Bug Fixes
* **item:** button outline ([f671008](https://github.com/ionic-team/ionic/commit/f671008))
* **router:** fix flickering ([f2ac6e3](https://github.com/ionic-team/ionic/commit/f2ac6e3))
* **router:** flickering 2 ([88f2981](https://github.com/ionic-team/ionic/commit/88f2981))
* **router:** tslint ([1ace045](https://github.com/ionic-team/ionic/commit/1ace045))
### Features
* **router:** adds redirectTo ([f5c6333](https://github.com/ionic-team/ionic/commit/f5c6333))
<a name="0.1.4-4"></a>
## [0.1.4-4](https://github.com/ionic-team/ionic/compare/v0.1.4-3...v0.1.4-4) (2018-03-08)
### Bug Fixes
* **back-button:** implements back animation ([64a787a](https://github.com/ionic-team/ionic/commit/64a787a))
* **route:** params is not undefined ([8b6df5a](https://github.com/ionic-team/ionic/commit/8b6df5a))
<a name="0.1.4-3"></a>
## [0.1.4-3](https://github.com/ionic-team/ionic/compare/v0.1.4-2...v0.1.4-3) (2018-03-08)
### Bug Fixes
* **router:** passing params to ion-nav ([d1263a8](https://github.com/ionic-team/ionic/commit/d1263a8))
### Features
* **back-button:** adds defaultHref ([5271f68](https://github.com/ionic-team/ionic/commit/5271f68))
* **nav:** params ([878d7e6](https://github.com/ionic-team/ionic/commit/878d7e6))
* **route:** adds route-link ([4a3030f](https://github.com/ionic-team/ionic/commit/4a3030f))
* **router:** reverse lookup with params ([3ce8a67](https://github.com/ionic-team/ionic/commit/3ce8a67))
<a name="0.1.4-2"></a>
## [0.1.4-2](https://github.com/ionic-team/ionic/compare/v0.1.4-0...v0.1.4-2) (2018-03-07)
### Bug Fixes
* **fab:** add side as a property for fab list ([7387d34](https://github.com/ionic-team/ionic/commit/7387d34))
* **ion-router:** fixes routing algorithm ([c8a27b7](https://github.com/ionic-team/ionic/commit/c8a27b7))
* **item:** href ([540c33b](https://github.com/ionic-team/ionic/commit/540c33b))
* **overlays:** bundling of overlays ([9650bec](https://github.com/ionic-team/ionic/commit/9650bec))
* **router:** invalid url ([c7fe694](https://github.com/ionic-team/ionic/commit/c7fe694))
* **routing:** flickering (part 1) ([7b264f9](https://github.com/ionic-team/ionic/commit/7b264f9))
* **tabs:** do not select when using router ([174d9b5](https://github.com/ionic-team/ionic/commit/174d9b5))
### Features
* **router:** adds parameters ([f29e3f4](https://github.com/ionic-team/ionic/commit/f29e3f4))
* **virtual-scroll:** adds JSX support ([dc8b363](https://github.com/ionic-team/ionic/commit/dc8b363))
<a name="0.1.4-1"></a>
## [0.1.4-1](https://github.com/ionic-team/ionic/compare/v0.1.4-0...v0.1.4-1) (2018-03-07)
### Bug Fixes
* **ion-router:** fixes routing algorithm ([c8a27b7](https://github.com/ionic-team/ionic/commit/c8a27b7))
* **overlays:** bundling of overlays ([9650bec](https://github.com/ionic-team/ionic/commit/9650bec))
* **routing:** flickering (part 1) ([7b264f9](https://github.com/ionic-team/ionic/commit/7b264f9))
* **tabs:** do not select when using router ([174d9b5](https://github.com/ionic-team/ionic/commit/174d9b5))
### Features
* **virtual-scroll:** adds JSX support ([dc8b363](https://github.com/ionic-team/ionic/commit/dc8b363))
<a name="0.1.4-0"></a>
## [0.1.4-0](https://github.com/ionic-team/ionic/compare/v0.1.3...v0.1.4-0) (2018-03-06)
### Refactor
- Refactored navigation system
### Bug Fixes
* **testing:** do not throw error for missing Ionic global ([aa91d11](https://github.com/ionic-team/ionic/commit/aa91d11))
* **zone:** forgot to remove console.logs ([4ec3e48](https://github.com/ionic-team/ionic/commit/4ec3e48))
<a name="0.1.3"></a>
## [0.1.3](https://github.com/ionic-team/ionic/compare/v0.1.2...v0.1.3) (2018-03-03)
### Performance Improvements
* Updates to latest stencil, that includes the zone bypassing abilities.
### Bug Fixes
* **ts:** ts strict fixes ([8ff02c7](https://github.com/ionic-team/ionic/commit/8ff02c7))
<a name="0.1.2"></a>
## [0.1.2](https://github.com/ionic-team/ionic/compare/v0.1.1...v0.1.2) (2018-03-03)
### Performance Improvements
* **events:** bypass ngzone ([7366c38](https://github.com/ionic-team/ionic/commit/7366c38))
* **scroll:** watchdog + simplification ([33a6274](https://github.com/ionic-team/ionic/commit/33a6274))
### Bug Fixes
* **scroll:** clearInterval just to be safe ([6da9882](https://github.com/ionic-team/ionic/commit/6da9882))
<a name="0.1.1"></a>
## [0.1.1](https://github.com/ionic-team/ionic/commit/291e85e61128b2f3101d9cea6b42d4cf751dc481) (2018-03-01)
### Bug Fixes
* **button:** pass the property type instead of hardcoding button ([10e481a](https://github.com/ionic-team/ionic/commit/10e481a))
<a name="0.1.0"></a>
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)

View File

@@ -1,17 +0,0 @@
import { Component, Prop } from '@stencil/core';
import { openURL } from '../../utils/theme';
@Component({
tag: 'ion-anchor'
})
export class Anchor {
@Prop() href: string;
render() {
return <a
href={this.href}
onClick={(ev) => openURL(this.href, ev)}><slot/></a>;
}
}

View File

@@ -1,71 +0,0 @@
import { Component, Element, Prop } from '@stencil/core';
import { Config } from '../../index';
import { openURL } from '../../utils/theme';
@Component({
tag: 'ion-back-button',
styleUrls: {
ios: 'back-button.ios.scss',
md: 'back-button.md.scss'
},
host: {
theme: 'back-button'
}
})
export class BackButton {
/**
* The mode determines which platform styles to use.
* Possible values are: `"ios"` or `"md"`.
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@Prop() mode: 'ios' | 'md';
/**
* The text property is used to provide custom text for the back button while using the
* default look-and-feel
*/
@Prop() text: string|undefined;
@Prop() icon: string;
@Prop() defaultHref: string;
@Prop({ context: 'config' }) config: Config;
@Element() el: HTMLElement;
hostData() {
return {
class: {
'show-back-button': !!this.defaultHref
}
};
}
private onClick(ev: Event) {
const nav = this.el.closest('ion-nav');
if (nav && nav.canGoBack()) {
ev.preventDefault();
nav.pop();
} else if (this.defaultHref) {
openURL(this.defaultHref, ev, true);
}
}
render() {
const backButtonIcon = this.icon || this.config.get('backButtonIcon', 'arrow-back');
const backButtonText = this.text || this.config.get('backButtonText', this.mode === 'ios' ? 'Back' : '');
return (
<button
class='back-button-inner'
onClick={(ev) => this.onClick(ev)}>
{ backButtonIcon && <ion-icon name={backButtonIcon}/> }
{ backButtonText && <span class='button-text'>{backButtonText}</span> }
{ this.mode === 'md' && <ion-ripple-effect/> }
</button>
);
}
}

View File

@@ -1,19 +0,0 @@
'use strict';
const { By, until } = require('selenium-webdriver');
const { register, Page, platforms } = require('../../../../../scripts/e2e');
class E2ETestPage extends Page {
constructor(driver, platform) {
super(driver, `http://localhost:3333/src/components/list/test/inset?ionicplatform=${platform}`);
}
}
platforms.forEach(platform => {
describe('list/inset', () => {
register('should init', driver => {
const page = new E2ETestPage(driver, platform);
return page.navigate('#content');
});
});
});

View File

@@ -1,70 +0,0 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>List - Basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>List - Inset</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content">
<ion-list inset>
<ion-item>
<ion-label>Normal Input</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Stacked Input</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item>
<ion-label>Normal Select</ion-label>
<ion-select>
<ion-select-option>1</ion-select-option>
<ion-select-option>2</ion-select-option>
<ion-select-option>3</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label stacked>Stacked Select</ion-label>
<ion-select>
<ion-select-option>1</ion-select-option>
<ion-select-option>2</ion-select-option>
<ion-select-option>3</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Normal Datetime</ion-label>
<ion-datetime></ion-datetime>
</ion-item>
<ion-item>
<ion-label stacked>Stacked Datetime</ion-label>
<ion-datetime></ion-datetime>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<style>
ion-content .scroll {
background: #e5e5e5;
}
</style>
</body>
</html>

View File

@@ -1,236 +0,0 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, Config, FrameworkDelegate } from '../../index';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import { BACKDROP, OverlayEventDetail, OverlayInterface, attachComponent, dismiss, eventMethod, present } from '../../utils/overlays';
import iosEnterAnimation from './animations/ios.enter';
import iosLeaveAnimation from './animations/ios.leave';
import mdEnterAnimation from './animations/md.enter';
import mdLeaveAnimation from './animations/md.leave';
@Component({
tag: 'ion-modal',
styleUrls: {
ios: 'modal.ios.scss',
md: 'modal.md.scss'
},
host: {
theme: 'modal'
}
})
export class Modal implements OverlayInterface {
private usersElement: HTMLElement;
animation: Animation|undefined;
presented = false;
@Element() el: HTMLElement;
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: HTMLIonAnimationControllerElement;
@Prop({ context: 'config' }) config: Config;
@Prop() overlayId: number;
@Prop() delegate: FrameworkDelegate;
/**
* The color to use from your Sass `$colors` map.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information, see [Theming your App](/docs/theming/theming-your-app).
*/
@Prop() color: string;
/**
* The mode determines which platform styles to use.
* Possible values are: `"ios"` or `"md"`.
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@Prop() mode: 'ios' | 'md';
/**
* Animation to use when the modal is presented.
*/
@Prop() enterAnimation: AnimationBuilder;
/**
* Animation to use when the modal is dismissed.
*/
@Prop() leaveAnimation: AnimationBuilder;
/**
* The component to display inside of the modal.
*/
@Prop() component: any;
/**
* The data to pass to the modal component.
*/
@Prop() data: any = {};
/**
* Additional classes to apply for custom CSS. If multiple classes are
* provided they should be separated by spaces.
*/
@Prop() cssClass: string;
/**
* If true, the modal will be dismissed when the backdrop is clicked. Defaults to `true`.
*/
@Prop() enableBackdropDismiss = true;
/**
* If true, a backdrop will be displayed behind the modal. Defaults to `true`.
*/
@Prop() showBackdrop = true;
/**
* If true, the modal will animate. Defaults to `true`.
*/
@Prop() willAnimate = true;
/**
* Emitted after the modal has loaded.
*/
@Event() ionModalDidLoad: EventEmitter<void>;
/**
* Emitted after the modal has unloaded.
*/
@Event() ionModalDidUnload: EventEmitter<void>;
/**
* Emitted after the modal has presented.
*/
@Event({eventName: 'ionModalDidPresent'}) didPresent: EventEmitter<void>;
/**
* Emitted before the modal has presented.
*/
@Event({eventName: 'ionModalWillPresent'}) willPresent: EventEmitter<void>;
/**
* Emitted before the modal has dismissed.
*/
@Event({eventName: 'ionModalWillDismiss'}) willDismiss: EventEmitter<OverlayEventDetail>;
/**
* Emitted after the modal has dismissed.
*/
@Event({eventName: 'ionModalDidDismiss'}) didDismiss: EventEmitter<OverlayEventDetail>;
componentDidLoad() {
this.ionModalDidLoad.emit();
}
componentDidUnload() {
this.ionModalDidUnload.emit();
}
@Listen('ionDismiss')
protected onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
@Listen('ionBackdropTap')
protected onBackdropTap() {
this.dismiss(null, BACKDROP);
}
@Listen('ionModalDidPresent')
@Listen('ionModalWillPresent')
@Listen('ionModalWillDismiss')
@Listen('ionModalDidDismiss')
protected lifecycle(modalEvent: CustomEvent) {
const el = this.usersElement;
const name = LIFECYCLE_MAP[modalEvent.type];
if (el && name) {
const event = new CustomEvent(name, {
bubbles: false,
cancelable: false,
detail: modalEvent.detail
});
el.dispatchEvent(event);
}
}
/**
* Present the modal overlay after it has been created.
*/
@Method()
present(): Promise<void> {
if (this.presented) {
return Promise.resolve();
}
const container = this.el.querySelector(`.modal-wrapper`);
const data = {
...this.data,
modal: this.el
};
const classes = {
...getClassMap(this.cssClass),
'ion-page': true
};
return attachComponent(this.delegate, container, this.component, classes, data)
.then(el => this.usersElement = el)
.then(() => present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, undefined));
}
/**
* Dismiss the modal overlay after it has been presented.
*/
@Method()
dismiss(data?: any, role?: string): Promise<void> {
return dismiss(this, data, role, 'modalLeave', iosLeaveAnimation, mdLeaveAnimation, undefined);
}
@Method()
onDidDismiss(callback: (data?: any, role?: string) => void): Promise<OverlayEventDetail> {
return eventMethod(this.el, 'ionModalDidDismiss', callback);
}
@Method()
onWillDismiss(callback: (data?: any, role?: string) => void): Promise<OverlayEventDetail> {
return eventMethod(this.el, 'ionModalWillDismiss', callback);
}
hostData() {
return {
'no-router': true,
style: {
zIndex: 20000 + this.overlayId,
}
};
}
render() {
const dialogClasses = createThemedClasses(this.mode, this.color, 'modal-wrapper');
return [
<ion-backdrop visible={this.showBackdrop} tappable={this.enableBackdropDismiss}/>,
<div role='dialog' class={dialogClasses}></div>
];
}
}
const LIFECYCLE_MAP: any = {
'ionModalDidPresent': 'ionViewDidEnter',
'ionModalWillPresent': 'ionViewWillEnter',
'ionModalWillDismiss': 'ionViewWillDismiss',
'ionModalDidDismiss': 'ionViewDidDismiss',
};
export interface ModalOptions {
component: any;
data?: any;
showBackdrop?: boolean;
enableBackdropDismiss?: boolean;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
cssClass?: string;
delegate?: FrameworkDelegate;
}

View File

@@ -1,121 +0,0 @@
import { ViewController, isViewController } from './view-controller';
import { NavControllerBase } from './nav';
import { Transition } from './transition';
export function convertToView(page: any, params: any): ViewController {
if (!page) {
return null;
}
if (isViewController(page)) {
return page;
}
return new ViewController(page, params);
}
export function convertToViews(pages: any[]): ViewController[] {
return pages.map(page => {
if (isViewController(page)) {
return page;
}
if ('page' in page) {
return convertToView(page.page, page.params);
}
return convertToView(page, undefined);
})
.filter(v => v !== null);
}
export function setZIndex(nav: NavControllerBase, enteringView: ViewController, leavingView: ViewController, direction: string) {
if (enteringView) {
leavingView = leavingView || nav.getPrevious(enteringView);
if (leavingView && isPresent(leavingView._zIndex)) {
if (direction === NavDirection.back) {
enteringView._setZIndex(leavingView._zIndex - 1);
} else {
enteringView._setZIndex(leavingView._zIndex + 1);
}
} else {
enteringView._setZIndex(INIT_ZINDEX);
}
}
}
export function isPresent(val: any): val is any {
return val !== undefined && val !== null;
}
export const enum ViewState {
New = 1,
Initialized,
Attached,
Destroyed
}
export const enum NavDirection {
back = 'back',
forward = 'forward'
}
export const INIT_ZINDEX = 100;
export type NavParams = {[key: string]: any};
export interface NavResult {
hasCompleted: boolean;
requiresTransition: boolean;
enteringName?: string;
leavingName?: string;
direction?: string;
}
export interface NavOptions {
animate?: boolean;
animation?: string;
direction?: string;
duration?: number;
easing?: string;
id?: string;
keyboardClose?: boolean;
progressAnimation?: boolean;
disableApp?: boolean;
minClickBlockDuration?: number;
ev?: any;
updateUrl?: boolean;
isNavRoot?: boolean;
viewIsReady?: () => Promise<any>;
}
export interface Page extends Function {
new (...args: any[]): any;
}
export interface TransitionResolveFn {
(hasCompleted: boolean, requiresTransition: boolean, enteringName?: string, leavingName?: string, direction?: string): void;
}
export interface TransitionRejectFn {
(rejectReason: any, transition?: Transition): void;
}
export interface TransitionDoneFn {
(hasCompleted: boolean, requiresTransition: boolean, enteringName?: string, leavingName?: string, direction?: string): void;
}
export interface TransitionInstruction {
opts: NavOptions;
insertStart?: number;
insertViews?: any[];
removeView?: ViewController;
removeStart?: number;
removeCount?: number;
resolve?: (hasCompleted: boolean) => void;
reject?: (rejectReason: string) => void;
done?: TransitionDoneFn;
leavingRequiresTransition?: boolean;
enteringRequiresTransition?: boolean;
requiresTransition?: boolean;
}

View File

@@ -1,25 +0,0 @@
import { Component, Event, Prop } from '@stencil/core';
import { EventEmitter } from 'ionicons/dist/types/stencil.core';
@Component({
tag: 'ion-route'
})
export class Route {
@Prop() url = '';
@Prop() component: string;
@Prop() redirectTo: string;
@Prop() componentProps: {[key: string]: any};
@Event() ionRouteDataChanged: EventEmitter;
componentDidLoad() {
this.ionRouteDataChanged.emit();
}
componentDidUnload() {
this.ionRouteDataChanged.emit();
}
componentDidUpdate() {
this.ionRouteDataChanged.emit();
}
}

View File

@@ -1,157 +0,0 @@
import { Build, Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Config, DomController } from '../../index';
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
import { readNavState, writeNavState } from './utils/dom';
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
import { RouteChain, RouteRedirect, RouterEventDetail } from './utils/interfaces';
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
import { printRoutes } from './utils/debug';
@Component({
tag: 'ion-router'
})
export class Router {
private routes: RouteChain[];
private previousPath: string = null;
private redirects: RouteRedirect[];
private busy = false;
private init = false;
private state = 0;
private timer: any;
@Element() el: HTMLElement;
@Prop({ context: 'config' }) config: Config;
@Prop({ context: 'dom' }) dom: DomController;
@Prop() base = '';
@Prop() useHash = true;
@Event() ionRouteChanged: EventEmitter<RouterEventDetail>;
componentDidLoad() {
this.init = true;
this.onRouteChanged();
}
@Listen('ionRouteDataChanged')
protected onRouteChanged() {
if (!this.init) {
return;
}
const tree = readRoutes(this.el);
this.routes = flattenRouterTree(tree);
this.redirects = readRedirects(this.el);
if (Build.isDev) {
printRoutes(this.routes);
}
// schedule write
if (this.timer) {
cancelAnimationFrame(this.timer);
this.timer = undefined;
}
this.timer = requestAnimationFrame(() => {
this.timer = undefined;
this.onPopState();
});
}
@Listen('window:popstate')
protected onPopState() {
if (window.history.state === null) {
this.state++;
window.history.replaceState(this.state, document.title, document.location.href);
}
this.writeNavStateRoot(this.getPath());
}
@Method()
navChanged(isPop: boolean): Promise<boolean> {
if (this.busy) {
return Promise.resolve(false);
}
console.debug('[IN] nav changed -> update URL');
const { ids, pivot } = readNavState(document.body);
const chain = routerIDsToChain(ids, this.routes);
if (!chain) {
console.warn('no matching URL for ', ids.map(i => i.id));
return Promise.resolve(false);
}
const path = chainToPath(chain);
this.setPath(path, isPop);
const promise = (chain.length > ids.length)
? this.writeNavState(pivot, chain.slice(ids.length), 0)
: Promise.resolve(true);
return promise.then(() => {
this.emitRouteChange(path, null);
return true;
});
}
@Method()
push(url: string, backDirection = false) {
const path = parsePath(url);
this.setPath(path, backDirection);
return this.writeNavStateRoot(path);
}
private writeNavStateRoot(path: string[]): Promise<boolean> {
if (this.busy) {
return Promise.resolve(false);
}
const redirect = routeRedirect(path, this.redirects);
let redirectFrom: string[] = null;
if (redirect) {
this.setPath(redirect.to, true);
redirectFrom = redirect.path;
path = redirect.to;
}
const direction = window.history.state >= this.state ? 1 : -1;
const chain = routerPathToChain(path, this.routes);
return this.writeNavState(document.body, chain, direction).then(changed => {
if (changed) {
this.emitRouteChange(path, redirectFrom);
}
return changed;
});
}
private writeNavState(node: any, chain: RouteChain, direction: number): Promise<boolean> {
if (this.busy) {
return Promise.resolve(false);
}
this.busy = true;
return writeNavState(node, chain, 0, direction).then(changed => {
this.busy = false;
return changed;
});
}
private setPath(path: string[], isPop: boolean) {
this.state++;
writePath(window.history, this.base, this.useHash, path, isPop, this.state);
}
private getPath(): string[] | null {
return readPath(window.location, this.base, this.useHash);
}
private emitRouteChange(path: string[], redirectPath: string[]|null) {
const from = this.previousPath;
const redirectedFrom = redirectPath ? generatePath(redirectPath) : null;
const to = generatePath(path);
this.previousPath = to;
this.ionRouteChanged.emit({
from,
redirectedFrom,
to: to
});
}
}

View File

@@ -1,361 +0,0 @@
import { RouteChain } from '../utils/interfaces';
import { RouterSegments, matchesIDs, matchesPath, mergeParams, routerPathToChain } from '../utils/matching';
import { parsePath } from '../utils/path';
const CHAIN_1: RouteChain = [
{ id: '2', path: ['to'], params: undefined },
{ id: '1', path: ['path'], params: undefined },
{ id: '3', path: ['segment'], params: undefined },
{ id: '4', path: [''], params: undefined },
];
const CHAIN_2: RouteChain = [
{ id: '2', path: [''], params: undefined },
{ id: '1', path: [''], params: undefined },
{ id: '3', path: ['segment', 'to'], params: undefined },
{ id: '4', path: [''], params: undefined },
{ id: '5', path: ['hola'], params: undefined },
{ id: '6', path: [''], params: undefined },
{ id: '7', path: [''], params: undefined },
{ id: '8', path: ['adios', 'que', 'tal'], params: undefined },
];
const CHAIN_3: RouteChain = [
{ id: '2', path: ['this', 'to'], params: undefined },
{ id: '1', path: ['path'], params: undefined },
{ id: '3', path: ['segment', 'to', 'element'], params: undefined },
{ id: '4', path: [''], params: undefined },
];
describe('matchesIDs', () => {
it('should match simple set of ids', () => {
const chain: RouteChain = CHAIN_1;
expect(matchesIDs(['2'], chain)).toBe(1);
expect(matchesIDs(['2', '1'], chain)).toBe(2);
expect(matchesIDs(['2', '1', '3'], chain)).toBe(3);
expect(matchesIDs(['2', '1', '3', '4'], chain)).toBe(4);
expect(matchesIDs(['2', '1', '3', '4', '5'], chain)).toBe(4);
expect(matchesIDs([], chain)).toBe(0);
expect(matchesIDs(['1'], chain)).toBe(0);
});
});
describe('matchesPath', () => {
it('should match simple path', () => {
const chain: RouteChain = CHAIN_3;
expect(matchesPath(['this'], chain)).toEqual(null);
expect(matchesPath(['this', 'to'], chain)).toEqual(null);
expect(matchesPath(['this', 'to', 'path'], chain)).toEqual(null);
expect(matchesPath(['this', 'to', 'path', 'segment'], chain)).toEqual(null);
expect(matchesPath(['this', 'to', 'path', 'segment', 'to'], chain)).toEqual(null);
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element'], chain)).toEqual(chain);
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element', 'more'], chain)).toEqual(null);
expect(matchesPath([], chain)).toEqual(null);
expect(matchesPath([''], chain)).toEqual(null);
expect(matchesPath(['path'], chain)).toEqual(null);
});
it('should match simple default route', () => {
const chain: RouteChain = CHAIN_2;
expect(matchesPath([''], chain)).toEqual(null);
expect(matchesPath(['segment'], chain)).toEqual(null);
expect(matchesPath(['segment', 'to'], chain)).toEqual(null);
expect(matchesPath(['segment', 'to', 'hola'], chain)).toEqual(null);
expect(matchesPath(['segment', 'to', 'hola', 'adios'], chain)).toEqual(null);
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que'], chain)).toEqual(null);
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que', 'tal'], chain)).toEqual(chain);
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que', 'tal', 'more'], chain)).toEqual(chain);
expect(matchesPath(['to'], chain)).toEqual(null);
expect(matchesPath(['path', 'to'], chain)).toEqual(null);
});
it('should match simple route 2', () => {
const chain: RouteChain = [{ id: '5', path: ['hola'], params: undefined }];
expect(matchesPath([''], chain)).toEqual(null);
expect(matchesPath(['hola'], chain)).toEqual(chain);
expect(matchesPath(['hola', 'hola'], chain)).toEqual(chain);
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
});
it('should match simple route 3', () => {
const chain: RouteChain = [{ id: '5', path: ['hola', 'adios'], params: undefined }];
expect(matchesPath([''], chain)).toEqual(null);
expect(matchesPath(['hola'], chain)).toEqual(null);
expect(matchesPath(['hola', 'hola'], chain)).toEqual(null);
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
expect(matchesPath(['hola', 'adios', 'bye'], chain)).toEqual(chain);
});
it('should match simple route 4', () => {
const chain: RouteChain = [
{ id: '5', path: ['hola'], params: undefined },
{ id: '5', path: ['adios'], params: undefined }];
expect(matchesPath([''], chain)).toEqual(null);
expect(matchesPath(['hola'], chain)).toEqual(null);
expect(matchesPath(['hola', 'hola'], chain)).toEqual(null);
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
});
it('should match with parameters', () => {
const chain: RouteChain = [
{ id: '5', path: ['profile', ':name'], params: undefined },
{ id: '5', path: [''], params: undefined },
{ id: '5', path: ['image'], params: {size: 'lg'} },
{ id: '5', path: ['image', ':size', ':type'], params: {size: 'mg'} },
];
const matched = matchesPath(parsePath('/profile/manu/image/image/large/retina'), chain);
expect(matched).toEqual([
{ id: '5', path: ['profile', ':name'], params: {name: 'manu'} },
{ id: '5', path: [''], params: undefined },
{ id: '5', path: ['image'], params: {size: 'lg'} },
{ id: '5', path: ['image', ':size', ':type'], params: {size: 'large', type: 'retina'} },
]);
});
});
describe('routerPathToChain', () => {
it('should match the route with higher priority', () => {
const chain3: RouteChain = [{ id: '5', path: ['hola'], params: undefined }];
const chain4: RouteChain = [
{ id: '5', path: ['hola'], params: undefined },
{ id: '5', path: ['adios'], params: undefined }];
const routes: RouteChain[] = [
CHAIN_1,
CHAIN_2,
chain3,
chain4
];
expect(routerPathToChain(['to'], routes)).toEqual(null);
expect(routerPathToChain([''], routes)).toEqual(null);
expect(routerPathToChain(['segment', 'to'], routes)).toEqual(null);
expect(routerPathToChain(['hola'], routes)).toEqual(chain3);
expect(routerPathToChain(['hola', 'hola'], routes)).toEqual(chain3);
expect(routerPathToChain(['hola', 'adios'], routes)).toEqual(chain4);
});
it('should match the route with higher priority 2', () => {
const chain1: RouteChain = [{ id: '1', path: ['categories', ':category_slug'], params: undefined }];
const chain2: RouteChain = [{ id: '2', path: ['workouts', ':workout_slug'], params: undefined }];
const chain3: RouteChain = [{ id: '3', path: ['workouts', ':workout_slug', 'time-select'], params: undefined }];
const chain4: RouteChain = [{ id: '4', path: ['workouts', ':workout_slug', 'end-workout'], params: undefined }];
const chain5: RouteChain = [{ id: '5', path: ['plans'], params: undefined }];
const chain6: RouteChain = [{ id: '6', path: ['custom'], params: undefined }];
const chain7: RouteChain = [{ id: '7', path: ['workouts', 'list'], params: undefined }];
const routes: RouteChain[] = [
chain1,
chain2,
chain3,
chain4,
chain5,
chain6,
chain7
];
// no match
expect(routerPathToChain(['categories'], routes)).toEqual(null);
expect(routerPathToChain(['workouts'], routes)).toEqual(null);
expect(routerPathToChain(['plans'], routes)).toEqual(chain5);
expect(routerPathToChain(['custom'], routes)).toEqual(chain6);
expect(routerPathToChain(['workouts', 'list'], routes)).toEqual(chain7);
expect(routerPathToChain(['workouts', 'hola'], routes)).toEqual(
[{ id: '2', path: ['workouts', ':workout_slug'], params: {'workout_slug': 'hola'} }]
);
expect(routerPathToChain(['workouts', 'hello', 'time-select'], routes)).toEqual(
[{ id: '3', path: ['workouts', ':workout_slug', 'time-select'], params: {'workout_slug': 'hello'} }]
);
expect(routerPathToChain(['workouts', 'hello2', 'end-workout'], routes)).toEqual(
[{ id: '4', path: ['workouts', ':workout_slug', 'end-workout'], params: {'workout_slug': 'hello2'} }]
);
});
it('should match the default route', () => {
const chain1: RouteChain = [
{ id: 'tabs', path: [''], params: undefined },
{ id: 'tab1', path: [''], params: undefined },
{ id: 'schedule', path: [''], params: undefined }
];
const chain2: RouteChain = [
{ id: 'tabs', path: [''], params: undefined },
{ id: 'tab2', path: ['tab2'], params: undefined },
{ id: 'page2', path: [''], params: undefined }
];
expect(routerPathToChain([''], [chain1])).toEqual(chain1);
expect(routerPathToChain(['tab2'], [chain1])).toEqual(null);
expect(routerPathToChain([''], [chain2])).toEqual(null);
expect(routerPathToChain(['tab2'], [chain2])).toEqual(chain2);
});
});
describe('mergeParams', () => {
it('should merge undefined', () => {
expect(mergeParams(undefined, undefined)).toBeUndefined();
expect(mergeParams(null, undefined)).toBeUndefined();
expect(mergeParams(undefined, null)).toBeUndefined();
expect(mergeParams(null, null)).toBeUndefined();
});
it('should merge undefined with params', () => {
const params = {data: '1'};
expect(mergeParams(undefined, params)).toEqual(params);
expect(mergeParams(null, params)).toEqual(params);
expect(mergeParams(params, undefined)).toEqual(params);
expect(mergeParams(params, null)).toEqual(params);
});
it('should merge params with params', () => {
const params1 = {data: '1', data3: 'hello'};
const params2 = {data: '2', data2: 'hola'};
expect(mergeParams(params1, params2)).toEqual({
data: '2',
data2: 'hola',
data3: 'hello'
});
expect(params1).toEqual({data: '1', data3: 'hello'});
expect(params2).toEqual({data: '2', data2: 'hola'});
});
});
describe('RouterSegments', () => {
it ('should initialize with empty array', () => {
const s = new RouterSegments([]);
expect(s.next()).toEqual('');
expect(s.next()).toEqual('');
expect(s.next()).toEqual('');
expect(s.next()).toEqual('');
expect(s.next()).toEqual('');
});
it ('should initialize with array', () => {
const s = new RouterSegments(['', 'path', 'to', 'destination']);
expect(s.next()).toEqual('');
expect(s.next()).toEqual('path');
expect(s.next()).toEqual('to');
expect(s.next()).toEqual('destination');
expect(s.next()).toEqual('');
expect(s.next()).toEqual('');
});
});
// describe('matchRoute', () => {
// it('should match simple route', () => {
// const path = ['path', 'to', 'component'];
// const routes: RouteChain[] = [
// [{ id: 2, path: ['to'], params: undefined }],
// [{ id: 1, path: ['path'], params: undefined }],
// [{ id: 3, path: ['segment'], params: undefined }],
// [{ id: 4, path: [''], params: undefined }],
// ];
// const match = routerPathToChain(path, routes);
// expect(match).toEqual({ id: 1, path: ['path'], children: [] });
// expect(seg.next()).toEqual('to');
// });
// it('should match default route', () => {
// const routes: RouteTree = [
// { id: 2, path: ['to'], children: [], params: undefined },
// { id: 1, path: ['path'], children: [], params: undefined },
// { id: 3, path: ['segment'], children: [], params: undefined },
// { id: 4, path: [''], children: [], params: undefined },
// ];
// const seg = new RouterSegments(['hola', 'path']);
// let match = matchRoute(seg, routes);
// expect(match).toBeNull();
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(1);
// for (let i = 0; i < 20; i++) {
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(4);
// }
// });
// it('should not match any route', () => {
// const routes: RouteTree = [
// { id: 2, path: ['to', 'to', 'to'], children: [], params: undefined },
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
// { id: 3, path: ['hola', 'adam'], children: [], params: undefined },
// { id: 4, path: [''], children: [], params: undefined },
// ];
// const seg = new RouterSegments(['hola', 'manu', 'adam']);
// const match = matchRoute(seg, routes);
// expect(match).toBeNull();
// });
// it('should not match if there are not routes', () => {
// const routes: RouteTree = [];
// const seg = new RouterSegments(['adam']);
// expect(matchRoute(seg, routes)).toBeNull();
// expect(matchRoute(seg, routes)).toBeNull();
// expect(matchRoute(seg, routes)).toBeNull();
// });
// it('should not match any route (2)', () => {
// const routes: RouteTree = [
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
// { id: 3, path: ['hola', 'adam'], children: [], params: undefined },
// ];
// const seg = new RouterSegments(['adam']);
// expect(matchRoute(seg, routes)).toBeNull();
// expect(matchRoute(seg, routes)).toBeNull();
// expect(matchRoute(seg, routes)).toBeNull();
// });
// it ('should match multiple segments', () => {
// const routes: RouteTree = [
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
// { id: 2, path: ['manu', 'hello'], children: [], params: undefined },
// { id: 3, path: ['hello'], children: [], params: undefined },
// { id: 4, path: [''], children: [], params: undefined },
// ];
// const seg = new RouterSegments(['adam', 'manu', 'hello', 'manu', 'hello']);
// let match = matchRoute(seg, routes);
// expect(match.id).toEqual(1);
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(3);
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(2);
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(4);
// match = matchRoute(seg, routes);
// expect(match.id).toEqual(4);
// });
// it('should match long multi segments', () => {
// const routes: RouteTree = [
// { id: 1, path: ['adam', 'manu', 'hello', 'menu', 'hello'], children: [], params: undefined },
// { id: 2, path: ['adam', 'manu', 'hello', 'menu'], children: [], params: undefined },
// { id: 3, path: ['adam', 'manu'], children: [], params: undefined },
// ];
// const seg = new RouterSegments(['adam', 'manu', 'hello', 'menu', 'hello']);
// const match = matchRoute(seg, routes);
// expect(match.id).toEqual(1);
// expect(matchRoute(seg, routes)).toBeNull();
// });
// it('should match long multi segments', () => {
// let match = matchRoute(new RouterSegments(['']), null);
// expect(match).toBeNull();
// match = matchRoute(new RouterSegments(['hola']), null);
// expect(match).toBeNull();
// });
// });

View File

@@ -1,12 +0,0 @@
import { generatePath } from './path';
import { RouteChain } from './interfaces';
export function printRoutes(routes: RouteChain[]) {
console.debug('%c[@ionic/core]', 'font-weight: bold', `ion-router registered ${routes.length} routes`);
for (const chain of routes) {
const path: string[] = [];
chain.forEach(r => path.push(...r.path));
const ids = chain.map(r => r.id);
console.debug(`%c ${generatePath(path)}`, 'font-weight: bold; padding-left: 20px', '=>\t', `(${ids.join(', ')})`);
}
}

View File

@@ -1,60 +0,0 @@
import { NavOutlet, NavOutletElement, RouteChain, RouteID } from './interfaces';
export function writeNavState(root: HTMLElement, chain: RouteChain|null, index: number, direction: number): Promise<boolean> {
if (!chain || index >= chain.length) {
return Promise.resolve(direction === 0);
}
const route = chain[index];
const node = searchNavNode(root);
if (!node) {
return Promise.resolve(direction === 0);
}
return node.componentOnReady()
.then(() => node.setRouteId(route.id, route.params, direction))
.then(result => {
if (result.changed) {
direction = 0;
}
const nextEl = node.getContainerEl();
const promise = (nextEl)
? writeNavState(nextEl, chain, index + 1, direction)
: Promise.resolve(direction === 0);
if (result.markVisible) {
return promise.then((c) => {
result.markVisible();
return c;
});
}
return promise;
});
}
export function readNavState(node: HTMLElement) {
const ids: RouteID[] = [];
let pivot: NavOutlet|null;
while (true) {
pivot = searchNavNode(node);
if (pivot) {
const id = pivot.getRouteId();
if (id) {
node = pivot.getContainerEl();
ids.push(id);
} else {
break;
}
} else {
break;
}
}
return {ids, pivot};
}
const QUERY = ':not([no-router]) ion-nav,:not([no-router]) ion-tabs';
function searchNavNode(root: HTMLElement): NavOutletElement {
if (root.matches(QUERY)) {
return root as NavOutletElement;
}
return root.querySelector(QUERY);
}

View File

@@ -1,43 +0,0 @@
export interface NavOutlet {
setRouteId(id: string, data: any, direction: number): Promise<RouteWrite>;
getRouteId(): RouteID|null;
getContainerEl(): HTMLElement | null;
}
export interface RouterEventDetail {
from: string|null;
redirectedFrom: string|null;
to: string;
}
export interface RouteRedirect {
path: string[];
to: string[];
}
export interface RouteWrite {
changed: boolean;
markVisible?: () => void|Promise<void>;
}
export interface RouteID {
id: string;
params?: any;
}
export type NavOutletElement = NavOutlet & HTMLStencilElement;
export interface RouteEntry {
id: string;
path: string[];
params: any|undefined;
}
export interface RouteNode extends RouteEntry {
children: RouteTree;
}
export type RouteChain = RouteEntry[];
export type RouteTree = RouteNode[];

View File

@@ -1,164 +0,0 @@
import { RouteChain, RouteID, RouteRedirect } from './interfaces';
export function matchesRedirect(input: string[], route: RouteRedirect): boolean {
const {path} = route;
if (path.length !== input.length) {
return false;
}
for (let i = 0; i < path.length; i++) {
if (path[i] !== input[i]) {
return false;
}
}
return true;
}
export function routeRedirect(path: string[], routes: RouteRedirect[]): RouteRedirect|null {
for (const route of routes) {
if (matchesRedirect(path, route)) {
return route;
}
}
return null;
}
export function matchesIDs(ids: string[], chain: RouteChain): number {
const len = Math.min(ids.length, chain.length);
let i = 0;
for (; i < len; i++) {
if (ids[i].toLowerCase() !== chain[i].id) {
break;
}
}
return i;
}
export function matchesPath(path: string[], chain: RouteChain): RouteChain | null {
const segments = new RouterSegments(path);
let matchesDefault = false;
let allparams: any[];
for (let i = 0; i < chain.length; i++) {
const path = chain[i].path;
if (path[0] === '') {
matchesDefault = true;
} else {
for (const segment of path) {
const data = segments.next();
// data param
if (segment[0] === ':') {
if (data === '') {
return null;
}
allparams = allparams || [];
const params = allparams[i] || (allparams[i] = {});
params[segment.slice(1)] = data;
} else if (data !== segment) {
return null;
}
}
matchesDefault = false;
}
}
const matches = (matchesDefault)
? matchesDefault === (segments.next() === '')
: true;
if (!matches) {
return null;
}
if (allparams) {
return chain.map((route, i) => ({
id: route.id,
path: route.path,
params: mergeParams(route.params, allparams[i])
}));
}
return chain;
}
export function mergeParams(a: any, b: any): any {
if (!a && b) {
return b;
} else if (a && !b) {
return a;
} else if (a && b) {
return {
...a,
...b
};
}
return undefined;
}
export function routerIDsToChain(ids: RouteID[], chains: RouteChain[]): RouteChain|null {
let match: RouteChain|null = null;
let maxMatches = 0;
const plainIDs = ids.map(i => i.id);
for (const chain of chains) {
const score = matchesIDs(plainIDs, chain);
if (score > maxMatches) {
match = chain;
maxMatches = score;
}
}
if (match) {
return match.map((route, i) => ({
id: route.id,
path: route.path,
params: mergeParams(route.params, ids[i] && ids[i].params)
}));
}
return null;
}
export function routerPathToChain(path: string[], chains: RouteChain[]): RouteChain|null {
let match: RouteChain = null;
let matches = 0;
for (const chain of chains) {
const matchedChain = matchesPath(path, chain);
if (matchedChain !== null) {
const score = computePriority(matchedChain);
if (score > matches) {
matches = score;
match = matchedChain;
}
}
}
return match;
}
export function computePriority(chain: RouteChain): number {
let score = 1;
let level = 1;
for (const route of chain) {
for (const path of route.path) {
if (path[0] === ':') {
score += Math.pow(1, level);
} else if (path !== '') {
score += Math.pow(2, level);
}
level++;
}
}
return score;
}
export class RouterSegments {
private path: string[];
constructor(path: string[]) {
this.path = path.slice();
}
next(): string {
if (this.path.length > 0) {
return this.path.shift() as string;
}
return '';
}
}

View File

@@ -1,5 +0,0 @@
export interface FrameworkDelegate {
attachViewToDom(container: any, component: any, propsOrDataObj?: any, cssClasses?: string[]): Promise<any>;
removeViewFromDom(container: any, component: any): Promise<void>;
}

View File

@@ -1,76 +0,0 @@
import { EventEmitter } from '@stencil/core';
export function clamp(min: number, n: number, max: number) {
return Math.max(min, Math.min(n, max));
}
export function isDef(v: any): boolean { return v !== undefined && v !== null; }
export function assert(actual: any, reason: string) {
if (!actual) {
const message = 'ASSERT: ' + reason;
console.error(message);
debugger; // tslint:disable-line
throw new Error(message);
}
}
export function now(ev: UIEvent) {
return ev.timeStamp || Date.now();
}
export function pointerCoord(ev: any): {x: number, y: number} {
// get X coordinates for either a mouse click
// or a touch depending on the given event
if (ev) {
const changedTouches = ev.changedTouches;
if (changedTouches && changedTouches.length > 0) {
const touch = changedTouches[0];
return {x: touch.clientX, y: touch.clientY};
}
if (ev.pageX !== undefined) {
return {x: ev.pageX, y: ev.pageY};
}
}
return {x: 0, y: 0};
}
export type Side = 'left' | 'right' | 'start' | 'end';
/**
* @hidden
* Given a side, return if it should be on the right
* based on the value of dir
* @param side the side
* @param isRTL whether the application dir is rtl
* @param defaultRight whether the default side is right
*/
export function isRightSide(side: Side, defaultRight = false): boolean {
const isRTL = document.dir === 'rtl';
switch (side) {
case 'right': return true;
case 'left': return false;
case 'end': return !isRTL;
case 'start': return isRTL;
default: return defaultRight ? !isRTL : isRTL;
}
}
export function deferEvent(event: EventEmitter): EventEmitter {
return debounceEvent(event, 0);
}
export function debounceEvent(event: EventEmitter, wait: number): EventEmitter {
const original = (event as any)._original || event;
return {
_original: event,
emit: debounce(original.emit.bind(original), wait)
} as EventEmitter;
}
export function debounce(func: Function, wait = 0) {
let timer: number;
return (...args: any[]): void => {
clearTimeout(timer);
timer = setTimeout(func, wait, ...args);
};
}

View File

@@ -1,216 +0,0 @@
import { EventEmitter } from '@stencil/core';
import { Animation, AnimationBuilder, Config, CssClassMap, FrameworkDelegate } from '..';
let lastId = 1;
/**
* Convert an interface where all the properties are optional to mandatory.
*/
export type Requires<K extends string> = {
[P in K]: any;
};
export function createOverlay<T extends HTMLIonOverlayElement & Requires<keyof B>, B>
(element: T, opts: B): Promise<T> {
// convert the passed in overlay options into props
// that get passed down into the new alert
Object.assign(element, opts);
element.overlayId = lastId++;
// append the alert element to the document body
const appRoot = document.querySelector('ion-app') || document.body;
appRoot.appendChild(element);
return element.componentOnReady();
}
export function dismissOverlay(data: any, role: string|undefined, overlays: OverlayMap, id: number): Promise<void> {
id = id >= 0 ? id : getHighestId(overlays);
const overlay = overlays.get(id);
if (!overlay) {
return Promise.reject('overlay does not exist');
}
return overlay.dismiss(data, role);
}
export function getTopOverlay<T extends HTMLIonOverlayElement>(overlays: OverlayMap): T {
return overlays.get(getHighestId(overlays)) as T;
}
export function getHighestId(overlays: OverlayMap) {
let minimum = -1;
overlays.forEach((_, id) => {
if (id > minimum) {
minimum = id;
}
});
return minimum;
}
export function removeLastOverlay(overlays: OverlayMap) {
const toRemove = getTopOverlay(overlays);
return toRemove ? toRemove.dismiss() : Promise.resolve();
}
export function present(
overlay: OverlayInterface,
name: string,
iosEnterAnimation: AnimationBuilder,
mdEnterAnimation: AnimationBuilder,
opts: any
) {
if (overlay.presented) {
return Promise.resolve();
}
overlay.presented = true;
overlay.willPresent.emit();
// get the user's animation fn if one was provided
const animationBuilder = (overlay.enterAnimation)
? overlay.enterAnimation
: overlay.config.get(name, overlay.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
return overlayAnimation(overlay, animationBuilder, overlay.el, opts).then(() => {
overlay.didPresent.emit();
});
}
export function dismiss(
overlay: OverlayInterface,
data: any|undefined,
role: string|undefined,
name: string,
iosLeaveAnimation: AnimationBuilder,
mdLeaveAnimation: AnimationBuilder,
opts: any
): Promise<void> {
if (!overlay.presented) {
return Promise.resolve();
}
overlay.presented = false;
overlay.willDismiss.emit({data, role});
const animationBuilder = (overlay.leaveAnimation)
? overlay.leaveAnimation
: overlay.config.get(name, overlay.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
return overlayAnimation(overlay, animationBuilder, overlay.el, opts).then(() => {
overlay.didDismiss.emit({data, role});
if (overlay.el.parentNode) {
overlay.el.parentNode.removeChild(overlay.el);
}
});
}
function overlayAnimation(
overlay: OverlayInterface,
animationBuilder: AnimationBuilder,
baseEl: HTMLElement,
opts: any
): Promise<void> {
if (overlay.animation) {
overlay.animation.destroy();
overlay.animation = undefined;
}
return overlay.animationCtrl.create(animationBuilder, baseEl, opts).then(animation => {
overlay.animation = animation;
if (!overlay.willAnimate) {
animation.duration(0);
}
return animation.playAsync();
}).then(animation => {
animation.destroy();
overlay.animation = undefined;
});
}
export function autoFocus(containerEl: HTMLElement): HTMLElement|null {
const focusableEls = containerEl.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]');
if (focusableEls.length > 0) {
const el = focusableEls[0] as HTMLInputElement;
el.focus();
return el;
}
return null;
}
export function attachComponent(delegate: FrameworkDelegate, container: Element, component: string|HTMLElement, cssClasses: CssClassMap, data: any): Promise<HTMLElement> {
if (delegate) {
return delegate.attachViewToDom(container, component, data, Object.keys(cssClasses));
}
const el = (typeof component === 'string') ? document.createElement(component) : component;
Object.assign(el, data);
Object.keys(cssClasses).forEach(c => el.classList.add(c));
container.appendChild(el);
if ((el as any).componentOnReady) {
return (el as any).componentOnReady();
}
return Promise.resolve(el);
}
export function eventMethod(element: HTMLElement, eventName: string, callback: Function): Promise<any> {
let resolve: Function;
const promise = new Promise(r => resolve = r);
onceEvent(element, eventName, (event) => {
const detail = event.detail;
callback && callback(detail);
resolve(detail);
});
return promise;
}
export function onceEvent(element: HTMLElement, eventName: string, callback: (ev: CustomEvent) => void) {
const handler = (ev: CustomEvent) => {
element.removeEventListener(eventName, handler);
callback(ev);
};
element.addEventListener(eventName, handler);
}
export function isCancel(role: string): boolean {
return role === 'cancel' || role === BACKDROP;
}
export interface OverlayEventDetail {
data?: any;
role?: string;
}
export interface OverlayInterface {
mode: string;
el: HTMLElement;
willAnimate: boolean;
config: Config;
overlayId: number;
presented: boolean;
animation: Animation|undefined;
animationCtrl: HTMLIonAnimationControllerElement;
enterAnimation: AnimationBuilder;
leaveAnimation: AnimationBuilder;
didPresent: EventEmitter;
willPresent: EventEmitter;
willDismiss: EventEmitter;
didDismiss: EventEmitter;
present(): Promise<void>;
dismiss(data?: any, role?: string): Promise<void>;
}
export interface OverlayController {
create(opts?: any): Promise<HTMLElement>;
dismiss(data?: any, role?: string, alertId?: number): Promise<void>;
getTop(): HTMLElement;
}
export interface HTMLIonOverlayElement extends HTMLStencilElement, OverlayInterface {}
export type OverlayMap = Map<number, HTMLIonOverlayElement>;
export const BACKDROP = 'backdrop';

View File

@@ -1,8 +1,8 @@
{
"lerna": "2.0.0-rc.5",
"packages": [
"*",
"demos/*"
"packages/*",
"packages/demos/*"
],
"commands": {
"bootstrap": {

3923
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"private": true,
"devDependencies": {
"jest": "^20.0.4",
"lerna": "2.9.0",
"lerna": "^2.0.0-rc.5",
"mocha": "^4.0.1",
"np": "^2.16.0"
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
# npm link local development
`npm link` doesn't work as expected due to the `devDependency` on `@angular/core`. This is the work around...
npm run build.link ../ionic-conference-app
When the command above is ran from the `packages/angular` directory, it will build `@ionic/angular` and copy the `dist` directory to the correct location of another local project. In the example above, the end result is that it copies the `dist` directory to `../ionic-conference-app/node_modules/@ionic/angular/dist`. The path given should be relative to the root of this mono repo.
# Deploy
1. `npm run prepare.deploy`
2. Review/update changelog
3. Commit updates using the package name and version number as the commit message.
4. `npm run deploy`
5. :tada:

View File

@@ -13,17 +13,15 @@ export { VirtualHeader } from './directives/virtual-header';
export { VirtualFooter } from './directives/virtual-footer';
/* Providers */
export { AngularDelegate } from './providers/angular-delegate';
export { ActionSheetController } from './providers/action-sheet-controller';
export { AlertController } from './providers/alert-controller';
export { ActionSheetController, ActionSheetProxy } from './providers/action-sheet-controller';
export { AlertController, AlertProxy } from './providers/alert-controller';
export { Events } from './providers/events';
export { LoadingController } from './providers/loading-controller';
export { LoadingController, LoadingProxy } from './providers/loading-controller';
export { MenuController } from './providers/menu-controller';
export { PickerController } from './providers/picker-controller';
export { ModalController } from './providers/modal-controller';
export { ModalController, ModalProxy } from './providers/modal-controller';
export { Platform } from './providers/platform';
export { PopoverController } from './providers/popover-controller';
export { ToastController } from './providers/toast-controller';
export { PopoverController, PopoverProxy } from './providers/popover-controller';
export { ToastController, ToastProxy } from './providers/toast-controller';
export * from './types/interfaces';

View File

@@ -25,14 +25,12 @@ import { VirtualHeader } from './directives/virtual-header';
import { VirtualFooter } from './directives/virtual-footer';
/* Providers */
import { AngularDelegate } from './providers/angular-delegate';
import { ActionSheetController } from './providers/action-sheet-controller';
import { AlertController } from './providers/alert-controller';
import { Events, setupProvideEvents } from './providers/events';
import { LoadingController } from './providers/loading-controller';
import { MenuController } from './providers/menu-controller';
import { ModalController } from './providers/modal-controller';
import { PickerController } from './providers/picker-controller';
import { Platform } from './providers/platform';
import { PopoverController } from './providers/popover-controller';
import { ToastController } from './providers/toast-controller';
@@ -69,14 +67,13 @@ import { ToastController } from './providers/toast-controller';
VirtualHeader,
VirtualFooter
],
providers: [
AngularDelegate,
ModalController,
PopoverController,
],
imports: [
CommonModule,
],
providers: [
ModalController,
PopoverController
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
@@ -90,7 +87,6 @@ export class IonicAngularModule {
ActionSheetController,
Events,
LoadingController,
PickerController,
MenuController,
Platform,
ToastController,

View File

@@ -0,0 +1,104 @@
import { Injectable } from '@angular/core';
import { ActionSheetDismissEvent, ActionSheetOptions } from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let actionSheetId = 0;
@Injectable()
export class ActionSheetController {
create(opts?: ActionSheetOptions): ActionSheetProxy {
return getActionSheetProxy(opts);
}
}
export function getActionSheetProxy(opts: ActionSheetOptions) {
return {
id: actionSheetId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as ActionSheetProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as ActionSheetProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(actionSheetProxy: ActionSheetProxyInternal): Promise<any> {
actionSheetProxy.state = PRESENTING;
return loadOverlay(actionSheetProxy.opts).then((actionSheetElement: HTMLIonActionSheetElement) => {
actionSheetProxy.element = actionSheetElement;
const onDidDismissHandler = (event: ActionSheetDismissEvent) => {
actionSheetElement.removeEventListener(ION_ACTION_SHEET_DID_DISMISS_EVENT, onDidDismissHandler);
if (actionSheetProxy.onDidDismissHandler) {
actionSheetProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: ActionSheetDismissEvent) => {
actionSheetElement.removeEventListener(ION_ACTION_SHEET_WILL_DISMISS_EVENT, onWillDismissHandler);
if (actionSheetProxy.onWillDismissHandler) {
actionSheetProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
actionSheetElement.addEventListener(ION_ACTION_SHEET_DID_DISMISS_EVENT, onDidDismissHandler);
actionSheetElement.addEventListener(ION_ACTION_SHEET_WILL_DISMISS_EVENT, onWillDismissHandler);
if (actionSheetProxy.state === PRESENTING) {
return actionSheetElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(actionSheetProxy: ActionSheetProxyInternal): Promise<any> {
actionSheetProxy.state = DISMISSING;
if (actionSheetProxy.element) {
if (actionSheetProxy.state === DISMISSING) {
return actionSheetProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: ActionSheetOptions): Promise<HTMLIonActionSheetElement> {
const element = ensureElementInBody('ion-action-sheet-controller') as HTMLIonActionSheetControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface ActionSheetProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface ActionSheetProxyInternal extends ActionSheetProxy {
id: number;
opts: ActionSheetOptions;
state: number;
element: HTMLIonActionSheetElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_ACTION_SHEET_DID_DISMISS_EVENT = 'ionActionSheetDidDismiss';
const ION_ACTION_SHEET_WILL_DISMISS_EVENT = 'ionActionSheetWillDismiss';

View File

@@ -0,0 +1,104 @@
import { Injectable } from '@angular/core';
import { AlertDismissEvent, AlertOptions } from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let alertId = 0;
@Injectable()
export class AlertController {
create(opts?: AlertOptions): AlertProxy {
return getAlertProxy(opts);
}
}
export function getAlertProxy(opts: AlertOptions) {
return {
id: alertId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as AlertProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as AlertProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(alertProxy: AlertProxyInternal): Promise<any> {
alertProxy.state = PRESENTING;
return loadOverlay(alertProxy.opts).then((alertElement: HTMLIonAlertElement) => {
alertProxy.element = alertElement;
const onDidDismissHandler = (event: AlertDismissEvent) => {
alertElement.removeEventListener(ION_ALERT_DID_DISMISS_EVENT, onDidDismissHandler);
if (alertProxy.onDidDismissHandler) {
alertProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: AlertDismissEvent) => {
alertElement.removeEventListener(ION_ALERT_WILL_DISMISS_EVENT, onWillDismissHandler);
if (alertProxy.onWillDismissHandler) {
alertProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
alertElement.addEventListener(ION_ALERT_DID_DISMISS_EVENT, onDidDismissHandler);
alertElement.addEventListener(ION_ALERT_WILL_DISMISS_EVENT, onWillDismissHandler);
if (alertProxy.state === PRESENTING) {
return alertElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(alertProxy: AlertProxyInternal): Promise<any> {
alertProxy.state = DISMISSING;
if (alertProxy.element) {
if (alertProxy.state === DISMISSING) {
return alertProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: AlertOptions): Promise<HTMLIonAlertElement> {
const element = ensureElementInBody('ion-alert-controller') as HTMLIonAlertControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface AlertProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface AlertProxyInternal extends AlertProxy {
id: number;
opts: AlertOptions;
state: number;
element: HTMLIonAlertElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_ALERT_DID_DISMISS_EVENT = 'ionAlertDidDismiss';
const ION_ALERT_WILL_DISMISS_EVENT = 'ionAlertWillDismiss';

View File

@@ -0,0 +1,104 @@
import { Injectable } from '@angular/core';
import { LoadingDismissEvent, LoadingOptions } from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let loadingId = 0;
@Injectable()
export class LoadingController {
create(opts?: LoadingOptions): LoadingProxy {
return getLoadingProxy(opts);
}
}
export function getLoadingProxy(opts: LoadingOptions) {
return {
id: loadingId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as LoadingProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as LoadingProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(loadingProxy: LoadingProxyInternal): Promise<any> {
loadingProxy.state = PRESENTING;
return loadOverlay(loadingProxy.opts).then((loadingElement: HTMLIonLoadingElement) => {
loadingProxy.element = loadingElement;
const onDidDismissHandler = (event: LoadingDismissEvent) => {
loadingElement.removeEventListener(ION_LOADING_DID_DISMISS_EVENT, onDidDismissHandler);
if (loadingProxy.onDidDismissHandler) {
loadingProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: LoadingDismissEvent) => {
loadingElement.removeEventListener(ION_LOADING_WILL_DISMISS_EVENT, onWillDismissHandler);
if (loadingProxy.onWillDismissHandler) {
loadingProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
loadingElement.addEventListener(ION_LOADING_DID_DISMISS_EVENT, onDidDismissHandler);
loadingElement.addEventListener(ION_LOADING_WILL_DISMISS_EVENT, onWillDismissHandler);
if (loadingProxy.state === PRESENTING) {
return loadingElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(loadingProxy: LoadingProxyInternal): Promise<any> {
loadingProxy.state = DISMISSING;
if (loadingProxy.element) {
if (loadingProxy.state === DISMISSING) {
return loadingProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: LoadingOptions): Promise<HTMLIonLoadingElement> {
const element = ensureElementInBody('ion-loading-controller') as HTMLIonLoadingControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface LoadingProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface LoadingProxyInternal extends LoadingProxy {
id: number;
opts: LoadingOptions;
state: number;
element: HTMLIonLoadingElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_LOADING_DID_DISMISS_EVENT = 'ionLoadingDidDismiss';
const ION_LOADING_WILL_DISMISS_EVENT = 'ionLoadingWillDismiss';

View File

@@ -0,0 +1,127 @@
import { ensureElementInBody } from '../util/util';
let element: HTMLIonMenuControllerElement;
export class MenuController {
constructor() {
element = ensureElementInBody('ion-menu-controller') as HTMLIonMenuControllerElement;
}
close(menuId?: string) {
return element.componentOnReady().then(() => {
return element.close(menuId);
});
}
// maintain legacy sync api
enable(enabled: boolean, menuId?: string) {
if (element && element.enable) {
return element.enable(enabled, menuId);
}
// IDK, this is not a good place to be in
return null;
}
enableAsync(menuId?: string): Promise<HTMLIonMenuElement> {
return element.componentOnReady().then(() => {
return element.enable(true, menuId);
});
}
get(menuId?: string) {
if (element && element.get) {
return element.get(menuId);
}
// IDK, this is not a good place to be in
return null;
}
getAsync(menuId?: string): Promise<HTMLIonMenuElement> {
return element.componentOnReady().then(() => {
return element.get(menuId);
});
}
getMenus() {
if (element && element.getMenus) {
return element.getMenus();
}
// IDK, this is not a good place to be in
return [];
}
getMenusAsync(): Promise<HTMLIonMenuElement[]> {
return element.componentOnReady().then(() => {
return element.getMenus();
});
}
getOpen() {
if (element && element.getOpen) {
return element.getOpen();
}
// IDK, this is not a good place to be in
return null;
}
getOpenAsync(): Promise<HTMLIonMenuElement> {
return element.componentOnReady().then(() => {
return element.getOpen();
});
}
isEnabled(menuId?: string) {
if (element && element.isEnabled) {
return element.isEnabled(menuId);
}
// IDK, this is not a good place to be in
return false;
}
isEnabledAsync(menuId?: string): Promise<boolean> {
return element.componentOnReady().then(() => {
return element.isEnabled(menuId);
});
}
isOpen(menuId?: string) {
if (element && element.isOpen) {
return element.isOpen(menuId);
}
// IDK, this is not a good place to be in
return false;
}
isOpenAsync(menuId?: string): Promise<boolean> {
return element.componentOnReady().then(() => {
return element.isOpen(menuId);
});
}
open(menuId?: string): Promise<boolean> {
return element.componentOnReady().then(() => {
return element.open(menuId);
});
}
swipeEnable(shouldEnable: boolean, menuId?: string) {
if (element && element.swipeEnable) {
return element.swipeEnable(shouldEnable, menuId);
}
// IDK, this is not a good place to be in
return null;
}
swipeEnableAsync(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return element.componentOnReady().then(() => {
return element.swipeEnable(shouldEnable, menuId);
});
}
toggle(menuId?: string): Promise<boolean> {
return element.componentOnReady().then(() => {
return element.toggle(menuId);
});
}
}

View File

@@ -0,0 +1,121 @@
import {
Injectable,
} from '@angular/core';
import {
ModalDismissEvent,
ModalOptions
} from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let modalId = 0;
@Injectable()
export class ModalController {
create(opts?: ModalOptions): ModalProxy {
return getModalProxy(opts);
}
dismiss(data?: any, role?: string, id?: number) {
const modalController = document.querySelector('ion-modal-controller');
return modalController.componentOnReady().then(() => {
return modalController.dismiss(data, role, id);
});
}
}
export function getModalProxy(opts: ModalOptions) {
return {
id: modalId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as ModalProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as ModalProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(modalProxy: ModalProxyInternal): Promise<any> {
modalProxy.state = PRESENTING;
return loadOverlay(modalProxy.opts).then((modalElement: HTMLIonModalElement) => {
Object.assign(modalElement, modalProxy.opts);
modalProxy.element = modalElement;
const onDidDismissHandler = (event: ModalDismissEvent) => {
modalElement.removeEventListener(ION_MODAL_DID_DISMISS_EVENT, onDidDismissHandler);
if (modalProxy.onDidDismissHandler) {
modalProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: ModalDismissEvent) => {
modalElement.removeEventListener(ION_MODAL_WILL_DISMISS_EVENT, onWillDismissHandler);
if (modalProxy.onWillDismissHandler) {
modalProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
modalElement.addEventListener(ION_MODAL_DID_DISMISS_EVENT, onDidDismissHandler);
modalElement.addEventListener(ION_MODAL_WILL_DISMISS_EVENT, onWillDismissHandler);
if (modalProxy.state === PRESENTING) {
return modalElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(modalProxy: ModalProxyInternal): Promise<any> {
modalProxy.state = DISMISSING;
if (modalProxy.element) {
if (modalProxy.state === DISMISSING) {
return modalProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: ModalOptions): Promise<HTMLIonModalElement> {
const element = ensureElementInBody('ion-modal-controller') as HTMLIonModalControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface ModalProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface ModalProxyInternal extends ModalProxy {
id: number;
opts: ModalOptions;
state: number;
element: HTMLIonModalElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_MODAL_DID_DISMISS_EVENT = 'ionModalDidDismiss';
const ION_MODAL_WILL_DISMISS_EVENT = 'ionModalWillDismiss';

View File

@@ -0,0 +1,120 @@
import {
Injectable,
} from '@angular/core';
import {
PopoverDismissEvent,
PopoverOptions
} from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let popoverId = 0;
@Injectable()
export class PopoverController {
create(opts?: PopoverOptions): PopoverProxy {
return getPopoverProxy(opts);
}
dismiss(data?: any, role?: string, id?: number) {
const popoverController = document.querySelector('ion-popover-controller');
return popoverController.componentOnReady().then(() => {
return popoverController.dismiss(data, role, id);
});
}
}
export function getPopoverProxy(opts: PopoverOptions) {
return {
id: popoverId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as PopoverProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as PopoverProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(popoverProxy: PopoverProxyInternal): Promise<any> {
popoverProxy.state = PRESENTING;
return loadOverlay(popoverProxy.opts).then((popoverElement: HTMLIonPopoverElement) => {
Object.assign(popoverElement, popoverProxy.opts);
popoverProxy.element = popoverElement;
const onDidDismissHandler = (event: PopoverDismissEvent) => {
popoverElement.removeEventListener(ION_POPOVER_DID_DISMISS_EVENT, onDidDismissHandler);
if (popoverProxy.onDidDismissHandler) {
popoverProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: PopoverDismissEvent) => {
popoverElement.removeEventListener(ION_POPOVER_WILL_DISMISS_EVENT, onWillDismissHandler);
if (popoverProxy.onWillDismissHandler) {
popoverProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
popoverElement.addEventListener(ION_POPOVER_DID_DISMISS_EVENT, onDidDismissHandler);
popoverElement.addEventListener(ION_POPOVER_WILL_DISMISS_EVENT, onWillDismissHandler);
if (popoverProxy.state === PRESENTING) {
return popoverElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(popoverProxy: PopoverProxyInternal): Promise<any> {
popoverProxy.state = DISMISSING;
if (popoverProxy.element) {
if (popoverProxy.state === DISMISSING) {
return popoverProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
const element = ensureElementInBody('ion-popover-controller') as HTMLIonPopoverControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface PopoverProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface PopoverProxyInternal extends PopoverProxy {
id: number;
opts: PopoverOptions;
state: number;
element: HTMLIonPopoverElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_POPOVER_DID_DISMISS_EVENT = 'ionPopoverDidDismiss';
const ION_POPOVER_WILL_DISMISS_EVENT = 'ionPopoverWillDismiss';

View File

@@ -0,0 +1,104 @@
import { Injectable } from '@angular/core';
import { ToastDismissEvent, ToastOptions } from '@ionic/core';
import { ensureElementInBody, hydrateElement } from '../util/util';
let toastId = 0;
@Injectable()
export class ToastController {
create(opts?: ToastOptions): ToastProxy {
return getToastProxy(opts);
}
}
export function getToastProxy(opts: ToastOptions) {
return {
id: toastId++,
state: PRESENTING,
opts: opts,
present: function() { return present(this); },
dismiss: function() { return dismiss(this); },
onDidDismiss: function(callback: (data: any, role: string) => void) {
(this as ToastProxyInternal).onDidDismissHandler = callback;
},
onWillDismiss: function(callback: (data: any, role: string) => void) {
(this as ToastProxyInternal).onWillDismissHandler = callback;
},
};
}
export function present(toastProxy: ToastProxyInternal): Promise<any> {
toastProxy.state = PRESENTING;
return loadOverlay(toastProxy.opts).then((toastElement: HTMLIonToastElement) => {
toastProxy.element = toastElement;
const onDidDismissHandler = (event: ToastDismissEvent) => {
toastElement.removeEventListener(ION_TOAST_DID_DISMISS_EVENT, onDidDismissHandler);
if (toastProxy.onDidDismissHandler) {
toastProxy.onDidDismissHandler(event.detail.data, event.detail.role);
}
};
const onWillDismissHandler = (event: ToastDismissEvent) => {
toastElement.removeEventListener(ION_TOAST_WILL_DISMISS_EVENT, onWillDismissHandler);
if (toastProxy.onWillDismissHandler) {
toastProxy.onWillDismissHandler(event.detail.data, event.detail.role);
}
};
toastElement.addEventListener(ION_TOAST_DID_DISMISS_EVENT, onDidDismissHandler);
toastElement.addEventListener(ION_TOAST_WILL_DISMISS_EVENT, onWillDismissHandler);
if (toastProxy.state === PRESENTING) {
return toastElement.present();
}
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
// attribute before it could async load and present itself.
// with that in mind, just return null to make the TS compiler happy
return null;
});
}
export function dismiss(toastProxy: ToastProxyInternal): Promise<any> {
toastProxy.state = DISMISSING;
if (toastProxy.element) {
if (toastProxy.state === DISMISSING) {
return toastProxy.element.dismiss();
}
}
// either we're not in the dismissing state
// or we're calling this before the element is created
// so just return a resolved promise
return Promise.resolve();
}
export function loadOverlay(opts: ToastOptions): Promise<HTMLIonToastElement> {
const element = ensureElementInBody('ion-toast-controller') as HTMLIonToastControllerElement;
return hydrateElement(element).then(() => {
return element.create(opts);
});
}
export interface ToastProxy {
present(): Promise<void>;
dismiss(): Promise<void>;
onDidDismiss(callback: (data: any, role: string) => void): void;
onWillDismiss(callback: (data: any, role: string) => void): void;
}
export interface ToastProxyInternal extends ToastProxy {
id: number;
opts: ToastOptions;
state: number;
element: HTMLIonToastElement;
onDidDismissHandler?: (data: any, role: string) => void;
onWillDismissHandler?: (data: any, role: string) => void;
}
export const PRESENTING = 1;
export const DISMISSING = 2;
const ION_TOAST_DID_DISMISS_EVENT = 'ionToastDidDismiss';
const ION_TOAST_WILL_DISMISS_EVENT = 'ionToastWillDismiss';

View File

@@ -0,0 +1,32 @@
export function hydrateElement(element: any) {
return element.componentOnReady();
}
export function getElement(elementName: string) {
return document.querySelector(elementName);
}
export function ensureElementInBody(elementName: string) {
let element = getElement(elementName);
if (!element) {
element = document.createElement(elementName);
document.body.appendChild(element);
}
return element;
}
export function removeAllNodeChildren(element: HTMLElement) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
export function isString(something: any) {
return typeof something === 'string' ? true : false;
}
export function getIonApp(): Promise<HTMLIonAppElement> {
const element = ensureElementInBody('ion-app') as HTMLIonAppElement;
return element.componentOnReady();
}

View File

@@ -0,0 +1,73 @@
<a name="0.1.4-1"></a>
## [0.1.4-1](https://github.com/ionic-team/ionic/compare/v0.1.4-0...v0.1.4-1) (2018-03-07)
### Bug Fixes
* **ion-router:** fixes routing algorithm ([c8a27b7](https://github.com/ionic-team/ionic/commit/c8a27b7))
* **overlays:** bundling of overlays ([9650bec](https://github.com/ionic-team/ionic/commit/9650bec))
* **routing:** flickering (part 1) ([7b264f9](https://github.com/ionic-team/ionic/commit/7b264f9))
* **tabs:** do not select when using router ([174d9b5](https://github.com/ionic-team/ionic/commit/174d9b5))
### Features
* **virtual-scroll:** adds JSX support ([dc8b363](https://github.com/ionic-team/ionic/commit/dc8b363))
<a name="0.1.4-0"></a>
## [0.1.4-0](https://github.com/ionic-team/ionic/compare/v0.1.3...v0.1.4-0) (2018-03-06)
### Refactor
- Refactored navigation system
### Bug Fixes
* **testing:** do not throw error for missing Ionic global ([aa91d11](https://github.com/ionic-team/ionic/commit/aa91d11))
* **zone:** forgot to remove console.logs ([4ec3e48](https://github.com/ionic-team/ionic/commit/4ec3e48))
<a name="0.1.3"></a>
## [0.1.3](https://github.com/ionic-team/ionic/compare/v0.1.2...v0.1.3) (2018-03-03)
### Performance Improvements
* Updates to latest stencil, that includes the zone bypassing abilities.
### Bug Fixes
* **ts:** ts strict fixes ([8ff02c7](https://github.com/ionic-team/ionic/commit/8ff02c7))
<a name="0.1.2"></a>
## [0.1.2](https://github.com/ionic-team/ionic/compare/v0.1.1...v0.1.2) (2018-03-03)
### Performance Improvements
* **events:** bypass ngzone ([7366c38](https://github.com/ionic-team/ionic/commit/7366c38))
* **scroll:** watchdog + simplification ([33a6274](https://github.com/ionic-team/ionic/commit/33a6274))
### Bug Fixes
* **scroll:** clearInterval just to be safe ([6da9882](https://github.com/ionic-team/ionic/commit/6da9882))
<a name="0.1.1"></a>
## [0.1.1](https://github.com/ionic-team/ionic/commit/291e85e61128b2f3101d9cea6b42d4cf751dc481) (2018-03-01)
### Bug Fixes
* **button:** pass the property type instead of hardcoding button ([10e481a](https://github.com/ionic-team/ionic/commit/10e481a))
<a name="0.1.0"></a>
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)

View File

View File

@@ -20,7 +20,7 @@ The Ionic Core package contains the Web Components that make up the reusable UI
Easiest way to start using Ionic Core is by adding a script tag to the CDN:
<script src="https://unpkg.com/@ionic/core@0.1.4-6/dist/ionic.js"></script>
<script src="https://unpkg.com/@ionic/core@0.1.4-1/dist/ionic.js"></script>
Any Ionic component added to the webpage will automatically load. This includes writing the component tag directly in HTML, or using JavaScript such as `document.createElement('ion-toggle')`.

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "0.1.4-6",
"version": "0.1.4-1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -41,8 +41,8 @@
"@ionic/discover": "0.3.3",
"chokidar": "1.7.0",
"ecstatic": "2.2.1",
"opn": "5.3.0",
"tiny-lr": "1.1.1"
"opn": "5.2.0",
"tiny-lr": "1.1.0"
},
"dependencies": {
"anymatch": {
@@ -5601,9 +5601,9 @@
}
},
"http-parser-js": {
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.11.tgz",
"integrity": "sha512-QCR5O2AjjMW8Mo4HyI1ctFcv+O99j/0g367V3YoVnrNw5hkDvAWZD0lWGcc+F4yN3V55USPCVix4efb75HxFfA==",
"version": "0.4.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
"dev": true
},
"http-signature": {
@@ -9678,9 +9678,9 @@
}
},
"opn": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz",
"integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz",
"integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==",
"dev": true,
"requires": {
"is-wsl": "1.1.0"
@@ -12024,28 +12024,17 @@
"dev": true
},
"tiny-lr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz",
"integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.0.tgz",
"integrity": "sha512-f4X68a6KHcCx/XJcZUKAa92APjY9EHxuGOzRFmPRjf+fOp1E7fi4dGJaHMxvRBxwZrHrIvn/AwkFaDS7O1WZDQ==",
"dev": true,
"requires": {
"body": "5.1.0",
"debug": "3.1.0",
"debug": "2.6.9",
"faye-websocket": "0.10.0",
"livereload-js": "2.3.0",
"object-assign": "4.1.1",
"qs": "6.5.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"tmp": {
@@ -12680,7 +12669,7 @@
"integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=",
"dev": true,
"requires": {
"http-parser-js": "0.4.11",
"http-parser-js": "0.4.10",
"websocket-extensions": "0.1.3"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "0.1.4-6",
"version": "0.1.4-1",
"description": "Base components for Ionic",
"keywords": [
"ionic",

View File

@@ -1,6 +1,6 @@
# End-To-End Testing Scripts
This document describes the process of installing the dependencies for, running, and writing end-to-end tests for ionic core. Your working directory is assumed to be `core`.
This document describes the process of installing the dependencies for, running, and writing end-to-end tests for ionic core. Your working directory is assumed to be `packages/core`.
---

View File

@@ -8,15 +8,15 @@
### 2. Run `npm install`
cd core
cd packages/core
npm install
Notice that `@ionic/core` lives in `core`.
Notice that `@ionic/core` lives in `packages/core`.
### 3. Run `npm run dev`
Make sure you are inside the `core` directory.
Make sure you are inside the `packages/core` directory.
npm run dev

View File

@@ -2,7 +2,7 @@
CD to core package:
cd core
cd packages/core
Pull latest:

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