mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(input): keyboard focus/scrolling/tabbing
This commit is contained in:
@ -4,7 +4,7 @@ import {Ion} from '../ion';
|
|||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
import {IonicKeyboard} from '../../util/keyboard';
|
import {IonicKeyboard} from '../../util/keyboard';
|
||||||
import {ViewController} from '../nav/view-controller';
|
import {ViewController} from '../nav/view-controller';
|
||||||
import {Tab} from '../tabs/tab';
|
import {Animation} from '../../animations/animation';
|
||||||
import {ScrollTo} from '../../animations/scroll-to';
|
import {ScrollTo} from '../../animations/scroll-to';
|
||||||
|
|
||||||
|
|
||||||
@ -25,8 +25,10 @@ import {ScrollTo} from '../../animations/scroll-to';
|
|||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-content',
|
selector: 'ion-content',
|
||||||
inputs: ['parallax'],
|
template:
|
||||||
template: '<scroll-content><ng-content></ng-content></scroll-content>'
|
'<scroll-content>' +
|
||||||
|
'<ng-content></ng-content>' +
|
||||||
|
'</scroll-content>'
|
||||||
})
|
})
|
||||||
export class Content extends Ion {
|
export class Content extends Ion {
|
||||||
/**
|
/**
|
||||||
@ -161,17 +163,29 @@ export class Content extends Ion {
|
|||||||
* Adds padding to the bottom of the scroll element when the keyboard is open
|
* Adds padding to the bottom of the scroll element when the keyboard is open
|
||||||
* so content below the keyboard can be scrolled into view.
|
* so content below the keyboard can be scrolled into view.
|
||||||
*/
|
*/
|
||||||
addKeyboardPadding(addPadding) {
|
addScrollPadding(newScrollPadding) {
|
||||||
if (addPadding > this.scrollPadding) {
|
if (newScrollPadding > this.scrollPadding) {
|
||||||
this.scrollPadding = addPadding;
|
console.debug('addScrollPadding', newScrollPadding);
|
||||||
this.scrollElement.style.paddingBottom = addPadding + 'px';
|
|
||||||
|
this.scrollPadding = newScrollPadding;
|
||||||
|
this.scrollElement.style.paddingBottom = newScrollPadding + 'px';
|
||||||
|
|
||||||
if (!this.keyboardPromise) {
|
if (!this.keyboardPromise) {
|
||||||
|
console.debug('add scroll keyboard close callback', newScrollPadding);
|
||||||
|
|
||||||
this.keyboardPromise = this.keyboard.onClose(() => {
|
this.keyboardPromise = this.keyboard.onClose(() => {
|
||||||
|
console.debug('scroll keyboard closed', newScrollPadding);
|
||||||
|
|
||||||
if (this) {
|
if (this) {
|
||||||
|
if (this.scrollPadding && this.scrollElement) {
|
||||||
|
let close = new Animation(this.scrollElement);
|
||||||
|
close
|
||||||
|
.duration(150)
|
||||||
|
.fromTo('paddingBottom', this.scrollPadding + 'px', '0px')
|
||||||
|
.play();
|
||||||
|
}
|
||||||
|
|
||||||
this.scrollPadding = 0;
|
this.scrollPadding = 0;
|
||||||
if (this.scrollElement) this.scrollElement.style.paddingBottom = '';
|
|
||||||
this.keyboardPromise = null;
|
this.keyboardPromise = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -25,9 +25,13 @@ export class Label {
|
|||||||
* TODO
|
* TODO
|
||||||
* @param {IonicConfig} config
|
* @param {IonicConfig} config
|
||||||
*/
|
*/
|
||||||
constructor(config: IonicConfig, @Optional() textInput: TextInput) {
|
constructor(config: IonicConfig, @Optional() container: TextInput) {
|
||||||
this.scrollAssist = config.get('keyboardScrollAssist');
|
this.scrollAssist = config.get('scrollAssist');
|
||||||
textInput && textInput.registerLabel(this);
|
if (!this.id) {
|
||||||
|
this.id = 'lbl-' + (++labelIds);
|
||||||
|
}
|
||||||
|
this.container = container;
|
||||||
|
container && container.registerLabel(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +59,7 @@ export class Label {
|
|||||||
if (!hasPointerMoved(20, this.startCoord, endCoord)) {
|
if (!hasPointerMoved(20, this.startCoord, endCoord)) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this.container.focus();
|
this.container.initFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.startCoord = null;
|
this.startCoord = null;
|
||||||
@ -63,3 +67,5 @@ export class Label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let labelIds = -1;
|
||||||
|
7
ionic/components/text-input/test/input-focus/index.ts
Normal file
7
ionic/components/text-input/test/input-focus/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import {App} from 'ionic/ionic';
|
||||||
|
|
||||||
|
|
||||||
|
@App({
|
||||||
|
templateUrl: 'main.html'
|
||||||
|
})
|
||||||
|
class E2EApp {}
|
188
ionic/components/text-input/test/input-focus/main.html
Normal file
188
ionic/components/text-input/test/input-focus/main.html
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
|
||||||
|
<ion-toolbar><ion-title>Input Focus</ion-title></ion-toolbar>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-content>
|
||||||
|
|
||||||
|
<p>Paragraph text with a <a href="#">link</a>.</p>
|
||||||
|
|
||||||
|
<ion-list>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Text 1:</ion-label>
|
||||||
|
<input type="text">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item with button right
|
||||||
|
<button item-right>Button 1</button>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label id="my-label1">Text 2:</ion-label>
|
||||||
|
<input value="value" type="text">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<button ion-item>
|
||||||
|
Button Item
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Text 3:</ion-label>
|
||||||
|
<input type="text">
|
||||||
|
<button clear item-right>
|
||||||
|
<icon power></icon>
|
||||||
|
</button>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Comments:</ion-label>
|
||||||
|
<textarea>Comment value</textarea>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<icon globe item-left></icon>
|
||||||
|
<ion-label>Website:</ion-label>
|
||||||
|
<input value="http://ionic.io/" type="url">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<icon mail item-left></icon>
|
||||||
|
<ion-label>Email:</ion-label>
|
||||||
|
<input value="email6@email.com" type="email">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<icon create item-left></icon>
|
||||||
|
<ion-label>Feedback:</ion-label>
|
||||||
|
<textarea placeholder="Placeholder Text"></textarea>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>More Info:</ion-label>
|
||||||
|
<input placeholder="Placeholder Text" type="text">
|
||||||
|
<icon flag item-right></icon>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Score:</ion-label>
|
||||||
|
<input value="10" type="number">
|
||||||
|
<button outline item-right>Update</button>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>First Name:</ion-label>
|
||||||
|
<input value="Lightning" type="text">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Last Name:</ion-label>
|
||||||
|
<input value="McQueen" type="text">
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-input>
|
||||||
|
<ion-label>Message:</ion-label>
|
||||||
|
<textarea>KA-CHOW!</textarea>
|
||||||
|
</ion-input>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
Item
|
||||||
|
</ion-item> -->
|
||||||
|
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
|
</ion-content>
|
@ -2,9 +2,6 @@
|
|||||||
// Text Input
|
// Text Input
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
$input-focus-border-color: #51a7e8 !default;
|
|
||||||
$input-focus-box-shadow: inset 0px 0px 8px 0px $input-focus-border-color !default;
|
|
||||||
|
|
||||||
$text-input-background-color: $list-background-color !default;
|
$text-input-background-color: $list-background-color !default;
|
||||||
|
|
||||||
|
|
||||||
@ -37,18 +34,6 @@ ion-input.item {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.key-input ion-input {
|
|
||||||
|
|
||||||
&.has-focus {
|
|
||||||
border-color: $input-focus-border-color;
|
|
||||||
box-shadow: $input-focus-box-shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-input [text-input] {
|
ion-input [text-input] {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background-color: $text-input-background-color;
|
background-color: $text-input-background-color;
|
||||||
@ -59,6 +44,13 @@ ion-input.has-focus [text-input] {
|
|||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-input input[scroll-assist] {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
ion-input textarea {
|
ion-input textarea {
|
||||||
padding-top: 9px;
|
padding-top: 9px;
|
||||||
}
|
}
|
||||||
@ -80,4 +72,3 @@ input,
|
|||||||
textarea {
|
textarea {
|
||||||
@include placeholder();
|
@include placeholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Directive, Host, Optional, ElementRef, Renderer, Attribute, Query, QueryList, NgZone} from 'angular2/angular2';
|
import {Component, Directive, NgIf, forwardRef, Host, Optional, ElementRef, Renderer, Attribute, Query, QueryList, NgZone} from 'angular2/angular2';
|
||||||
|
|
||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
import {IonicForm} from '../../util/form';
|
import {IonicForm} from '../../util/form';
|
||||||
@ -12,29 +12,20 @@ import {IonicPlatform} from '../../platform/platform';
|
|||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
*/
|
*/
|
||||||
@Directive({
|
@Component({
|
||||||
selector: 'ion-input',
|
selector: 'ion-input',
|
||||||
host: {
|
host: {
|
||||||
'(focus)': 'receivedFocus(true)',
|
|
||||||
'(blur)': 'receivedFocus(false)',
|
|
||||||
'(touchstart)': 'pointerStart($event)',
|
'(touchstart)': 'pointerStart($event)',
|
||||||
'(touchend)': 'pointerEnd($event)',
|
'(touchend)': 'pointerEnd($event)',
|
||||||
'(mouseup)': 'pointerEnd($event)',
|
'(mouseup)': 'pointerEnd($event)'
|
||||||
'[class.has-focus]': 'hasFocus',
|
},
|
||||||
'[class.has-value]': 'hasValue'
|
template:
|
||||||
}
|
'<ng-content></ng-content>' +
|
||||||
|
'<input [type]="type" aria-hidden="true" scroll-assist *ng-if="scrollAssist">',
|
||||||
|
directives: [NgIf, forwardRef(() => InputScrollAssist)]
|
||||||
})
|
})
|
||||||
export class TextInput {
|
export class TextInput {
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {ElementRef} elementRef TODO
|
|
||||||
* @param {IonicConfig} config TODO
|
|
||||||
* @param {IonicApp} app TODO
|
|
||||||
* @param {NgZone} ngZone TODO
|
|
||||||
* @param {Content=} scrollView The parent scroll view.
|
|
||||||
* @param {QueryList<TextInputElement>} inputQry TODO
|
|
||||||
* @param {QueryList<Label>} labelQry TODO
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
form: IonicForm,
|
form: IonicForm,
|
||||||
elementRef: ElementRef,
|
elementRef: ElementRef,
|
||||||
@ -46,40 +37,44 @@ export class TextInput {
|
|||||||
@Optional() @Host() scrollView: Content
|
@Optional() @Host() scrollView: Content
|
||||||
) {
|
) {
|
||||||
renderer.setElementClass(elementRef, 'item', true);
|
renderer.setElementClass(elementRef, 'item', true);
|
||||||
|
this.renderer = renderer;
|
||||||
|
|
||||||
this.form = form;
|
this.form = form;
|
||||||
form.register(this);
|
form.register(this);
|
||||||
|
|
||||||
|
this.type = 'text';
|
||||||
|
this.lastTouch = 0;
|
||||||
|
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.elementRef = elementRef;
|
this.elementRef = elementRef;
|
||||||
this.zone = zone;
|
this.zone = zone;
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
|
|
||||||
this.scrollView = scrollView;
|
this.scrollView = scrollView;
|
||||||
this.scrollAssist = config.get('keyboardScrollAssist');
|
this.scrollAssist = config.get('scrollAssist');
|
||||||
this.keyboardHeight = config.get('keyboardHeight');
|
this.keyboardHeight = config.get('keyboardHeight');
|
||||||
}
|
}
|
||||||
|
|
||||||
registerInput(textInputElement) {
|
registerInput(textInputElement) {
|
||||||
this.input = textInputElement;
|
this.input = textInputElement;
|
||||||
this.type = textInputElement.type;
|
this.type = textInputElement.type || 'text';
|
||||||
}
|
}
|
||||||
|
|
||||||
registerLabel(label) {
|
registerLabel(label) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
onInit() {
|
onInit() {
|
||||||
if (this.input && this.label) {
|
if (this.input && this.label) {
|
||||||
this.label.id = (this.label.id || 'label-' + this.inputId)
|
// if there is an input and an label
|
||||||
|
// then give the label an ID
|
||||||
|
// and tell the input the ID of who it's labelled by
|
||||||
this.input.labelledBy(this.label.id);
|
this.input.labelledBy(this.label.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
self.scrollMove = (ev) => {
|
self.scrollMove = (ev) => {
|
||||||
|
console.debug('content scrollMove');
|
||||||
self.deregListeners();
|
self.deregListeners();
|
||||||
|
|
||||||
if (self.hasFocus) {
|
if (self.hasFocus) {
|
||||||
@ -88,10 +83,6 @@ export class TextInput {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {Event} ev TODO
|
|
||||||
*/
|
|
||||||
pointerStart(ev) {
|
pointerStart(ev) {
|
||||||
if (this.scrollAssist && this.app.isEnabled()) {
|
if (this.scrollAssist && this.app.isEnabled()) {
|
||||||
// remember where the touchstart/mousedown started
|
// remember where the touchstart/mousedown started
|
||||||
@ -99,10 +90,6 @@ export class TextInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {Event} ev TODO
|
|
||||||
*/
|
|
||||||
pointerEnd(ev) {
|
pointerEnd(ev) {
|
||||||
if (!this.app.isEnabled()) {
|
if (!this.app.isEnabled()) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@ -122,29 +109,21 @@ export class TextInput {
|
|||||||
this.initFocus();
|
this.initFocus();
|
||||||
|
|
||||||
// temporarily prevent mouseup's from focusing
|
// temporarily prevent mouseup's from focusing
|
||||||
this.preventMouse = true;
|
this.lastTouch = Date.now();
|
||||||
clearTimeout(this.mouseTimer);
|
|
||||||
this.mouseTimer = setTimeout(() => {
|
|
||||||
this.preventMouse = false;
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!this.preventMouse) {
|
} else if (this.lastTouch + 500 < Date.now()) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
this.zone.runOutsideAngular(() => {
|
|
||||||
this.setFocus();
|
this.setFocus();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @returns {TODO} TODO
|
|
||||||
*/
|
|
||||||
initFocus() {
|
initFocus() {
|
||||||
|
// begin the process of setting focus to the inner input element
|
||||||
|
|
||||||
let scrollView = this.scrollView;
|
let scrollView = this.scrollView;
|
||||||
|
|
||||||
if (scrollView && this.scrollAssist) {
|
if (scrollView && this.scrollAssist) {
|
||||||
@ -161,7 +140,7 @@ export class TextInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add padding to the bottom of the scroll view (if needed)
|
// add padding to the bottom of the scroll view (if needed)
|
||||||
scrollView.addKeyboardPadding(scrollData.scrollPadding);
|
scrollView.addScrollPadding(scrollData.scrollPadding);
|
||||||
|
|
||||||
// manually scroll the text input to the top
|
// manually scroll the text input to the top
|
||||||
// do not allow any clicks while it's scrolling
|
// do not allow any clicks while it's scrolling
|
||||||
@ -308,33 +287,42 @@ export class TextInput {
|
|||||||
return scrollData;
|
return scrollData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
focusChange(hasFocus) {
|
||||||
* TODO
|
this.renderer.setElementClass(this.elementRef, 'has-focus', hasFocus);
|
||||||
*/
|
}
|
||||||
deregListeners() {
|
|
||||||
this.deregScroll && this.deregScroll();
|
hasValue(inputValue) {
|
||||||
|
this.renderer.setElementClass(this.elementRef, 'has-value', inputValue && inputValue !== '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
setFocus() {
|
setFocus() {
|
||||||
|
if (this.input) {
|
||||||
|
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
// set focus on the input element
|
|
||||||
this.input && this.input.initFocus();
|
this.form.setAsFocused(this);
|
||||||
|
|
||||||
|
// set focus on the actual input element
|
||||||
|
this.input.setFocus();
|
||||||
|
|
||||||
// ensure the body hasn't scrolled down
|
// ensure the body hasn't scrolled down
|
||||||
document.body.scrollTop = 0;
|
document.body.scrollTop = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (this.scrollAssist && this.scrollView) {
|
if (this.scrollAssist && this.scrollView) {
|
||||||
setTimeout(() => {
|
this.zone.runOutsideAngular(() => {
|
||||||
this.deregListeners();
|
this.deregListeners();
|
||||||
this.deregScroll = this.scrollView.addScrollEventListener(this.scrollMove);
|
this.deregScroll = this.scrollView.addScrollEventListener(this.scrollMove);
|
||||||
}, 100);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deregListeners() {
|
||||||
|
this.deregScroll && this.deregScroll();
|
||||||
|
}
|
||||||
|
|
||||||
tempFocusMove() {
|
tempFocusMove() {
|
||||||
this.form.setFocusHolder(this.type);
|
this.form.setFocusHolder(this.type);
|
||||||
}
|
}
|
||||||
@ -343,33 +331,6 @@ export class TextInput {
|
|||||||
return !!this.input && this.input.hasFocus;
|
return !!this.input && this.input.hasFocus;
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasValue() {
|
|
||||||
return !!this.input && this.input.hasValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
get tabIndex() {
|
|
||||||
return this.input && this.input.tabIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
set tabIndex(val) {
|
|
||||||
if (this.input) {
|
|
||||||
this.input.tabIndex = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {boolean} receivedFocus TODO
|
|
||||||
*/
|
|
||||||
receivedFocus(receivedFocus) {
|
|
||||||
if (receivedFocus && !this.hasFocus) {
|
|
||||||
this.initFocus();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.deregListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
this.deregListeners();
|
this.deregListeners();
|
||||||
this.form.deregister(this);
|
this.form.deregister(this);
|
||||||
@ -377,73 +338,80 @@ export class TextInput {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'textarea,input[type=text],input[type=password],input[type=number],input[type=search],input[type=email],input[type=url],input[type=tel]',
|
selector: 'textarea,input[type=text],input[type=password],input[type=number],input[type=search],input[type=email],input[type=url],input[type=tel]',
|
||||||
inputs: [
|
inputs: ['value'],
|
||||||
'tabIndex'
|
|
||||||
],
|
|
||||||
host: {
|
host: {
|
||||||
'[tabIndex]': 'tabIndex'
|
'(focus)': 'wrapper.focusChange(true)',
|
||||||
|
'(blur)': 'wrapper.focusChange(false)',
|
||||||
|
'(keyup)': 'onKeyup($event)'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
export class TextInputElement {
|
export class TextInputElement {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
form: IonicForm,
|
|
||||||
@Attribute('type') type: string,
|
@Attribute('type') type: string,
|
||||||
elementRef: ElementRef,
|
elementRef: ElementRef,
|
||||||
renderer: Renderer,
|
renderer: Renderer,
|
||||||
@Optional() textInputWrapper: TextInput
|
@Optional() wrapper: TextInput
|
||||||
) {
|
) {
|
||||||
this.form = form;
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.elementRef = elementRef;
|
this.elementRef = elementRef;
|
||||||
this.tabIndex = 0;
|
this.wrapper = wrapper;
|
||||||
|
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
renderer.setElementAttribute(this.elementRef, 'text-input', '');
|
renderer.setElementAttribute(this.elementRef, 'text-input', '');
|
||||||
|
|
||||||
if (textInputWrapper) {
|
if (wrapper) {
|
||||||
// it's within ionic's ion-input, let ion-input handle what's up
|
// it's within ionic's ion-input, let ion-input handle what's up
|
||||||
textInputWrapper.registerInput(this);
|
wrapper.registerInput(this);
|
||||||
|
|
||||||
} else {
|
|
||||||
// not within ion-input
|
|
||||||
form.register(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onKeyup(ev) {
|
||||||
|
this.wrapper.hasValue(ev.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onInit() {
|
||||||
|
this.wrapper.hasValue(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
labelledBy(val) {
|
labelledBy(val) {
|
||||||
this.renderer.setElementAttribute(this.elementRef, 'aria-labelledby', val);
|
val && this.renderer.setElementAttribute(this.elementRef, 'aria-labelledby', val);
|
||||||
}
|
}
|
||||||
|
|
||||||
initFocus() {
|
setFocus() {
|
||||||
this.elementRef.nativeElement.focus();
|
this.getNativeElement().focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the input has focus or not.
|
|
||||||
* @returns {boolean} true if the input has focus, otherwise false.
|
|
||||||
*/
|
|
||||||
get hasFocus() {
|
get hasFocus() {
|
||||||
return dom.hasFocus(this.elementRef.nativeElement);
|
return dom.hasFocus(this.getNativeElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
getNativeElement() {
|
||||||
* Whether the input has a value.
|
return this.elementRef.nativeElement;
|
||||||
* @returns {boolean} true if the input has a value, otherwise false.
|
|
||||||
*/
|
|
||||||
get hasValue() {
|
|
||||||
return (this.elementRef.nativeElement.value !== '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
|
||||||
this.form.deregister(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[scroll-assist]',
|
||||||
|
host: {
|
||||||
|
'(focus)': 'receivedFocus($event)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class InputScrollAssist {
|
||||||
|
|
||||||
|
constructor(form: IonicForm, textInput: TextInput) {
|
||||||
|
this.form = form;
|
||||||
|
this.textInput = textInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
receivedFocus(ev) {
|
||||||
|
this.form.focusNext(this.textInput);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ IonicPlatform.register({
|
|||||||
settings: {
|
settings: {
|
||||||
mode: 'md',
|
mode: 'md',
|
||||||
keyboardHeight: 290,
|
keyboardHeight: 290,
|
||||||
keyboardScrollAssist: true,
|
scrollAssist: true,
|
||||||
hoverCSS: false,
|
hoverCSS: false,
|
||||||
},
|
},
|
||||||
isMatch(p) {
|
isMatch(p) {
|
||||||
@ -71,7 +71,7 @@ IonicPlatform.register({
|
|||||||
],
|
],
|
||||||
settings: {
|
settings: {
|
||||||
mode: 'ios',
|
mode: 'ios',
|
||||||
keyboardScrollAssist: function(p) {
|
scrollAssist: function(p) {
|
||||||
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
|
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
|
||||||
},
|
},
|
||||||
keyboardHeight: 290,
|
keyboardHeight: 290,
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import {Injectable, NgZone} from 'angular2/angular2';
|
import {Injectable, NgZone} from 'angular2/angular2';
|
||||||
|
|
||||||
import {IonicConfig} from '../config/config';
|
import {IonicConfig} from '../config/config';
|
||||||
import {raf} from './dom';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Input component is used to focus text input elements.
|
* 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
|
* @usage
|
||||||
* ```html
|
* ```html
|
||||||
* <ion-input>
|
* <ion-input>
|
||||||
@ -25,150 +22,18 @@ export class IonicForm {
|
|||||||
this._zone = zone;
|
this._zone = zone;
|
||||||
|
|
||||||
this._inputs = [];
|
this._inputs = [];
|
||||||
this._ids = -1;
|
|
||||||
this._focused = null;
|
this._focused = null;
|
||||||
|
|
||||||
zone.runOutsideAngular(() => {
|
zone.runOutsideAngular(() => {
|
||||||
this.initHolders(document, this._config.get('keyboardScrollAssist'));
|
this.focusCtrl(document);
|
||||||
|
|
||||||
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) {
|
register(input) {
|
||||||
console.debug('register input', input);
|
|
||||||
|
|
||||||
input.inputId = ++this._ids;
|
|
||||||
input.tabIndex = NORMAL_FOCUS_TAB_INDEX;
|
|
||||||
this._inputs.push(input);
|
this._inputs.push(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
deregister(input) {
|
deregister(input) {
|
||||||
console.debug('deregister input', input);
|
|
||||||
|
|
||||||
let index = this._inputs.indexOf(input);
|
let index = this._inputs.indexOf(input);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this._inputs.splice(index, 1);
|
this._inputs.splice(index, 1);
|
||||||
@ -178,72 +43,72 @@ export class IonicForm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetInputs() {
|
focusCtrl(document) {
|
||||||
this._focused = null;
|
let scrollAssist = this._config.get('scrollAssist');
|
||||||
|
|
||||||
for (let i = 0, ii = this._inputs.length; i < ii; i++) {
|
// raw DOM fun
|
||||||
if (!this._focused && this._inputs[i].hasFocus) {
|
let focusCtrl = document.createElement('focus-ctrl');
|
||||||
this._focused = this._inputs[i];
|
focusCtrl.setAttribute('aria-hidden', true);
|
||||||
this._focused.tabIndex = ACTIVE_FOCUS_TAB_INDEX;
|
|
||||||
|
|
||||||
} else {
|
if (scrollAssist) {
|
||||||
this._inputs[i].tabIndex = NORMAL_FOCUS_TAB_INDEX;
|
this._tmp = document.createElement('input');
|
||||||
}
|
this._tmp.tabIndex = -1;
|
||||||
|
focusCtrl.appendChild(this._tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._temp) {
|
this._blur = document.createElement('button');
|
||||||
this._temp.tabIndex = NO_FOCUS_TAB_INDEX;
|
this._blur.tabIndex = -1;
|
||||||
|
focusCtrl.appendChild(this._blur);
|
||||||
|
|
||||||
if (this._focused) {
|
document.body.appendChild(focusCtrl);
|
||||||
// there's a focused input
|
|
||||||
this._prev.tabIndex = PREV_TAB_INDEX;
|
|
||||||
this._next.tabIndex = NEXT_TAB_INDEX;
|
|
||||||
|
|
||||||
} else {
|
if (scrollAssist) {
|
||||||
this._prev.tabIndex = this._next.tabIndex = NO_FOCUS_TAB_INDEX;
|
this._tmp.addEventListener('keydown', (ev) => {
|
||||||
}
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
focusOut() {
|
||||||
* Focuses the previous input element, if it exists.
|
console.debug('focusOut');
|
||||||
*/
|
this._blur.focus();
|
||||||
focusPrevious() {
|
}
|
||||||
console.debug('focusPrevious');
|
|
||||||
this.focusMove(-1);
|
setFocusHolder(type) {
|
||||||
|
if (this._tmp && this._config.get('scrollAssist')) {
|
||||||
|
this._tmp.type = type;
|
||||||
|
console.debug('setFocusHolder', this._tmp.type);
|
||||||
|
this._tmp.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsFocused(input) {
|
||||||
|
this._focused = input;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focuses the next input element, if it exists.
|
* Focuses the next input element, if it exists.
|
||||||
*/
|
*/
|
||||||
focusNext() {
|
focusNext(currentInput) {
|
||||||
console.debug('focusNext');
|
console.debug('focusNext');
|
||||||
this.focusMove(1);
|
|
||||||
|
let index = this._inputs.indexOf(currentInput);
|
||||||
|
if (index > -1 && (index + 1) < this._inputs.length) {
|
||||||
|
let nextInput = this._inputs[index + 1];
|
||||||
|
if (nextInput !== this._focused) {
|
||||||
|
return nextInput.initFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
index = this._inputs.indexOf(this._focused);
|
||||||
* @param {Number} inc TODO
|
if (index > 0) {
|
||||||
*/
|
let previousInput = this._inputs[index - 1];
|
||||||
focusMove(inc) {
|
if (previousInput) {
|
||||||
let input = this._focused;
|
previousInput.initFocus();
|
||||||
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;
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable, NgZone} from 'angular2/angular2';
|
||||||
|
|
||||||
|
import {IonicConfig} from '../config/config';
|
||||||
import {IonicForm} from './form';
|
import {IonicForm} from './form';
|
||||||
import * as dom from './dom';
|
import * as dom from './dom';
|
||||||
|
|
||||||
@ -7,8 +8,13 @@ import * as dom from './dom';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class IonicKeyboard {
|
export class IonicKeyboard {
|
||||||
|
|
||||||
constructor(form: IonicForm) {
|
constructor(config: IonicConfig, form: IonicForm, zone: NgZone) {
|
||||||
this.form = form;
|
this.form = form;
|
||||||
|
this.zone = zone;
|
||||||
|
|
||||||
|
zone.runOutsideAngular(() => {
|
||||||
|
this.focusOutline(config.get('focusOutline'), document);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isOpen() {
|
isOpen() {
|
||||||
@ -25,16 +31,23 @@ export class IonicKeyboard {
|
|||||||
promise = new Promise(resolve => { callback = resolve; });
|
promise = new Promise(resolve => { callback = resolve; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.zone.runOutsideAngular(() => {
|
||||||
|
|
||||||
function checkKeyboard() {
|
function checkKeyboard() {
|
||||||
if (!self.isOpen()) {
|
if (!self.isOpen()) {
|
||||||
|
self.zone.run(() => {
|
||||||
|
console.debug('keyboard closed');
|
||||||
callback();
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setTimeout(checkKeyboard, 500);
|
setTimeout(checkKeyboard, KEYBOARD_CLOSE_POLLING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(checkKeyboard, 100);
|
setTimeout(checkKeyboard, KEYBOARD_CLOSE_POLLING);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
@ -48,4 +61,64 @@ export class IonicKeyboard {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focusOutline(setting, document) {
|
||||||
|
/* Focus Outline
|
||||||
|
* --------------------------------------------------
|
||||||
|
* By default, when a keydown event happens from a tab key, then
|
||||||
|
* the 'focus-outline' css class is added to the body element
|
||||||
|
* so focusable elements have an outline. On a mousedown or
|
||||||
|
* touchstart event, then the 'focus-outline' css class is removed.
|
||||||
|
*
|
||||||
|
* Config default overrides:
|
||||||
|
* focusOutline: true - Always add the focus-outline
|
||||||
|
* focusOutline: false - Do not add the focus-outline
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
let isKeyInputEnabled = false;
|
||||||
|
|
||||||
|
function cssClass() {
|
||||||
|
dom.raf(() => {
|
||||||
|
document.body.classList[isKeyInputEnabled ? 'add' : 'remove']('focus-outline');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setting === true) {
|
||||||
|
isKeyInputEnabled = true;
|
||||||
|
return cssClass();
|
||||||
|
|
||||||
|
} else if (setting === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default is to add the focus-outline when the tab key is used
|
||||||
|
function keyDown(ev) {
|
||||||
|
if (!isKeyInputEnabled && ev.keyCode == 9) {
|
||||||
|
isKeyInputEnabled = true;
|
||||||
|
enableKeyInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pointerDown() {
|
||||||
|
isKeyInputEnabled = false;
|
||||||
|
enableKeyInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableKeyInput() {
|
||||||
|
cssClass();
|
||||||
|
|
||||||
|
document.removeEventListener('mousedown', pointerDown);
|
||||||
|
document.removeEventListener('touchstart', pointerDown);
|
||||||
|
|
||||||
|
if (isKeyInputEnabled) {
|
||||||
|
document.addEventListener('mousedown', pointerDown);
|
||||||
|
document.addEventListener('touchstart', pointerDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', keyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const KEYBOARD_CLOSE_POLLING = 150;
|
||||||
|
@ -27,17 +27,17 @@
|
|||||||
|
|
||||||
// Focus Outline
|
// Focus Outline
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// When a keydown event happens, from a tab key, then the
|
|
||||||
// 'key-input' class is added to the body element so focusable
|
$focus-outline-border-color: #51a7e8 !default;
|
||||||
// elements have an outline. On a mousedown or touchstart
|
$focus-outline-box-shadow: 0px 0px 8px 0px $focus-outline-border-color !default;
|
||||||
// event then the 'key-input' class is removed.
|
|
||||||
|
|
||||||
:focus,
|
:focus,
|
||||||
:active {
|
:active {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.key-input {
|
.focus-outline {
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
@ -46,8 +46,20 @@
|
|||||||
|
|
||||||
button:focus,
|
button:focus,
|
||||||
[button]:focus {
|
[button]:focus {
|
||||||
outline-offset: -2px;
|
border-color: $focus-outline-border-color;
|
||||||
outline: 2px solid red;
|
box-shadow: $focus-outline-box-shadow;
|
||||||
|
outline: thin solid $focus-outline-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-input.has-focus,
|
||||||
|
button[ion-item]:focus,
|
||||||
|
a[ion-item]:focus {
|
||||||
|
border-color: $focus-outline-border-color;
|
||||||
|
box-shadow: inset $focus-outline-box-shadow !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-input :focus {
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user