
# sleepless

Sleepless Inc.'s handy Javascript stuff.


## Install

	npm install sleepless


## Usage


### Browser

	<script src="sleepless.js"></script>
    <script>
        sleepless.globalize()  // optional
    </script>


### Node

	sleepless = require( "sleepless" )
    sleepless.globalize()  // optional


## Documentation

The sleepless.js file contains a bunch of code built over the course of years
to help me speed up development on both the front and backend.

There is some code that is common to both environments, and there are also
things that are only present for one or the other.  There are also some things
which are common in terms of the function calls, but which have different underlying
code depending on the environment.


### globalize()

    sleepless.globalize()   // typeof globalThis.log === "function"

### log()

    log( "foo", 7 )

### throwIf( c, s )

    throwIf( something === null, "ERROR: something is null" )

### o2j(o)

    o2j( { foo: 7 } )   // "{\"foo\":7}"

### j2o(j)

    j2o( "{\"foo\":7}" )    // { foo: 7 }

### toFlt(v)

    toFlt( "123.4" )    // 123.4
    toFlt( 123.9 )      // 123.9

### toInt(v)

    toInt( "123.4" )    // 123
    toInt( 123.9 )      // 124

### centsToBucks(cents)

    centsToBucks( 1234 )   // 12.34 
    centsToBucks( "1234" )   // 12.34 

### bucksToCents(bucks)

    bucksToCents( "1234.56" )   // 123456
    bucksToCents( 1234.56 )   // 123456

### numFmt(n, plcs, dot, sep)

    numFmt( 1234.56 )	// "1,235"
    numFmt( 1234.56, 1 )	// "1,234.6"
    numFmt( 1234.56, 1, "," )	// "1,234,6"
    numFmt( 1234.56, 1, "_" )	// "1,234_6"
    numFmt( 1234.56, 1, ",", "." )	// "1.234,6"
    numFmt( 1234.56, 1, ".", "" )	// "1234.6"

### toPct(n, plcs, dot, sep)

	toPct( 0.4 ) + "%"		// "40%"
	toPct( 123.4,",", "." )	// "12,340"

### toMoney(n, dot, sep)

	toMoney( 1234.56 )				// "1,234.56"
	toMoney( 1234.56, 1, ".", "" )	// "1.234,56"

### byteSize(sz)

	byteSize( 1024 )    // "1 KB"

### time( dt )
    
    time()      // 1716740316

### my2ts(m)
    
    my2ts( "2024-05-26 17:18:36" )  // 1716740316

### ts2my(ts)

    ts2my( 1716740316 )     // "2024-05-26 17:18:36"

### ts2dt(ts)
    
    ts2dt( 1716740316 ) instanceof Date     // true

### dt2ts(dt)

    dt2ts( ts2dt( 1716740316 ) )    // 1716740316

### us2dt(us, utc)
### us2ts(us, utc)
### ts2us(ts)
### ts2us_md(ts)
### ts2us_mdy(ts)
### ts2us_mdy2(ts)
### ts2us_hm(ts)
### ts2us_mdyhm(ts)
### ts2us_mdy2hm(ts)
### ts2us_dMy(ts)

### Array.prototype.distinct( cb )

	[ 1,2,2 ].distinct()		// [1,2]

### String.prototype.lcase()
	"Foo".lcase()		// "foo"

### String.prototype.ucase()

	"Foo".ucase()		// "FOO"

### String.prototype.ucfirst()

	"foo bar".ucfirst()		// "Foo bar"

### String.prototype.ucwords( sep )

	"foo bar".ucwords()		// "Foo Bar"

### String.prototype.startsWith(prefix)

	"Foobar".startsWith( "Foo" ) 		// true
	"foobar".startsWith( "Foo" ) 		// false

### String.prototype.endsWith(suffix)

	"Foobar".endsWith( "bar" ) 		// true
	"foobar".endsWith( "Bar" ) 		// false

### String.prototype.abbr(l)

	"Foo bar baz".abbr(6)  // "Fo ..."

### String.prototype.toLabel()

    "foo_bAr".toLabel()     // "Foo BAr"

### String.prototype.toId()

    "Foo BAr".toId()        // "foo_bar"
    "#Foo.,BAr!!".toId()    // "foo_bar"


### String.prototype.looks_like()

	"I,\nhave a lovely bunch of coconuts".looksLike("i have", "coconuts") == true

### String.prototype.substitute( data )
    
    "Welcome, __name__".substitute( { name: "Bart" } )  // "Welcome, Bart"

### String.prototype.is_email()

    "joe@sleepless.com".is_email()  // true
    "a@b.cd".is_email()             // true
    "joe@sleepless".is_email()      // false
    "joe.sleepless.com".is_email()  // false

### ago_str(ts, no_suffix)

	agoStr( time() - 60 ) 	// "60 seconds ago"
	agoStr( time() - 63 ) 	// "1 minute ago"

### runp( a_this, ...args )

### runq( a_this, ...args )

### text2html( t )

### log5( ...)

    logger = log5.mkLog( "Me: " )
    logger( 3 )
    logger.V( "verbosity" )
    logger.W( "warning" )                // 2024-05-26_17:41:12 Me: - - - - warning


### Non-Browser Context Stuff

#### get_file(path, enc, cb)

    let s = get_file( "./foo.json" )    // "{\"foo\":7}"

#### file_info( path, cb )

#### is_file( path, cb )

    is_file( "./README.md" ) // true
    is_file( "./missing.txt" )  // false

#### is_dir( path, cb )
    
    is_dir( "/" )       // true

#### sha1(s)

    sha1( "Bond. James Bond." )   // '045a3cfa9e2ec907262d47174ff9b980d72f7040'

#### sha256(s)

    sha256( "Bond. James Bond." ) // '15f0045e4ba244ef613aeccfc0e3f1399fe0aaa79771add66ea02770cf3a1a74'

#### rand_hash()

    rand_hash()     // '8a3301c8b2e71f5a60617bc9215323e1ac7f1d24'
    rand_hash()     // 'c02bf00ed381c381bfa0c741224a4c0f715d2434'


#### rpc( url, opts, data, okay, fail )


### Browser-Only Stuff

#### LS

    LS.set( "foo", [ "foo", 2, true ] )
    LS.get( "foo" ).length              // 3
    LS.clear()

#### get_file(url, cb)

    get_file( "/data.json", function( text ) {
        log( text )     // "{\"foo\":7}"
    } )

#### rpc( url, opts, data, okay, fail )

#### query_data( key )

    "https://example.com/?arg1=foo&arg2=bar"

    query_data()            // { arg1: "foo", arg2: "bar" }
    query_data( "arg1" )    // "foo"


#### HTMLCollection.prototype.toArray()

#### NodeList.prototype.toArray();

#### HTMLElement.prototype.addClass(c)

#### HTMLElement.prototype.hasClass(c)

    <div class="foo bar">...</div>

    let elem = document.body.find( "div" )
    elem.hasClass( "foo" )      // true
    elem.hasClass( "bar" )      // true
    elem.hasClass( "qux" )      // false

#### HTMLElement.prototype.remClass(c)

    <div class="foo bar">
    </div>

    let elem = document.body.find( "div" )

    elem.remClass( "foo" );


#### HTMLElement.prototype.findAll( qs )
    
    <div name=a>
        <div name=b>Yelp</div>
    </div>

    let arr = document.body.findAll( "div" )    // [ ... ]
    arr.length          // 2
    arr[ 1 ].html()     // "Yelp"

#### HTMLElement.prototype.find( qs )

    <foo-element>
        <bar data=yada>qux</bar>
    </foo-element>

    let foo = document.body.find( "foo-element" )
    foo.find( "wobble" )        // null
    let bar = foo.find( "bar" );
    bar.html()                  // "qux"


#### HTMLElement.prototype.named( name )

    <input name="blort">

    document.body.named( "blort" )  // HTMLElement { name: "blort" }
    document.body.named( "bloop" )  // null

#### HTMLElement.prototype.attr(a, v)
    
    <input data="foo">

    let elem = document.body.find( "input" )
    elem.attr( "data" )     // "foo"
    elem.attr( "data", "bar" )


#### HTMLElement.prototype.val(v, chg = false)

    <form name=login>
        <input name=name value="Bobby">
    </form>

    let elem = document.forms.login.name
    elem.val()        // "Bobby"
    elem.val( "Sally" )

#### HTMLElement.prototype.html(h)

    let elem = document.body.find( "div.foo" )
    let h = elem.html()      // "<p>Hi there!</p>"
    elem.html( h.replace( /there/, "Bob" )


#### HTMLElement.prototype.change()

    document.forms.login.username.change()

#### HTMLElement.prototype.inject( data )

    <form>
        <input name="username" value="__default_user__">
    </form>

    document.forms.login.inject( { default_user: "elmer" } )


#### HTMLFormElement.prototype.getData()

    let f = document.body.find( "form" )
    f.setData( { name: "Bob", email: "bob@example.com } )
    f.onsubmit = function() {
        let data = f.getData()      // { name: "Robert", email: "rob@example.com" } 
    }

#### HTMLFormElement.prototype.setData( d, change_cb )

#### rplc8( elem, data, cb )

    r8 = rplc8( document.body.find( "div.a_song" )

    objs = [
        { band: "Abba", title: "Waterloo" },
        { band: "AC/DC", title: "T.N.T" },
    ]

    r8.update( objs )

    r8.update( objs, function( element, object, index ) {
        ...
    } )

#### navigate( data, new_show )

Use history.push/popstate to navigate through pseudo-pages.

    navigate( { page: "dashboard" } )

#### FDrop

Drag/Drop support

    let elem = document.body.find( "#droptarget" )
    FDrop.attach( elem, function( files, event ) {
        let f = files[ 0 ]
        FDrop.mk_data_url( f, function( url ) {
            elem.find( "img" ).src = url
            elem.find( "label" ).src = f.name
        } )
    } )

#### scale_data_image( image_data_url, new_width, new_height, cb )

Load an image asyncrhonously, scale it to a specific width/height, convert
the image to a "data:" url, and return it via callback.

