3.4.3 • Published 6 months ago

hlp v3.4.3

Weekly downloads
434
License
MIT
Repository
github
Last release
6 months ago

build status

motivation

tired of writing

if( Object.keys(obj).length === 0 && obj.constructor === Object )
{

}

or

if (typeof arr !== 'undefined' && arr.length > 0)
{

}

or

for(const [obj__key, obj__value] of Object.entries(obj))
{

}

?

installation

npm init -y
npm install hlp

now use it as a module:

import hlp from 'hlp';

or embed it directly:

<script src="hlp.js"></script> 

usage

existence

// check existence
if( hlp.x(vrbl) )
{

}

// check non-existence
if( hlp.nx(vrbl) )
{

}

equality

// js has a lot of pitfalls, when comparing loosely
if( '' == [] ) // true
if( '' == [''] ) // true
if( '' == 0 ) // true
if( ' ' == false ) // true
if( [0] == false ) // true
if( [0] == '0' ) // true
if( [] == false ) // true
if( [''] == false ) // true
if( 0 == false ) // true
if( 0 == [] ) // true
if( 0 == [''] ) // true
if( [0] == false ) // true
if( [0] == 0 ) // true

// also don't forget those delicacies
0 === -0 // true
NaN === NaN // false
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] === 'fail' // true

// this non-strict equality is symmetric, but not transitive
a = ''; b = 0; c = [0];
a == b; // true
b == c; // true
c == a; // false

// to overcome this issue, we...

// ...use strict comparison when possible
if( vrbl === 'foo' )
{

}

// ...use loose comparison when appropriate
if( hlp.getParam('number') == 1337 )
{

}

// ...check for truthness / falsiness with these helper methods
if( hlp.true(vrbl) )
{

}

if( hlp.false(vrbl) )
{

}

// be aware, that hlp.true is not always the logic negation of hlp.false
hlp.true(null) // false
hlp.false(null) // false

value

// get variable if exists, otherwise ''
hlp.v( vrbl )

// get variable if exists, otherwise 'default'
hlp.v( vrbl, 'default' )

// get first variable that exists, otherwise ''
hlp.v( vrbl1, vrbl2, vrbl3 )

loop

// loop over arrays/objects only if possible
hlp.loop(['foo','bar','baz'], (vrbl__value) =>
{

});
hlp.loop(['foo','bar','baz'], (vrbl__value, vrbl__key) =>
{

});
hlp.loop({bar: 'foo', baz: 'bar', foo: 'baz'}, (vrbl__value, vrbl__key) =>
{

});
hlp.loop([], (vrbl__value, vrbl__key) => { }) // does nothing
hlp.loop({}, (vrbl__value, vrbl__key) => { }) // does nothing
hlp.loop(null, (vrbl__value, vrbl__key) => { }) // does nothing

try

// if you are unsure, if a variable is even set before checking its existence,
// simply put it inside this helper function
if( hlp.x(() => vrbl) )
if( hlp.nx(() => vrbl)  )
if( hlp.true(() => vrbl) )
if( hlp.false(() => vrbl)  )
if( hlp.v(() => vrbl) === 'foo' )
if( hlp.v(() => vrbl) == 1337 )
echo hlp.v(() => vrbl)
hlp.loop((() => vrbl), (vrbl__value, vrbl__key) => { })

that works because javascript only evaluates the content of the inner callback (or closure) when it is actually executed.

helpers

there are also some other neat little helpers available:

// capitalize
hlp.capitalize('foo') // Foo

// check if object
hlp.isObject({}) // true
hlp.isObject({foo: 'bar'}) // true
hlp.isObject(null) // false
hlp.isObject([]) // false (be aware: an array in js is scrictly an object, but this function returns false)

// check if array
hlp.isArray([]) // true
hlp.isArray(['foo','bar']) // true
hlp.isArray(null) // false

// check if string
hlp.isString('foo'); // true
hlp.isString(42); // false
hlp.isString(null); // false

// check if date
hlp.isDate('2018-01-01') // true
hlp.isDate('2018-02-29') // false
hlp.isDate('1700-01-01') // true
hlp.isDate(42) // false

// format date
hlp.formatDate('d.m.Y', '2018-01-01') // 01.01.2018
hlp.formatDate('Y-m-d H:i:s', new Date()) // 01.01.2018

// get week number from date
hlp.dateToWeek(new Date('2021-02-22')) // 8
hlp.dateToWeek() // hlp.dateToWeek(new Date())

// get date (of monday) from week number
hlp.weekToDate(42, 2018) // new Date('2018-10-14')
hlp.weekToDate(17, 2023) // new Date('2023-04-23')

// add days to date
hlp.addDays(new Date('2018-01-01'), 7) // new Date('2018-01-08')
hlp.addDays(new Date('2018-02-22'), 658) // new Date('2019-12-12')
hlp.addDays(new Date('2018-02-22'), 1) // new Date('2018-02-21')

// compare dates
let d1 = new Date();
let d2 = new Date();
hlp.compareDates(d1, d2) // 0
hlp.addDays(d1, -1);
hlp.compareDates(d1, d2) // -1
hlp.addDays(d1, 2);
hlp.compareDates(d1, d2) // 1
hlp.compareDates('2020-01-01', '2020-01-17 17:42:19') // -1

// spaceship operator
hlp.spaceship(5,7) // -1
hlp.spaceship(9,7) // 1
hlp.spaceship(7,7) // 0
hlp.spaceship('foo','bar') // 1
hlp.spaceship('bar','foo') // -1

// check if objects are equal
hlp.objectsAreEqual({}, {}) // true
hlp.objectsAreEqual({ foo: 'bar' }, { foo: 'bar'}) // true
hlp.objectsAreEqual({ foo: 'bar' }, { bar: 'baz'}) // false

// check if object is inside an array/object
hlp.containsObject({ foo: 'bar' }, []) // false
hlp.containsObject({ foo: 'bar' }, [{ foo: 'bar' }, { bar: 'baz' }]) // true
hlp.containsObject({ foo: 'bar' }, { foo: { foo: 'bar' } }) // true

// recursively search key/value in nested object and return dotprop array
hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id'); // ['foo', 'bar.foo']
hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id', 42); // ['foo']
hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, null, 7); // ['bar.foo', 'baz']

// deep clone reference types (object/array/date/regex)
hlp.deepCopy({ foo: 'bar' })
hlp.deepCopy(['foo','bar'])
hlp.deepCopy(new Date())
hlp.deepCopy(new Date('2018-01-01'))
hlp.deepCopy(new RegExp('ab+c', 'i'))

// generate uuid/guid v4
hlp.uuid() // e86e393c-9788-857b-27c2-f80c8ca1a302
hlp.uuid() // 8b25a8f8-9525-bd73-4679-3539321db93b

// replace all occurences
hlp.replaceAll('foo bar baz', 'a', 'b') // 'foo bbr bbz'

// replace last occurence
hlp.replaceLast('foo bar baz', 'a', 'b') // 'foo bar bbz'

// replace last occurence
hlp.replaceFirst('foo bar baz', 'a', 'b') // 'foo bbr baz'

// case insensitive search
hlp.indexOfCaseInsensitive('foo', 'this is a FOO') // 10
hlp.indexOfCaseInsensitive('foo', 'this is a FOO and a foobar', 15) // 20

// count occurences in string
hlp.countAllOccurences('foo', 'this is a foo and a foobar') // 2
hlp.countAllOccurencesCaseInsensitive('FoO', 'this is a FOO and a foobar') // 2

// find all positions in string
hlp.findAllPositions('foo', 'this is a foo and a foobar') // [10,20]
hlp.findAllPositionsCaseInsensitive('FoO', 'this is a FOO and a foobar') // [10,20]

// highlight strings
hlp.highlight('that is a search string', 'is') // that <strong class="highlight">is</strong> a search string
hlp.highlight('abc def geh ijk lmn opq rst abc def geh ijk lmn opq rst', 'ijk', true, 5) // '... geh <strong class="highlight">ijk</strong> lmn ... geh <strong class="highlight">ijk</strong> lmn ...'

// remove empty elements from array
hlp.removeEmpty(['foo',null,[],'','bar']) // ['foo','bar']

// return unique array (remove duplicate values, order-safe)
hlp.uniqueArray(['foo','bar','foo','baz']) // ['foo','bar','baz']

// powerset of array (all subsets of a set)
hlp.powerset([1,2,3]) // [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

// shuffle array
hlp.shuffle(['foo','bar']) // ['foo','bar']
hlp.shuffle(['foo','bar']) // ['foo','bar']
hlp.shuffle(['foo','bar']) // ['foo','bar'] (yikes)
hlp.shuffle(['foo','bar']) // ['bar','foo']

// char helpers
hlp.charToInt('D') // 4
hlp.intToChar(4) // 'D'
hlp.incChar('D') // 'E'
hlp.incChar('Z') // 'AA'
hlp.incChar('A',2) // 'C'
hlp.decChar('U') // 'T'

// slugify / sanitize string
hlp.slugify('That röcks!') // that-roecks

// range
hlp.range('A','Z') // ['A','B',...,'Z']
hlp.range(1,42) // [1,2,...,42]
hlp.range('C','A') // ['C','B','A']

// get last item of object/array
hlp.last(['foo', 'bar', 'baz']) // 'baz'
hlp.last({ foo: 'bar', bar: 'baz'}) // 'baz'

// get first item of object/array
hlp.first(['foo', 'bar', 'baz']) // 'foo'
hlp.first({ foo: 'bar', bar: 'baz'}) // 'bar'

// get random element from object/array
hlp.rand(['foo', 'bar', 'baz']) // 'bar'

// generate a random string
hlp.random_string() // edPhi34d
hlp.random_string(10) // abCa321aC6
hlp.random_string(16, 'idkfa') // idifafafifaifafk

// generate a random integer
hlp.random_int() // 42
hlp.random_int(7,42) // 17

// proper rounding to n digits
hlp.round(1.005, 2) // 1.01
hlp.round(1.005) // 1

// check if variable is integer
hlp.isInteger('foo') // false
hlp.isInteger(42) // true
hlp.isInteger('42') // true
hlp.isInteger(4e2) // true
hlp.isInteger('4e2') // true
hlp.isInteger(' 1 ') // true
hlp.isInteger('') // false
hlp.isInteger('  ') // false
hlp.isInteger(42.1) // false
hlp.isInteger('1a') // false
hlp.isInteger('4e2a') // false
hlp.isInteger(null) // false
hlp.isInteger(undefined) // false
hlp.isInteger(NaN) // false

// check if variable is numeric
hlp.isNumeric(1337) // true
hlp.isNumeric('42') // true
hlp.isNumeric('42.7') // true
hlp.isNumeric('a') // false

// json parsing
hlp.jsonStringToObject('["foo","bar","baz"]') // ['foo','bar','baz']
hlp.jsonStringToObject('["foo","bar","baz",]') // null
hlp.jsonObjectToString(['foo','bar','baz']) // '["foo","bar","baz"]'
hlp.isJsonString('["foo","bar","baz",]') // false
hlp.isJsonString('["foo","bar","baz"]') // true

// map for objects
hlp.map({ foo: 'bar', bar: 'baz' }, (obj__key, obj__value) => obj__value += '!'); // { foo: 'bar!', bar: 'baz!' }

// fun with blobs
hlp.stringtoblob(string)
hlp.stringtoblob(string, 'image/png')
hlp.blobtostring(blob).then((string) => { })
hlp.blobtobase64(blob).then((base64) => { })
hlp.base64toblob(base64)
hlp.base64toblob(base64, 'image/png')
hlp.filetobase64(file).then((base64) => { })
hlp.blobtofile(blob)
hlp.blobtofile(blob, 'filename.png')
hlp.filetoblob(file)
hlp.base64tofile(base64)
hlp.base64tofile(base64, 'image/png')
hlp.base64tofile(base64, 'image/png', 'filename.png')
hlp.base64tostring(base64)
hlp.stringtobase64(string)
hlp.blobtourl(blob)
hlp.stringtourl(string)
hlp.base64tourl(base64)
hlp.filetourl(file)

// fix exif image orientation
hlp.fixImageOrientation(base64).then((base64) => { });
hlp.getImageOrientation(base64).then((orientation) => { });

// html entity encode/decode
hlp.htmlEncode('&<>"`\'') // &amp;&lt;&gt;&quot;&#96;&#x27;
hlp.htmlDecode('&amp;&lt;&gt;&quot;&#96;&#x27;') // &<>"`'

// line break conversion
hlp.nl2br('foo\nbar') // foo<br/>bar
hlp.br2nl('foo<br/>bar') // foo\nbar

// floating point math made easy
hlp.fmath('*', 0.1, 0.2) // 0.02
hlp.fmath('+', 0.1, 0.2) // 0.3
hlp.fmath('-', 0.1, 0.2) // -0.1
hlp.fmath('/', 0.2, 0.1) // 2
hlp.fmath('/', 0.39, 100, 12) // 0.0039 (precision of 12)

// trim helpers
hlp.trim('  foo ') // 'foo'
hlp.trim('xxfoox', 'x') // 'foo'
hlp.ltrim('  foo ') // 'foo '
hlp.ltrim('xxfoox', 'x') // 'foox'
hlp.rtrim('  foo ') // '  foo'
hlp.rtrim('xxfoox', 'x') // 'xxfoo'

// truncate/trim long strings
hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20); // Lorem ipsum dolor ...
hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20, '…'); // Lorem ipsum dolor …

// fun with emojis
let str = 'This❤️😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.';
str.match(hlp.emojiRegex()) // ['❤️', '😀', '👩‍⚖️', '🧗‍♀️', '👩🏼‍❤️‍💋‍👩🏽']
str.replaceAll(hlp.emojiRegex(), '') // This is a text full of emojis.
str.replace(hlp.emojiRegex(false), '') // This😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.
hlp.emojiRegex().test(str) // true

// create lexicographically ordered string ids like in firebase 
hlp.pushId() // -LDiDooGs9PyGHmghk5i
hlp.pushId() // -LDiDooGs9PyGHmghk5j

// access object properties with dotprop notation
// today it is better to use optional chaining in combination with nullish coalescing ({}?.c?.a?.a??'default')
hlp.getProp({
    a: 1,
    b: { a: 3, b: 3 },
    c: { a: { a: 7 } }
}, 'c.a.a') // 7

check out also the following helpers for the frontend:

// cookies
hlp.cookieSet('foo', 'bar', 7)
hlp.cookieSet('foo', 'bar', 7, false) // only for current domain (no subdomains)
hlp.cookieGet('foo') // bar
hlp.cookieDelete('foo')
hlp.cookieDelete('foo', false) // only for current domain (no subdomains)
hlp.cookieExists('foo') // true|false

// localstorage (with expiration time and object support)
hlp.localStorageSet('foo', {some: 'data'}, 7)
hlp.localStorageGet('foo') // {'some': 'data'}
hlp.localStorageDelete('foo')
hlp.localStorageExists('foo') // true|false

// get parameter (example url: https://tld.com/?foo=bar&bar=baz)
hlp.getParam('foo') // foo
hlp.getParam('bar') // baz
hlp.getParam('baz') // null

// device detection helpers
hlp.getDevice() // ['phone','tablet','desktop']
hlp.isPhone()
hlp.isTablet()
hlp.isDesktop()
hlp.isMobile()
hlp.isTouch()

// os detection helpers
hlp.getOs() // ['windows','mac','linux','unknown']
hlp.isWindows()
hlp.isMac()
hlp.isLinux()

// browser detection helpers
hlp.getBrowser() // ['ie','edge','firefox','chrome','safari','opera','unknown']

// smooth scroll to position / element
hlp.scrollTo( 0, 1000 ).then(() => { console.log('done'); });
hlp.scrollTo( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
hlp.scrollTo( 0, 1000, document.querySelector('.bar') ).then(() => { console.log('done'); }); // scoll inside .bar
hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200 ).then(() => { console.log('done'); }); // apply offset
hlp.scrollTo( document.querySelector('.foo'), 1000, null, document.querySelector('.header') ).then(() => { console.log('done'); }); // apply offset (height of dom element only if it exists and is fixed!)
hlp.scrollTo( document.querySelector('.foo'), 1000, null, [document.querySelector('.header'), -200] ).then(() => { console.log('done'); }); // you can also provide multiple values (of different type)
hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200, true ).then(() => { console.log('done'); }); // only scroll up (never down)

// get top/left scroll position
hlp.scrollTop()
hlp.scrollLeft()

// get closest vertical scrollable element (including oneself)
hlp.closestScrollable( document.querySelector('.foo') )

// get offset of element (excluding margin)
hlp.offsetTop( document.querySelector('.foo') )
hlp.offsetLeft( document.querySelector('.foo') )
hlp.offsetRight( document.querySelector('.foo') )
hlp.offsetBottom( document.querySelector('.foo') )

// get offset of element (including margin)
hlp.offsetTopWithMargin( document.querySelector('.foo') )
hlp.offsetLeftWithMargin( document.querySelector('.foo') )
hlp.offsetRightWithMargin( document.querySelector('.foo') )
hlp.offsetBottomWithMargin( document.querySelector('.foo') )

// get document size
hlp.documentWidth()
hlp.documentHeight()

// get window size
hlp.windowWidth()
hlp.windowHeight()
hlp.windowWidthWithoutScrollbar()
hlp.windowHeightWithoutScrollbar()

// get width with margin
hlp.outerWidthWithMargin( document.querySelector('.foo') )
hlp.outerHeightWithMargin( document.querySelector('.foo') )

// polyfills for ie11
hlp.closest( document.querySelector('.children'), '.parent' )
hlp.matches( document.querySelector('.parent'), '.parent' ) // true
hlp.remove( document.querySelector('.foo') ) // also works if .foo does not exist

// dom traversal
hlp.prevAll( document.querySelector('.foo') )
hlp.prevAll( document.querySelector('.foo'), '.bar' )
hlp.nextAll( document.querySelector('.foo') )
hlp.nextAll( document.querySelector('.foo'), '.bar' )
hlp.siblings( document.querySelector('.foo') )
hlp.siblings( document.querySelector('.foo'), '.bar' )
hlp.parents( document.querySelector('.foo') )
hlp.parents( document.querySelector('.foo'), '.bar' )
hlp.prevUntil( document.querySelector('.foo'), '.bar' ) // prev until selector not including
hlp.nextUntil( document.querySelector('.foo'), '.bar' ) // next until selector not including
hlp.prev( document.querySelector('.foo') )
hlp.prev( document.querySelector('.foo'), '.bar' )
hlp.next( document.querySelector('.foo') )
hlp.next( document.querySelector('.foo'), '.bar' )

// wrap element
hlp.wrap( document.querySelector('.foo'), '<div class="wrapper"></div>' )

// wrap all text nodes with new node
hlp.wrapTextNodes( document.querySelector('.foo'), 'p' )

// html string to dom (also supports ie11 and td nodes that cannot be root nodes)
hlp.html2dom('<p>foo</p>')
hlp.html2dom('<td>bar</td>')

// get all styles of a dom element (extracted from both inline styling and external styling through stylesheets)
hlp.css( document.querySelector('.foo') )

// visually focus element on page
hlp.focus('.foo')
hlp.focus(document.querySelector('.foo'))
hlp.unfocus()

// on delegate
hlp.on('click', '.selector', (e, el) => { });
hlp.on('click', '.selector', '.scope', (e, el) => { });

// classic debounce
window.addEventListener('resize', hlp.debounce(() => { console.log('debounce at resize') }, 1000));
document.querySelector('.container').addEventListener('input', hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000));
let debounce = hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000); // conditional debounce
document.querySelector('.container').addEventListener('input', e => { debounce(e); });

// classic throttle
window.addEventListener('resize', hlp.throttle(() => { console.log('throttle at resize') }, 1000));
document.querySelector('.container').addEventListener('input', hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000));
let throttle = hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000); // conditional throttle
document.querySelector('.container').addEventListener('input', e => { throttle(e); });

// get current url
hlp.url() // https://github.com/vielhuber/hlp
hlp.urlWithHash() // https://github.com/vielhuber/hlp#foo
hlp.fullUrl() // https://github.com/vielhuber/hlp?foo=bar#foo
hlp.urlWithArgs() // https://github.com/vielhuber/hlp?foo=bar
hlp.baseUrl() // https://github.com
hlp.urlHost(); // github.com
hlp.urlHostTopLevel(); // github.com
hlp.urlPath(); // /vielhuber/hlp
hlp.urlHash(); // #foo
hlp.urlArgs(); // ?foo=bar

// get url of current running script
hlp.urlOfScript(); // https://tld.com/wp-content/themes/dummy/script.js
hlp.pathOfScript(); // https://tld.com/wp-content/themes/dummy

// set 100vh for a dom element (respecting the visibility of the address bar)
hlp.real100vh('.foo') // 100vh
hlp.real100vh('.foo', 60) // 60vh
hlp.real100vh() // sets up a css variable which can be used with e.g. calc(100 * var(--vh, 1vh)); to mimic 100vh

// remove hover states on ios to prevent double clicks (see https://stackoverflow.com/questions/47802530/a-click-in-ios-safari-triggers-a-hover-state-on-element-underneath-where-you-t);
hlp.iOsRemoveHover();

// fade in/out dom element
hlp.fadeIn( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
hlp.fadeOut( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });

// check if dom element is generally visible
hlp.isVisible( document.querySelector('.foo') )
// check if dom element is visible inside viewport
hlp.isVisibleInViewport( document.querySelector('.foo') )

// wait until a dom element has a certain css property
// this is quite useful when working with async loaded stylesheets like loadCSS
// .beacon is an element below the fold populated by the stylesheet
hlp.waitUntil('.beacon').then(() => { });
hlp.waitUntil('.beacon','position').then(() => { });
hlp.waitUntil('.beacon','position','relative').then(() => { });

// wait until a variable is set or has a specific value
hlp.waitUntilVar('globalVar').then(() => { });
hlp.waitUntilVar(obj, 'objectVar').then(() => { });
hlp.waitUntilVar(obj, 'objectVar', true).then(() => { });

// run a function for every dom element, even it is added dynamically later on
hlp.runForEl('.beacon', el => { el.style.backgroundColor = 'red'; });

// automatically change height of all textareas based on content
hlp.textareaAutoHeight()
hlp.textareaAutoHeight('.special')
hlp.textareaSetHeight( document.querySelector('.special') )

// load external js file in dom with promise
hlp.loadJs('https://apis.google.com/js/api.js').then(() => { console.log('done'); });
hlp.loadJs([
    'https://www.tld.com/1.js',
    'https://www.tld.com/2.js',
    'https://www.tld.com/3.js'
]).then(() => { console.log('done'); });
hlp.loadJsSequentially([
    'https://www.tld.com/1.js',
    'https://www.tld.com/2.js',
    'https://www.tld.com/3.js'
]).then(() => { console.log('done'); });

// run event after all images are loaded inside container
// works even after dynamic changes
// runs more than once (after each change)
// run this outside of window load / document ready events
hlp.triggerAfterAllImagesLoaded('.container', '.container__image', () => {});

// proper document read/load events, that are guaranteed to be run (also if the script is embedded via async)
hlp.ready().then(() => {});
hlp.load().then(() => {});

// easy ajax requests (without the fetch api; also works in ie11)
hlp.get('https://httpbin.org/anything').then((response) => { }).catch((error) => { }) // { "method": "GET", ... }
hlp.get('/relpath').then((response) => { }).catch((error) => { }) // if a full url is omitted, the call is done on the baseurl
hlp.get('https://httpbin.org/anything', { throttle: 1000 }).then((response) => { }).catch((error) => { }) // same but with a throttle of 1 second
hlp.get('https://httpbin.org/status/404', { allow_errors: false }).then((response) => { }) // deny 404 and other status codes as a response (inside catch())
hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "data": {"foo": "bar"}, ... }
hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' }, headers: { Bar: 'baz' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "headers" = { "Bar": "baz", ... }, ... }
let formData = new FormData(); formData.append('foo', 'bar'); hlp.post('https://httpbin.org/anything', { data: formData }) // this also works with FormData

// on resize vertically/horizontally
window.addEventListener('resize', () => {}) // inaccurate, triggers too often (especially when scrolling on android/iphone)
hlp.onResizeHorizontal(() => {}) // only triggers when viewport width changes; also triggers on first run
hlp.onResizeVertical(() => {}) // only triggers when viewport height changes; also triggers on first run

// add event listener once
hlp.addEventListenerOnce(
    document.getElementById('foo'),
    'click',
    (event) => { alert('this gets called only once'); }
);
hlp.addEventListenerOnce(
    document.getElementById('foo'),
    'click',
    (event) => { if(1==1) { return false; } } // if you return false, the event listener is not removed
);

// simple animations (via css transitions)
hlp.animate(
    document.getElementById('.single'),
    'transform: translateX(0)',
    'transform: translateX(-100%)',
    'ease-in-out',
    1000
).then(() => { console.log('done'); });
hlp.animate(
    document.querySelectorAll('.multiple'),
    'opacity: 1; pointer-events:auto',
    'opacity: 0; pointer-events:none',
    'linear',
    5000
).then(() => { console.log('done'); });

php implementation

there is also a php implemenation stringhelper with similiar functions available.

appendix

existence matrix

hlp.x()hlp.true()hlp.false()!== null!= null!== false!= false=== true== truetypeof !== 'undefined'!= undefined!== undefinedif/elseternarylength > 0!= ''!== ''
undefinedfalsetruefalsetruefalsetruetruefalsefalsefalsefalsefalsefalsefalseerrortruetrue
nullfalsefalsefalsefalsefalsetruetruefalsefalsetruefalsetruefalsefalseerrortruetrue
falsefalsefalsetruetruetruefalsefalsefalsefalsetruetruetruefalsefalsefalsefalsetrue
truetruetruefalsetruetruetruetruetruetruetruetruetruetruetruefalsetruetrue
[]falsefalsefalsetruetruetruefalsefalsefalsetruetruetruetruetruefalsefalsetrue
''falsefalsefalsetruetruetruefalsefalsefalsetruetruetruetruetruetruefalsetrue
0truefalsetruetruetruetruefalsefalsefalsetruetruetruefalsefalsefalsefalsetrue
1truetruefalsetruetruetruetruefalsetruetruetruetruetruetruefalsetruetrue
-1truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruefalsetruetrue
'0'truefalsetruetruetruetruefalsefalsefalsetruetruetruetruetruetruetruetrue
'1'truetruefalsetruetruetruetruefalsetruetruetruetruetruetruetruetruetrue
'-1'truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
''falsefalsefalsetruetruetruefalsefalsefalsetruetruetruefalsefalsefalsefalsefalse
' 'falsefalsefalsetruetruetruefalsefalsefalsetruetruetruetruetruetruetruetrue
'null'truefalsefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
'false'truefalsetruetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
'true'truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
'str'truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
0,1truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue
0truetruefalsetruetruetruefalsefalsefalsetruetruetruetruetruetruetruetrue
{}falsefalsefalsetruetruetruetruefalsefalsetruetruetruetruetruefalsetruetrue
un.known.propertyerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorfalsefalseerrorerrorerrorerrorerror
(()=>un.known.property)truetruefalsetruetruetruetruefalsefalsetruetruetruetruetruetruetruetrue

loose comparison matrix

==undefinednullfalsetrue[]''01-1'0''1''-1'''' ''null''false''true''str'0,10{}un.known.property(()=>un.known.property)
undefinedtruetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
nulltruetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
falsefalsefalsetruefalsetruetruetruefalsefalsetruefalsefalsetruetruefalsefalsefalsefalsefalsetruefalseerrorfalse
truefalsefalsefalsetruefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
[]falsefalsetruefalsetruefalsetruefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
''falsefalsetruefalsefalsetruetruefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
0falsefalsetruefalsetruetruetruefalsefalsetruefalsefalsetruetruefalsefalsefalsefalsefalsetruefalseerrorfalse
1falsefalsefalsetruefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
-1falsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
'0'falsefalsetruefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalseerrorfalse
'1'falsefalsefalsetruefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
'-1'falsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
''falsefalsetruefalsetruetruetruefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalseerrorfalse
' 'falsefalsetruefalsefalsefalsetruefalsefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalsefalsefalseerrorfalse
'null'falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalsefalseerrorfalse
'false'falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsefalsefalsefalseerrorfalse
'true'falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsefalsefalseerrorfalse
'str'falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalsefalsefalseerrorfalse
0,1falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalsefalseerrorfalse
0falsefalsetruefalsefalsefalsetruefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsetruefalseerrorfalse
{}falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetrueerrorfalse
un.known.propertyerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerrorerror
(()=>un.known.property)falsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalseerrortrue
3.3.9

6 months ago

3.3.8

6 months ago

3.3.7

6 months ago

3.3.6

6 months ago

3.4.0

6 months ago

3.4.3

6 months ago

3.4.2

6 months ago

3.4.1

6 months ago

3.3.5

6 months ago

3.3.4

8 months ago

3.3.3

8 months ago

3.3.2

8 months ago

3.3.1

1 year ago

3.3.0

1 year ago

3.2.8

2 years ago

3.2.7

2 years ago

3.2.6

2 years ago

3.2.5

2 years ago

3.2.2

2 years ago

3.2.4

2 years ago

3.2.3

2 years ago

3.2.1

2 years ago

3.2.0

2 years ago

3.1.3

2 years ago

3.1.7

2 years ago

3.1.4

2 years ago

3.1.9

2 years ago

3.1.8

2 years ago

3.1.2

2 years ago

3.1.1

3 years ago

3.1.0

3 years ago

3.0.8

3 years ago

3.0.7

3 years ago

3.0.6

3 years ago

3.0.5

3 years ago

3.0.9

3 years ago

3.0.4

3 years ago

3.0.3

3 years ago

3.0.2

3 years ago

2.9.4

3 years ago

2.9.6

3 years ago

2.9.5

3 years ago

2.9.7

3 years ago

3.0.1

3 years ago

2.9.2

3 years ago

2.9.1

3 years ago

2.9.3

3 years ago

2.9.0

3 years ago

2.8.7

3 years ago

2.8.9

3 years ago

2.8.8

3 years ago

2.8.3

3 years ago

2.8.5

3 years ago

2.8.4

3 years ago

2.8.6

3 years ago

2.8.1

3 years ago

2.8.2

3 years ago

2.8.0

3 years ago

2.7.9

3 years ago

2.7.8

3 years ago

2.7.6

3 years ago

2.7.7

3 years ago

2.7.5

3 years ago

2.7.4

3 years ago

2.7.3

4 years ago

2.7.2

4 years ago

2.7.1

4 years ago

2.7.0

4 years ago

2.6.9

4 years ago

2.6.7

4 years ago

2.6.8

4 years ago

2.6.6

4 years ago

2.6.5

4 years ago

2.6.4

4 years ago

2.6.3

4 years ago

2.6.2

4 years ago

2.6.1

4 years ago

2.6.0

4 years ago

2.5.9

4 years ago

2.5.8

4 years ago

2.5.7

4 years ago

2.5.6

4 years ago

2.5.5

4 years ago

2.5.4

4 years ago

2.5.3

4 years ago

2.5.2

4 years ago

2.5.1

5 years ago

2.5.0

5 years ago

2.4.9

5 years ago

2.4.8

5 years ago

2.4.7

5 years ago

2.4.6

5 years ago

2.4.5

5 years ago

2.4.4

5 years ago

2.4.3

5 years ago

2.4.2

5 years ago

2.4.1

5 years ago

2.4.0

5 years ago

2.3.9

5 years ago

2.3.8

5 years ago

2.3.7

5 years ago

2.3.4

5 years ago

2.3.3

5 years ago

2.3.2

5 years ago

2.3.0

6 years ago

2.2.9

6 years ago

2.2.8

6 years ago

2.2.7

6 years ago

2.2.6

6 years ago

2.2.5

6 years ago

2.2.4

6 years ago

2.2.3

6 years ago

2.2.2

6 years ago

2.2.0

6 years ago

2.1.9

6 years ago

2.1.8

6 years ago

2.1.7

6 years ago

2.1.6

6 years ago

2.1.5

6 years ago

2.1.4

6 years ago

2.1.3

6 years ago

2.1.2

6 years ago

2.1.1

6 years ago

2.1.0

6 years ago

2.0.9

6 years ago

2.0.8

6 years ago

2.0.7

6 years ago

2.0.6

6 years ago

2.0.5

6 years ago

2.0.4

6 years ago

2.0.3

6 years ago

2.0.2

6 years ago

2.0.1

6 years ago

2.0.0

6 years ago

1.9.9

6 years ago

1.9.8

6 years ago

1.9.7

6 years ago

1.9.6

6 years ago

1.9.5

6 years ago

1.9.4

6 years ago

1.9.3

6 years ago

1.9.2

6 years ago

1.9.1

6 years ago

1.9.0

6 years ago

1.8.9

6 years ago

1.8.8

6 years ago

1.8.7

6 years ago

1.8.6

6 years ago

1.8.5

6 years ago

1.8.4

6 years ago

1.8.3

6 years ago

1.8.2

6 years ago

1.8.1

6 years ago

1.8.0

6 years ago

1.7.9

6 years ago

1.7.8

6 years ago

1.7.7

6 years ago

1.7.6

6 years ago

1.7.5

6 years ago

1.7.4

6 years ago

1.7.3

6 years ago

1.7.1

6 years ago

1.7.0

6 years ago

1.6.9

6 years ago

1.6.8

6 years ago

1.6.7

6 years ago

1.6.6

6 years ago

1.6.5

6 years ago

1.6.4

6 years ago

1.6.3

6 years ago

1.6.2

6 years ago

1.6.1

6 years ago

1.6.0

6 years ago

1.5.9

6 years ago

1.5.8

6 years ago

1.5.7

6 years ago

1.5.6

6 years ago

1.5.5

6 years ago

1.5.4

6 years ago

1.5.3

6 years ago

1.5.2

6 years ago

1.5.1

6 years ago

1.5.0

6 years ago

1.4.9

6 years ago

1.4.8

6 years ago

1.4.7

6 years ago

1.4.6

6 years ago

1.4.4

6 years ago

1.4.3

6 years ago

1.4.2

6 years ago

1.4.1

6 years ago

1.4.0

6 years ago

1.3.9

6 years ago

1.3.8

6 years ago

1.3.7

6 years ago

1.3.6

6 years ago

1.3.5

6 years ago

1.3.4

6 years ago

1.3.3

6 years ago

1.3.2

6 years ago

1.3.1

6 years ago

1.3.0

6 years ago

1.2.9

6 years ago

1.2.8

6 years ago

1.2.7

6 years ago

1.2.6

6 years ago

1.2.5

6 years ago

1.2.4

6 years ago

1.2.3

6 years ago

1.2.2

6 years ago

1.2.1

6 years ago

1.2.0

6 years ago

1.1.9

6 years ago

1.1.8

6 years ago

1.1.7

6 years ago

1.1.6

6 years ago

1.1.5

6 years ago

1.1.4

6 years ago

1.1.3

6 years ago

1.1.2

6 years ago

1.1.1

6 years ago

1.1.0

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.1

6 years ago