2020-07-01 02:12:33 +02:00
import { UIElement } from "../UIElement" ;
2020-07-20 15:54:50 +02:00
import { InputElement } from "./InputElement" ;
2020-07-21 00:38:03 +02:00
import Translations from "../i18n/Translations" ;
2020-08-17 17:23:15 +02:00
import { UIEventSource } from "../../Logic/UIEventSource" ;
2020-08-22 02:12:46 +02:00
2020-09-25 12:44:04 +02:00
export class TextField extends InputElement < string > {
2020-08-30 01:13:18 +02:00
private readonly value : UIEventSource < string > ;
public readonly enterPressed = new UIEventSource < string > ( undefined ) ;
private readonly _placeholder : UIElement ;
2020-08-31 02:59:47 +02:00
public readonly IsSelected : UIEventSource < boolean > = new UIEventSource < boolean > ( false ) ;
private readonly _isArea : boolean ;
2020-09-24 23:56:08 +02:00
private readonly _textAreaRows : number ;
2020-09-26 03:02:19 +02:00
private readonly _isValid : ( string ) = > boolean ;
2020-09-25 12:44:04 +02:00
constructor ( options ? : {
2020-07-20 15:54:50 +02:00
placeholder? : string | UIElement ,
2020-09-25 12:44:04 +02:00
value? : UIEventSource < string > ,
2020-09-07 01:03:23 +02:00
textArea? : boolean ,
2020-09-24 23:56:08 +02:00
textAreaRows? : number ,
2020-09-25 12:44:04 +02:00
isValid ? : ( ( s : string ) = > boolean )
2020-07-20 13:28:45 +02:00
} ) {
2020-07-20 15:54:50 +02:00
super ( undefined ) ;
2020-07-20 21:39:07 +02:00
const self = this ;
2020-07-20 13:28:45 +02:00
this . value = new UIEventSource < string > ( "" ) ;
2020-09-25 12:44:04 +02:00
options = options ? ? { } ;
2020-08-31 02:59:47 +02:00
this . _isArea = options . textArea ? ? false ;
2020-09-25 12:44:04 +02:00
this . value = options ? . value ? ? new UIEventSource < string > ( undefined ) ;
2020-07-20 13:28:45 +02:00
2020-09-07 01:03:23 +02:00
this . _textAreaRows = options . textAreaRows ;
2020-09-26 03:02:19 +02:00
this . _isValid = options . isValid ? ? ( ( str ) = > true ) ;
2020-07-20 13:28:45 +02:00
2020-07-21 00:38:03 +02:00
this . _placeholder = Translations . W ( options . placeholder ? ? "" ) ;
this . ListenTo ( this . _placeholder . _source ) ;
2020-07-20 15:54:50 +02:00
2020-09-10 21:06:56 +02:00
this . onClick ( ( ) = > {
self . IsSelected . setData ( true )
} ) ;
2020-09-25 12:44:04 +02:00
this . value . addCallback ( ( t ) = > {
2020-09-26 03:02:19 +02:00
const field = document . getElementById ( "txt-" + this . id ) ;
2020-09-25 12:44:04 +02:00
if ( field === undefined || field === null ) {
2020-07-20 13:28:45 +02:00
return ;
}
2020-09-26 03:02:19 +02:00
field . className = self . IsValid ( t ) ? "" : "invalid" ;
2020-09-25 12:44:04 +02:00
if ( t === undefined || t === null ) {
2020-07-20 13:28:45 +02:00
return ;
}
2020-07-20 15:54:50 +02:00
// @ts-ignore
2020-09-25 12:44:04 +02:00
field . value = t ;
2020-08-22 02:12:46 +02:00
} ) ;
2020-09-25 17:57:01 +02:00
this . dumbMode = false ;
2020-09-25 12:44:04 +02:00
}
2020-07-05 18:59:47 +02:00
2020-09-25 12:44:04 +02:00
GetValue ( ) : UIEventSource < string > {
return this . value ;
2020-07-01 02:12:33 +02:00
}
2020-09-25 12:44:04 +02:00
2020-07-20 21:03:55 +02:00
InnerRender ( ) : string {
2020-09-25 12:44:04 +02:00
if ( this . _isArea ) {
2020-09-25 17:57:01 +02: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 02:59:47 +02:00
}
2020-09-25 12:44:04 +02:00
2020-09-12 23:15:17 +02:00
const placeholder = this . _placeholder . InnerRender ( ) . replace ( "'" , "'" ) ;
2020-09-25 12:44:04 +02:00
2020-09-25 17:57:01 +02: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 02:12:33 +02:00
2020-09-25 17:57:01 +02:00
InnerUpdate() {
const field = document . getElementById ( "txt-" + this . id ) ;
2020-07-01 02:12:33 +02:00
const self = this ;
field . oninput = ( ) = > {
2020-09-26 01:10:10 +02:00
// @ts-ignore
2020-09-26 03:02:19 +02:00
const endDistance = field . value . length - field . selectionEnd ;
2020-07-05 18:59:47 +02:00
// @ts-ignore
2020-09-26 03:02:19 +02:00
const val : string = field . value ;
if ( ! self . IsValid ( val ) ) {
self . value . setData ( undefined ) ;
} else {
self . value . setData ( val ) ;
}
2020-09-26 01:10:10 +02: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 03:02:19 +02:00
// We reread the field value - it might have changed!
// @ts-ignore
2020-09-26 01:10:10 +02:00
self . SetCursorPosition ( field . value . length - endDistance ) ;
2020-07-01 02:12:33 +02:00
} ;
2020-09-25 12:44:04 +02:00
if ( this . value . data !== undefined && this . value . data !== null ) {
// @ts-ignore
field . value = this . value . data ;
}
2020-08-31 02:59:47 +02:00
field . addEventListener ( "focusin" , ( ) = > self . IsSelected . setData ( true ) ) ;
field . addEventListener ( "focusout" , ( ) = > self . IsSelected . setData ( false ) ) ;
2020-09-10 21:06:56 +02:00
2020-07-01 02:12:33 +02:00
field . addEventListener ( "keyup" , function ( event ) {
if ( event . key === "Enter" ) {
2020-07-05 18:59:47 +02:00
// @ts-ignore
2020-07-01 02:12:33 +02:00
self . enterPressed . setData ( field . value ) ;
}
} ) ;
2020-07-05 18:59:47 +02:00
2020-07-01 02:12:33 +02:00
}
2020-09-11 00:23:19 +02:00
public SetCursorPosition ( i : number ) {
2020-09-26 01:10:10 +02:00
const field = document . getElementById ( 'txt-' + this . id ) ;
2020-09-11 00:23:19 +02:00
if ( field === undefined || field === null ) {
return ;
}
2020-09-25 12:44:04 +02:00
if ( i === - 1 ) {
2020-09-11 00:23:19 +02:00
// @ts-ignore
i = field . value . length ;
}
field . focus ( ) ;
// @ts-ignore
field . setSelectionRange ( i , i ) ;
2020-09-26 01:10:10 +02:00
2020-09-11 00:23:19 +02:00
}
2020-09-25 12:44:04 +02:00
IsValid ( t : string ) : boolean {
2020-09-26 03:02:19 +02:00
if ( t === undefined || t === null ) {
return false
}
return this . _isValid ( t ) ;
2020-07-20 15:54:50 +02:00
}
2020-09-12 23:15:17 +02:00
}