mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
text input focus updates
This commit is contained in:
@ -189,7 +189,7 @@ gulp.task('bundle', ['bundle.ionic'], function() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('tests', function() {
|
gulp.task('tests', function() {
|
||||||
return gulp.src('ionic/components/*/test/*/**/*.spec.ts')
|
return gulp.src('ionic/**/test/**/*.spec.ts')
|
||||||
.pipe(tsc(tscOptions, null, tscReporter))
|
.pipe(tsc(tscOptions, null, tscReporter))
|
||||||
.pipe(babel(getBabelOptions('dist/tests')))
|
.pipe(babel(getBabelOptions('dist/tests')))
|
||||||
.pipe(rename(function(file) {
|
.pipe(rename(function(file) {
|
||||||
@ -307,9 +307,8 @@ gulp.task('fonts', function() {
|
|||||||
|
|
||||||
require('./scripts/snapshot/snapshot.task')(gulp, argv, buildConfig);
|
require('./scripts/snapshot/snapshot.task')(gulp, argv, buildConfig);
|
||||||
|
|
||||||
gulp.task('karma', function() {
|
gulp.task('karma', ['tests'], function() {
|
||||||
return karma.start({ configFile: __dirname + '/scripts/karma/karma.conf.js' })
|
return karma.start({ configFile: __dirname + '/scripts/karma/karma.conf.js' })
|
||||||
//return karma.start({ configFile: __dirname + '/karma.conf.js' })
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('karma-watch', function() {
|
gulp.task('karma-watch', function() {
|
||||||
|
@ -10,10 +10,7 @@ import {ScrollTo} from '../../animations/scroll-to';
|
|||||||
selector: 'ion-content',
|
selector: 'ion-content',
|
||||||
properties: [
|
properties: [
|
||||||
'parallax'
|
'parallax'
|
||||||
],
|
]
|
||||||
host: {
|
|
||||||
['[class.scroll-padding]']: 'scrollPadding'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
@View({
|
@View({
|
||||||
template: '<div class="scroll-content"><ng-content></ng-content></div>'
|
template: '<div class="scroll-content"><ng-content></ng-content></div>'
|
||||||
@ -21,8 +18,6 @@ import {ScrollTo} from '../../animations/scroll-to';
|
|||||||
export class Content extends Ion {
|
export class Content extends Ion {
|
||||||
constructor(elementRef: ElementRef, config: IonicConfig) {
|
constructor(elementRef: ElementRef, config: IonicConfig) {
|
||||||
super(elementRef, config);
|
super(elementRef, config);
|
||||||
|
|
||||||
this.scrollPadding = config.setting('keyboardScrollAssist');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onIonInit() {
|
onIonInit() {
|
||||||
@ -88,12 +83,4 @@ export class Content extends Ion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get scrollPadding() {
|
|
||||||
return this._sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
set scrollPadding(val) {
|
|
||||||
this._sp = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -108,10 +108,6 @@ focus-holder input {
|
|||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-padding.scroll-padding .scroll-content {
|
|
||||||
padding-bottom: 1000px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*focus-holder input[tabindex="999"] {
|
/*focus-holder input[tabindex="999"] {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Ion} from 'ionic/ion';
|
import {Ion} from 'ionic/ion';
|
||||||
|
|
||||||
export function run() {
|
export function main() {
|
||||||
it('should be true', () => {
|
it('should be true', () => {
|
||||||
expect(true).toBe(true);
|
expect(true).toBe(true);
|
||||||
});
|
});
|
@ -160,8 +160,11 @@ export class TextInput extends Ion {
|
|||||||
// this input is inside of a scroll view
|
// this input is inside of a scroll view
|
||||||
|
|
||||||
// find out if text input should be manually scrolled into view
|
// find out if text input should be manually scrolled into view
|
||||||
let scrollToY = this.getScollToY();
|
let ele = this.elementRef.nativeElement;
|
||||||
if (scrollToY === 0) {
|
let safeAreaBottom = (Platform.height() * 0.6);
|
||||||
|
|
||||||
|
let scrollData = this.getScollData(ele.offsetTop, ele.offsetHeight, scrollView.getDimensions(), safeAreaBottom);
|
||||||
|
if (scrollData.noScroll) {
|
||||||
// the text input is in a safe position that doesn't require
|
// the text input is in a safe position that doesn't require
|
||||||
// it to be scrolled into view, just set focus now
|
// it to be scrolled into view, just set focus now
|
||||||
return this.setFocus();
|
return this.setFocus();
|
||||||
@ -171,16 +174,13 @@ export class TextInput extends Ion {
|
|||||||
// do not allow any clicks while it's scrolling
|
// do not allow any clicks while it's scrolling
|
||||||
ClickBlock(true, SCROLL_INTO_VIEW_DURATION + 200);
|
ClickBlock(true, SCROLL_INTO_VIEW_DURATION + 200);
|
||||||
|
|
||||||
// used to put a lot of padding on the bottom of the scroll view
|
|
||||||
scrollView.scrollPadding = true;
|
|
||||||
|
|
||||||
// temporarily move the focus to the focus holder so the browser
|
// temporarily move the focus to the focus holder so the browser
|
||||||
// doesn't freak out while it's trying to get the input in place
|
// doesn't freak out while it's trying to get the input in place
|
||||||
// at this point the native text input still does not have focus
|
// at this point the native text input still does not have focus
|
||||||
this.tempFocusMove();
|
this.tempFocusMove();
|
||||||
|
|
||||||
// scroll the input into place
|
// scroll the input into place
|
||||||
scrollView.scrollTo(0, scrollToY, SCROLL_INTO_VIEW_DURATION, 8).then(() => {
|
scrollView.scrollTo(0, scrollData.scrollTo, SCROLL_INTO_VIEW_DURATION, 8).then(() => {
|
||||||
// the scroll view is in the correct position now
|
// the scroll view is in the correct position now
|
||||||
// give the native text input focus
|
// give the native text input focus
|
||||||
this.setFocus();
|
this.setFocus();
|
||||||
@ -196,67 +196,70 @@ export class TextInput extends Ion {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getScollToY() {
|
getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, safeAreaBottom) {
|
||||||
let ele = this.elementRef.nativeElement;
|
// compute input's Y values relative to the body
|
||||||
let viewDimensions = this.scrollView.getDimensions();
|
let inputTop = (inputOffsetTop + scrollViewDimensions.top - scrollViewDimensions.scrollTop);
|
||||||
|
let inputBottom = (inputTop + inputOffsetHeight);
|
||||||
|
|
||||||
// get the inputs Y position relative to the scroll view
|
// compute the safe area which is the viewable content area when the soft keyboard is up
|
||||||
let inputOffsetTop = ele.offsetTop;
|
let safeAreaTop = (scrollViewDimensions.top - 1);
|
||||||
|
let safeAreaHeight = (safeAreaBottom - safeAreaTop);
|
||||||
|
|
||||||
// compute offset values relative to the body
|
let inputTopWithinSafeArea = (inputTop >= safeAreaTop && inputTop <= safeAreaBottom);
|
||||||
let contentTop = viewDimensions.top;
|
let inputBottomWithinSafeArea = (inputBottom >= safeAreaTop && inputBottom <= safeAreaBottom);
|
||||||
let inputTop = inputOffsetTop + contentTop - viewDimensions.scrollTop;
|
let inputBottomBelowSafeArea = (inputBottom > safeAreaBottom);
|
||||||
let inputBottom = (inputTop + ele.offsetHeight);
|
let inputFitsWithinSafeArea = (inputOffsetHeight <= safeAreaHeight);
|
||||||
|
let distanceInputBottomBelowSafeArea = (safeAreaBottom - inputBottom);
|
||||||
|
|
||||||
// compute the safe area which is the viewable
|
/*
|
||||||
// content area when the soft keyboard is up
|
Text Input Scroll To Scenarios
|
||||||
let safeTop = contentTop - 1;
|
---------------------------------------
|
||||||
let safeBottom = (Platform.height() * 0.6);
|
1) Input top within safe area, bottom within safe area
|
||||||
|
2) Input top within safe area, bottom below safe area, room to scroll
|
||||||
|
3) Input top above safe area, bottom within safe area, room to scroll
|
||||||
|
4) Input top below safe area, no room to scroll, input smaller than safe area
|
||||||
|
5) Input top within safe area, bottom below safe area, no room to scroll, input smaller than safe area
|
||||||
|
6) Input top within safe area, bottom below safe area, no room to scroll, input larger than safe area
|
||||||
|
7) Input top below safe area, no room to scroll, input larger than safe area
|
||||||
|
*/
|
||||||
|
|
||||||
// Text Input Scroll To Scenarios
|
if (inputTopWithinSafeArea && inputBottomWithinSafeArea) {
|
||||||
// ---------------------------------------
|
// Input top within safe area, bottom within safe area
|
||||||
// 1) Input top within safe area, bottom within safe area
|
// no need to scroll to a position, it's good as-is
|
||||||
// 2) Input top within safe area, bottom below safe area
|
return { noScroll: true };
|
||||||
// 3) Input top and bottom below safe area
|
}
|
||||||
// 4) Input top above safe area, bottom within safe area
|
|
||||||
// 5) Input top above safe area, bottom below safe area
|
|
||||||
|
|
||||||
if (inputTop >= safeTop && inputTop <= safeBottom) {
|
// looks like we'll have to do some auto-scrolling
|
||||||
// Input top within safe area
|
let scrollData = {
|
||||||
|
scrollUp: 0,
|
||||||
|
scrollDown: 0,
|
||||||
|
scrollTo: inputOffsetTop,
|
||||||
|
scrollPadding: 0,
|
||||||
|
};
|
||||||
|
|
||||||
if (inputBottom <= safeBottom) {
|
if (inputTopWithinSafeArea && inputBottomBelowSafeArea) {
|
||||||
// 1) Input top within safe area, bottom within safe area
|
// Input top within safe area, bottom below safe area
|
||||||
// no need to scroll to a position, it's good as-is
|
let distanceInputTopIntoSafeArea = (safeAreaTop - inputTop);
|
||||||
return 0;
|
let distanceInputBottomBelowSafeArea = (inputBottom - safeAreaBottom);
|
||||||
|
|
||||||
|
if (distanceInputBottomBelowSafeArea < distanceInputTopIntoSafeArea) {
|
||||||
|
// the input's top is farther into the safe area then the bottom is out of it
|
||||||
|
// this means we can scroll it up a little bit and the top will still be
|
||||||
|
// within the safe area
|
||||||
|
scrollData.scrollUp = distanceInputTopIntoSafeArea;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// the input's top is less below the safe area top than the
|
||||||
|
// input's bottom is below the safe area bottom. So scroll the input
|
||||||
|
// to be at the top of the safe area, knowing that the bottom will go below
|
||||||
|
scrollData.scrollUp = distanceInputTopIntoSafeArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Input top within safe area, bottom below safe area
|
|
||||||
// TODO: What if the input is still taller than safe area?
|
|
||||||
return inputOffsetTop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputTop > safeBottom) {
|
|
||||||
// 3) Input top and bottom below safe area
|
|
||||||
// TODO: What if the input is still taller than safe area?
|
|
||||||
return inputOffsetTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputTop < safeTop) {
|
|
||||||
// Input top above safe area
|
|
||||||
|
|
||||||
if (inputBottom <= safeTop) {
|
|
||||||
// 4) Input top above safe area, bottom within safe area
|
|
||||||
// TODO: What if the input is still taller than safe area?
|
|
||||||
return inputOffsetTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5) Input top above safe area, bottom below safe area
|
|
||||||
// TODO: What if the input is still taller than safe area?
|
|
||||||
return inputOffsetTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback for whatever reason
|
// fallback for whatever reason
|
||||||
return inputOffsetTop;
|
return scrollData;
|
||||||
}
|
}
|
||||||
|
|
||||||
deregListeners() {
|
deregListeners() {
|
||||||
|
@ -2,7 +2,7 @@ var buildConfig = require('../build/config');
|
|||||||
|
|
||||||
module.exports = function(config) {
|
module.exports = function(config) {
|
||||||
config.set({
|
config.set({
|
||||||
//singleRun: true,
|
singleRun: true,
|
||||||
basePath: '../../',
|
basePath: '../../',
|
||||||
|
|
||||||
frameworks: ['jasmine'],
|
frameworks: ['jasmine'],
|
||||||
|
Reference in New Issue
Block a user