mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
fix(textInputs): register components, don't use Query
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
import {Directive} from 'angular2/angular2';
|
import {Directive, Optional} from 'angular2/angular2';
|
||||||
|
|
||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
|
import {TextInput} from './text-input';
|
||||||
import {pointerCoord, hasPointerMoved} from '../../util/dom';
|
import {pointerCoord, hasPointerMoved} from '../../util/dom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,8 +26,9 @@ export class Label {
|
|||||||
* TODO
|
* TODO
|
||||||
* @param {IonicConfig} config
|
* @param {IonicConfig} config
|
||||||
*/
|
*/
|
||||||
constructor(config: IonicConfig) {
|
constructor(config: IonicConfig, @Optional() textInput: TextInput) {
|
||||||
this.scrollAssist = config.get('keyboardScrollAssist');
|
this.scrollAssist = config.get('keyboardScrollAssist');
|
||||||
|
textInput && textInput.registerLabel(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,61 +11,6 @@ import * as dom from '../../util/dom';
|
|||||||
import {IonicPlatform} from '../../platform/platform';
|
import {IonicPlatform} from '../../platform/platform';
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
@Directive({
|
|
||||||
selector: 'textarea,input[type=text],input[type=password],input[type=number],input[type=search],input[type=email],input[type=url],input[type=tel]',
|
|
||||||
property: [
|
|
||||||
'tabIndex'
|
|
||||||
],
|
|
||||||
host: {
|
|
||||||
'[tabIndex]': 'tabIndex',
|
|
||||||
'[attr.aria-labelledby]': 'labelledBy',
|
|
||||||
'class': 'text-input input'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
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(
|
|
||||||
@Attribute('type') type: string,
|
|
||||||
elementRef: ElementRef,
|
|
||||||
config: IonicConfig
|
|
||||||
) {
|
|
||||||
this.type = type;
|
|
||||||
this.elementRef = elementRef;
|
|
||||||
this.tabIndex = this.tabIndex || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Focus the input.
|
|
||||||
*/
|
|
||||||
setFocus() {
|
|
||||||
this.elementRef.nativeElement.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the input has focus or not.
|
|
||||||
* @returns {boolean} true if the input has focus, otherwise false.
|
|
||||||
*/
|
|
||||||
get hasFocus() {
|
|
||||||
return dom.hasFocus(this.elementRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the input has a value.
|
|
||||||
* @returns {boolean} true if the input has a value, otherwise false.
|
|
||||||
*/
|
|
||||||
get hasValue() {
|
|
||||||
return (this.elementRef.nativeElement.value !== '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*/
|
*/
|
||||||
@ -104,9 +49,7 @@ export class TextInput extends Ion {
|
|||||||
app: IonicApp,
|
app: IonicApp,
|
||||||
ngZone: NgZone,
|
ngZone: NgZone,
|
||||||
platform: IonicPlatform,
|
platform: IonicPlatform,
|
||||||
@Optional() @Host() scrollView: Content,
|
@Optional() @Host() scrollView: Content
|
||||||
@Query(TextInputElement) inputQry: QueryList<TextInputElement>,
|
|
||||||
@Query(Label) labelQry: QueryList<Label>
|
|
||||||
) {
|
) {
|
||||||
super(elementRef, config);
|
super(elementRef, config);
|
||||||
|
|
||||||
@ -118,33 +61,31 @@ export class TextInput extends Ion {
|
|||||||
this.app = app;
|
this.app = app;
|
||||||
this.zone = ngZone;
|
this.zone = ngZone;
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
this.inputQry = inputQry;
|
|
||||||
this.labelQry = labelQry;
|
|
||||||
|
|
||||||
this.keyboardHeight = this.config.get('keyboardHeight');
|
this.keyboardHeight = this.config.get('keyboardHeight');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerInputElement(textInputElement) {
|
||||||
|
this.input = textInputElement;
|
||||||
|
this.type = textInputElement.type;
|
||||||
|
textInputElement.tabIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLabel(label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*/
|
*/
|
||||||
onInit() {
|
onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
|
||||||
let label = this.labelQry.first;
|
if (this.input && this.label) {
|
||||||
this.input = this.inputQry.first;
|
this.input.labelledBy = this.label.id = (this.label.id || 'label-' + this.id);
|
||||||
|
|
||||||
if (this.input) {
|
|
||||||
this.type = this.input.type;
|
|
||||||
this.input.tabIndex = -1;
|
|
||||||
|
|
||||||
if (label) {
|
|
||||||
label.id = (label.id || 'label-' + this.id);
|
|
||||||
this.input.labelledBy = label.id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
self.scrollMove = (ev) => {
|
self.scrollMove = (ev) => {
|
||||||
self.deregListeners();
|
self.deregListeners();
|
||||||
|
|
||||||
@ -440,4 +381,62 @@ export class TextInput extends Ion {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'textarea,input[type=text],input[type=password],input[type=number],input[type=search],input[type=email],input[type=url],input[type=tel]',
|
||||||
|
inputs: [
|
||||||
|
'tabIndex'
|
||||||
|
],
|
||||||
|
host: {
|
||||||
|
'[tabIndex]': 'tabIndex',
|
||||||
|
'[attr.aria-labelledby]': 'labelledBy',
|
||||||
|
'class': 'text-input input'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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(
|
||||||
|
@Attribute('type') type: string,
|
||||||
|
elementRef: ElementRef,
|
||||||
|
@Optional() textInput: TextInput
|
||||||
|
) {
|
||||||
|
this.type = type;
|
||||||
|
this.elementRef = elementRef;
|
||||||
|
this.tabIndex = this.tabIndex || '';
|
||||||
|
textInput && textInput.registerInputElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus the input.
|
||||||
|
*/
|
||||||
|
setFocus() {
|
||||||
|
this.elementRef.nativeElement.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the input has focus or not.
|
||||||
|
* @returns {boolean} true if the input has focus, otherwise false.
|
||||||
|
*/
|
||||||
|
get hasFocus() {
|
||||||
|
return dom.hasFocus(this.elementRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the input has a value.
|
||||||
|
* @returns {boolean} true if the input has a value, otherwise false.
|
||||||
|
*/
|
||||||
|
get hasValue() {
|
||||||
|
return (this.elementRef.nativeElement.value !== '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const SCROLL_INTO_VIEW_DURATION = 400;
|
const SCROLL_INTO_VIEW_DURATION = 400;
|
||||||
|
@ -1,256 +0,0 @@
|
|||||||
import {Component, Directive, View, bootstrap} from 'angular2/angular2'
|
|
||||||
|
|
||||||
import * as util from 'ionic/util';
|
|
||||||
<<<<<<< HEAD
|
|
||||||
import {ionicBindings} from './bootstrap';
|
|
||||||
import {IONIC_DIRECTIVES} from './directives';
|
|
||||||
=======
|
|
||||||
import {IonicConfig} from './config';
|
|
||||||
import {ionicBootstrap} from '../components/app/app';
|
|
||||||
import {
|
|
||||||
Menu, MenuToggle, MenuClose,
|
|
||||||
Button, Content, Scroll, Refresher,
|
|
||||||
Slides, Slide, SlideLazy,
|
|
||||||
Tabs, Tab,
|
|
||||||
Card, List, ListHeader, Item, ItemGroup, ItemGroupTitle, ItemSliding,
|
|
||||||
Toolbar, ToolbarTitle, ToolbarItem,
|
|
||||||
Icon,
|
|
||||||
Checkbox, Switch,
|
|
||||||
TextInput, TextInputElement, Label,
|
|
||||||
Segment, SegmentButton, SegmentControlValueAccessor,
|
|
||||||
RadioGroup, RadioButton, SearchBar,
|
|
||||||
Nav, NavbarTemplate, Navbar,
|
|
||||||
NavPush, NavPop, NavRouter,
|
|
||||||
IdRef,
|
|
||||||
ShowWhen, HideWhen
|
|
||||||
} from '../ionic';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The core Ionic directives. Automatically available in every IonicView
|
|
||||||
* template.
|
|
||||||
*/
|
|
||||||
export const IONIC_DIRECTIVES = [
|
|
||||||
// Angular
|
|
||||||
CORE_DIRECTIVES,
|
|
||||||
FORM_DIRECTIVES,
|
|
||||||
|
|
||||||
NgStyle,
|
|
||||||
|
|
||||||
// Content
|
|
||||||
forwardRef(() => Menu),
|
|
||||||
forwardRef(() => MenuToggle),
|
|
||||||
forwardRef(() => MenuClose),
|
|
||||||
|
|
||||||
forwardRef(() => Button),
|
|
||||||
forwardRef(() => Content),
|
|
||||||
forwardRef(() => Scroll),
|
|
||||||
forwardRef(() => Refresher),
|
|
||||||
|
|
||||||
// Lists
|
|
||||||
forwardRef(() => Card),
|
|
||||||
forwardRef(() => List),
|
|
||||||
forwardRef(() => ListHeader),
|
|
||||||
forwardRef(() => Item),
|
|
||||||
forwardRef(() => ItemGroup),
|
|
||||||
forwardRef(() => ItemGroupTitle),
|
|
||||||
forwardRef(() => ItemSliding),
|
|
||||||
|
|
||||||
// Slides
|
|
||||||
forwardRef(() => Slides),
|
|
||||||
forwardRef(() => Slide),
|
|
||||||
forwardRef(() => SlideLazy),
|
|
||||||
|
|
||||||
// Tabs
|
|
||||||
forwardRef(() => Tabs),
|
|
||||||
forwardRef(() => Tab),
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
forwardRef(() => Toolbar),
|
|
||||||
forwardRef(() => ToolbarTitle),
|
|
||||||
forwardRef(() => ToolbarItem),
|
|
||||||
|
|
||||||
// Media
|
|
||||||
forwardRef(() => Icon),
|
|
||||||
|
|
||||||
// Forms
|
|
||||||
forwardRef(() => SearchBar),
|
|
||||||
forwardRef(() => Segment),
|
|
||||||
forwardRef(() => SegmentButton),
|
|
||||||
forwardRef(() => SegmentControlValueAccessor),
|
|
||||||
forwardRef(() => Checkbox),
|
|
||||||
forwardRef(() => RadioGroup),
|
|
||||||
forwardRef(() => RadioButton),
|
|
||||||
forwardRef(() => Switch),
|
|
||||||
forwardRef(() => TextInput),
|
|
||||||
forwardRef(() => TextInputElement),
|
|
||||||
forwardRef(() => Label),
|
|
||||||
|
|
||||||
// Nav
|
|
||||||
forwardRef(() => Nav),
|
|
||||||
forwardRef(() => NavbarTemplate),
|
|
||||||
forwardRef(() => Navbar),
|
|
||||||
|
|
||||||
forwardRef(() => NavPush),
|
|
||||||
forwardRef(() => NavPop),
|
|
||||||
forwardRef(() => NavRouter),
|
|
||||||
forwardRef(() => IdRef),
|
|
||||||
|
|
||||||
forwardRef(() => ShowWhen),
|
|
||||||
forwardRef(() => HideWhen)
|
|
||||||
];
|
|
||||||
>>>>>>> master
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
class IonicViewImpl extends View {
|
|
||||||
constructor(args = {}) {
|
|
||||||
args.directives = (args.directives || []).concat(IONIC_DIRECTIVES);
|
|
||||||
super(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The IonicView decorator indicates that the decorated class is an Ionic
|
|
||||||
* navigation view, meaning it can be navigated to using a [NavController](../../Nav/NavController/#creating_views)
|
|
||||||
*
|
|
||||||
* Ionic views have all [IONIC_DIRECTIVES](../IONIC_DIRECTIVES/), which include
|
|
||||||
* all Ionic components, as well as Angular's [CORE_DIRECTIVES](https://angular.io/docs/js/latest/api/core/CORE_DIRECTIVES-const.html)
|
|
||||||
* and [FORM_DIRECTIVES](https://angular.io/docs/js/latest/api/core/FORM_DIRECTIVES-const.html),
|
|
||||||
* already provided to them, so you only need to supply custom directives to
|
|
||||||
* your Ionic views:
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* @IonicView({
|
|
||||||
* template: '<ion-checkbox my-custom-dir>' +
|
|
||||||
* '</ion-checkbox>'
|
|
||||||
* directives: [MyCustomDirective]
|
|
||||||
* })
|
|
||||||
* class MyPage {}
|
|
||||||
* ```
|
|
||||||
* Here [Checkbox](../../../components/checkbox/Checkbox/) will load because
|
|
||||||
* it is in IONIC_DIRECTIVES, so there is no need to add it to the `directives`
|
|
||||||
* array.
|
|
||||||
*
|
|
||||||
* For custom components that use Ionic components, you will need to include
|
|
||||||
* IONIC_DIRECTIVES in the `directives` array:
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* import {IONIC_DIRECTIVES} from 'ionic/ionic';
|
|
||||||
* @Component({
|
|
||||||
* template: `<div class="customStyle">
|
|
||||||
* <ion-checkbox></ion-checkbox>
|
|
||||||
* </div>`
|
|
||||||
* })
|
|
||||||
* @View({
|
|
||||||
* directives: [IONIC_DIRECTIVES]
|
|
||||||
* })
|
|
||||||
* class MyCustomCheckbox {}
|
|
||||||
*```
|
|
||||||
* Alternatively, you could:
|
|
||||||
* ```ts
|
|
||||||
* import {Checkbox} from 'ionic/ionic'
|
|
||||||
* ```
|
|
||||||
* along with any other components and add them individually:
|
|
||||||
* ```
|
|
||||||
* @View({
|
|
||||||
* directives: [Checkbox]
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
* However, using IONIC_DIRECTIVES will always Just Work :tm: with no
|
|
||||||
* performance overhead, so there is really no reason to not always use it.
|
|
||||||
*
|
|
||||||
* Ionic views are also automatically wrapped in `<ion-view>`, so although you
|
|
||||||
* may see these tags if you inspect your markup, you don't need to include them
|
|
||||||
* in your templates.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export function IonicView(args) {
|
|
||||||
return function(cls) {
|
|
||||||
var annotations = Reflect.getMetadata('annotations', cls) || [];
|
|
||||||
annotations.push(new IonicViewImpl(args));
|
|
||||||
Reflect.defineMetadata('annotations', annotations, cls);
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
export function IonicDirective(config) {
|
|
||||||
return function(cls) {
|
|
||||||
var annotations = Reflect.getMetadata('annotations', cls) || [];
|
|
||||||
annotations.push(new Directive(appendConfig(cls, config)));
|
|
||||||
Reflect.defineMetadata('annotations', annotations, cls);
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
export function IonicComponent(config) {
|
|
||||||
return function(cls) {
|
|
||||||
return makeComponent(cls, appendConfig(cls, config));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeComponent(cls, config) {
|
|
||||||
var annotations = Reflect.getMetadata('annotations', cls) || [];
|
|
||||||
annotations.push(new Component(config));
|
|
||||||
Reflect.defineMetadata('annotations', annotations, cls);
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendConfig(cls, config) {
|
|
||||||
config.host = config.host || {};
|
|
||||||
|
|
||||||
cls.defaultProperties = config.defaultProperties || {};
|
|
||||||
|
|
||||||
config.properties = config.properties || [];
|
|
||||||
|
|
||||||
for (let prop in cls.defaultProperties) {
|
|
||||||
// add the property to the component "properties"
|
|
||||||
config.properties.push(prop);
|
|
||||||
|
|
||||||
// set the component "hostProperties", so the instance's
|
|
||||||
// property value will be used to set the element's attribute
|
|
||||||
config.host['[attr.' + util.pascalCaseToDashCase(prop) + ']'] = prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
cls.delegates = config.delegates;
|
|
||||||
|
|
||||||
let componentId = config.classId || (config.selector && config.selector.replace('ion-', ''));
|
|
||||||
config.host['class'] = ((config.host['class'] || '') + ' ' + componentId).trim();
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
export function App(args={}) {
|
|
||||||
return function(cls) {
|
|
||||||
// get current annotations
|
|
||||||
let annotations = Reflect.getMetadata('annotations', cls) || [];
|
|
||||||
|
|
||||||
// create @Component
|
|
||||||
args.selector = args.selector || 'ion-app';
|
|
||||||
annotations.push(new Component(args));
|
|
||||||
|
|
||||||
// create @View
|
|
||||||
// if no template was provided, default so it has a root ion-nav
|
|
||||||
if (!args.templateUrl && !args.template) {
|
|
||||||
args.template = '<ion-nav></ion-nav>';
|
|
||||||
}
|
|
||||||
|
|
||||||
annotations.push(new IonicViewImpl(args));
|
|
||||||
|
|
||||||
// redefine with added annotations
|
|
||||||
Reflect.defineMetadata('annotations', annotations, cls);
|
|
||||||
|
|
||||||
bootstrap(cls, ionicBindings(cls, args.config));
|
|
||||||
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,6 +15,7 @@ import {Card} from '../components/card/card';
|
|||||||
import {List, ListHeader} from '../components/list/list';
|
import {List, ListHeader} from '../components/list/list';
|
||||||
import {Item} from '../components/item/item';
|
import {Item} from '../components/item/item';
|
||||||
import {ItemGroup, ItemGroupTitle} from '../components/item/item-group';
|
import {ItemGroup, ItemGroupTitle} from '../components/item/item-group';
|
||||||
|
import {ItemSliding} from '../components/item/item-sliding';
|
||||||
import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar';
|
import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar';
|
||||||
import {Icon} from '../components/icon/icon';
|
import {Icon} from '../components/icon/icon';
|
||||||
import {Checkbox} from '../components/checkbox/checkbox';
|
import {Checkbox} from '../components/checkbox/checkbox';
|
||||||
@ -58,6 +59,7 @@ export const IONIC_DIRECTIVES = [
|
|||||||
Item,
|
Item,
|
||||||
ItemGroup,
|
ItemGroup,
|
||||||
ItemGroupTitle,
|
ItemGroupTitle,
|
||||||
|
ItemSliding,
|
||||||
|
|
||||||
// Slides
|
// Slides
|
||||||
Slides,
|
Slides,
|
||||||
|
Reference in New Issue
Block a user