2020-07-31 04:58:58 +02:00
import { UIElement } from "./UI/UIElement" ;
2020-10-02 19:00:24 +02:00
import * as $ from "jquery"
import { FixedUiElement } from "./UI/Base/FixedUiElement" ;
2020-07-31 04:58:58 +02:00
2020-07-24 01:12:57 +02:00
export class Utils {
2020-09-30 22:22:58 +02:00
static EncodeXmlValue ( str ) {
return str . replace ( /&/g , '&' )
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /"/g , '"' )
. replace ( /'/g , ''' )
}
2020-07-24 01:12:57 +02:00
/ * *
* Gives a clean float , or undefined if parsing fails
* @param str
* /
static asFloat ( str ) : number {
if ( str ) {
const i = parseFloat ( str ) ;
if ( isNaN ( i ) ) {
return undefined ;
}
return i ;
}
return undefined ;
}
2020-09-30 22:22:58 +02:00
public static Upper ( str : string ) {
return str . substr ( 0 , 1 ) . toUpperCase ( ) + str . substr ( 1 ) ;
}
2020-10-04 01:04:46 +02:00
public static TwoDigits ( i : number ) {
if ( i < 10 ) {
return "0" + i ;
}
return "" + i ;
}
public static Times ( f : ( ( i : number ) = > string ) , count : number ) : string {
2020-09-30 22:22:58 +02:00
let res = "" ;
for ( let i = 0 ; i < count ; i ++ ) {
2020-10-04 01:04:46 +02:00
res += f ( i ) ;
2020-09-30 22:22:58 +02:00
}
return res ;
2020-07-24 14:46:25 +02:00
}
2020-07-31 04:58:58 +02:00
static DoEvery ( millis : number , f : ( ( ) = > void ) ) {
2020-08-31 02:59:47 +02:00
if ( UIElement . runningFromConsole ) {
2020-07-31 17:11:44 +02:00
return ;
}
2020-07-31 04:58:58 +02:00
window . setTimeout (
function ( ) {
f ( ) ;
Utils . DoEvery ( millis , f ) ;
}
, millis )
}
2020-08-08 02:16:42 +02:00
public static NoNull < T > ( array : T [ ] ) : T [ ] {
const ls : T [ ] = [ ] ;
for ( const t of array ) {
if ( t === undefined || t === null ) {
continue ;
}
ls . push ( t ) ;
}
return ls ;
}
2020-08-22 13:02:31 +02:00
public static NoEmpty ( array : string [ ] ) : string [ ] {
const ls : string [ ] = [ ] ;
for ( const t of array ) {
if ( t === "" ) {
continue ;
}
ls . push ( t ) ;
}
return ls ;
}
2020-08-08 02:16:42 +02:00
2020-08-26 00:21:34 +02:00
public static EllipsesAfter ( str : string , l : number = 100 ) {
2020-09-03 03:16:43 +02:00
if ( str === undefined ) {
return undefined ;
}
2020-08-26 00:21:34 +02:00
if ( str . length <= l ) {
return str ;
}
return str . substr ( 0 , l - 3 ) + "..." ;
}
2020-08-26 15:36:04 +02:00
public static Dedup ( arr : string [ ] ) : string [ ] {
if ( arr === undefined ) {
return undefined ;
}
const newArr = [ ] ;
for ( const string of arr ) {
2020-10-02 19:00:24 +02:00
if ( newArr . indexOf ( string ) < 0 ) {
2020-08-26 15:36:04 +02:00
newArr . push ( string ) ;
}
}
return newArr ;
}
2020-10-02 19:00:24 +02:00
public static MergeTags ( a : any , b : any ) {
2020-08-27 00:08:00 +02:00
const t = { } ;
for ( const k in a ) {
t [ k ] = a [ k ] ;
}
for ( const k in b ) {
t [ k ] = b [ k ] ;
}
return t ;
}
2020-10-02 19:00:24 +02:00
public static SplitFirst ( a : string , sep : string ) : string [ ] {
2020-08-31 02:59:47 +02:00
const index = a . indexOf ( sep ) ;
2020-10-02 19:00:24 +02:00
if ( index < 0 ) {
2020-08-31 02:59:47 +02:00
return [ a ] ;
}
2020-10-02 19:00:24 +02:00
return [ a . substr ( 0 , index ) , a . substr ( index + sep . length ) ] ;
2020-08-31 02:59:47 +02:00
}
2020-07-31 04:58:58 +02:00
2020-10-02 19:00:24 +02:00
public static isRetina ( ) : boolean {
if ( UIElement . runningFromConsole ) {
2020-09-27 21:01:46 +02:00
return ;
}
2020-09-27 21:00:37 +02:00
// The cause for this line of code: https://github.com/pietervdvn/MapComplete/issues/115
// See https://stackoverflow.com/questions/19689715/what-is-the-best-way-to-detect-retina-support-on-a-device-using-javascript
return ( ( window . matchMedia && ( window . matchMedia ( 'only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx), only screen and (min-resolution: 75.6dpcm)' ) . matches || window . matchMedia ( 'only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min--moz-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2)' ) . matches ) ) || ( window . devicePixelRatio && window . devicePixelRatio >= 2 ) ) ;
}
2020-10-02 19:00:24 +02:00
// Date will be undefined on failure
public static changesetDate ( id : number , action : ( ( isFound : Date ) = > void ) ) : void {
$ . getJSON ( "https://www.openstreetmap.org/api/0.6/changeset/" + id ,
function ( data ) {
console . log ( data )
action ( new Date ( data . elements [ 0 ] . created_at ) ) ;
} )
. fail ( ( ) = > {
action ( undefined ) ;
} ) ;
}
public static generateStats ( action : ( stats :string ) = > void ) {
// Binary searches the latest changeset
function search ( lowerBound : number ,
upperBound : number ,
onCsFound : ( ( id : number , lastDate : Date ) = > void ) ,
depth = 0 ) {
if ( depth > 30 ) {
return ;
}
const tested = Math . floor ( ( lowerBound + upperBound ) / 2 ) ;
console . log ( "Testing" , tested )
Utils . changesetDate ( tested , ( createdAtDate : Date ) = > {
new FixedUiElement ( ` Searching, value between ${ lowerBound } and ${ upperBound } . Queries till now: ${ depth } ` ) . AttachTo ( 'maindiv' )
if ( lowerBound + 1 >= upperBound ) {
onCsFound ( lowerBound , createdAtDate ) ;
return ;
}
if ( createdAtDate !== undefined ) {
search ( tested , upperBound , onCsFound , depth + 1 )
} else {
search ( lowerBound , tested , onCsFound , depth + 1 ) ;
}
} )
}
search ( 91000000 , 100000000 , ( last , lastDate : Date ) = > {
const link = "http://osm.org/changeset/" + last ;
const delta = 100000 ;
Utils . changesetDate ( last - delta , ( prevDate ) = > {
const diff = ( lastDate . getTime ( ) - prevDate . getTime ( ) ) / 1000 ;
// Diff: seconds needed/delta changesets
const secsPerCS = diff / delta ;
const stillNeeded = 1000000 - ( last % 1000000 ) ;
const timeNeededSeconds = Math . floor ( secsPerCS * stillNeeded ) ;
const secNeeded = timeNeededSeconds % 60 ;
const minNeeded = Math . floor ( timeNeededSeconds / 60 ) % 60 ;
const hourNeeded = Math . floor ( timeNeededSeconds / ( 60 * 60 ) ) % 24 ;
const daysNeeded = Math . floor ( timeNeededSeconds / ( 24 * 60 * 60 ) ) ;
const result = ` Last changeset: <a href=' ${ link } '> ${ link } </a><br/>We needed ${ ( Math . floor ( diff / 60 ) ) } minutes for the last ${ delta } changesets.<br/>
This is around $ { secsPerCS } seconds / changeset . < br / > The next million ( still $ { stillNeeded } away ) will be broken in around $ { daysNeeded } days $ { hourNeeded } : $ { minNeeded } : $ { secNeeded } `
action ( result ) ;
} )
}
) ;
}
2020-10-04 01:04:46 +02:00
2020-07-24 14:46:25 +02:00
}