2016-06-23 09:47:54 -07:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
|
*/
|
|
|
|
|
|
2017-06-20 11:35:16 +02:00
|
|
|
import {Directive, ElementRef, Inject, InjectionToken, Optional, Renderer2, forwardRef} from '@angular/core';
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
import {ɵgetDOM as getDOM} from '@angular/platform-browser';
|
2016-06-08 16:38:52 -07:00
|
|
|
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
2016-06-08 15:36:24 -07:00
|
|
|
|
2016-07-30 19:18:14 -07:00
|
|
|
export const DEFAULT_VALUE_ACCESSOR: any = {
|
|
|
|
|
provide: NG_VALUE_ACCESSOR,
|
|
|
|
|
useExisting: forwardRef(() => DefaultValueAccessor),
|
|
|
|
|
multi: true
|
|
|
|
|
};
|
2016-06-08 15:36:24 -07:00
|
|
|
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
/**
|
|
|
|
|
* We must check whether the agent is Android because composition events
|
|
|
|
|
* behave differently between iOS and Android.
|
|
|
|
|
*/
|
|
|
|
|
function _isAndroid(): boolean {
|
|
|
|
|
const userAgent = getDOM() ? getDOM().getUserAgent() : '';
|
|
|
|
|
return /android (\d+)/.test(userAgent.toLowerCase());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Turn this mode on if you want form directives to buffer IME input until compositionend
|
|
|
|
|
* @experimental
|
|
|
|
|
*/
|
|
|
|
|
export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionEventMode');
|
|
|
|
|
|
2016-06-08 15:36:24 -07:00
|
|
|
/**
|
|
|
|
|
* The default accessor for writing a value and listening to changes that is used by the
|
2016-06-12 13:17:07 -07:00
|
|
|
* {@link NgModel}, {@link FormControlDirective}, and {@link FormControlName} directives.
|
2016-06-08 15:36:24 -07:00
|
|
|
*
|
|
|
|
|
* ### Example
|
|
|
|
|
* ```
|
2016-06-12 13:17:07 -07:00
|
|
|
* <input type="text" name="searchQuery" ngModel>
|
2016-06-08 15:36:24 -07:00
|
|
|
* ```
|
|
|
|
|
*
|
2016-08-17 07:44:39 -07:00
|
|
|
* @stable
|
2016-06-08 15:36:24 -07:00
|
|
|
*/
|
|
|
|
|
@Directive({
|
|
|
|
|
selector:
|
2016-06-12 13:17:07 -07:00
|
|
|
'input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
|
2016-06-08 15:36:24 -07:00
|
|
|
// TODO: vsavkin replace the above selector with the one below it once
|
|
|
|
|
// https://github.com/angular/angular/issues/3011 is implemented
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
// selector: '[ngModel],[formControl],[formControlName]',
|
|
|
|
|
host: {
|
|
|
|
|
'(input)': '_handleInput($event.target.value)',
|
|
|
|
|
'(blur)': 'onTouched()',
|
|
|
|
|
'(compositionstart)': '_compositionStart()',
|
|
|
|
|
'(compositionend)': '_compositionEnd($event.target.value)'
|
|
|
|
|
},
|
2016-06-08 15:36:24 -07:00
|
|
|
providers: [DEFAULT_VALUE_ACCESSOR]
|
|
|
|
|
})
|
|
|
|
|
export class DefaultValueAccessor implements ControlValueAccessor {
|
|
|
|
|
onChange = (_: any) => {};
|
|
|
|
|
onTouched = () => {};
|
|
|
|
|
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
/** Whether the user is creating a composition string (IME events). */
|
|
|
|
|
private _composing = false;
|
|
|
|
|
|
|
|
|
|
constructor(
|
2017-06-20 11:35:16 +02:00
|
|
|
private _renderer: Renderer2, private _elementRef: ElementRef,
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
@Optional() @Inject(COMPOSITION_BUFFER_MODE) private _compositionMode: boolean) {
|
|
|
|
|
if (this._compositionMode == null) {
|
|
|
|
|
this._compositionMode = !_isAndroid();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-08 15:36:24 -07:00
|
|
|
|
|
|
|
|
writeValue(value: any): void {
|
2016-11-11 10:47:34 -08:00
|
|
|
const normalizedValue = value == null ? '' : value;
|
2017-06-20 11:35:16 +02:00
|
|
|
this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
|
2016-06-08 15:36:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
|
|
|
|
|
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
|
2016-08-24 16:58:43 -07:00
|
|
|
|
|
|
|
|
setDisabledState(isDisabled: boolean): void {
|
2017-06-20 11:35:16 +02:00
|
|
|
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
|
2016-08-24 16:58:43 -07:00
|
|
|
}
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
|
2017-07-27 16:13:16 -07:00
|
|
|
/** @internal */
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
_handleInput(value: any): void {
|
|
|
|
|
if (!this._compositionMode || (this._compositionMode && !this._composing)) {
|
|
|
|
|
this.onChange(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-27 16:13:16 -07:00
|
|
|
/** @internal */
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
_compositionStart(): void { this._composing = true; }
|
|
|
|
|
|
2017-07-27 16:13:16 -07:00
|
|
|
/** @internal */
|
fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.
However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.
As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:
```ts
providers: [
{provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```
Or, if you want to change the mode based on locale or platform,
you can use a factory:
```ts
import {shouldUseBuffering} from 'my/lib';
....
providers: [
{provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```
Closes #15079.
PR Close #15256
2017-03-20 17:38:33 -07:00
|
|
|
_compositionEnd(value: any): void {
|
|
|
|
|
this._composing = false;
|
|
|
|
|
this._compositionMode && this.onChange(value);
|
|
|
|
|
}
|
2016-06-08 15:36:24 -07:00
|
|
|
}
|