2020-07-01 00:12:33 +00:00
import { UIElement } from "../UIElement" ;
2020-07-20 13:54:50 +00:00
import { InputElement } from "./InputElement" ;
2020-07-20 22:38:03 +00:00
import Translations from "../i18n/Translations" ;
2020-08-17 15:23:15 +00:00
import { UIEventSource } from "../../Logic/UIEventSource" ;
2020-08-22 00:12:46 +00:00
2020-09-25 10:44:04 +00:00
export class TextField extends InputElement < string > {
2020-08-29 23:13:18 +00:00
private readonly value : UIEventSource < string > ;
public readonly enterPressed = new UIEventSource < string > ( undefined ) ;
private readonly _placeholder : UIElement ;
2020-08-31 00:59:47 +00:00
public readonly IsSelected : UIEventSource < boolean > = new UIEventSource < boolean > ( false ) ;
private readonly _isArea : boolean ;
2020-09-24 21:56:08 +00:00
private readonly _textAreaRows : number ;
2020-09-26 01:02:19 +00:00
private readonly _isValid : ( string ) = > boolean ;
2020-09-25 10:44:04 +00:00
constructor ( options ? : {
2020-07-20 13:54:50 +00:00
placeholder? : string | UIElement ,
2020-09-25 10:44:04 +00:00
value? : UIEventSource < string > ,
2020-09-06 23:03:23 +00:00
textArea? : boolean ,
2020-09-24 21:56:08 +00:00
textAreaRows? : number ,
2020-09-25 10:44:04 +00:00
isValid ? : ( ( s : string ) = > boolean )
2020-07-20 11:28:45 +00:00
} ) {
2020-07-20 13:54:50 +00:00
super ( undefined ) ;
2020-07-20 19:39:07 +00:00
const self = this ;
2020-07-20 11:28:45 +00:00
this . value = new UIEventSource < string > ( "" ) ;
2020-09-25 10:44:04 +00:00
options = options ? ? { } ;
2020-08-31 00:59:47 +00:00
this . _isArea = options . textArea ? ? false ;
2020-09-25 10:44:04 +00:00
this . value = options ? . value ? ? new UIEventSource < string > ( undefined ) ;
2020-07-20 11:28:45 +00:00
2020-09-06 23:03:23 +00:00
this . _textAreaRows = options . textAreaRows ;
2020-09-26 01:02:19 +00:00
this . _isValid = options . isValid ? ? ( ( str ) = > true ) ;
2020-07-20 11:28:45 +00:00
2020-07-20 22:38:03 +00:00
this . _placeholder = Translations . W ( options . placeholder ? ? "" ) ;
this . ListenTo ( this . _placeholder . _source ) ;
2020-07-20 13:54:50 +00:00
2020-09-10 19:06:56 +00:00
this . onClick ( ( ) = > {
self . IsSelected . setData ( true )
} ) ;
2020-09-25 10:44:04 +00:00
this . value . addCallback ( ( t ) = > {
2020-09-26 01:02:19 +00:00
const field = document . getElementById ( "txt-" + this . id ) ;
2020-09-25 10:44:04 +00:00
if ( field === undefined || field === null ) {
2020-07-20 11:28:45 +00:00
return ;
}
2020-09-26 01:02:19 +00:00
field . className = self . IsValid ( t ) ? "" : "invalid" ;
2020-09-25 10:44:04 +00:00
if ( t === undefined || t === null ) {
2020-07-20 11:28:45 +00:00
return ;
}
2020-07-20 13:54:50 +00:00
// @ts-ignore
2020-09-25 10:44:04 +00:00
field . value = t ;
2020-08-22 00:12:46 +00:00
} ) ;
2020-09-25 15:57:01 +00:00
this . dumbMode = false ;
2020-09-25 10:44:04 +00:00
}
2020-07-05 16:59:47 +00:00
2020-09-25 10:44:04 +00:00
GetValue ( ) : UIEventSource < string > {
return this . value ;
2020-07-01 00:12:33 +00:00
}
2020-09-25 10:44:04 +00:00
2020-07-20 19:03:55 +00:00
InnerRender ( ) : string {
2020-09-25 10:44:04 +00:00
if ( this . _isArea ) {
2020-09-25 15:57:01 +00:00
return ` <span id=" ${ this . id } "><textarea id="txt- ${ this . id } " class="form-text-field" rows=" ${ this . _textAreaRows } " cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea></span> `
2020-08-31 00:59:47 +00:00
}
2020-09-25 10:44:04 +00:00
2020-09-12 21:15:17 +00:00
const placeholder = this . _placeholder . InnerRender ( ) . replace ( "'" , "'" ) ;
2020-09-25 10:44:04 +00:00
2020-09-25 15:57:01 +00:00
return ` <span id=" ${ this . id } "><form onSubmit='return false' class='form-text-field'> ` +
` <input type='text' placeholder=' ${ placeholder } ' id='txt- ${ this . id } '> ` +
` </form></span> ` ;
}
2020-07-01 00:12:33 +00:00
2020-09-25 15:57:01 +00:00
InnerUpdate() {
const field = document . getElementById ( "txt-" + this . id ) ;
2020-07-01 00:12:33 +00:00
const self = this ;
field . oninput = ( ) = > {
2020-09-25 23:10:10 +00:00
// @ts-ignore
2020-09-26 01:02:19 +00:00
const endDistance = field . value . length - field . selectionEnd ;
2020-07-05 16:59:47 +00:00
// @ts-ignore
2020-09-26 01:02:19 +00:00
const val : string = field . value ;
if ( ! self . IsValid ( val ) ) {
self . value . setData ( undefined ) ;
} else {
self . value . setData ( val ) ;
}
2020-09-25 23:10:10 +00:00
// Setting the value might cause the value to be set again. We keep the distance _to the end_ stable, as phone number formatting might cause the start to change
// See https://github.com/pietervdvn/MapComplete/issues/103
2020-09-26 01:02:19 +00:00
// We reread the field value - it might have changed!
// @ts-ignore
2020-09-25 23:10:10 +00:00
self . SetCursorPosition ( field . value . length - endDistance ) ;
2020-07-01 00:12:33 +00:00
} ;
2020-09-25 10:44:04 +00:00
if ( this . value . data !== undefined && this . value . data !== null ) {
// @ts-ignore
field . value = this . value . data ;
}
2020-08-31 00:59:47 +00:00
field . addEventListener ( "focusin" , ( ) = > self . IsSelected . setData ( true ) ) ;
field . addEventListener ( "focusout" , ( ) = > self . IsSelected . setData ( false ) ) ;
2020-09-10 19:06:56 +00:00
2020-07-01 00:12:33 +00:00
field . addEventListener ( "keyup" , function ( event ) {
if ( event . key === "Enter" ) {
2020-07-05 16:59:47 +00:00
// @ts-ignore
2020-07-01 00:12:33 +00:00
self . enterPressed . setData ( field . value ) ;
}
} ) ;
2020-07-05 16:59:47 +00:00
2020-07-01 00:12:33 +00:00
}
2020-09-10 22:23:19 +00:00
public SetCursorPosition ( i : number ) {
2020-09-25 23:10:10 +00:00
const field = document . getElementById ( 'txt-' + this . id ) ;
2020-09-10 22:23:19 +00:00
if ( field === undefined || field === null ) {
return ;
}
2020-09-25 10:44:04 +00:00
if ( i === - 1 ) {
2020-09-10 22:23:19 +00:00
// @ts-ignore
i = field . value . length ;
}
field . focus ( ) ;
// @ts-ignore
field . setSelectionRange ( i , i ) ;
2020-09-25 23:10:10 +00:00
2020-09-10 22:23:19 +00:00
}
2020-09-25 10:44:04 +00:00
IsValid ( t : string ) : boolean {
2020-09-26 01:02:19 +00:00
if ( t === undefined || t === null ) {
return false
}
return this . _isValid ( t ) ;
2020-07-20 13:54:50 +00:00
}
2020-09-12 21:15:17 +00:00
}