1
1
import { Directive , Attribute , ElementRef , Renderer , Input , Output , EventEmitter , HostListener } from 'angular2/core' ;
2
2
import { NgControl } from 'angular2/common' ;
3
3
4
+ import { Config } from '../../config/config' ;
4
5
import { CSS , hasFocus , raf } from '../../util/dom' ;
5
6
6
7
@@ -12,35 +13,30 @@ import {CSS, hasFocus, raf} from '../../util/dom';
12
13
} )
13
14
export class NativeInput {
14
15
private _relocated : boolean ;
16
+ private _clone : boolean ;
15
17
16
18
@Output ( ) focusChange : EventEmitter < boolean > = new EventEmitter ( ) ;
17
19
@Output ( ) valueChange : EventEmitter < string > = new EventEmitter ( ) ;
18
20
19
21
constructor (
20
22
private _elementRef : ElementRef ,
21
23
private _renderer : Renderer ,
24
+ config : Config ,
22
25
public ngControl : NgControl
23
- ) { }
26
+ ) {
27
+ this . _clone = config . getBoolean ( 'inputCloning' , false ) ;
28
+ }
24
29
25
- /**
26
- * @private
27
- */
28
30
@HostListener ( 'input' , [ '$event' ] )
29
31
private _change ( ev ) {
30
32
this . valueChange . emit ( ev . target . value ) ;
31
33
}
32
34
33
- /**
34
- * @private
35
- */
36
35
@HostListener ( 'focus' )
37
36
private _focus ( ) {
38
37
this . focusChange . emit ( true ) ;
39
38
}
40
39
41
- /**
42
- * @private
43
- */
44
40
@HostListener ( 'blur' )
45
41
private _blur ( ) {
46
42
this . focusChange . emit ( false ) ;
@@ -55,55 +51,69 @@ export class NativeInput {
55
51
this . _renderer . setElementAttribute ( this . _elementRef . nativeElement , 'disabled' , val ? '' : null ) ;
56
52
}
57
53
58
- /**
59
- * @private
60
- */
61
54
setFocus ( ) {
62
- this . element ( ) . focus ( ) ;
55
+ // let's set focus to the element
56
+ // but only if it does not already have focus
57
+ if ( document . activeElement !== this . element ( ) ) {
58
+ this . element ( ) . focus ( ) ;
59
+ }
63
60
}
64
61
65
- /**
66
- * @private
67
- */
68
- relocate ( shouldRelocate : boolean , inputRelativeY : number ) {
69
- console . debug ( 'native input relocate' , shouldRelocate , inputRelativeY ) ;
70
-
71
- if ( this . _relocated !== shouldRelocate ) {
72
-
73
- let focusedInputEle = this . element ( ) ;
74
- if ( shouldRelocate ) {
75
- let clonedInputEle = cloneInput ( focusedInputEle , 'cloned-focus' ) ;
76
-
77
- focusedInputEle . parentNode . insertBefore ( clonedInputEle , focusedInputEle ) ;
78
- focusedInputEle . style [ CSS . transform ] = `translate3d(-9999px,${ inputRelativeY } px,0)` ;
79
- focusedInputEle . style . opacity = '0' ;
80
-
62
+ beginFocus ( shouldFocus : boolean , inputRelativeY : number ) {
63
+ if ( this . _relocated !== shouldFocus ) {
64
+ var focusedInputEle = this . element ( ) ;
65
+ if ( shouldFocus ) {
66
+ // we should focus into this element
67
+
68
+ if ( this . _clone ) {
69
+ // this platform needs the input to be cloned
70
+ // this allows for the actual input to receive the focus from
71
+ // the user's touch event, but before it receives focus, it
72
+ // moves the actual input to a location that will not screw
73
+ // up the app's layout, and does not allow the native browser
74
+ // to attempt to scroll the input into place (messing up headers/footers)
75
+ // the cloned input fills the area of where native input should be
76
+ // while the native input fakes out the browser by relocating itself
77
+ // before it receives the actual focus event
78
+ var clonedInputEle = cloneInput ( focusedInputEle , 'cloned-focus' ) ;
79
+ focusedInputEle . parentNode . insertBefore ( clonedInputEle , focusedInputEle ) ;
80
+
81
+ // move the native input to a location safe to receive focus
82
+ // according to the browser, the native input receives focus in an
83
+ // area which doesn't require the browser to scroll the input into place
84
+ focusedInputEle . style [ CSS . transform ] = `translate3d(-9999px,${ inputRelativeY } px,0)` ;
85
+ focusedInputEle . style . opacity = '0' ;
86
+ }
87
+
88
+ // let's now set focus to the actual native element
89
+ // at this point it is safe to assume the browser will not attempt
90
+ // to scroll the input into view itself (screwing up headers/footers)
81
91
this . setFocus ( ) ;
82
92
83
- raf ( ( ) => {
93
+ if ( this . _clone ) {
84
94
focusedInputEle . classList . add ( 'cloned-active' ) ;
85
- } ) ;
95
+ }
86
96
87
97
} else {
88
- focusedInputEle . classList . remove ( 'cloned-active' ) ;
89
- focusedInputEle . style [ CSS . transform ] = '' ;
90
- focusedInputEle . style . opacity = '' ;
91
-
92
- removeClone ( focusedInputEle , 'cloned-focus' ) ;
98
+ // should remove the focus
99
+ if ( this . _clone ) {
100
+ // should remove the cloned node
101
+ focusedInputEle . classList . remove ( 'cloned-active' ) ;
102
+ focusedInputEle . style [ CSS . transform ] = '' ;
103
+ focusedInputEle . style . opacity = '' ;
104
+ removeClone ( focusedInputEle , 'cloned-focus' ) ;
105
+ }
93
106
}
94
107
95
- this . _relocated = shouldRelocate ;
108
+ this . _relocated = shouldFocus ;
96
109
}
97
110
}
98
111
99
- /**
100
- * @private
101
- */
102
112
hideFocus ( shouldHideFocus : boolean ) {
103
- console . debug ( 'native input hideFocus' , shouldHideFocus ) ;
104
-
105
113
let focusedInputEle = this . element ( ) ;
106
114
115
+ console . debug ( `native input hideFocus, shouldHideFocus: ${ shouldHideFocus } , input value: ${ focusedInputEle . value } ` ) ;
116
+
107
117
if ( shouldHideFocus ) {
108
118
let clonedInputEle = cloneInput ( focusedInputEle , 'cloned-move' ) ;
109
119
@@ -124,9 +134,6 @@ export class NativeInput {
124
134
return this . element ( ) . value ;
125
135
}
126
136
127
- /**
128
- * @private
129
- */
130
137
element ( ) : HTMLInputElement {
131
138
return this . _elementRef . nativeElement ;
132
139
}
@@ -141,6 +148,8 @@ function cloneInput(focusedInputEle, addCssClass) {
141
148
clonedInputEle . removeAttribute ( 'aria-labelledby' ) ;
142
149
clonedInputEle . tabIndex = - 1 ;
143
150
clonedInputEle . style . width = ( focusedInputEle . offsetWidth + 10 ) + 'px' ;
151
+ clonedInputEle . style . height = focusedInputEle . offsetHeight + 'px' ;
152
+ clonedInputEle . value = focusedInputEle . value ;
144
153
return clonedInputEle ;
145
154
}
146
155
@@ -164,6 +173,7 @@ export class NextInput {
164
173
165
174
@HostListener ( 'focus' )
166
175
receivedFocus ( ) {
176
+ console . debug ( 'native-input, next-input received focus' ) ;
167
177
this . focused . emit ( true ) ;
168
178
}
169
179
0 commit comments