Merge remote-tracking branch 'origin/master'

This commit is contained in:
Brandy Carney
2015-10-09 10:42:24 -04:00
62 changed files with 857 additions and 845 deletions

View File

@@ -6,7 +6,7 @@
* The ActionSheet is a modal menu with options to select based on an action.
*/
import {Component, View, Injectable, NgFor, NgIf} from 'angular2/angular2';
import {Component, Injectable, NgFor, NgIf} from 'angular2/angular2';
import {OverlayController} from '../overlay/overlay-controller';
import {IonicConfig} from '../../config/config';
@@ -54,9 +54,7 @@ import * as util from 'ionic/util';
* ```
*/
@Component({
selector: 'ion-action-sheet'
})
@View({
selector: 'ion-action-sheet',
template:
'<backdrop (click)="_cancel()" tappable disable-activated></backdrop>' +
'<action-sheet-wrapper>' +

View File

@@ -1,4 +1,4 @@
import {Directive, ElementRef, Renderer} from 'angular2/angular2';
import {Directive, ElementRef, Renderer, Attribute} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
@@ -14,18 +14,13 @@ export class Button {
constructor(
config: IonicConfig,
elementRef: ElementRef,
renderer: Renderer
renderer: Renderer,
@Attribute('type') type: string
) {
let element = elementRef.nativeElement;
if (config.get('hoverCSS') === false) {
element.classList.add('disable-hover');
}
// TODO this isn't working in the popup
if (element.hasAttribute('type')) {
let type = element.getAttribute("type");
renderer.setElementAttribute(elementRef, type, "");
renderer.setElementClass(elementRef, 'disable-hover', true);
}
if (element.hasAttribute('ion-item')) {
@@ -33,6 +28,10 @@ export class Button {
return;
}
if (type) {
renderer.setElementAttribute(elementRef, type, '');
}
// figure out if and where the icon lives in the button
let childNodes = element.childNodes;
let childNode;

View File

@@ -10,6 +10,11 @@
<button block>button[block]</button>
</p>
<p>
<a button block href="#"><icon help-circle></icon> a[button][block] icon</a>
<button block><icon help-circle></icon> button[block] icon</button>
</p>
<p>
<a button block outline secondary href="#">a[button][block][outline][secondary]</a>
<button block outline secondary>button[block][outline][secondary]</button>

View File

@@ -1,8 +1,7 @@
import {Component, View, Directive, ElementRef, Optional, NgControl} from 'angular2/angular2';
import {Component, Directive, Optional, NgControl, ElementRef, Renderer} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonInput} from '../form/input';
import {IonicConfig} from '../../config/config';
import {IonicForm} from '../form/form';
/**
* The checkbox is no different than the HTML checkbox input, except it's styled differently
@@ -25,7 +24,6 @@ import {IonicConfig} from '../../config/config';
'id'
],
host: {
'class': 'item',
'role': 'checkbox',
'tappable': 'true',
'[attr.tab-index]': 'tabIndex',
@@ -33,32 +31,26 @@ import {IonicConfig} from '../../config/config';
'[attr.aria-disabled]': 'disabled',
'[attr.aria-labelledby]': 'labelId',
'(click)': 'click($event)'
}
})
@View({
},
template:
'<media-checkbox disable-activated>' +
'<checkbox-icon></checkbox-icon>' +
'</media-checkbox>' +
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>'
'<media-checkbox disable-activated>' +
'<checkbox-icon></checkbox-icon>' +
'</media-checkbox>' +
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>'
})
export class Checkbox extends Ion {
/**
* TODO
* @param {ElementRef} elementRef TODO
* @param {IonicConfig} ionicConfig TODO
* @param {NgControl=} ngControl TODO
*/
export class Checkbox {
constructor(
form: IonicForm,
@Optional() ngControl: NgControl,
elementRef: ElementRef,
config: IonicConfig,
@Optional() ngControl: NgControl
renderer: Renderer
) {
super(elementRef, config);
this.tabIndex = 0;
this.id = IonInput.nextId();
renderer.setElementClass(elementRef, 'item', true);
this.form = form;
form.register(this);
this.onChange = (_) => {};
this.onTouched = (_) => {};
@@ -72,8 +64,7 @@ export class Checkbox extends Ion {
* TODO
*/
onInit() {
super.onInit();
this.labelId = 'label-' + this.id;
this.labelId = 'label-' + this.inputId;
}
/**
@@ -121,4 +112,8 @@ export class Checkbox extends Ion {
* @param {Function} fn onTouched event handler.
*/
registerOnTouched(fn) { this.onTouched = fn; }
onDestroy() {
this.form.deregister(this);
}
}

View File

@@ -1,4 +1,4 @@
import {Component, View, ElementRef, Optional, Host} from 'angular2/angular2';
import {Component, ElementRef, Optional} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
@@ -25,11 +25,7 @@ import {ScrollTo} from '../../animations/scroll-to';
*/
@Component({
selector: 'ion-content',
inputs: [
'parallax'
]
})
@View({
inputs: ['parallax'],
template: '<scroll-content><ng-content></ng-content></scroll-content>'
})
export class Content extends Ion {

View File

@@ -1,96 +0,0 @@
import {Component, Directive, View, Host, Attribute, ElementRef, forwardRef} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
import {IonInput} from './input';
/**
* TODO
*/
@Component({
selector: 'focus-holder'
})
@View({
template: '<input tabindex="999"><input tabindex="1001"><input tabindex="1002">',
directives: [forwardRef(() => FocusInput)]
})
export class FocusHolder {
/**
* TODO
*/
constructor() {
this.i = [];
}
/**
* TODO
* @param {TODO} inputType TODO
*/
setFocusHolder(inputType) {
this.i[2].type = inputType;
this.i[2].setFocus();
}
/**
* TODO
* @param {TODO} tabIndex TODO
*/
receivedFocus(tabIndex) {
if (tabIndex === '999') {
// focus on the previous input
IonInput.focusPrevious();
} else if (tabIndex === '1001') {
// focus on the next input
IonInput.focusNext();
}
}
/**
* TODO
* @param {TODO} input TODO
*/
register(input) {
this.i.push(input);
}
}
@Directive({
selector: 'input',
host: {
'[type]': 'type',
'(focus)': 'holder.receivedFocus(tabindex)',
'(keydown)': 'keydown($event)'
}
})
class FocusInput {
constructor(
elementRef: ElementRef,
@Host() holder: FocusHolder,
@Attribute('tabindex') tabindex: string
) {
this.elementRef = elementRef;
this.holder = holder;
this.tabindex = tabindex;
this.holder.register(this);
}
setFocus() {
this.elementRef.nativeElement.focus();
}
keydown(ev) {
// prevent any keyboard typing when a holder has focus
ev.preventDefault();
ev.stopPropagation();
}
get type() {
// default to text type if unknown
return this._t || 'text';
}
set type(val) {
this._t = val;
}
}

View File

@@ -66,27 +66,33 @@ select[readonly] {
// Focus Utils
// -------------------------------
focus-holder input {
focus-ctrl {
position: fixed;
top: 1px;
width: 9px;
left: -9999px;
z-index: 9999;
input,
button {
position: fixed;
top: 1px;
width: 9px;
left: -9999px;
z-index: 9999;
}
}
/*focus-holder input[tabindex="999"] {
/*focus-ctrl input[tabindex="999"] {
left: 0px;
}
focus-holder input[tabindex="1001"] {
focus-ctrl input[tabindex="1001"] {
left: 20px;
}
focus-holder input[tabindex="1002"] {
focus-ctrl input[tabindex="1002"] {
left: auto;
right: 10px;
}
focus-holder input:focus {
focus-ctrl input:focus {
background: red;
}*/

View File

@@ -0,0 +1,248 @@
import {Injectable, NgZone} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
import {raf} from '../../util/dom';
/**
* The Input component is used to focus text input elements.
*
* The `focusNext()` and `focusPrevious()` methods make it easy to focus input elements across all devices.
*
* @usage
* ```html
* <ion-input>
* <ion-label>Name</ion-label>
* <input value="Name" type="text">
* </ion-input>
* ```
*/
@Injectable()
export class IonicForm {
constructor(config: IonicConfig, zone: NgZone) {
this._config = config;
this._zone = zone;
this._inputs = [];
this._ids = -1;
this._focused = null;
zone.runOutsideAngular(() => {
this.initHolders(document, this._config.get('keyboardScrollAssist'));
if (this._config.get('keyboardInputListener') !== false) {
this.initKeyInput(document);
}
});
}
initKeyInput(document) {
/* Focus Outline
* --------------------------------------------------
* When a keydown event happens, from a tab key, then the
* 'key-input' class is added to the body element so focusable
* elements have an outline. On a mousedown or touchstart
* event then the 'key-input' class is removed.
*/
let isKeyInputEnabled = false;
function keyDown(ev) {
if (!isKeyInputEnabled && ev.keyCode == 9) {
isKeyInputEnabled = true;
raf(enableKeyInput);
}
}
function pointerDown() {
isKeyInputEnabled = false;
raf(enableKeyInput);
}
function enableKeyInput() {
document.body.classList[isKeyInputEnabled ? 'add' : 'remove']('key-input');
document.removeEventListener('mousedown', pointerDown);
document.removeEventListener('touchstart', pointerDown);
if (isKeyInputEnabled) {
document.addEventListener('mousedown', pointerDown);
document.addEventListener('touchstart', pointerDown);
}
}
document.addEventListener('keydown', keyDown);
}
initHolders(document, scrollAssist) {
// raw DOM fun
this._ctrl = document.createElement('focus-ctrl');
this._ctrl.setAttribute('aria-hidden', true);
if (scrollAssist) {
this._prev = document.createElement('input');
this._prev.tabIndex = NO_FOCUS_TAB_INDEX;
this._ctrl.appendChild(this._prev);
this._next = document.createElement('input');
this._next.tabIndex = NO_FOCUS_TAB_INDEX;
this._ctrl.appendChild(this._next);
this._temp = document.createElement('input');
this._temp.tabIndex = NO_FOCUS_TAB_INDEX;
this._ctrl.appendChild(this._temp);
}
this._blur = document.createElement('button');
this._blur.tabIndex = NO_FOCUS_TAB_INDEX;
this._ctrl.appendChild(this._blur);
document.body.appendChild(this._ctrl);
function preventDefault(ev) {
ev.preventDefault();
ev.stopPropagation();
}
if (scrollAssist) {
this._prev.addEventListener('keydown', preventDefault);
this._next.addEventListener('keydown', preventDefault);
this._temp.addEventListener('keydown', preventDefault);
this._prev.addEventListener('focus', () => {
this.focusPrevious();
});
this._next.addEventListener('focus', () => {
this.focusNext();
});
let self = this;
let resetTimer;
function queueReset() {
clearTimeout(resetTimer);
resetTimer = setTimeout(function() {
self._zone.run(() => {
self.resetInputs();
});
}, 100);
}
document.addEventListener('focusin', queueReset);
document.addEventListener('focusout', queueReset);
}
}
focusOut() {
console.debug('focusOut')
this._blur.tabIndex = NORMAL_FOCUS_TAB_INDEX;
this._blur.focus();
this._blur.tabIndex = NO_FOCUS_TAB_INDEX;
}
setFocusHolder(type) {
if (this._temp) {
this._temp.tabIndex = TEMP_TAB_INDEX;
this._temp.type = type || 'text';
console.debug('setFocusHolder', this._temp.type);
this._temp.focus();
}
}
/**
* @param {TODO} input TODO
*/
register(input) {
console.debug('register input', input);
input.inputId = ++this._ids;
input.tabIndex = NORMAL_FOCUS_TAB_INDEX;
this._inputs.push(input);
}
deregister(input) {
console.debug('deregister input', input);
let index = this._inputs.indexOf(input);
if (index > -1) {
this._inputs.splice(index, 1);
}
if (input === this._focused) {
this._focused = null;
}
}
resetInputs() {
this._focused = null;
for (let i = 0, ii = this._inputs.length; i < ii; i++) {
if (!this._focused && this._inputs[i].hasFocus) {
this._focused = this._inputs[i];
this._focused.tabIndex = ACTIVE_FOCUS_TAB_INDEX;
} else {
this._inputs[i].tabIndex = NORMAL_FOCUS_TAB_INDEX;
}
}
if (this._temp) {
this._temp.tabIndex = NO_FOCUS_TAB_INDEX;
if (this._focused) {
// there's a focused input
this._prev.tabIndex = PREV_TAB_INDEX;
this._next.tabIndex = NEXT_TAB_INDEX;
} else {
this._prev.tabIndex = this._next.tabIndex = NO_FOCUS_TAB_INDEX;
}
}
}
/**
* Focuses the previous input element, if it exists.
*/
focusPrevious() {
console.debug('focusPrevious');
this.focusMove(-1);
}
/**
* Focuses the next input element, if it exists.
*/
focusNext() {
console.debug('focusNext');
this.focusMove(1);
}
/**
* @param {Number} inc TODO
*/
focusMove(inc) {
let input = this._focused;
if (input) {
let index = this._inputs.indexOf(input);
if (index > -1 && (index + inc) < this._inputs.length) {
let siblingInput = this._inputs[index + inc];
if (siblingInput) {
return siblingInput.initFocus();
}
}
this._focused.initFocus();
}
}
}
const NO_FOCUS_TAB_INDEX = -1;
const NORMAL_FOCUS_TAB_INDEX = 0;
const PREV_TAB_INDEX = 999;
const ACTIVE_FOCUS_TAB_INDEX = 1000;
const NEXT_TAB_INDEX = 1001;
const TEMP_TAB_INDEX = 2000;

View File

@@ -1,87 +0,0 @@
import {Directive, ElementRef, Query, QueryList} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicApp} from '../app/app';
import {IonicConfig} from '../../config/config';
let inputRegistry = [];
let inputItemIds = -1;
let activeInput = null;
let lastInput = null;
/**
* The Input component is used to focus text input elements.
*
* The `focusNext()` and `focusPrevious()` methods make it easy to focus input elements across all devices.
*
* @usage
* ```html
* <ion-input>
* <ion-label>Name</ion-label>
* <input value="Name" type="text">
* </ion-input>
* ```
*/
export class IonInput extends Ion {
/**
* @param {TODO} input TODO
*/
static registerInput(input) {
inputRegistry.push(input);
}
/**
* TODO
* @param {TODO} input TODO
*/
static setAsLastInput(input) {
lastInput = input;
}
/**
* Focuses the previous input element, if it exists.
*/
static focusPrevious() {
this.focusMove(-1);
}
/**
* Focuses the next input element, if it exists.
*/
static focusNext() {
this.focusMove(1);
}
/**
* @param {Number} inc TODO
*/
static focusMove(inc) {
let input = activeInput || lastInput;
if (input) {
let index = inputRegistry.indexOf(input);
if (index > -1 && (index + inc) < inputRegistry.length) {
let siblingInput = inputRegistry[index + inc];
siblingInput && siblingInput.initFocus();
}
}
}
/**
* @returns {Number} The ID of the next input element.
*/
static nextId() {
return ++inputItemIds;
}
/**
* TODO
*/
static clearTabIndexes() {
for (let i = 0; i < inputRegistry.length; i++) {
inputRegistry[i].tabIndex = -1;
}
}
}

View File

@@ -3,9 +3,6 @@ import {Directive, ElementRef, Attribute, Renderer} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
/**
* TODO
*/
@Directive({
selector: 'icon',
inputs: [
@@ -15,17 +12,11 @@ import {IonicConfig} from '../../config/config';
'isActive'
],
host: {
'[attr.aria-label]': 'label',
'role': 'img'
}
})
export class Icon {
/**
* TODO
* @param {ElementRef} elementRef TODO
* @param {IonicConfig} config TODO
* @param {Renderer} renderer TODO
*/
constructor(
private elementRef: ElementRef,
config: IonicConfig,
@@ -37,9 +28,6 @@ export class Icon {
this.mode = config.get('iconMode');
}
/**
* TODO
*/
onInit() {
let ele = this.eleRef.nativeElement;
@@ -101,7 +89,8 @@ export class Icon {
this._name = this.name;
this.renderer.setElementClass(this.elementRef, this.name, true);
this.label = this.name.replace('ion-', '').replace('ios-', '').replace('md-', '').replace('-', ' ');
this.renderer.setElementAttribute(this.elementRef, 'aria-label',
this.name.replace('ion-', '').replace('ios-', '').replace('md-', '').replace('-', ' '));
}
}

View File

@@ -38,7 +38,7 @@ export class ItemGroupTitle {
* TODO
* @param {ElementRef} elementRef TODO
*/
constructor(elementRef: ElementRef, config: IonicConfig, @Host() content: Content) {
constructor(elementRef: ElementRef, config: IonicConfig, @Optional() @Host() content: Content) {
this.isSticky = true;
this.content = content;
this.ele = elementRef.nativeElement;
@@ -46,6 +46,7 @@ export class ItemGroupTitle {
}
onInit() {
if(!this.content) { return; }
this.scrollContent = this.content.elementRef.nativeElement.children[0];
@@ -85,7 +86,7 @@ export class ItemGroupTitle {
if (element.style[CSS.transform] == transformString) {
}
else {
element.style[CSS.transform] = transformString;
element.style[CSS.transform] = transformString;
}
}
@@ -94,12 +95,12 @@ export class ItemGroupTitle {
// if immediate execution is requested, then just execute immediately
// if not, execute in the animation frame.
if (executeImmediately) {
this.applyTransform(element, translateDyPixelsUp);
this.applyTransform(element, translateDyPixelsUp);
}
else {
// see http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// see http://ionicframework.com/docs/api/utility/ionic.DomUtil/
requestAnimationFrame( a => this.applyTransform(element, translateDyPixelsUp) );
// see http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// see http://ionicframework.com/docs/api/utility/ionic.DomUtil/
requestAnimationFrame( a => this.applyTransform(element, translateDyPixelsUp) );
}
}
@@ -122,10 +123,10 @@ export class ItemGroupTitle {
// if you want to experiment, always use the throttled one and just click on the page
// you will see all affix elements stacked on top
if (scrollTop == 0) {
this.calculateScrollLimits(scrollTop);
this.calculateScrollLimits(scrollTop);
}
else {
this.throttledCalculateScrollLimits(scrollTop);
this.throttledCalculateScrollLimits(scrollTop);
}
// when we scrolled to the container, create the clone of element and place it on top
@@ -136,9 +137,9 @@ export class ItemGroupTitle {
var cloneCreatedJustNow = false;
if (!this.affixClone) {
this.affixClone = this.createAffixClone();
cloneCreatedJustNow = true;
this.isSticking = true;
this.affixClone = this.createAffixClone();
cloneCreatedJustNow = true;
this.isSticking = true;
}
// if we're reaching towards the end of the container, apply some nice translation to move up/down the clone

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, ElementRef, NgIf, Host, Optional} from 'angular2/angular2';
import {Component, Directive, ElementRef, NgIf, Host, Optional, Renderer} from 'angular2/angular2';
import {Gesture} from 'ionic/gestures/gesture';
import {DragGesture} from 'ionic/gestures/drag-gesture';
@@ -30,22 +30,17 @@ import {CSS, raf} from 'ionic/util/dom';
*/
@Component({
selector: 'ion-item-sliding,[ion-item-sliding]',
host: {
'class': 'item'
},
properties: [
inputs: [
'sliding'
]
})
@View({
],
template:
'<ng-content select="ion-item-options"></ng-content>' +
'<ion-item-sliding-content>' +
'<ion-item-content>' +
'<ng-content></ng-content>'+
'</ion-item-content>' +
'<ng-content select="[item-right]"></ng-content>' +
'</ion-item-sliding-content>',
'<ng-content select="ion-item-options"></ng-content>' +
'<ion-item-sliding-content>' +
'<ion-item-content>' +
'<ng-content></ng-content>'+
'</ion-item-content>' +
'<ng-content select="[item-right]"></ng-content>' +
'</ion-item-sliding-content>',
directives: [NgIf]
})
export class ItemSliding {
@@ -53,7 +48,9 @@ export class ItemSliding {
* TODO
* @param {ElementRef} elementRef A reference to the component's DOM element.
*/
constructor(elementRef: ElementRef, @Optional() @Host() list: List) {
constructor(elementRef: ElementRef, renderer: Renderer, @Optional() @Host() list: List) {
renderer.setElementClass(elementRef, 'item', true);
this._isOpen = false;
this._isSlideActive = false;
this._isTransitioning = false;

View File

@@ -1,4 +1,4 @@
import {Component, View, ElementRef, Renderer} from 'angular2/angular2';
import {Component, ElementRef, Renderer} from 'angular2/angular2';
/**
@@ -18,9 +18,7 @@ import {Component, View, ElementRef, Renderer} from 'angular2/angular2';
* ```
*/
@Component({
selector: 'ion-item,[ion-item]'
})
@View({
selector: 'ion-item,[ion-item]',
template:
'<ng-content select="[item-left]"></ng-content>' +
'<ng-content select="[item-right]"></ng-content>' +

View File

@@ -149,7 +149,7 @@ $item-md-sliding-transition: transform 250ms ease-in-out !default;
}
icon[item-left] + ion-item-content,
icon[item-left] + .text-input {
icon[item-left] + [text-input] {
margin-left: $item-md-padding-left + ($item-md-padding-left / 2);
}

View File

@@ -1,4 +1,4 @@
import {Directive, ElementRef} from 'angular2/angular2';
import {Directive, ElementRef, Renderer} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
@@ -22,10 +22,7 @@ import * as util from 'ionic/util';
'items',
'virtual',
'content'
],
host: {
'class': 'list'
}
]
})
export class List extends Ion {
/**
@@ -33,8 +30,9 @@ export class List extends Ion {
* @param {ElementRef} elementRef TODO
* @param {IonicConfig} config TODO
*/
constructor(elementRef: ElementRef, config: IonicConfig) {
constructor(elementRef: ElementRef, config: IonicConfig, renderer: Renderer) {
super(elementRef, config);
renderer.setElementClass(elementRef, 'list', true);
this.ele = elementRef.nativeElement;
}
/**

View File

@@ -1,4 +1,4 @@
import {forwardRef, Directive, Host, View, EventEmitter, ElementRef} from 'angular2/angular2';
import {forwardRef, Directive, Host, EventEmitter, ElementRef} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicApp} from '../app/app';
@@ -54,12 +54,10 @@ import * as gestures from './menu-gestures';
'side': 'left',
'type': 'reveal'
},
outputs: ['opening'],
host: {
'role': 'navigation'
},
outputs: ['opening']
})
@View({
template: '<ng-content></ng-content><backdrop tappable disable-activated></backdrop>',
directives: [forwardRef(() => MenuBackdrop)]
})

View File

@@ -5,6 +5,6 @@
$navbar-ios-height: 4.4rem !default;
.nav .navbar-container {
.navbar-container {
min-height: $navbar-ios-height;
}

View File

@@ -5,23 +5,19 @@
$navbar-md-height: 5.6rem !default;
.nav {
.navbar-container {
min-height: $navbar-md-height;
}
.back-button {
margin: 0 0 0 12px;
box-shadow: none;
}
.back-button-icon {
margin: 0;
min-width: 44px;
font-size: 2.4rem;
font-weight: normal;
text-align: left;
}
.navbar-container {
min-height: $navbar-md-height;
}
.toolbar .back-button {
margin: 0 0 0 12px;
box-shadow: none;
}
.toolbar .back-button-icon {
margin: 0;
min-width: 44px;
font-size: 2.4rem;
font-weight: normal;
text-align: left;
}

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, Optional, ElementRef, TemplateRef, forwardRef, Inject} from 'angular2/angular2';
import {Component, Directive, Optional, ElementRef, Renderer, TemplateRef, forwardRef, Inject} from 'angular2/angular2';
import {Ion} from '../ion';
import {Icon} from '../icon/icon';
@@ -51,11 +51,6 @@ class BackButtonText extends Ion {
@Component({
selector: 'ion-navbar',
host: {
'class': 'toolbar'
}
})
@View({
template:
'<div class="toolbar-inner">' +
'<button class="back-button">' +
@@ -77,9 +72,11 @@ export class Navbar extends ToolbarBase {
app: IonicApp,
@Optional() viewCtrl: ViewController,
elementRef: ElementRef,
config: IonicConfig
config: IonicConfig,
renderer: Renderer
) {
super(elementRef, config);
renderer.setElementClass(elementRef, 'toolbar', true);
this.app = app;
viewCtrl && viewCtrl.navbarView(this);

View File

@@ -1,4 +1,4 @@
import {ComponentRef, Compiler, ElementRef, Injector, bind, NgZone, DynamicComponentLoader, AppViewManager} from 'angular2/angular2';
import {Compiler, ElementRef, Injector, bind, NgZone, DynamicComponentLoader, AppViewManager} from 'angular2/angular2';
import {Ion} from '../ion';
import {makeComponent} from '../../config/decorators';
@@ -188,7 +188,7 @@ export class NavController extends Ion {
let enteringView = new ViewController(this, componentType, params);
// add the view to the stack
this.add(enteringView);
this._add(enteringView);
if (this.router) {
// notify router of the state change
@@ -253,12 +253,13 @@ export class NavController extends Ion {
}
/**
* @private
* Pop to a specific view in the history stack
*
* @param view {Component} to pop to
* @param view {ViewController} to pop to
* @param opts {object} pop options
*/
popTo(view, opts = {}) {
_popTo(view, opts = {}) {
// Get the target index of the view to pop to
let viewIndex = this._views.indexOf(view);
@@ -304,7 +305,7 @@ export class NavController extends Ion {
* @param opts extra animation options
*/
popToRoot(opts = {}) {
this.popTo(this._views[0]);
this._popTo(this.first());
}
/**
@@ -331,6 +332,27 @@ export class NavController extends Ion {
this._incrementId(viewCtrl);
this._views.splice(index, 0, viewCtrl);
return Promise.resolve();
}
/**
* Removes a view from the nav stack at the specified index.
* @param {TODO} index TODO
* @returns {Promise} TODO
*/
remove(index) {
if (index < 0 || index >= this._views.length) {
return Promise.reject("Index out of range");
}
let viewToRemove = this._views[index];
if (this.isActive(viewToRemove)){
return this.pop();
} else {
this._remove(index);
viewToRemove.destroy();
return Promise.resolve();
}
}
/**
@@ -383,7 +405,7 @@ export class NavController extends Ion {
viewCtrl.shouldCache = false;
// add the item to the stack
this.add(viewCtrl);
this._add(viewCtrl);
}
}
}
@@ -505,7 +527,7 @@ export class NavController extends Ion {
* @private
* TODO
*/
createViewComponetRef(type, hostProtoViewRef, viewContainer, viewCtrlBindings) {
createViewComponentRef(type, hostProtoViewRef, viewContainer, viewCtrlBindings) {
let bindings = this.bindings.concat(viewCtrlBindings);
// the same guts as DynamicComponentLoader.loadNextToLocation
@@ -520,7 +542,14 @@ export class NavController extends Ion {
viewContainer.remove(index);
}
};
return new ComponentRef(newLocation, component, type, null, dispose);
// TODO: make-shift ComponentRef_, this is pretty much going to
// break in future versions of ng2, keep an eye on it
return {
location: newLocation,
instance: component,
dispose: dispose
};
}
/**
@@ -749,7 +778,7 @@ export class NavController extends Ion {
});
destroys.forEach(view => {
this.remove(view);
this._remove(view);
view.destroy();
});
@@ -873,11 +902,12 @@ export class NavController extends Ion {
}
/**
* @private
* TODO
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
add(view) {
_add(view) {
this._incrementId(view);
this._views.push(view);
}
@@ -887,11 +917,12 @@ export class NavController extends Ion {
}
/**
* @private
* TODO
* @param {TODO} viewOrIndex TODO
* @returns {TODO} TODO
*/
remove(viewOrIndex) {
_remove(viewOrIndex) {
util.array.remove(this._views, viewOrIndex);
}

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, ElementRef, Host, Optional, forwardRef, Inject, NgZone, Compiler, AppViewManager, DynamicComponentLoader, Renderer, ViewContainerRef} from 'angular2/angular2';
import {Component, Directive, ElementRef, Host, Optional, forwardRef, Inject, NgZone, Compiler, AppViewManager, DynamicComponentLoader, Renderer, ViewContainerRef} from 'angular2/angular2';
import {IonicApp} from '../app/app';
import {IonicConfig} from '../../config/config';
@@ -129,9 +129,7 @@ import {NavController} from './nav-controller';
],
defaultInputs: {
'swipeBackEnabled': true
}
})
@View({
},
template: '<template pane-anchor></template>',
directives: [forwardRef(() => NavPaneAnchor)]
})
@@ -195,11 +193,11 @@ export class Nav extends NavController {
// the component being loaded is an <ion-tabs>
// Tabs is essentially a pane, cuz it has its own navbar and content containers
let contentContainerRef = this._viewManager.getViewContainer(this.anchorElementRef());
let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, contentContainerRef, this.getBindings(viewCtrl));
viewComponetRef.instance._paneView = true;
let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, contentContainerRef, this.getBindings(viewCtrl));
viewComponentRef.instance._paneView = true;
viewCtrl.disposals.push(() => {
viewComponetRef.dispose();
viewComponentRef.dispose();
});
viewCtrl.onReady().then(() => {
@@ -210,9 +208,9 @@ export class Nav extends NavController {
// normal ion-view going into pane
this.getPane(structure, viewCtrl, (pane) => {
// add the content of the view into the pane's content area
let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, pane.contentContainerRef, this.getBindings(viewCtrl));
let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, pane.contentContainerRef, this.getBindings(viewCtrl));
viewCtrl.disposals.push(() => {
viewComponetRef.dispose();
viewComponentRef.dispose();
// remove the pane if there are no view items left
pane.totalViews--;
@@ -226,10 +224,10 @@ export class Nav extends NavController {
// a new ComponentRef has been created
// set the ComponentRef's instance to this ViewController
viewCtrl.setInstance(viewComponetRef.instance);
viewCtrl.setInstance(viewComponentRef.instance);
// remember the ElementRef to the content that was just created
viewCtrl.viewElementRef(viewComponetRef.location);
viewCtrl.viewElementRef(viewComponentRef.location);
// get the NavController's container for navbars, which is
// the place this NavController will add each ViewController's navbar
@@ -406,12 +404,7 @@ class ContentAnchor {
*/
@Component({
selector: 'ion-pane',
host: {
'class': 'nav'
}
})
@View({
template: '' +
template:
'<section class="navbar-container">' +
'<template navbar-anchor></template>' +
'</section>' +
@@ -437,9 +430,7 @@ class Pane {
showNavbar(hasNavbar) {
this.navbar = hasNavbar;
if (!hasNavbar) {
this.renderer.setElementAttribute(this.elementRef, 'no-navbar', '');
}
this.renderer.setElementAttribute(this.elementRef, 'no-navbar', hasNavbar ? null : '' );
}
}

View File

@@ -104,6 +104,7 @@ class SecondPage {
<p>
<button id="from3To2" (click)="pop()">Pop (Go back to 2nd)</button>
<button id="insert" (click)="insert()">Insert first page into history before this</button>
<button id="remove" (click)="removeSecond()">Remove second page in history</button>
</p>
<div class="yellow"><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f></div>
</ion-content>
@@ -124,6 +125,10 @@ class ThirdPage {
this.nav.insert(FirstPage, 2);
}
removeSecond() {
this.nav.remove(1);
}
}

View File

@@ -1,19 +1,19 @@
import {
ddescribe,
describe,
xdescribe,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
AsyncTestCompleter,
inject,
beforeEachBindings
} from 'angular2/test';
// import {
// ddescribe,
// describe,
// xdescribe,
// it,
// iit,
// xit,
// expect,
// beforeEach,
// afterEach,
// AsyncTestCompleter,
// inject,
// beforeEachBindings
// } from 'angular2/test';
import {Compiler} from 'angular2/angular2';
// import {Compiler} from 'angular2/angular2';
import {
NavController,
@@ -23,18 +23,43 @@ import {
} from 'ionic/ionic';
@Page({
template: ''
})
class SomePage {}
export function run() {
describe("NavController", () => {
let nav;
beforeEach(inject([Compiler], compiler => {
nav = new NavController(null, null, new IonicConfig(), null, compiler, null, null, null);
}));
class FirstPage {}
class SecondPage {}
class ThirdPage {}
function mockTransitionFn(enteringView, leavingView, opts, cb) {
let destroys = [];
nav._views.forEach(view => {
if (view) {
if (view.shouldDestroy) {
destroys.push(view);
} else if (view.state === 2 && view.shouldCache) {
view.shouldCache = false;
}
}
});
destroys.forEach(view => {
nav._remove(view);
view.destroy();
});
cb();
}
function mockCanGoBackFn() {
return true;
}
// beforeEach(inject([Compiler], compiler => {
beforeEach(() => {
nav = new NavController(null, null, new IonicConfig(), null, null, null, null, null);
});
it('should exist', () => {
expect(nav).not.toBeUndefined();
@@ -50,7 +75,7 @@ export function run() {
let activeView = new ViewController();
activeView.state = 1; // ACTIVE_STATE
nav.add(activeView);
nav._add(activeView);
var active = nav.getActive();
expect(active).toBe(activeView);
@@ -58,7 +83,7 @@ export function run() {
let secondActiveView = new ViewController();
secondActiveView.state = 1; // ACTIVE_STATE
nav.add(secondActiveView);
nav._add(secondActiveView);
active = nav.getActive();
expect(active).toBe(activeView);
@@ -93,13 +118,128 @@ export function run() {
expect(push).toThrow();
});
it('be successful', () => {
expect(SomePage).toBeDefined();
it('to add the pushed page to the nav stack', (done) => {
expect(FirstPage).toBeDefined();
expect(nav._views.length).toBe(0);
nav.push(SomePage, {}, {});
spyOn(nav, '_add').and.callThrough();
nav.transition = mockTransitionFn;
nav.push(FirstPage, {}, {}).then(() => {
expect(nav._add).toHaveBeenCalled();
expect(nav._views.length).toBe(1);
done();
});
});
});
describe("setViews", () => {
it('should return a resolved Promise if components is falsy', done => {
let s = jasmine.createSpy('success');
let f = jasmine.createSpy('fail');
let promise = nav.setViews();
promise.then(s, f).then(() => {
expect(s).toHaveBeenCalled();
expect(f).not.toHaveBeenCalled();
done();
});
});
})
});
it('replace views with the supplied views', () => {
let vc1 = new ViewController(),
vc2 = new ViewController(),
vc3 = new ViewController();
nav._views = [vc1, vc2, vc3];
let arr = [FirstPage, SecondPage, ThirdPage];
nav.transition = mockTransitionFn;
nav.setViews(arr);
//_views[0] will be transitioned out of
expect(nav._views[1].componentType).toBe(FirstPage);
expect(nav._views[2].componentType).toBe(SecondPage);
expect(nav._views[3].componentType).toBe(ThirdPage);
});
});
describe("insert", () => {
it('insert page at the specified index', () => {
nav._views = [{}, {}, {}];
expect(nav._views[2].componentType).toBeUndefined();
nav.insert(FirstPage, 2);
expect(nav._views[2].componentType).toBe(FirstPage);
});
it('push page if index >= _views.length', () => {
nav._views = [{}, {}, {}];
spyOn(nav, 'push').and.callThrough();
nav.insert(FirstPage, 2);
expect(nav.push).not.toHaveBeenCalled();
nav.transition = mockTransitionFn;
nav.insert(FirstPage, 4);
expect(nav._views[4].componentType).toBe(FirstPage);
expect(nav.push).toHaveBeenCalled();
nav.insert(FirstPage, 10);
expect(nav._views[5].componentType).toBe(FirstPage);
expect(nav.push.calls.count()).toBe(2);
});
});
describe("setRoot", () => {
it('remove previous views and set root', () => {
let vc1 = new ViewController(),
vc2 = new ViewController(),
vc3 = new ViewController();
nav._views = [vc1, vc2, vc3];
expect(nav._views.length).toBe(3);
nav.transition = mockTransitionFn;
nav.setRoot(FirstPage);
//_views[0] will be transitioned out of
expect(nav._views.length).toBe(2);
expect(nav._views[1].componentType).toBe(FirstPage);
});
});
describe("remove", () => {
it('should remove the view at the specified index', () => {
let vc1 = new ViewController(),
vc2 = new ViewController(null, FirstPage),
vc3 = new ViewController(null, SecondPage);
nav._views = [vc1, vc2, vc3];
expect(nav._views.length).toBe(3);
expect(nav._views[1].componentType).toBe(FirstPage);
nav.remove(1);
expect(nav._views.length).toBe(2);
expect(nav._views[1].componentType).toBe(SecondPage);
});
it('should pop if index is of active view', () => {
let vc1 = new ViewController(),
vc2 = new ViewController(null, FirstPage),
vc3 = new ViewController(null, SecondPage);
vc3.state = 1; //ACTIVE_STATE
nav._views = [vc1, vc2, vc3];
spyOn(nav, 'pop').and.callThrough();
nav.remove(1);
expect(nav.pop).not.toHaveBeenCalled();
nav.remove(1);
expect(nav.pop).toHaveBeenCalled();
});
});
});
}

View File

@@ -1,143 +0,0 @@
import {
Directive,
Component,
View,
bootstrap,
Injectable,
Inject,
forwardRef,
Inject,
DynamicComponentLoader,
ElementRef,
Query,
QueryList,
ComponentRef
} from 'angular2/angular2';
@Injectable()
class IonicModal {
constructor() {
console.log('IonicModal constructor');
}
open(componentType) {
console.log('IonicModal open:', componentType.name);
}
}
@Injectable()
class UserService {
constructor() {
console.log('UserService constructor');
this.id = Math.random();
}
}
@Directive({
selector: 'button',
host: {
'ionic-button': 'true'
}
})
class IonicButton {
constructor() {
console.log('IonicButton')
}
}
@Directive({
selector: 'button',
host: {
'user-button': 'true'
}
})
class UserButton {
constructor() {
console.log('UserButton')
}
}
var IONIC_DIRECTIVES = [IonicButton];
@Component({
selector: 'user-modal'
})
@View({
template: `
<div style="position:absolute;top:0;right:0;bottom:0;left:0;background:#ddd;">
<h2>user modal</h2>
<p>UserService: {{userService.id}}
</div>
`
})
class UserModal {
constructor(userService: UserService) {
console.log('UserModal constructor');
this.userService = userService;
}
}
@Component({
selector: 'user-app',
hostInjector: [UserService]
})
@View({
template: `
<h1>user root component</h1>
<button (click)="openModal()">Open Modal</button>
<ng-content></ng-content>
`,
directives: IONIC_DIRECTIVES.concat([UserButton])
})
class UserRootComponent {
constructor(ionicModal: IonicModal, userService: UserService) {
console.log('UserRootComponent constructor');
this.ionicModal = ionicModal;
}
openModal(){
this.ionicModal.open(UserModal);
}
}
@Directive({
selector: 'overlay-anchor'
})
class OverlayAnchor {
constructor(
userService: UserService,
public elementRef: ElementRef,
loader: DynamicComponentLoader)
{
console.log('OverlayAnchor constructor', userService);
loader.loadNextToLocation(UserModal, elementRef).then((ref: ComponentRef) => {
});
}
}
function ionicApp(userApp: Type) {
function IonicRootComponent() {}
IonicRootComponent.annotations = [
new Component({
selector: 'ion-app',
viewInjector: [IonicModal]
}),
new View({
template: `
<user-app>
<overlay-anchor></overlay-anchor>
</user-app>`,
directives: [userApp, OverlayAnchor]
})
];
return IonicRootComponent;
}
console.log('bootstrap')
bootstrap(ionicApp(UserRootComponent)).catch(err => {
console.error('bootstrap', err);
});

View File

@@ -1,4 +1,4 @@
import {Component, View, NgZone, Injectable, Renderer} from 'angular2/angular2';
import {Component, NgZone, Injectable, Renderer} from 'angular2/angular2';
import {IonicApp} from '../app/app';
import {Animation} from '../../animations/animation';

View File

@@ -1,12 +1,10 @@
import {Component, View, ElementRef, DynamicComponentLoader} from 'angular2/angular2';
import {Component, ElementRef, DynamicComponentLoader} from 'angular2/angular2';
import {OverlayController} from './overlay-controller';
@Component({
selector: 'ion-overlay'
})
@View({
selector: 'ion-overlay',
template: ''
})
export class OverlayAnchor {

View File

@@ -1,5 +1,5 @@
import {FORM_DIRECTIVES, NgControl, NgControlGroup,
Component, View, ElementRef, Injectable, NgClass, NgIf, NgFor} from 'angular2/angular2';
Component, ElementRef, Injectable, NgClass, NgIf, NgFor} from 'angular2/angular2';
import {OverlayController} from '../overlay/overlay-controller';
import {IonicConfig} from '../../config/config';
@@ -265,25 +265,23 @@ export class Popup {
const OVERLAY_TYPE = 'popup';
@Component({
selector: 'ion-popup'
})
// TODO add button type to button: [type]="button.type"
@View({
@Component({
selector: 'ion-popup',
template:
'<backdrop (click)="_cancel($event)" tappable disable-activated></backdrop>' +
'<popup-wrapper [ng-class]="cssClass">' +
'<div class="popup-head">' +
'<h2 class="popup-title" [inner-html]="title" *ng-if="title"></h2>' +
'<h3 class="popup-sub-title" [inner-html]="subTitle" *ng-if="subTitle"></h3>' +
'</div>' +
'<div class="popup-body">' +
'<div [inner-html]="template" *ng-if="template"></div>' +
'<input type="{{inputType || \'text\'}}" placeholder="{{inputPlaceholder}}" *ng-if="showPrompt" class="prompt-input">' +
'</div>' +
'<div class="popup-buttons" *ng-if="buttons.length">' +
'<button *ng-for="#button of buttons" (click)="buttonTapped(button, $event)" [inner-html]="button.text"></button>' +
'</div>' +
'<backdrop (click)="_cancel($event)" tappable disable-activated></backdrop>' +
'<popup-wrapper [ng-class]="cssClass">' +
'<div class="popup-head">' +
'<h2 class="popup-title" [inner-html]="title" *ng-if="title"></h2>' +
'<h3 class="popup-sub-title" [inner-html]="subTitle" *ng-if="subTitle"></h3>' +
'</div>' +
'<div class="popup-body">' +
'<div [inner-html]="template" *ng-if="template"></div>' +
'<input type="{{inputType || \'text\'}}" placeholder="{{inputPlaceholder}}" *ng-if="showPrompt" class="prompt-input">' +
'</div>' +
'<div class="popup-buttons" *ng-if="buttons.length">' +
'<button *ng-for="#button of buttons" (click)="buttonTapped(button, $event)" [inner-html]="button.text"></button>' +
'</div>' +
'</popup-wrapper>',
directives: [FORM_DIRECTIVES, NgClass, NgIf, NgFor, Button]
})

View File

@@ -1,4 +1,4 @@
import {Component, Directive, ElementRef, Host, Optional, NgControl, Query, QueryList, View} from 'angular2/angular2';
import {Component, Directive, ElementRef, Renderer, Host, Optional, NgControl, Query, QueryList} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
import {Ion} from '../ion';
@@ -45,7 +45,6 @@ import {ListHeader} from '../list/list';
@Directive({
selector: 'ion-radio-group',
host: {
'class': 'list',
'role': 'radiogroup',
'[attr.aria-activedescendant]': 'activeId',
'[attr.aria-describedby]': 'describedById'
@@ -64,10 +63,13 @@ export class RadioGroup extends Ion {
constructor(
elementRef: ElementRef,
config: IonicConfig,
renderer: Renderer,
@Optional() ngControl: NgControl,
@Query(ListHeader) private headerQuery: QueryList<ListHeader>
) {
super(elementRef, config);
renderer.setElementClass(elementRef, 'list', true);
this.id = ++radioGroupIds;
this.radioIds = -1;
this.onChange = (_) => {};
@@ -170,7 +172,6 @@ export class RadioGroup extends Ion {
'id'
],
host: {
'class': 'item',
'role': 'radio',
'tappable': 'true',
'[attr.id]': 'id',
@@ -179,16 +180,14 @@ export class RadioGroup extends Ion {
'[attr.aria-disabled]': 'disabled',
'[attr.aria-labelledby]': 'labelId',
'(click)': 'click($event)'
}
})
@View({
},
template:
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>' +
'<media-radio>' +
'<radio-icon></radio-icon>' +
'</media-radio>'
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>' +
'<media-radio>' +
'<radio-icon></radio-icon>' +
'</media-radio>'
})
export class RadioButton extends Ion {
/**
@@ -200,9 +199,12 @@ export class RadioButton extends Ion {
constructor(
@Host() @Optional() group: RadioGroup,
elementRef: ElementRef,
config: IonicConfig
config: IonicConfig,
renderer: Renderer
) {
super(elementRef, config)
super(elementRef, config);
renderer.setElementClass(elementRef, 'item', true);
this.group = group;
this.tabIndex = 0;
}

View File

@@ -1,10 +1,10 @@
import {Component, View, NgIf, NgClass, ElementRef, EventEmitter, Host} from 'angular2/angular2'
import {Component, NgIf, NgClass, ElementRef, EventEmitter, Host} from 'angular2/angular2'
import {Content} from '../content/content';
import * as util from 'ionic/util';
import {raf, ready, CSS} from 'ionic/util/dom';
/**
* Allows you to add pull-to-refresh to an Content component.
*
@@ -50,20 +50,18 @@ import {raf, ready, CSS} from 'ionic/util/dom';
'[class.active]': 'isActive',
'[class.refreshing]': 'isRefreshing',
'[class.refreshingTail]': 'isRefreshingTail'
}
})
@View({
template: `<div class="refresher-content" [class.refresher-with-text]="pullingText || refreshingText">
<div class="icon-pulling">
<i class="icon" [ng-class]="pullingIcon"></i>
</div>
<div class="text-pulling" [inner-html]="pullingText" *ng-if="pullingText"></div>
<div class="icon-refreshing">
<!--<ion-spinner ng-if="showSpinner" icon="{{spinner}}"></ion-spinner>-->
<i class="icon" [ng-class]="refreshingIcon"></i>
</div>
<div class="text-refreshing" [inner-html]="refreshingText" *ng-if="refreshingText"></div>
</div>`,
},
template:
'<div class="refresher-content" [class.refresher-with-text]="pullingText || refreshingText">' +
'<div class="icon-pulling">' +
'<i class="icon" [ng-class]="pullingIcon"></i>' +
'</div>' +
'<div class="text-pulling" [inner-html]="pullingText" *ng-if="pullingText"></div>' +
'<div class="icon-refreshing">' +
'<i class="icon" [ng-class]="refreshingIcon"></i>' +
'</div>' +
'<div class="text-refreshing" [inner-html]="refreshingText" *ng-if="refreshingText"></div>' +
'</div>',
directives: [NgIf, NgClass]
})
export class Refresher {

View File

@@ -1,4 +1,4 @@
import {Component, View, ElementRef, onInit} from 'angular2/angular2';
import {Component, ElementRef, onInit} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
@@ -21,9 +21,12 @@ import * as util from 'ionic/util';
'[class.scroll-x]': 'scrollX',
'[class.scroll-y]': 'scrollY'
},
})
@View({
template: '<scroll-content><div class="scroll-zoom-wrapper"><ng-content></ng-content></div></scroll-content>'
template:
'<scroll-content>' +
'<div class="scroll-zoom-wrapper">' +
'<ng-content></ng-content>' +
'</div>' +
'</scroll-content>'
})
export class Scroll extends Ion {
/**

View File

@@ -23,7 +23,7 @@ $search-bar-ios-input-close-icon-svg: "<svg xmlns='http://www.w3.org/2000/sv
$search-bar-ios-input-close-icon-size: 17px !default;
.search-bar {
ion-search-bar {
padding: $search-bar-ios-padding;
background: $search-bar-ios-background-color;
border-bottom: 1px solid $search-bar-ios-border-color;
@@ -98,6 +98,14 @@ $search-bar-ios-input-close-icon-size: 17px !default;
}
}
&.hairlines .search-bar {
.search-bar-cancel {
@extend button[clear];
transition: $search-bar-ios-cancel-transition;
padding-left: 8px;
min-height: 0;
padding-right: 0;
}
&.hairlines ion-search-bar {
border-bottom-width: 0.55px;
}

View File

@@ -21,7 +21,7 @@ $search-bar-md-input-close-icon-svg: "<svg xmlns='http://www.w3.org/2000/svg
$search-bar-md-input-close-icon-size: 22px !default;
.search-bar {
ion-search-bar {
padding: $search-bar-md-padding;
background: $search-bar-md-background-color;
}

View File

@@ -3,7 +3,7 @@
// --------------------------------------------------
.search-bar {
ion-search-bar {
position: relative;
display: flex;
align-items: center;

View File

@@ -1,4 +1,4 @@
import {ElementRef, Pipe, NgControl, Renderer, View, FORM_DIRECTIVES, NgIf, NgClass} from 'angular2/angular2';
import {ElementRef, Pipe, NgControl, Renderer, FORM_DIRECTIVES, NgIf, NgClass} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
@@ -33,17 +33,15 @@ import {ConfigComponent} from '../../config/decorators';
this.element = this.elementRef.nativeElement.querySelector('input');
this.element.blur();
}
}
})
@View({
template: `
<div class="search-bar-input-container" [class.left-align]="shouldLeftAlign">
<div class="search-bar-search-icon"></div>
<input (focus)="inputFocused()" (blur)="inputBlurred()"
(input)="inputChanged($event)" class="search-bar-input" type="search" [attr.placeholder]="placeholder" [(ng-model)]="value">
<div class="search-bar-close-icon" (click)="clearInput()"></div>
</div>
<button *ng-if="showCancel" (click)="cancelAction()" class="search-bar-cancel" [class.left-align]="shouldLeftAlign">{{cancelText}}</button>`,
},
template:
'<div class="search-bar-input-container" [class.left-align]="shouldLeftAlign">' +
'<div class="search-bar-search-icon"></div>' +
'<input (focus)="inputFocused()" (blur)="inputBlurred()" ' +
'(input)="inputChanged($event)" class="search-bar-input" type="search" [attr.placeholder]="placeholder" [(ng-model)]="value">' +
'<div class="search-bar-close-icon" (click)="clearInput()"></div>' +
'</div>' +
'<button *ng-if="showCancel" (click)="cancelAction()" class="search-bar-cancel" [class.left-align]="shouldLeftAlign">{{cancelText}}</button>',
directives: [FORM_DIRECTIVES, NgIf, NgClass]
})

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, Renderer, ElementRef, EventEmitter, Host, forwardRef, Optional} from 'angular2/angular2';
import {Component, Directive, Renderer, ElementRef, EventEmitter, Host, forwardRef, Optional} from 'angular2/angular2';
import {Control, NgControl, NgFormControl, ControlGroup, ControlDirective} from 'angular2/angular2';
import {Ion} from '../ion';
@@ -25,9 +25,7 @@ import {dom} from 'ionic/util';
'[class.ng-valid]': 'cd.control?.valid == true',
'[class.ng-invalid]': 'cd.control?.valid == false'
*/
}
})
@View({
},
template: '<div class="ion-segment"><ng-content></ng-content></div>',
directives: [forwardRef(() => SegmentButton)]
})

View File

@@ -1,4 +1,4 @@
import {Directive, Component, View, ElementRef, Host, NgIf, NgClass} from 'angular2/angular2';
import {Directive, Component, ElementRef, Host, NgClass} from 'angular2/angular2';
import {Ion} from '../ion';
import {Animation} from 'ionic/animations/animation';
@@ -39,16 +39,15 @@ import {Scroll} from '../scroll/scroll';
'zoom',
'zoomDuration',
'zoomMax'
]
})
@View({
template: `<div class="swiper-container">
<div class="swiper-wrapper">
<ng-content></ng-content>
</div>
<div [class.hide]="!showPager" class="swiper-pagination"></div>
</div>`,
directives: [NgIf, NgClass]
],
template:
'<div class="swiper-container">' +
'<div class="swiper-wrapper">' +
'<ng-content></ng-content>' +
'</div>' +
'<div [class.hide]="!showPager" class="swiper-pagination"></div>' +
'</div>',
directives: [NgClass]
})
export class Slides extends Ion {
@@ -448,10 +447,8 @@ export class Slides extends Ion {
*/
@Component({
selector: 'ion-slide',
inputs: ['zoom']
})
@View({
template: `<div class="slide-zoom"><ng-content></ng-content></div>`
inputs: ['zoom'],
template: '<div class="slide-zoom"><ng-content></ng-content></div>'
})
export class Slide {
/**

View File

@@ -1,17 +1,6 @@
import {
Component,
View,
Directive,
ElementRef,
Host,
Optional,
NgControl,
Inject,
forwardRef
} from 'angular2/angular2';
import {Component, Directive, ElementRef, Renderer, Host, Optional, NgControl, Inject, forwardRef} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonInput} from '../form/input';
import {IonicForm} from '../form/form';
import {IonicConfig} from '../../config/config';
import {pointerCoord} from '../../util/dom';
@@ -85,7 +74,6 @@ class MediaSwitch {
'id'
],
host: {
'class': 'item',
'role': 'checkbox',
'tappable': 'true',
'[attr.tab-index]': 'tabIndex',
@@ -96,20 +84,18 @@ class MediaSwitch {
'(mousedown)': 'pointerDown($event)',
'(touchend)': 'pointerUp($event)',
'(mouseup)': 'pointerUp($event)'
}
})
@View({
},
template:
'<ng-content select="[item-left]"></ng-content>' +
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>' +
'<media-switch disable-activated>' +
'<switch-icon></switch-icon>' +
'</media-switch>',
'<ng-content select="[item-left]"></ng-content>' +
'<ion-item-content id="{{labelId}}">' +
'<ng-content></ng-content>' +
'</ion-item-content>' +
'<media-switch disable-activated>' +
'<switch-icon></switch-icon>' +
'</media-switch>',
directives: [MediaSwitch]
})
export class Switch extends Ion {
export class Switch {
/**
* TODO
* @param {ElementRef} elementRef TODO
@@ -117,24 +103,27 @@ export class Switch extends Ion {
* @param {NgControl=} ngControl TODO
*/
constructor(
form: IonicForm,
elementRef: ElementRef,
config: IonicConfig,
renderer: Renderer,
@Optional() private ngControl: NgControl
) {
super(elementRef, config);
let self = this;
this.form = form;
form.register(this);
self.id = IonInput.nextId();
self.tabIndex = 0;
self.lastTouch = 0;
self.mode = config.get('mode');
renderer.setElementClass(elementRef, 'item', true);
self.onChange = (_) => {};
self.onTouched = (_) => {};
this.lastTouch = 0;
this.mode = config.get('mode');
this.onChange = (_) => {};
this.onTouched = (_) => {};
if (ngControl) ngControl.valueAccessor = this;
let self = this;
function pointerMove(ev) {
let currentX = pointerCoord(ev).x;
@@ -156,21 +145,20 @@ export class Switch extends Ion {
}
this.addMoveListener = function() {
this.switchEle.addEventListener('touchmove', pointerMove);
this.switchEle.addEventListener('mousemove', pointerMove);
self.switchEle.addEventListener('touchmove', pointerMove);
self.switchEle.addEventListener('mousemove', pointerMove);
elementRef.nativeElement.addEventListener('mouseout', pointerOut);
};
this.removeMoveListener = function() {
this.switchEle.removeEventListener('touchmove', pointerMove);
this.switchEle.removeEventListener('mousemove', pointerMove);
self.switchEle.removeEventListener('touchmove', pointerMove);
self.switchEle.removeEventListener('mousemove', pointerMove);
elementRef.nativeElement.removeEventListener('mouseout', pointerOut);
};
}
onInit() {
super.onInit();
this.labelId = 'label-' + this.id;
this.labelId = 'label-' + this.inputId;
}
/**
@@ -234,6 +222,7 @@ export class Switch extends Ion {
onDestroy() {
this.removeMoveListener();
this.switchEle = this.addMoveListener = this.removeMoveListener = null;
this.form.deregister(this);
}
isDisabled(ev) {

View File

@@ -1,4 +1,4 @@
import {Directive, Component, View, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, forwardRef, Injector, NgZone, ViewContainerRef} from 'angular2/angular2';
import {Directive, Component, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, forwardRef, Injector, NgZone, ViewContainerRef} from 'angular2/angular2';
import {IonicApp} from '../app/app';
import {IonicConfig} from '../../config/config';
@@ -63,9 +63,7 @@ import {Tabs} from './tabs';
'[attr.aria-labelledby]': 'labeledBy',
'[attr.aria-hidden]': 'isNotSelected',
'role': 'tabpanel'
}
})
@View({
},
template: '<template content-anchor></template><ng-content></ng-content>',
directives: [forwardRef(() => TabContentAnchor)]
})
@@ -155,17 +153,17 @@ export class Tab extends NavController {
loadContainer(componentType, hostProtoViewRef, viewCtrl, done) {
let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, this.contentContainerRef, this.getBindings(viewCtrl));
let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, this.contentContainerRef, this.getBindings(viewCtrl));
viewCtrl.disposals.push(() => {
viewComponetRef.dispose();
viewComponentRef.dispose();
});
// a new ComponentRef has been created
// set the ComponentRef's instance to this ViewController
viewCtrl.setInstance(viewComponetRef.instance);
viewCtrl.setInstance(viewComponentRef.instance);
// remember the ElementRef to the content that was just created
viewCtrl.viewElementRef(viewComponetRef.location);
viewCtrl.viewElementRef(viewComponentRef.location);
// get the NavController's container for navbars, which is
// the place this NavController will add each ViewController's navbar

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, Injector, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, NgZone, Optional, Host, NgFor, forwardRef, ViewContainerRef} from 'angular2/angular2';
import {Component, Directive, Injector, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, NgZone, Optional, Host, NgFor, forwardRef, ViewContainerRef} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicApp} from '../app/app';
@@ -65,10 +65,8 @@ import * as dom from 'ionic/util/dom';
defaultInputs: {
'tabBarPlacement': 'bottom',
'tabBarIcons': 'top'
}
})
@View({
template: '' +
},
template:
'<section class="navbar-container">' +
'<template navbar-anchor></template>' +
'</section>' +
@@ -146,7 +144,7 @@ export class Tabs extends NavController {
* TODO
*/
addTab(tab) {
this.add(tab.viewCtrl);
this._add(tab.viewCtrl);
// return true/false if it's the initial tab
return (this.length() === 1);

View File

@@ -32,7 +32,7 @@ ion-input[floating-label] {
max-width: 100%;
}
.text-input {
[text-input] {
align-self: stretch;
width: auto;
}

View File

@@ -14,7 +14,6 @@ import {pointerCoord, hasPointerMoved} from '../../util/dom';
],
host: {
'[attr.id]': 'id',
'class': 'input-label',
'(touchstart)': 'pointerStart($event)',
'(touchend)': 'pointerEnd($event)',
'(mousedown)': 'pointerStart($event)',

View File

@@ -8,12 +8,12 @@ $input-label-ios-color: #7f7f7f !default;
.list,
ion-card {
.text-input {
[text-input] {
margin: $item-ios-padding-top ($item-ios-padding-right / 2) $item-ios-padding-bottom ($item-ios-padding-left / 2);
padding: 0;
}
ion-input[inset] .text-input {
ion-input[inset] [text-input] {
margin: ($item-ios-padding-top / 2) $item-ios-padding-right ($item-ios-padding-bottom / 2) $item-ios-padding-left;
padding: ($item-ios-padding-top / 2) ($item-ios-padding-right / 2) ($item-ios-padding-bottom / 2) ($item-ios-padding-left / 2);
}
@@ -28,8 +28,8 @@ ion-card {
margin-bottom: 4px;
}
[stacked-label] .text-input,
[floating-label] .text-input {
[stacked-label] [text-input],
[floating-label] [text-input] {
margin-top: 8px;
margin-bottom: 8px;
}

View File

@@ -9,7 +9,7 @@ $input-label-md-color: #999 !default;
.list,
ion-card {
.text-input {
[text-input] {
margin: $item-md-padding-top ($item-md-padding-right / 2) $item-md-padding-bottom ($item-md-padding-left / 2);
padding: 0;
}
@@ -19,7 +19,7 @@ ion-card {
left: 0;
}
ion-input[inset] .text-input {
ion-input[inset] [text-input] {
margin: ($item-md-padding-top / 2) $item-md-padding-right ($item-md-padding-bottom / 2) $item-md-padding-left;
padding: ($item-md-padding-top / 2) ($item-md-padding-right / 2) ($item-md-padding-bottom / 2) ($item-md-padding-left / 2);
}
@@ -48,8 +48,8 @@ ion-card {
color: $text-input-highlight-color;
}
[stacked-label] .text-input,
[floating-label] .text-input {
[stacked-label] [text-input],
[floating-label] [text-input] {
margin-bottom: 8px;
margin-top: 8px;
}

View File

@@ -24,13 +24,13 @@ ion-input.item {
}
}
ion-input .text-input {
ion-input [text-input] {
flex: 1;
background-color: $text-input-background-color;
pointer-events: none;
}
ion-input.has-focus .text-input {
ion-input.has-focus [text-input] {
pointer-events: auto;
}

View File

@@ -1,9 +1,8 @@
import {Directive, View, Host, Optional, ElementRef, Attribute, Query, QueryList, NgZone} from 'angular2/angular2';
import {Directive, Host, Optional, ElementRef, Renderer, Attribute, Query, QueryList, NgZone} from 'angular2/angular2';
import {IonicConfig} from '../../config/config';
import {IonInput} from '../form/input';
import {IonicForm} from '../form/form';
import {Label} from './label';
import {Ion} from '../ion';
import {IonicApp} from '../app/app';
import {Content} from '../content/content';
import * as dom from '../../util/dom';
@@ -15,22 +14,17 @@ import {IonicPlatform} from '../../platform/platform';
*/
@Directive({
selector: 'ion-input',
inputs: [
'tabIndex'
],
host: {
'(focus)': 'receivedFocus(true)',
'(blur)': 'receivedFocus(false)',
'(touchstart)': 'pointerStart($event)',
'(touchend)': 'pointerEnd($event)',
'(mouseup)': 'pointerEnd($event)',
'[class.has-focus]': 'inputHasFocus',
'[class.has-value]': 'inputHasValue',
'[tabIndex]': 'activeTabIndex',
'class': 'item'
'[class.has-focus]': 'hasFocus',
'[class.has-value]': 'hasValue'
}
})
export class TextInput extends Ion {
export class TextInput {
/**
* TODO
* @param {ElementRef} elementRef TODO
@@ -42,31 +36,33 @@ export class TextInput extends Ion {
* @param {QueryList<Label>} labelQry TODO
*/
constructor(
form: IonicForm,
elementRef: ElementRef,
config: IonicConfig,
renderer: Renderer,
app: IonicApp,
ngZone: NgZone,
zone: NgZone,
platform: IonicPlatform,
@Optional() @Host() scrollView: Content
) {
super(elementRef, config);
renderer.setElementClass(elementRef, 'item', true);
this.form = form;
form.register(this);
this.app = app;
this.elementRef = elementRef;
this.zone = zone;
this.platform = platform;
this.scrollView = scrollView;
this.scrollAssist = config.get('keyboardScrollAssist');
this.id = IonInput.nextId();
IonInput.registerInput(this);
this.app = app;
this.zone = ngZone;
this.platform = platform;
this.keyboardHeight = this.config.get('keyboardHeight');
this.keyboardHeight = config.get('keyboardHeight');
}
registerInputElement(textInputElement) {
registerInput(textInputElement) {
this.input = textInputElement;
this.type = textInputElement.type;
textInputElement.tabIndex = -1;
}
registerLabel(label) {
@@ -77,17 +73,16 @@ export class TextInput extends Ion {
* TODO
*/
onInit() {
super.onInit();
if (this.input && this.label) {
this.input.labelledBy = this.label.id = (this.label.id || 'label-' + this.id);
this.label.id = (this.label.id || 'label-' + this.inputId)
this.input.labelledBy(this.label.id);
}
let self = this;
self.scrollMove = (ev) => {
self.deregListeners();
if (self.inputHasFocus) {
if (self.hasFocus) {
self.tempFocusMove();
}
};
@@ -119,7 +114,7 @@ export class TextInput extends Ion {
// focus this input if the pointer hasn't moved XX pixels
// and the input doesn't already have focus
if (!dom.hasPointerMoved(8, this.startCoord, endCoord) && !this.inputHasFocus) {
if (!dom.hasPointerMoved(8, this.startCoord, endCoord) && !this.hasFocus) {
ev.preventDefault();
ev.stopPropagation();
@@ -149,7 +144,6 @@ export class TextInput extends Ion {
* TODO
* @returns {TODO} TODO
*/
//TODO inconsistent return value, sometimes undefined
initFocus() {
let scrollView = this.scrollView;
@@ -327,12 +321,10 @@ export class TextInput extends Ion {
setFocus() {
this.zone.run(() => {
// set focus on the input element
this.input && this.input.setFocus();
this.input && this.input.initFocus();
// ensure the body hasn't scrolled down
document.body.scrollTop = 0;
IonInput.setAsLastInput(this);
});
if (this.scrollAssist && this.scrollView) {
@@ -343,25 +335,26 @@ export class TextInput extends Ion {
}
}
/**
* TODO
*/
tempFocusMove() {
let focusHolder = this.app.focusHolder();
focusHolder.setFocusHolder(this.type);
this.form.setFocusHolder(this.type);
}
get inputHasFocus() {
get hasFocus() {
return !!this.input && this.input.hasFocus;
}
get inputHasValue() {
get hasValue() {
return !!this.input && this.input.hasValue;
}
get activeTabIndex() {
this.input.tabIndex = (this.inputHasFocus ? 1000 : -1);
return -1;
get tabIndex() {
return this.input && this.input.tabIndex;
}
set tabIndex(val) {
if (this.input) {
this.input.tabIndex = val;
}
}
/**
@@ -369,7 +362,7 @@ export class TextInput extends Ion {
* @param {boolean} receivedFocus TODO
*/
receivedFocus(receivedFocus) {
if (receivedFocus && !this.inputHasFocus) {
if (receivedFocus && !this.hasFocus) {
this.initFocus();
} else {
@@ -377,6 +370,11 @@ export class TextInput extends Ion {
}
}
onDestroy() {
this.deregListeners();
this.form.deregister(this);
}
}
/**
@@ -389,33 +387,41 @@ export class TextInput extends Ion {
'tabIndex'
],
host: {
'[tabIndex]': 'tabIndex',
'[attr.aria-labelledby]': 'labelledBy',
'class': 'text-input input'
'[tabIndex]': 'tabIndex'
}
})
export class TextInputElement {
/**
* TODO
* @param {string} type The value of the underlying element's type attribute.
* @param {ElementRef} elementRef TODO
* @param {IonicConfig} config TODO
*/
constructor(
form: IonicForm,
@Attribute('type') type: string,
elementRef: ElementRef,
@Optional() textInput: TextInput
renderer: Renderer,
@Optional() textInputWrapper: TextInput
) {
this.form = form;
this.type = type;
this.elementRef = elementRef;
this.tabIndex = this.tabIndex || '';
textInput && textInput.registerInputElement(this);
this.tabIndex = 0;
this.renderer = renderer;
renderer.setElementAttribute(this.elementRef, 'text-input', '');
if (textInputWrapper) {
// it's within ionic's ion-input, let ion-input handle what's up
textInputWrapper.registerInput(this);
} else {
// not within ion-input
form.register(this);
}
}
/**
* Focus the input.
*/
setFocus() {
labelledBy(val) {
this.renderer.setElementAttribute(this.elementRef, 'aria-labelledby', val);
}
initFocus() {
this.elementRef.nativeElement.focus();
}
@@ -424,7 +430,7 @@ export class TextInputElement {
* @returns {boolean} true if the input has focus, otherwise false.
*/
get hasFocus() {
return dom.hasFocus(this.elementRef);
return dom.hasFocus(this.elementRef.nativeElement);
}
/**
@@ -434,6 +440,10 @@ export class TextInputElement {
get hasValue() {
return (this.elementRef.nativeElement.value !== '');
}
onDestroy() {
this.form.deregister(this);
}
}

View File

@@ -1,4 +1,4 @@
import {Component, Directive, View, Host, ElementRef, Optional, forwardRef, Inject} from 'angular2/angular2';
import {Component, Directive, Host, ElementRef, Renderer, Optional, forwardRef, Inject} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
@@ -57,11 +57,6 @@ export class ToolbarBase extends Ion {
*/
@Component({
selector: 'ion-toolbar',
host: {
'class': 'toolbar'
}
})
@View({
template:
'<div class="toolbar-inner">' +
'<ng-content select="[menu-toggle]"></ng-content>' +
@@ -74,18 +69,18 @@ export class ToolbarBase extends Ion {
export class Toolbar extends ToolbarBase {
constructor(
elementRef: ElementRef,
config: IonicConfig
config: IonicConfig,
renderer: Renderer
) {
super(elementRef, config);
renderer.setElementClass(elementRef, 'toolbar', true);
}
}
@Component({
selector: 'ion-title'
})
@View({
selector: 'ion-title',
template:
'<div class="toolbar-title">' +
'<ng-content></ng-content>' +