hlp 3.7.6 → 3.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +754 -748
  3. package/package.json +5 -2
package/README.md CHANGED
@@ -1,748 +1,754 @@
1
- [![build status](https://github.com/vielhuber/hlp/actions/workflows/ci.yml/badge.svg)](https://github.com/vielhuber/hlp/actions)
2
-
3
- # ⛏️ hlp ⛏️
4
-
5
- ## motivation
6
-
7
- this is a lightweight javascript utility library that provides essential helpers for everyday coding tasks. it offers intuitive methods for variable existence checks, type validation, string manipulation, date operations, and more. designed with simplicity in mind, `hlp` eliminates boilerplate code and makes common programming patterns more concise and readable, allowing developers to focus on building features rather than writing repetitive utility code.
8
-
9
- ## installation
10
-
11
- ```
12
- npm init -y
13
- npm install hlp
14
- ```
15
-
16
- now use it as a module:
17
- ```js
18
- import hlp from 'hlp';
19
- ```
20
-
21
- or embed it directly:
22
- ```html
23
- <script src="hlp.js"></script>
24
- ```
25
-
26
- ## usage
27
-
28
- ```js
29
- // check existence
30
- if( hlp.x(vrbl) ) { }
31
-
32
- // check non-existence
33
- if( hlp.nx(vrbl) ) {}
34
-
35
- // get variable if exists, otherwise ''
36
- hlp.v( vrbl )
37
-
38
- // get variable if exists, otherwise 'default'
39
- hlp.v( vrbl, 'default' )
40
-
41
- // get first variable that exists, otherwise ''
42
- hlp.v( vrbl1, vrbl2, vrbl3 )
43
-
44
- // truthness
45
- if( hlp.true(vrbl) ) {}
46
- if( hlp.false(vrbl) ) {}
47
-
48
- // be aware, that hlp.true is not always the logic negation of hlp.false
49
- hlp.true(null) // false
50
- hlp.false(null) // false
51
-
52
- // loop over arrays/objects only if possible
53
- hlp.loop(['foo','bar','baz'], (vrbl__value) => {});
54
- hlp.loop(['foo','bar','baz'], (vrbl__value, vrbl__key) => {});
55
- hlp.loop({bar: 'foo', baz: 'bar', foo: 'baz'}, (vrbl__value, vrbl__key) => {});
56
- hlp.loop([], (vrbl__value, vrbl__key) => { }) // does nothing
57
- hlp.loop({}, (vrbl__value, vrbl__key) => { }) // does nothing
58
- hlp.loop(null, (vrbl__value, vrbl__key) => { }) // does nothing
59
-
60
- // if you are unsure, if a variable is even set before checking its existence,
61
- // simply put it inside this helper function
62
- // that works because javascript only evaluates the content
63
- // of the inner callback (or closure) when it is actually executed.
64
- if( hlp.x(() => vrbl) )
65
- if( hlp.nx(() => vrbl) )
66
- if( hlp.true(() => vrbl) )
67
- if( hlp.false(() => vrbl) )
68
- if( hlp.v(() => vrbl) === 'foo' )
69
- if( hlp.v(() => vrbl) == 1337 )
70
- hlp.v(() => vrbl)
71
- hlp.loop((() => vrbl), (vrbl__value, vrbl__key) => { })
72
-
73
- // capitalize
74
- hlp.capitalize('foo') // Foo
75
-
76
- // check if object
77
- hlp.isObject({}) // true
78
- hlp.isObject({foo: 'bar'}) // true
79
- hlp.isObject(null) // false
80
- hlp.isObject([]) // false (be aware: an array in js is scrictly an object, but this function returns false)
81
-
82
- // check if array
83
- hlp.isArray([]) // true
84
- hlp.isArray(['foo','bar']) // true
85
- hlp.isArray(null) // false
86
-
87
- // check if string
88
- hlp.isString('foo'); // true
89
- hlp.isString(42); // false
90
- hlp.isString(null); // false
91
-
92
- // check if date
93
- hlp.isDate('2018-01-01') // true
94
- hlp.isDate('2018-02-29') // false
95
- hlp.isDate('1700-01-01') // true
96
- hlp.isDate(42) // false
97
-
98
- // format date
99
- hlp.formatDate('d.m.Y', '2018-01-01') // 01.01.2018
100
- hlp.formatDate('Y-m-d H:i:s', new Date()) // 01.01.2018
101
-
102
- // get week number from date
103
- hlp.dateToWeek(new Date('2021-02-22')) // 8
104
- hlp.dateToWeek() // hlp.dateToWeek(new Date())
105
-
106
- // get date (of monday) from week number
107
- hlp.weekToDate(42, 2018) // new Date('2018-10-14')
108
- hlp.weekToDate(17, 2023) // new Date('2023-04-23')
109
-
110
- // add days to date
111
- hlp.addDays(new Date('2018-01-01'), 7) // new Date('2018-01-08')
112
- hlp.addDays(new Date('2018-02-22'), 658) // new Date('2019-12-12')
113
- hlp.addDays(new Date('2018-02-22'), 1) // new Date('2018-02-21')
114
-
115
- // diff in months of two dates
116
- hlp.diffInMonths(new Date('2025-02-01'), new Date('2025-03-18')) // 1.548...
117
-
118
- // compare dates
119
- let d1 = new Date();
120
- let d2 = new Date();
121
- hlp.compareDates(d1, d2) // 0
122
- hlp.addDays(d1, -1);
123
- hlp.compareDates(d1, d2) // -1
124
- hlp.addDays(d1, 2);
125
- hlp.compareDates(d1, d2) // 1
126
- hlp.compareDates('2020-01-01', '2020-01-17 17:42:19') // -1
127
-
128
- // format number
129
- hlp.formatNumber(1337.427, 2, ',','.') // 1.337,43
130
-
131
- // spaceship operator
132
- hlp.spaceship(5,7) // -1
133
- hlp.spaceship(9,7) // 1
134
- hlp.spaceship(7,7) // 0
135
- hlp.spaceship('foo','bar') // 1
136
- hlp.spaceship('bar','foo') // -1
137
-
138
- // check if objects are equal
139
- hlp.objectsAreEqual({}, {}) // true
140
- hlp.objectsAreEqual({ foo: 'bar' }, { foo: 'bar'}) // true
141
- hlp.objectsAreEqual({ foo: 'bar' }, { bar: 'baz'}) // false
142
-
143
- // check if object is inside an array/object
144
- hlp.containsObject({ foo: 'bar' }, []) // false
145
- hlp.containsObject({ foo: 'bar' }, [{ foo: 'bar' }, { bar: 'baz' }]) // true
146
- hlp.containsObject({ foo: 'bar' }, { foo: { foo: 'bar' } }) // true
147
-
148
- // recursively search key/value in nested object and return dotprop array
149
- hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id'); // ['foo', 'bar.foo']
150
- hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id', 42); // ['foo']
151
- hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, null, 7); // ['bar.foo', 'baz']
152
-
153
- // deep clone reference types (object/array/date/regex)
154
- hlp.deepCopy({ foo: 'bar' })
155
- hlp.deepCopy(['foo','bar'])
156
- hlp.deepCopy(new Date())
157
- hlp.deepCopy(new Date('2018-01-01'))
158
- hlp.deepCopy(new RegExp('ab+c', 'i'))
159
-
160
- // generate uuid/guid v4
161
- hlp.uuid() // e86e393c-9788-857b-27c2-f80c8ca1a302
162
- hlp.uuid() // 8b25a8f8-9525-bd73-4679-3539321db93b
163
-
164
- // replace all occurences
165
- hlp.replaceAll('foo bar baz', 'a', 'b') // 'foo bbr bbz'
166
-
167
- // replace last occurence
168
- hlp.replaceLast('foo bar baz', 'a', 'b') // 'foo bar bbz'
169
-
170
- // replace last occurence
171
- hlp.replaceFirst('foo bar baz', 'a', 'b') // 'foo bbr baz'
172
-
173
- // case insensitive search
174
- hlp.indexOfCaseInsensitive('foo', 'this is a FOO') // 10
175
- hlp.indexOfCaseInsensitive('foo', 'this is a FOO and a foobar', 15) // 20
176
-
177
- // count occurences in string
178
- hlp.countAllOccurences('foo', 'this is a foo and a foobar') // 2
179
- hlp.countAllOccurencesCaseInsensitive('FoO', 'this is a FOO and a foobar') // 2
180
-
181
- // find all positions in string
182
- hlp.findAllPositions('foo', 'this is a foo and a foobar') // [10,20]
183
- hlp.findAllPositionsCaseInsensitive('FoO', 'this is a FOO and a foobar') // [10,20]
184
-
185
- // highlight strings
186
- hlp.highlight('that is a search string', 'is') // that <strong class="highlight">is</strong> a search string
187
- 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 ...'
188
-
189
- // remove empty elements from array
190
- hlp.removeEmpty(['foo',null,[],'','bar']) // ['foo','bar']
191
-
192
- // return unique array (remove duplicate values, order-safe)
193
- hlp.uniqueArray(['foo','bar','foo','baz']) // ['foo','bar','baz']
194
-
195
- // powerset of array (all subsets of a set)
196
- hlp.powerset([1,2,3]) // [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
197
-
198
- // shuffle array
199
- hlp.shuffle(['foo','bar']) // ['foo','bar']
200
- hlp.shuffle(['foo','bar']) // ['foo','bar']
201
- hlp.shuffle(['foo','bar']) // ['foo','bar'] (yikes)
202
- hlp.shuffle(['foo','bar']) // ['bar','foo']
203
-
204
- // char helpers
205
- hlp.charToInt('D') // 4
206
- hlp.intToChar(4) // 'D'
207
- hlp.incChar('D') // 'E'
208
- hlp.incChar('Z') // 'AA'
209
- hlp.incChar('A',2) // 'C'
210
- hlp.decChar('U') // 'T'
211
-
212
- // slugify / sanitize string
213
- hlp.slugify('That röcks!') // that-roecks
214
-
215
- // range
216
- hlp.range('A','Z') // ['A','B',...,'Z']
217
- hlp.range(1,42) // [1,2,...,42]
218
- hlp.range('C','A') // ['C','B','A']
219
-
220
- // get last item of object/array
221
- hlp.last(['foo', 'bar', 'baz']) // 'baz'
222
- hlp.last({ foo: 'bar', bar: 'baz'}) // 'baz'
223
-
224
- // get first item of object/array
225
- hlp.first(['foo', 'bar', 'baz']) // 'foo'
226
- hlp.first({ foo: 'bar', bar: 'baz'}) // 'bar'
227
-
228
- // get random element from object/array
229
- hlp.rand(['foo', 'bar', 'baz']) // 'bar'
230
-
231
- // generate a random string
232
- hlp.random_string() // edPhi34d
233
- hlp.random_string(10) // abCa321aC6
234
- hlp.random_string(16, 'idkfa') // idifafafifaifafk
235
-
236
- // generate a random integer
237
- hlp.random_int() // 42
238
- hlp.random_int(7,42) // 17
239
-
240
- // generate password
241
- hlp.password_generate(
242
- 20, // length
243
- ['a-z', 'A-Z', '0-9', '$!?'], // password contains at minimum one character of each value
244
- 'lI' // exclude confusing chars
245
- )
246
-
247
- // proper rounding to n digits
248
- hlp.round(1.005, 2) // 1.01
249
- hlp.round(1.005) // 1
250
-
251
- // check if variable is integer
252
- hlp.isInteger('foo') // false
253
- hlp.isInteger(42) // true
254
- hlp.isInteger('42') // true
255
- hlp.isInteger(4e2) // true
256
- hlp.isInteger('4e2') // true
257
- hlp.isInteger(' 1 ') // true
258
- hlp.isInteger('') // false
259
- hlp.isInteger(' ') // false
260
- hlp.isInteger(42.1) // false
261
- hlp.isInteger('1a') // false
262
- hlp.isInteger('4e2a') // false
263
- hlp.isInteger(null) // false
264
- hlp.isInteger(undefined) // false
265
- hlp.isInteger(NaN) // false
266
-
267
- // check if variable is numeric
268
- hlp.isNumeric(1337) // true
269
- hlp.isNumeric('42') // true
270
- hlp.isNumeric('42.7') // true
271
- hlp.isNumeric('a') // false
272
-
273
- // serialize/unserialize
274
- hlp.serialize({ foo: 'bar' }); // 'a:1:{s:3:"foo";s:3:"bar";}'
275
- hlp.unserialize('a:1:{s:3:"foo";s:3:"bar";}'); // {foo:'bar'}
276
-
277
- // json parsing
278
- hlp.jsonStringToObject('["foo","bar","baz"]') // ['foo','bar','baz']
279
- hlp.jsonStringToObject('["foo","bar","baz",]') // null
280
- hlp.jsonObjectToString(['foo','bar','baz']) // '["foo","bar","baz"]'
281
- hlp.isJsonString('["foo","bar","baz",]') // false
282
- hlp.isJsonString('["foo","bar","baz"]') // true
283
-
284
- // map for objects
285
- hlp.map({ foo: 'bar', bar: 'baz' }, (obj__key, obj__value) => obj__value += '!'); // { foo: 'bar!', bar: 'baz!' }
286
-
287
- // fun with blobs
288
- hlp.stringtoblob(string)
289
- hlp.stringtoblob(string, 'image/png')
290
- hlp.blobtostring(blob).then((string) => { })
291
- hlp.blobtobase64(blob).then((base64) => { })
292
- hlp.base64toblob(base64)
293
- hlp.base64toblob(base64, 'image/png')
294
- hlp.filetobase64(file).then((base64) => { })
295
- hlp.blobtofile(blob)
296
- hlp.blobtofile(blob, 'filename.png')
297
- hlp.filetoblob(file)
298
- hlp.base64tofile(base64)
299
- hlp.base64tofile(base64, 'image/png')
300
- hlp.base64tofile(base64, 'image/png', 'filename.png')
301
- hlp.base64tostring(base64)
302
- hlp.stringtobase64(string)
303
- hlp.blobtourl(blob)
304
- hlp.stringtourl(string)
305
- hlp.base64tourl(base64)
306
- hlp.filetourl(file)
307
-
308
- // fix exif image orientation
309
- hlp.fixImageOrientation(base64).then((base64) => { });
310
- hlp.getImageOrientation(base64).then((orientation) => { });
311
-
312
- // html entity encode/decode
313
- hlp.htmlEncode('&<>"`\'') // &amp;&lt;&gt;&quot;&#96;&#x27;
314
- hlp.htmlDecode('&amp;&lt;&gt;&quot;&#96;&#x27;') // &<>"`'
315
-
316
- // line break conversion
317
- hlp.nl2br('foo\nbar') // foo<br/>bar
318
- hlp.br2nl('foo<br/>bar') // foo\nbar
319
-
320
- // floating point math made easy
321
- hlp.fmath('*', 0.1, 0.2) // 0.02
322
- hlp.fmath('+', 0.1, 0.2) // 0.3
323
- hlp.fmath('-', 0.1, 0.2) // -0.1
324
- hlp.fmath('/', 0.2, 0.1) // 2
325
- hlp.fmath('/', 0.39, 100, 12) // 0.0039 (precision of 12)
326
-
327
- // trim helpers
328
- hlp.trim(' foo ') // 'foo'
329
- hlp.trim('xxfoox', 'x') // 'foo'
330
- hlp.ltrim(' foo ') // 'foo '
331
- hlp.ltrim('xxfoox', 'x') // 'foox'
332
- hlp.rtrim(' foo ') // ' foo'
333
- hlp.rtrim('xxfoox', 'x') // 'xxfoo'
334
-
335
- // truncate long strings
336
- hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20); // Lorem ipsum dolor ...
337
- hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20, ''); // Lorem ipsum dolor …
338
-
339
- // fun with emojis
340
- let str = 'This❤️😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.';
341
- str.match(hlp.emojiRegex()) // ['❤️', '😀', '👩‍⚖️', '🧗‍♀️', '👩🏼‍❤️‍💋‍👩🏽']
342
- str.replaceAll(hlp.emojiRegex(), '') // This is a text full of emojis.
343
- str.replace(hlp.emojiRegex(false), '') // This😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.
344
- hlp.emojiRegex().test(str) // true
345
- hlp.emojiSplit(str) // ['T','h','i','s','❤️','😀','👩‍⚖️',' ','i','s',' ','a',' ','t','e','x','t',' ','f','u','l','l',' ','o','f',' ','🧗‍♀️','e','m','o','j','i','s','👩🏼‍❤️‍💋‍👩🏽','.']
346
-
347
- // create lexicographically ordered string ids like in firebase
348
- hlp.pushId() // -LDiDooGs9PyGHmghk5i
349
- hlp.pushId() // -LDiDooGs9PyGHmghk5j
350
-
351
- // access object properties with dotprop notation
352
- // today it is better to use optional chaining in combination with nullish coalescing ({}?.c?.a?.a??'default')
353
- hlp.getProp({
354
- a: 1,
355
- b: { a: 3, b: 3 },
356
- c: { a: { a: 7 } }
357
- }, 'c.a.a') // 7
358
- ```
359
-
360
- ### frontend
361
-
362
- ```js
363
- // cookies
364
- hlp.cookieSet('foo', 'bar', 7)
365
- hlp.cookieSet('foo', 'bar', 7, false) // only for current domain (no subdomains)
366
- hlp.cookieGet('foo') // bar
367
- hlp.cookieDelete('foo')
368
- hlp.cookieDelete('foo', false) // only for current domain (no subdomains)
369
- hlp.cookieExists('foo') // true|false
370
-
371
- // localstorage (with expiration time and object support)
372
- hlp.localStorageSet('foo', {some: 'data'}, 7)
373
- hlp.localStorageGet('foo') // {'some': 'data'}
374
- hlp.localStorageDelete('foo')
375
- hlp.localStorageExists('foo') // true|false
376
-
377
- // get parameter (example url: https://tld.com/?foo=bar&bar=baz)
378
- hlp.getParam('foo') // foo
379
- hlp.getParam('bar') // baz
380
- hlp.getParam('baz') // null
381
-
382
- // device detection helpers
383
- hlp.getDevice() // ['phone','tablet','desktop']
384
- hlp.isPhone()
385
- hlp.isTablet()
386
- hlp.isDesktop()
387
- hlp.isMobile()
388
- hlp.isTouch()
389
-
390
- // os detection helpers
391
- hlp.getOs() // ['windows','mac','linux','unknown']
392
- hlp.isWindows()
393
- hlp.isMac()
394
- hlp.isLinux()
395
-
396
- // browser detection helpers
397
- hlp.getBrowser() // ['ie','edge','firefox','chrome','safari','opera','unknown']
398
- hlp.isPageSpeed()
399
-
400
- // smooth scroll to position / element
401
- hlp.scrollTo( 0, 1000 ).then(() => { console.log('done'); });
402
- hlp.scrollTo( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
403
- hlp.scrollTo( 0, 1000, document.querySelector('.bar') ).then(() => { console.log('done'); }); // scoll inside .bar
404
- hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200 ).then(() => { console.log('done'); }); // apply offset
405
- 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!)
406
- hlp.scrollTo( document.querySelector('.foo'), 1000, null, [document.querySelector('.header'), -200] ).then(() => { console.log('done'); }); // you can also provide multiple values (of different type)
407
- hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200, true ).then(() => { console.log('done'); }); // only scroll up (never down)
408
-
409
- // get top/left scroll position
410
- hlp.scrollTop()
411
- hlp.scrollLeft()
412
-
413
- // get closest vertical scrollable element (including oneself)
414
- hlp.closestScrollable( document.querySelector('.foo') )
415
-
416
- // get offset of element (excluding margin)
417
- hlp.offsetTop( document.querySelector('.foo') )
418
- hlp.offsetLeft( document.querySelector('.foo') )
419
- hlp.offsetRight( document.querySelector('.foo') )
420
- hlp.offsetBottom( document.querySelector('.foo') )
421
-
422
- // get offset of element (including margin)
423
- hlp.offsetTopWithMargin( document.querySelector('.foo') )
424
- hlp.offsetLeftWithMargin( document.querySelector('.foo') )
425
- hlp.offsetRightWithMargin( document.querySelector('.foo') )
426
- hlp.offsetBottomWithMargin( document.querySelector('.foo') )
427
-
428
- // get document size
429
- hlp.documentWidth()
430
- hlp.documentHeight()
431
-
432
- // get window size
433
- hlp.windowWidth()
434
- hlp.windowHeight()
435
- hlp.windowWidthWithoutScrollbar()
436
- hlp.windowHeightWithoutScrollbar()
437
-
438
- // get width with margin
439
- hlp.outerWidthWithMargin( document.querySelector('.foo') )
440
- hlp.outerHeightWithMargin( document.querySelector('.foo') )
441
-
442
- // get cursor position (without mouse events)
443
- hlp.cursorPosition().then(pos => { console.log(pos); /* pos: { x: ..., y: ... } */ });
444
-
445
- // polyfills for ie11
446
- hlp.closest( document.querySelector('.children'), '.parent' )
447
- hlp.matches( document.querySelector('.parent'), '.parent' ) // true
448
- hlp.remove( document.querySelector('.foo') ) // also works if .foo does not exist
449
-
450
- // dom traversal
451
- hlp.prevAll( document.querySelector('.foo') )
452
- hlp.prevAll( document.querySelector('.foo'), '.bar' )
453
- hlp.nextAll( document.querySelector('.foo') )
454
- hlp.nextAll( document.querySelector('.foo'), '.bar' )
455
- hlp.siblings( document.querySelector('.foo') )
456
- hlp.siblings( document.querySelector('.foo'), '.bar' )
457
- hlp.parents( document.querySelector('.foo') )
458
- hlp.parents( document.querySelector('.foo'), '.bar' )
459
- hlp.prevUntil( document.querySelector('.foo'), '.bar' ) // prev until selector not including
460
- hlp.nextUntil( document.querySelector('.foo'), '.bar' ) // next until selector not including
461
- hlp.prev( document.querySelector('.foo') )
462
- hlp.prev( document.querySelector('.foo'), '.bar' )
463
- hlp.next( document.querySelector('.foo') )
464
- hlp.next( document.querySelector('.foo'), '.bar' )
465
- hlp.querySelectorAllShadowDom('.foo') // finds all elements with that selector (also in nested shadowdom elements)
466
-
467
- // wrap element
468
- hlp.wrap( document.querySelector('.foo'), '<div class="wrapper"></div>' )
469
-
470
- // wrap all text nodes with new node
471
- hlp.wrapTextNodes( document.querySelector('.foo'), 'p' )
472
-
473
- // html string to dom (also supports ie11 and td nodes that cannot be root nodes)
474
- hlp.html2dom('<p>foo</p>')
475
- hlp.html2dom('<td>bar</td>')
476
-
477
- // get all styles of a dom element (extracted from both inline styling and external styling through stylesheets)
478
- hlp.css( document.querySelector('.foo') )
479
-
480
- // visually focus element on page
481
- hlp.focus('.foo')
482
- hlp.focus(document.querySelector('.foo'))
483
- hlp.unfocus()
484
-
485
- // on delegate
486
- hlp.on('click', '.selector', (e, el) => { });
487
- hlp.on('click', '.selector', '.scope', (e, el) => { });
488
-
489
- // classic debounce
490
- window.addEventListener('resize', hlp.debounce(() => { console.log('debounce at resize') }, 1000));
491
- document.querySelector('.container').addEventListener('input', hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000));
492
- let debounce = hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000); // conditional debounce
493
- document.querySelector('.container').addEventListener('input', e => { debounce(e); });
494
-
495
- // classic throttle
496
- window.addEventListener('resize', hlp.throttle(() => { console.log('throttle at resize') }, 1000));
497
- document.querySelector('.container').addEventListener('input', hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000));
498
- let throttle = hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000); // conditional throttle
499
- document.querySelector('.container').addEventListener('input', e => { throttle(e); });
500
-
501
- // get current url
502
- hlp.url() // https://github.com/vielhuber/hlp
503
- hlp.urlWithHash() // https://github.com/vielhuber/hlp#foo
504
- hlp.fullUrl() // https://github.com/vielhuber/hlp?foo=bar#foo
505
- hlp.urlWithArgs() // https://github.com/vielhuber/hlp?foo=bar
506
- hlp.baseUrl() // https://github.com
507
- hlp.urlHost(); // github.com
508
- hlp.urlHostTopLevel(); // github.com
509
- hlp.urlPath(); // /vielhuber/hlp
510
- hlp.urlHash(); // #foo
511
- hlp.urlArgs(); // ?foo=bar
512
-
513
- // get url of current running script
514
- hlp.urlOfScript(); // https://tld.com/wp-content/themes/dummy/script.js
515
- hlp.pathOfScript(); // https://tld.com/wp-content/themes/dummy
516
-
517
- // set 100vh for a dom element (respecting the visibility of the address bar)
518
- hlp.real100vh('.foo') // 100vh
519
- hlp.real100vh('.foo', 60) // 60vh
520
- hlp.real100vh() // sets up a css variable which can be used with e.g. calc(100 * var(--vh, 1vh)); to mimic 100vh
521
-
522
- // 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);
523
- hlp.iOsRemoveHover();
524
-
525
- // fade in/out dom element
526
- hlp.fadeIn( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
527
- hlp.fadeOut( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
528
-
529
- // check if dom element is generally visible
530
- hlp.isVisible( document.querySelector('.foo') )
531
- // check if dom element is visible inside viewport
532
- hlp.isVisibleInViewport( document.querySelector('.foo') )
533
-
534
- // wait until a dom element has a certain css property
535
- // this is quite useful when working with async loaded stylesheets like loadCSS
536
- // .beacon is an element below the fold populated by the stylesheet
537
- hlp.waitUntil('.beacon').then(() => { });
538
- hlp.waitUntil('.beacon','position').then(() => { });
539
- hlp.waitUntil('.beacon','position','relative').then(() => { });
540
-
541
- // wait for elements (that appear also afterwards)
542
- hlp.waitUntilEach('.el', ($el) => { });
543
-
544
- // wait until a variable is set or has a specific value
545
- hlp.waitUntilVar('globalVar').then(() => { });
546
- hlp.waitUntilVar(obj, 'objectVar').then(() => { });
547
- hlp.waitUntilVar(obj, 'objectVar', true).then(() => { });
548
-
549
- // run a function for every dom element, even it is added dynamically later on
550
- hlp.runForEl('.beacon', el => { el.style.backgroundColor = 'red'; });
551
-
552
- // automatically change height of all textareas based on content
553
- hlp.textareaAutoHeight()
554
- hlp.textareaAutoHeight('.special')
555
- hlp.textareaSetHeight( document.querySelector('.special') )
556
-
557
- // load external js file in dom with promise
558
- hlp.loadJs('https://apis.google.com/js/api.js').then(() => { console.log('done'); });
559
- hlp.loadJs([
560
- 'https://www.tld.com/1.js',
561
- 'https://www.tld.com/2.js',
562
- 'https://www.tld.com/3.js'
563
- ]).then(() => { console.log('done'); });
564
- hlp.loadJsSequentially([
565
- 'https://www.tld.com/1.js',
566
- 'https://www.tld.com/2.js',
567
- 'https://www.tld.com/3.js'
568
- ]).then(() => { console.log('done'); });
569
-
570
- // run event after all images are loaded inside container
571
- // works even after dynamic changes
572
- // runs more than once (after each change)
573
- // run this outside of window load / document ready events
574
- hlp.triggerAfterAllImagesLoaded('.container', '.container__image', () => {});
575
-
576
- // proper document read/load events, that are guaranteed to be run (also if the script is embedded via async)
577
- hlp.ready().then(() => {});
578
- hlp.load().then(() => {});
579
-
580
- // easy ajax requests (without the fetch api; also works in ie11)
581
- hlp.get('https://httpbin.org/anything').then((response) => { }).catch((error) => { }) // { "method": "GET", ... }
582
- hlp.get('/relpath').then((response) => { }).catch((error) => { }) // if a full url is omitted, the call is done on the baseurl
583
- hlp.get('https://httpbin.org/anything', { throttle: 1000 }).then((response) => { }).catch((error) => { }) // same but with a throttle of 1 second
584
- hlp.get('https://httpbin.org/status/404', { allow_errors: false }).then((response) => { }) // deny 404 and other status codes as a response (inside catch())
585
- hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "data": {"foo": "bar"}, ... }
586
- hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' }, headers: { Bar: 'baz' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "headers" = { "Bar": "baz", ... }, ... }
587
- let formData = new FormData(); formData.append('foo', 'bar'); hlp.post('https://httpbin.org/anything', { data: formData }) // this also works with FormData
588
-
589
- // on resize vertically/horizontally
590
- window.addEventListener('resize', () => {}) // inaccurate, triggers too often (especially when scrolling on android/iphone)
591
- hlp.onResizeHorizontal(() => {}) // only triggers when viewport width changes; also triggers on first run
592
- hlp.onResizeVertical(() => {}) // only triggers when viewport height changes; also triggers on first run
593
-
594
- // add event listener once
595
- hlp.addEventListenerOnce(
596
- document.getElementById('foo'),
597
- 'click',
598
- (event) => { alert('this gets called only once'); }
599
- );
600
- hlp.addEventListenerOnce(
601
- document.getElementById('foo'),
602
- 'click',
603
- (event) => { if(1==1) { return false; } } // if you return false, the event listener is not removed
604
- );
605
-
606
- // simple animations (via css transitions)
607
- hlp.animate(
608
- document.getElementById('.single'),
609
- 'transform: translateX(0)',
610
- 'transform: translateX(-100%)',
611
- 'ease-in-out',
612
- 1000
613
- ).then(() => { console.log('done'); });
614
- hlp.animate(
615
- document.querySelectorAll('.multiple'),
616
- 'opacity: 1; pointer-events:auto',
617
- 'opacity: 0; pointer-events:none',
618
- 'linear',
619
- 5000
620
- ).then(() => { console.log('done'); });
621
- ```
622
-
623
- ## php implementation
624
-
625
- there is also a php implemenation [stringhelper](https://github.com/vielhuber/stringhelper) with similiar functions available.
626
-
627
- ## testing
628
-
629
- `npm run js:tests`
630
-
631
- ## recommendations
632
-
633
- ### existence
634
-
635
- ```js
636
- if (foo) {} // ⚠️ be aware of: '0'/[]/{}
637
- if (foo?.prop) {}
638
- if (foo?.someFun1()?.someFun2()?.getName()) {}
639
- ```
640
-
641
- ### truthness
642
-
643
- ```js
644
- if (foo === true) {}
645
- if (foo?.prop === true) {}
646
- if (foo?.someFun1()?.someFun2()?.getName() === true) {}
647
- ```
648
-
649
- ### comparison
650
-
651
- ```js
652
- if (foo === 'foo') {}
653
- if (foo?.prop === 'foo') {}
654
- if (foo?.someFun1()?.someFun2()?.getName() === 'foo') {}
655
- ```
656
-
657
- these recommendations ground on the fact, that js has a lot of pitfalls, when comparing loosely:
658
-
659
- ```js
660
- if( '' == [] ) // true
661
- if( '' == [''] ) // true
662
- if( '' == 0 ) // true
663
- if( ' ' == false ) // true
664
- if( [0] == false ) // true
665
- if( [0] == '0' ) // true
666
- if( [] == false ) // true
667
- if( [''] == false ) // true
668
- if( 0 == false ) // true
669
- if( 0 == [] ) // true
670
- if( 0 == [''] ) // true
671
- if( [0] == false ) // true
672
- if( [0] == 0 ) // true
673
- ```
674
-
675
- also don't forget those delicacies:
676
-
677
- ```js
678
- 0 === -0 // true
679
- NaN === NaN // false
680
- (![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] === 'fail' // true
681
- ```
682
-
683
- this non-strict equality is symmetric, but not transitive:
684
-
685
- ```js
686
- a = ''; b = 0; c = [0];
687
- a == b; // true
688
- b == c; // true
689
- c == a; // false
690
- ```
691
-
692
- ## appendix
693
-
694
- ### existence matrix
695
-
696
- | | <sub>hlp.x()</sub> | <sub>hlp.true()</sub> | <sub>hlp.false()</sub> | <sub>!== null</sub> | <sub>!= null</sub> | <sub>!== false</sub> | <sub>!= false</sub> | <sub>=== true</sub> | <sub>== true</sub> | <sub>typeof !== 'undefined'</sub> | <sub>!= undefined</sub> | <sub>!== undefined</sub> | <sub>if/else</sub> | <sub>ternary</sub> | <sub>length > 0</sub> | <sub>!= ''</sub> | <sub>!== ''</sub> |
697
- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
698
- | <sub>undefined</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> | <sub>true</sub> |
699
- | <sub>null</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> | <sub>true</sub> |
700
- | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
701
- | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
702
- | <sub>[]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
703
- | <sub>['']</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> |
704
- | <sub>0</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
705
- | <sub>1</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
706
- | <sub>-1</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
707
- | <sub>'0'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
708
- | <sub>'1'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
709
- | <sub>'-1'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
710
- | <sub>''</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> |
711
- | <sub>' '</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
712
- | <sub>'null'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
713
- | <sub>'false'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
714
- | <sub>'true'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
715
- | <sub>'str'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
716
- | <sub>[0,1]</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
717
- | <sub>[0]</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
718
- | <sub>{}</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
719
- | <sub>un.known.property</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> |
720
- | <sub>(()=>un.known.property)</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
721
-
722
- ### loose comparison matrix
723
-
724
- | <sub>==</sub> | <sub>undefined</sub> | <sub>null</sub> | <sub>false</sub> | <sub>true</sub> | <sub>[]</sub> | <sub>['']</sub> | <sub>0</sub> | <sub>1</sub> | <sub>-1</sub> | <sub>'0'</sub> | <sub>'1'</sub> | <sub>'-1'</sub> | <sub>''</sub> | <sub>' '</sub> | <sub>'null'</sub> | <sub>'false'</sub> | <sub>'true'</sub> | <sub>'str'</sub> | <sub>[0,1]</sub> | <sub>[0]</sub> | <sub>{}</sub> | <sub>un.known.property</sub> | <sub>(()=>un.known.property)</sub> |
725
- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
726
- | <sub>undefined</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
727
- | <sub>null</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
728
- | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
729
- | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
730
- | <sub>[]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
731
- | <sub>['']</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
732
- | <sub>0</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
733
- | <sub>1</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
734
- | <sub>-1</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
735
- | <sub>'0'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
736
- | <sub>'1'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
737
- | <sub>'-1'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
738
- | <sub>''</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
739
- | <sub>' '</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
740
- | <sub>'null'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
741
- | <sub>'false'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
742
- | <sub>'true'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
743
- | <sub>'str'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
744
- | <sub>[0,1]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
745
- | <sub>[0]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
746
- | <sub>{}</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>error</sub> | <sub>false</sub> |
747
- | <sub>un.known.property</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> |
748
- | <sub>(()=>un.known.property)</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> |
1
+ [![build status](https://github.com/vielhuber/hlp/actions/workflows/ci.yml/badge.svg)](https://github.com/vielhuber/hlp/actions)
2
+ [![GitHub Tag](https://img.shields.io/github/v/tag/vielhuber/hlp)](https://github.com/vielhuber/hlp/tags)
3
+ [![Code Style](https://img.shields.io/badge/code_style-psr--12-ff69b4.svg)](https://www.php-fig.org/psr/psr-12/)
4
+ [![License](https://img.shields.io/github/license/vielhuber/hlp)](https://github.com/vielhuber/hlp/blob/main/LICENSE.md)
5
+ [![Last Commit](https://img.shields.io/github/last-commit/vielhuber/hlp)](https://github.com/vielhuber/hlp/commits)
6
+ [![node version](https://img.shields.io/node/v/hlp)](https://www.npmjs.com/package/hlp)
7
+ [![npm Downloads](https://img.shields.io/npm/dt/hlp)](https://www.npmjs.com/package/hlp)
8
+
9
+ # ⛏️ hlp ⛏️
10
+
11
+ ## motivation
12
+
13
+ this is a lightweight javascript utility library that provides essential helpers for everyday coding tasks. it offers intuitive methods for variable existence checks, type validation, string manipulation, date operations, and more. designed with simplicity in mind, `hlp` eliminates boilerplate code and makes common programming patterns more concise and readable, allowing developers to focus on building features rather than writing repetitive utility code.
14
+
15
+ ## installation
16
+
17
+ ```
18
+ npm init -y
19
+ npm install hlp
20
+ ```
21
+
22
+ now use it as a module:
23
+ ```js
24
+ import hlp from 'hlp';
25
+ ```
26
+
27
+ or embed it directly:
28
+ ```html
29
+ <script src="hlp.js"></script>
30
+ ```
31
+
32
+ ## usage
33
+
34
+ ```js
35
+ // check existence
36
+ if( hlp.x(vrbl) ) { }
37
+
38
+ // check non-existence
39
+ if( hlp.nx(vrbl) ) {}
40
+
41
+ // get variable if exists, otherwise ''
42
+ hlp.v( vrbl )
43
+
44
+ // get variable if exists, otherwise 'default'
45
+ hlp.v( vrbl, 'default' )
46
+
47
+ // get first variable that exists, otherwise ''
48
+ hlp.v( vrbl1, vrbl2, vrbl3 )
49
+
50
+ // truthness
51
+ if( hlp.true(vrbl) ) {}
52
+ if( hlp.false(vrbl) ) {}
53
+
54
+ // be aware, that hlp.true is not always the logic negation of hlp.false
55
+ hlp.true(null) // false
56
+ hlp.false(null) // false
57
+
58
+ // loop over arrays/objects only if possible
59
+ hlp.loop(['foo','bar','baz'], (vrbl__value) => {});
60
+ hlp.loop(['foo','bar','baz'], (vrbl__value, vrbl__key) => {});
61
+ hlp.loop({bar: 'foo', baz: 'bar', foo: 'baz'}, (vrbl__value, vrbl__key) => {});
62
+ hlp.loop([], (vrbl__value, vrbl__key) => { }) // does nothing
63
+ hlp.loop({}, (vrbl__value, vrbl__key) => { }) // does nothing
64
+ hlp.loop(null, (vrbl__value, vrbl__key) => { }) // does nothing
65
+
66
+ // if you are unsure, if a variable is even set before checking its existence,
67
+ // simply put it inside this helper function
68
+ // that works because javascript only evaluates the content
69
+ // of the inner callback (or closure) when it is actually executed.
70
+ if( hlp.x(() => vrbl) )
71
+ if( hlp.nx(() => vrbl) )
72
+ if( hlp.true(() => vrbl) )
73
+ if( hlp.false(() => vrbl) )
74
+ if( hlp.v(() => vrbl) === 'foo' )
75
+ if( hlp.v(() => vrbl) == 1337 )
76
+ hlp.v(() => vrbl)
77
+ hlp.loop((() => vrbl), (vrbl__value, vrbl__key) => { })
78
+
79
+ // capitalize
80
+ hlp.capitalize('foo') // Foo
81
+
82
+ // check if object
83
+ hlp.isObject({}) // true
84
+ hlp.isObject({foo: 'bar'}) // true
85
+ hlp.isObject(null) // false
86
+ hlp.isObject([]) // false (be aware: an array in js is scrictly an object, but this function returns false)
87
+
88
+ // check if array
89
+ hlp.isArray([]) // true
90
+ hlp.isArray(['foo','bar']) // true
91
+ hlp.isArray(null) // false
92
+
93
+ // check if string
94
+ hlp.isString('foo'); // true
95
+ hlp.isString(42); // false
96
+ hlp.isString(null); // false
97
+
98
+ // check if date
99
+ hlp.isDate('2018-01-01') // true
100
+ hlp.isDate('2018-02-29') // false
101
+ hlp.isDate('1700-01-01') // true
102
+ hlp.isDate(42) // false
103
+
104
+ // format date
105
+ hlp.formatDate('d.m.Y', '2018-01-01') // 01.01.2018
106
+ hlp.formatDate('Y-m-d H:i:s', new Date()) // 01.01.2018
107
+
108
+ // get week number from date
109
+ hlp.dateToWeek(new Date('2021-02-22')) // 8
110
+ hlp.dateToWeek() // hlp.dateToWeek(new Date())
111
+
112
+ // get date (of monday) from week number
113
+ hlp.weekToDate(42, 2018) // new Date('2018-10-14')
114
+ hlp.weekToDate(17, 2023) // new Date('2023-04-23')
115
+
116
+ // add days to date
117
+ hlp.addDays(new Date('2018-01-01'), 7) // new Date('2018-01-08')
118
+ hlp.addDays(new Date('2018-02-22'), 658) // new Date('2019-12-12')
119
+ hlp.addDays(new Date('2018-02-22'), 1) // new Date('2018-02-21')
120
+
121
+ // diff in months of two dates
122
+ hlp.diffInMonths(new Date('2025-02-01'), new Date('2025-03-18')) // 1.548...
123
+
124
+ // compare dates
125
+ let d1 = new Date();
126
+ let d2 = new Date();
127
+ hlp.compareDates(d1, d2) // 0
128
+ hlp.addDays(d1, -1);
129
+ hlp.compareDates(d1, d2) // -1
130
+ hlp.addDays(d1, 2);
131
+ hlp.compareDates(d1, d2) // 1
132
+ hlp.compareDates('2020-01-01', '2020-01-17 17:42:19') // -1
133
+
134
+ // format number
135
+ hlp.formatNumber(1337.427, 2, ',','.') // 1.337,43
136
+
137
+ // spaceship operator
138
+ hlp.spaceship(5,7) // -1
139
+ hlp.spaceship(9,7) // 1
140
+ hlp.spaceship(7,7) // 0
141
+ hlp.spaceship('foo','bar') // 1
142
+ hlp.spaceship('bar','foo') // -1
143
+
144
+ // check if objects are equal
145
+ hlp.objectsAreEqual({}, {}) // true
146
+ hlp.objectsAreEqual({ foo: 'bar' }, { foo: 'bar'}) // true
147
+ hlp.objectsAreEqual({ foo: 'bar' }, { bar: 'baz'}) // false
148
+
149
+ // check if object is inside an array/object
150
+ hlp.containsObject({ foo: 'bar' }, []) // false
151
+ hlp.containsObject({ foo: 'bar' }, [{ foo: 'bar' }, { bar: 'baz' }]) // true
152
+ hlp.containsObject({ foo: 'bar' }, { foo: { foo: 'bar' } }) // true
153
+
154
+ // recursively search key/value in nested object and return dotprop array
155
+ hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id'); // ['foo', 'bar.foo']
156
+ hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, 'id', 42); // ['foo']
157
+ hlp.findRecursiveInObject({ foo: { id: 42 }, bar: { foo: { id: 7 } }, baz: { id1: 42, id2: 7 } }, null, 7); // ['bar.foo', 'baz']
158
+
159
+ // deep clone reference types (object/array/date/regex)
160
+ hlp.deepCopy({ foo: 'bar' })
161
+ hlp.deepCopy(['foo','bar'])
162
+ hlp.deepCopy(new Date())
163
+ hlp.deepCopy(new Date('2018-01-01'))
164
+ hlp.deepCopy(new RegExp('ab+c', 'i'))
165
+
166
+ // generate uuid/guid v4
167
+ hlp.uuid() // e86e393c-9788-857b-27c2-f80c8ca1a302
168
+ hlp.uuid() // 8b25a8f8-9525-bd73-4679-3539321db93b
169
+
170
+ // replace all occurences
171
+ hlp.replaceAll('foo bar baz', 'a', 'b') // 'foo bbr bbz'
172
+
173
+ // replace last occurence
174
+ hlp.replaceLast('foo bar baz', 'a', 'b') // 'foo bar bbz'
175
+
176
+ // replace last occurence
177
+ hlp.replaceFirst('foo bar baz', 'a', 'b') // 'foo bbr baz'
178
+
179
+ // case insensitive search
180
+ hlp.indexOfCaseInsensitive('foo', 'this is a FOO') // 10
181
+ hlp.indexOfCaseInsensitive('foo', 'this is a FOO and a foobar', 15) // 20
182
+
183
+ // count occurences in string
184
+ hlp.countAllOccurences('foo', 'this is a foo and a foobar') // 2
185
+ hlp.countAllOccurencesCaseInsensitive('FoO', 'this is a FOO and a foobar') // 2
186
+
187
+ // find all positions in string
188
+ hlp.findAllPositions('foo', 'this is a foo and a foobar') // [10,20]
189
+ hlp.findAllPositionsCaseInsensitive('FoO', 'this is a FOO and a foobar') // [10,20]
190
+
191
+ // highlight strings
192
+ hlp.highlight('that is a search string', 'is') // that <strong class="highlight">is</strong> a search string
193
+ 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 ...'
194
+
195
+ // remove empty elements from array
196
+ hlp.removeEmpty(['foo',null,[],'','bar']) // ['foo','bar']
197
+
198
+ // return unique array (remove duplicate values, order-safe)
199
+ hlp.uniqueArray(['foo','bar','foo','baz']) // ['foo','bar','baz']
200
+
201
+ // powerset of array (all subsets of a set)
202
+ hlp.powerset([1,2,3]) // [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
203
+
204
+ // shuffle array
205
+ hlp.shuffle(['foo','bar']) // ['foo','bar']
206
+ hlp.shuffle(['foo','bar']) // ['foo','bar']
207
+ hlp.shuffle(['foo','bar']) // ['foo','bar'] (yikes)
208
+ hlp.shuffle(['foo','bar']) // ['bar','foo']
209
+
210
+ // char helpers
211
+ hlp.charToInt('D') // 4
212
+ hlp.intToChar(4) // 'D'
213
+ hlp.incChar('D') // 'E'
214
+ hlp.incChar('Z') // 'AA'
215
+ hlp.incChar('A',2) // 'C'
216
+ hlp.decChar('U') // 'T'
217
+
218
+ // slugify / sanitize string
219
+ hlp.slugify('That röcks!') // that-roecks
220
+
221
+ // range
222
+ hlp.range('A','Z') // ['A','B',...,'Z']
223
+ hlp.range(1,42) // [1,2,...,42]
224
+ hlp.range('C','A') // ['C','B','A']
225
+
226
+ // get last item of object/array
227
+ hlp.last(['foo', 'bar', 'baz']) // 'baz'
228
+ hlp.last({ foo: 'bar', bar: 'baz'}) // 'baz'
229
+
230
+ // get first item of object/array
231
+ hlp.first(['foo', 'bar', 'baz']) // 'foo'
232
+ hlp.first({ foo: 'bar', bar: 'baz'}) // 'bar'
233
+
234
+ // get random element from object/array
235
+ hlp.rand(['foo', 'bar', 'baz']) // 'bar'
236
+
237
+ // generate a random string
238
+ hlp.random_string() // edPhi34d
239
+ hlp.random_string(10) // abCa321aC6
240
+ hlp.random_string(16, 'idkfa') // idifafafifaifafk
241
+
242
+ // generate a random integer
243
+ hlp.random_int() // 42
244
+ hlp.random_int(7,42) // 17
245
+
246
+ // generate password
247
+ hlp.password_generate(
248
+ 20, // length
249
+ ['a-z', 'A-Z', '0-9', '$!?'], // password contains at minimum one character of each value
250
+ 'lI' // exclude confusing chars
251
+ )
252
+
253
+ // proper rounding to n digits
254
+ hlp.round(1.005, 2) // 1.01
255
+ hlp.round(1.005) // 1
256
+
257
+ // check if variable is integer
258
+ hlp.isInteger('foo') // false
259
+ hlp.isInteger(42) // true
260
+ hlp.isInteger('42') // true
261
+ hlp.isInteger(4e2) // true
262
+ hlp.isInteger('4e2') // true
263
+ hlp.isInteger(' 1 ') // true
264
+ hlp.isInteger('') // false
265
+ hlp.isInteger(' ') // false
266
+ hlp.isInteger(42.1) // false
267
+ hlp.isInteger('1a') // false
268
+ hlp.isInteger('4e2a') // false
269
+ hlp.isInteger(null) // false
270
+ hlp.isInteger(undefined) // false
271
+ hlp.isInteger(NaN) // false
272
+
273
+ // check if variable is numeric
274
+ hlp.isNumeric(1337) // true
275
+ hlp.isNumeric('42') // true
276
+ hlp.isNumeric('42.7') // true
277
+ hlp.isNumeric('a') // false
278
+
279
+ // serialize/unserialize
280
+ hlp.serialize({ foo: 'bar' }); // 'a:1:{s:3:"foo";s:3:"bar";}'
281
+ hlp.unserialize('a:1:{s:3:"foo";s:3:"bar";}'); // {foo:'bar'}
282
+
283
+ // json parsing
284
+ hlp.jsonStringToObject('["foo","bar","baz"]') // ['foo','bar','baz']
285
+ hlp.jsonStringToObject('["foo","bar","baz",]') // null
286
+ hlp.jsonObjectToString(['foo','bar','baz']) // '["foo","bar","baz"]'
287
+ hlp.isJsonString('["foo","bar","baz",]') // false
288
+ hlp.isJsonString('["foo","bar","baz"]') // true
289
+
290
+ // map for objects
291
+ hlp.map({ foo: 'bar', bar: 'baz' }, (obj__key, obj__value) => obj__value += '!'); // { foo: 'bar!', bar: 'baz!' }
292
+
293
+ // fun with blobs
294
+ hlp.stringtoblob(string)
295
+ hlp.stringtoblob(string, 'image/png')
296
+ hlp.blobtostring(blob).then((string) => { })
297
+ hlp.blobtobase64(blob).then((base64) => { })
298
+ hlp.base64toblob(base64)
299
+ hlp.base64toblob(base64, 'image/png')
300
+ hlp.filetobase64(file).then((base64) => { })
301
+ hlp.blobtofile(blob)
302
+ hlp.blobtofile(blob, 'filename.png')
303
+ hlp.filetoblob(file)
304
+ hlp.base64tofile(base64)
305
+ hlp.base64tofile(base64, 'image/png')
306
+ hlp.base64tofile(base64, 'image/png', 'filename.png')
307
+ hlp.base64tostring(base64)
308
+ hlp.stringtobase64(string)
309
+ hlp.blobtourl(blob)
310
+ hlp.stringtourl(string)
311
+ hlp.base64tourl(base64)
312
+ hlp.filetourl(file)
313
+
314
+ // fix exif image orientation
315
+ hlp.fixImageOrientation(base64).then((base64) => { });
316
+ hlp.getImageOrientation(base64).then((orientation) => { });
317
+
318
+ // html entity encode/decode
319
+ hlp.htmlEncode('&<>"`\'') // &amp;&lt;&gt;&quot;&#96;&#x27;
320
+ hlp.htmlDecode('&amp;&lt;&gt;&quot;&#96;&#x27;') // &<>"`'
321
+
322
+ // line break conversion
323
+ hlp.nl2br('foo\nbar') // foo<br/>bar
324
+ hlp.br2nl('foo<br/>bar') // foo\nbar
325
+
326
+ // floating point math made easy
327
+ hlp.fmath('*', 0.1, 0.2) // 0.02
328
+ hlp.fmath('+', 0.1, 0.2) // 0.3
329
+ hlp.fmath('-', 0.1, 0.2) // -0.1
330
+ hlp.fmath('/', 0.2, 0.1) // 2
331
+ hlp.fmath('/', 0.39, 100, 12) // 0.0039 (precision of 12)
332
+
333
+ // trim helpers
334
+ hlp.trim(' foo ') // 'foo'
335
+ hlp.trim('xxfoox', 'x') // 'foo'
336
+ hlp.ltrim(' foo ') // 'foo '
337
+ hlp.ltrim('xxfoox', 'x') // 'foox'
338
+ hlp.rtrim(' foo ') // ' foo'
339
+ hlp.rtrim('xxfoox', 'x') // 'xxfoo'
340
+
341
+ // truncate long strings
342
+ hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20); // Lorem ipsum dolor ...
343
+ hlp.truncate_string('Lorem ipsum dolor sit amet, consectetuer.', 20, '…'); // Lorem ipsum dolor
344
+
345
+ // fun with emojis
346
+ let str = 'This❤️😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.';
347
+ str.match(hlp.emojiRegex()) // ['❤️', '😀', '👩‍⚖️', '🧗‍♀️', '👩🏼‍❤️‍💋‍👩🏽']
348
+ str.replaceAll(hlp.emojiRegex(), '') // This is a text full of emojis.
349
+ str.replace(hlp.emojiRegex(false), '') // This😀👩‍⚖️ is a text full of 🧗‍♀️emojis👩🏼‍❤️‍💋‍👩🏽.
350
+ hlp.emojiRegex().test(str) // true
351
+ hlp.emojiSplit(str) // ['T','h','i','s','❤️','😀','👩‍⚖️',' ','i','s',' ','a',' ','t','e','x','t',' ','f','u','l','l',' ','o','f',' ','🧗‍♀️','e','m','o','j','i','s','👩🏼‍❤️‍💋‍👩🏽','.']
352
+
353
+ // create lexicographically ordered string ids like in firebase
354
+ hlp.pushId() // -LDiDooGs9PyGHmghk5i
355
+ hlp.pushId() // -LDiDooGs9PyGHmghk5j
356
+
357
+ // access object properties with dotprop notation
358
+ // today it is better to use optional chaining in combination with nullish coalescing ({}?.c?.a?.a??'default')
359
+ hlp.getProp({
360
+ a: 1,
361
+ b: { a: 3, b: 3 },
362
+ c: { a: { a: 7 } }
363
+ }, 'c.a.a') // 7
364
+ ```
365
+
366
+ ### frontend
367
+
368
+ ```js
369
+ // cookies
370
+ hlp.cookieSet('foo', 'bar', 7)
371
+ hlp.cookieSet('foo', 'bar', 7, false) // only for current domain (no subdomains)
372
+ hlp.cookieGet('foo') // bar
373
+ hlp.cookieDelete('foo')
374
+ hlp.cookieDelete('foo', false) // only for current domain (no subdomains)
375
+ hlp.cookieExists('foo') // true|false
376
+
377
+ // localstorage (with expiration time and object support)
378
+ hlp.localStorageSet('foo', {some: 'data'}, 7)
379
+ hlp.localStorageGet('foo') // {'some': 'data'}
380
+ hlp.localStorageDelete('foo')
381
+ hlp.localStorageExists('foo') // true|false
382
+
383
+ // get parameter (example url: https://tld.com/?foo=bar&bar=baz)
384
+ hlp.getParam('foo') // foo
385
+ hlp.getParam('bar') // baz
386
+ hlp.getParam('baz') // null
387
+
388
+ // device detection helpers
389
+ hlp.getDevice() // ['phone','tablet','desktop']
390
+ hlp.isPhone()
391
+ hlp.isTablet()
392
+ hlp.isDesktop()
393
+ hlp.isMobile()
394
+ hlp.isTouch()
395
+
396
+ // os detection helpers
397
+ hlp.getOs() // ['windows','mac','linux','unknown']
398
+ hlp.isWindows()
399
+ hlp.isMac()
400
+ hlp.isLinux()
401
+
402
+ // browser detection helpers
403
+ hlp.getBrowser() // ['ie','edge','firefox','chrome','safari','opera','unknown']
404
+ hlp.isPageSpeed()
405
+
406
+ // smooth scroll to position / element
407
+ hlp.scrollTo( 0, 1000 ).then(() => { console.log('done'); });
408
+ hlp.scrollTo( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
409
+ hlp.scrollTo( 0, 1000, document.querySelector('.bar') ).then(() => { console.log('done'); }); // scoll inside .bar
410
+ hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200 ).then(() => { console.log('done'); }); // apply offset
411
+ 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!)
412
+ hlp.scrollTo( document.querySelector('.foo'), 1000, null, [document.querySelector('.header'), -200] ).then(() => { console.log('done'); }); // you can also provide multiple values (of different type)
413
+ hlp.scrollTo( document.querySelector('.foo'), 1000, null, -200, true ).then(() => { console.log('done'); }); // only scroll up (never down)
414
+
415
+ // get top/left scroll position
416
+ hlp.scrollTop()
417
+ hlp.scrollLeft()
418
+
419
+ // get closest vertical scrollable element (including oneself)
420
+ hlp.closestScrollable( document.querySelector('.foo') )
421
+
422
+ // get offset of element (excluding margin)
423
+ hlp.offsetTop( document.querySelector('.foo') )
424
+ hlp.offsetLeft( document.querySelector('.foo') )
425
+ hlp.offsetRight( document.querySelector('.foo') )
426
+ hlp.offsetBottom( document.querySelector('.foo') )
427
+
428
+ // get offset of element (including margin)
429
+ hlp.offsetTopWithMargin( document.querySelector('.foo') )
430
+ hlp.offsetLeftWithMargin( document.querySelector('.foo') )
431
+ hlp.offsetRightWithMargin( document.querySelector('.foo') )
432
+ hlp.offsetBottomWithMargin( document.querySelector('.foo') )
433
+
434
+ // get document size
435
+ hlp.documentWidth()
436
+ hlp.documentHeight()
437
+
438
+ // get window size
439
+ hlp.windowWidth()
440
+ hlp.windowHeight()
441
+ hlp.windowWidthWithoutScrollbar()
442
+ hlp.windowHeightWithoutScrollbar()
443
+
444
+ // get width with margin
445
+ hlp.outerWidthWithMargin( document.querySelector('.foo') )
446
+ hlp.outerHeightWithMargin( document.querySelector('.foo') )
447
+
448
+ // get cursor position (without mouse events)
449
+ hlp.cursorPosition().then(pos => { console.log(pos); /* pos: { x: ..., y: ... } */ });
450
+
451
+ // polyfills for ie11
452
+ hlp.closest( document.querySelector('.children'), '.parent' )
453
+ hlp.matches( document.querySelector('.parent'), '.parent' ) // true
454
+ hlp.remove( document.querySelector('.foo') ) // also works if .foo does not exist
455
+
456
+ // dom traversal
457
+ hlp.prevAll( document.querySelector('.foo') )
458
+ hlp.prevAll( document.querySelector('.foo'), '.bar' )
459
+ hlp.nextAll( document.querySelector('.foo') )
460
+ hlp.nextAll( document.querySelector('.foo'), '.bar' )
461
+ hlp.siblings( document.querySelector('.foo') )
462
+ hlp.siblings( document.querySelector('.foo'), '.bar' )
463
+ hlp.parents( document.querySelector('.foo') )
464
+ hlp.parents( document.querySelector('.foo'), '.bar' )
465
+ hlp.prevUntil( document.querySelector('.foo'), '.bar' ) // prev until selector not including
466
+ hlp.nextUntil( document.querySelector('.foo'), '.bar' ) // next until selector not including
467
+ hlp.prev( document.querySelector('.foo') )
468
+ hlp.prev( document.querySelector('.foo'), '.bar' )
469
+ hlp.next( document.querySelector('.foo') )
470
+ hlp.next( document.querySelector('.foo'), '.bar' )
471
+ hlp.querySelectorAllShadowDom('.foo') // finds all elements with that selector (also in nested shadowdom elements)
472
+
473
+ // wrap element
474
+ hlp.wrap( document.querySelector('.foo'), '<div class="wrapper"></div>' )
475
+
476
+ // wrap all text nodes with new node
477
+ hlp.wrapTextNodes( document.querySelector('.foo'), 'p' )
478
+
479
+ // html string to dom (also supports ie11 and td nodes that cannot be root nodes)
480
+ hlp.html2dom('<p>foo</p>')
481
+ hlp.html2dom('<td>bar</td>')
482
+
483
+ // get all styles of a dom element (extracted from both inline styling and external styling through stylesheets)
484
+ hlp.css( document.querySelector('.foo') )
485
+
486
+ // visually focus element on page
487
+ hlp.focus('.foo')
488
+ hlp.focus(document.querySelector('.foo'))
489
+ hlp.unfocus()
490
+
491
+ // on delegate
492
+ hlp.on('click', '.selector', (e, el) => { });
493
+ hlp.on('click', '.selector', '.scope', (e, el) => { });
494
+
495
+ // classic debounce
496
+ window.addEventListener('resize', hlp.debounce(() => { console.log('debounce at resize') }, 1000));
497
+ document.querySelector('.container').addEventListener('input', hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000));
498
+ let debounce = hlp.debounce((e) => { console.log('debounce at '+e.target.value); }, 1000); // conditional debounce
499
+ document.querySelector('.container').addEventListener('input', e => { debounce(e); });
500
+
501
+ // classic throttle
502
+ window.addEventListener('resize', hlp.throttle(() => { console.log('throttle at resize') }, 1000));
503
+ document.querySelector('.container').addEventListener('input', hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000));
504
+ let throttle = hlp.throttle((e) => { console.log('throttle at '+e.target.value); }, 1000); // conditional throttle
505
+ document.querySelector('.container').addEventListener('input', e => { throttle(e); });
506
+
507
+ // get current url
508
+ hlp.url() // https://github.com/vielhuber/hlp
509
+ hlp.urlWithHash() // https://github.com/vielhuber/hlp#foo
510
+ hlp.fullUrl() // https://github.com/vielhuber/hlp?foo=bar#foo
511
+ hlp.urlWithArgs() // https://github.com/vielhuber/hlp?foo=bar
512
+ hlp.baseUrl() // https://github.com
513
+ hlp.urlHost(); // github.com
514
+ hlp.urlHostTopLevel(); // github.com
515
+ hlp.urlPath(); // /vielhuber/hlp
516
+ hlp.urlHash(); // #foo
517
+ hlp.urlArgs(); // ?foo=bar
518
+
519
+ // get url of current running script
520
+ hlp.urlOfScript(); // https://tld.com/wp-content/themes/dummy/script.js
521
+ hlp.pathOfScript(); // https://tld.com/wp-content/themes/dummy
522
+
523
+ // set 100vh for a dom element (respecting the visibility of the address bar)
524
+ hlp.real100vh('.foo') // 100vh
525
+ hlp.real100vh('.foo', 60) // 60vh
526
+ hlp.real100vh() // sets up a css variable which can be used with e.g. calc(100 * var(--vh, 1vh)); to mimic 100vh
527
+
528
+ // 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);
529
+ hlp.iOsRemoveHover();
530
+
531
+ // fade in/out dom element
532
+ hlp.fadeIn( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
533
+ hlp.fadeOut( document.querySelector('.foo'), 1000 ).then(() => { console.log('done'); });
534
+
535
+ // check if dom element is generally visible
536
+ hlp.isVisible( document.querySelector('.foo') )
537
+ // check if dom element is visible inside viewport
538
+ hlp.isVisibleInViewport( document.querySelector('.foo') )
539
+
540
+ // wait until a dom element has a certain css property
541
+ // this is quite useful when working with async loaded stylesheets like loadCSS
542
+ // .beacon is an element below the fold populated by the stylesheet
543
+ hlp.waitUntil('.beacon').then(() => { });
544
+ hlp.waitUntil('.beacon','position').then(() => { });
545
+ hlp.waitUntil('.beacon','position','relative').then(() => { });
546
+
547
+ // wait for elements (that appear also afterwards)
548
+ hlp.waitUntilEach('.el', ($el) => { });
549
+
550
+ // wait until a variable is set or has a specific value
551
+ hlp.waitUntilVar('globalVar').then(() => { });
552
+ hlp.waitUntilVar(obj, 'objectVar').then(() => { });
553
+ hlp.waitUntilVar(obj, 'objectVar', true).then(() => { });
554
+
555
+ // run a function for every dom element, even it is added dynamically later on
556
+ hlp.runForEl('.beacon', el => { el.style.backgroundColor = 'red'; });
557
+
558
+ // automatically change height of all textareas based on content
559
+ hlp.textareaAutoHeight()
560
+ hlp.textareaAutoHeight('.special')
561
+ hlp.textareaSetHeight( document.querySelector('.special') )
562
+
563
+ // load external js file in dom with promise
564
+ hlp.loadJs('https://apis.google.com/js/api.js').then(() => { console.log('done'); });
565
+ hlp.loadJs([
566
+ 'https://www.tld.com/1.js',
567
+ 'https://www.tld.com/2.js',
568
+ 'https://www.tld.com/3.js'
569
+ ]).then(() => { console.log('done'); });
570
+ hlp.loadJsSequentially([
571
+ 'https://www.tld.com/1.js',
572
+ 'https://www.tld.com/2.js',
573
+ 'https://www.tld.com/3.js'
574
+ ]).then(() => { console.log('done'); });
575
+
576
+ // run event after all images are loaded inside container
577
+ // works even after dynamic changes
578
+ // runs more than once (after each change)
579
+ // run this outside of window load / document ready events
580
+ hlp.triggerAfterAllImagesLoaded('.container', '.container__image', () => {});
581
+
582
+ // proper document read/load events, that are guaranteed to be run (also if the script is embedded via async)
583
+ hlp.ready().then(() => {});
584
+ hlp.load().then(() => {});
585
+
586
+ // easy ajax requests (without the fetch api; also works in ie11)
587
+ hlp.get('https://httpbin.org/anything').then((response) => { }).catch((error) => { }) // { "method": "GET", ... }
588
+ hlp.get('/relpath').then((response) => { }).catch((error) => { }) // if a full url is omitted, the call is done on the baseurl
589
+ hlp.get('https://httpbin.org/anything', { throttle: 1000 }).then((response) => { }).catch((error) => { }) // same but with a throttle of 1 second
590
+ hlp.get('https://httpbin.org/status/404', { allow_errors: false }).then((response) => { }) // deny 404 and other status codes as a response (inside catch())
591
+ hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "data": {"foo": "bar"}, ... }
592
+ hlp.post('https://httpbin.org/anything', { data: { foo: 'bar' }, headers: { Bar: 'baz' } }).then((response) => { }).catch((error) => { }) // { "method": "POST", "headers" = { "Bar": "baz", ... }, ... }
593
+ let formData = new FormData(); formData.append('foo', 'bar'); hlp.post('https://httpbin.org/anything', { data: formData }) // this also works with FormData
594
+
595
+ // on resize vertically/horizontally
596
+ window.addEventListener('resize', () => {}) // inaccurate, triggers too often (especially when scrolling on android/iphone)
597
+ hlp.onResizeHorizontal(() => {}) // only triggers when viewport width changes; also triggers on first run
598
+ hlp.onResizeVertical(() => {}) // only triggers when viewport height changes; also triggers on first run
599
+
600
+ // add event listener once
601
+ hlp.addEventListenerOnce(
602
+ document.getElementById('foo'),
603
+ 'click',
604
+ (event) => { alert('this gets called only once'); }
605
+ );
606
+ hlp.addEventListenerOnce(
607
+ document.getElementById('foo'),
608
+ 'click',
609
+ (event) => { if(1==1) { return false; } } // if you return false, the event listener is not removed
610
+ );
611
+
612
+ // simple animations (via css transitions)
613
+ hlp.animate(
614
+ document.getElementById('.single'),
615
+ 'transform: translateX(0)',
616
+ 'transform: translateX(-100%)',
617
+ 'ease-in-out',
618
+ 1000
619
+ ).then(() => { console.log('done'); });
620
+ hlp.animate(
621
+ document.querySelectorAll('.multiple'),
622
+ 'opacity: 1; pointer-events:auto',
623
+ 'opacity: 0; pointer-events:none',
624
+ 'linear',
625
+ 5000
626
+ ).then(() => { console.log('done'); });
627
+ ```
628
+
629
+ ## php implementation
630
+
631
+ there is also a php implemenation [stringhelper](https://github.com/vielhuber/stringhelper) with similiar functions available.
632
+
633
+ ## testing
634
+
635
+ `npm run js:tests`
636
+
637
+ ## recommendations
638
+
639
+ ### existence
640
+
641
+ ```js
642
+ if (foo) {} // ⚠️ be aware of: '0'/[]/{}
643
+ if (foo?.prop) {}
644
+ if (foo?.someFun1()?.someFun2()?.getName()) {}
645
+ ```
646
+
647
+ ### truthness
648
+
649
+ ```js
650
+ if (foo === true) {}
651
+ if (foo?.prop === true) {}
652
+ if (foo?.someFun1()?.someFun2()?.getName() === true) {}
653
+ ```
654
+
655
+ ### comparison
656
+
657
+ ```js
658
+ if (foo === 'foo') {}
659
+ if (foo?.prop === 'foo') {}
660
+ if (foo?.someFun1()?.someFun2()?.getName() === 'foo') {}
661
+ ```
662
+
663
+ these recommendations ground on the fact, that js has a lot of pitfalls, when comparing loosely:
664
+
665
+ ```js
666
+ if( '' == [] ) // true
667
+ if( '' == [''] ) // true
668
+ if( '' == 0 ) // true
669
+ if( ' ' == false ) // true
670
+ if( [0] == false ) // true
671
+ if( [0] == '0' ) // true
672
+ if( [] == false ) // true
673
+ if( [''] == false ) // true
674
+ if( 0 == false ) // true
675
+ if( 0 == [] ) // true
676
+ if( 0 == [''] ) // true
677
+ if( [0] == false ) // true
678
+ if( [0] == 0 ) // true
679
+ ```
680
+
681
+ also don't forget those delicacies:
682
+
683
+ ```js
684
+ 0 === -0 // true
685
+ NaN === NaN // false
686
+ (![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] === 'fail' // true
687
+ ```
688
+
689
+ this non-strict equality is symmetric, but not transitive:
690
+
691
+ ```js
692
+ a = ''; b = 0; c = [0];
693
+ a == b; // true
694
+ b == c; // true
695
+ c == a; // false
696
+ ```
697
+
698
+ ## appendix
699
+
700
+ ### existence matrix
701
+
702
+ | | <sub>hlp.x()</sub> | <sub>hlp.true()</sub> | <sub>hlp.false()</sub> | <sub>!== null</sub> | <sub>!= null</sub> | <sub>!== false</sub> | <sub>!= false</sub> | <sub>=== true</sub> | <sub>== true</sub> | <sub>typeof !== 'undefined'</sub> | <sub>!= undefined</sub> | <sub>!== undefined</sub> | <sub>if/else</sub> | <sub>ternary</sub> | <sub>length > 0</sub> | <sub>!= ''</sub> | <sub>!== ''</sub> |
703
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
704
+ | <sub>undefined</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> | <sub>true</sub> |
705
+ | <sub>null</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> | <sub>true</sub> |
706
+ | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
707
+ | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
708
+ | <sub>[]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
709
+ | <sub>['']</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> |
710
+ | <sub>0</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> |
711
+ | <sub>1</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
712
+ | <sub>-1</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
713
+ | <sub>'0'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
714
+ | <sub>'1'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
715
+ | <sub>'-1'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
716
+ | <sub>''</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> |
717
+ | <sub>' '</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
718
+ | <sub>'null'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
719
+ | <sub>'false'</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
720
+ | <sub>'true'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
721
+ | <sub>'str'</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
722
+ | <sub>[0,1]</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
723
+ | <sub>[0]</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
724
+ | <sub>{}</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> |
725
+ | <sub>un.known.property</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> |
726
+ | <sub>(()=>un.known.property)</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> |
727
+
728
+ ### loose comparison matrix
729
+
730
+ | <sub>==</sub> | <sub>undefined</sub> | <sub>null</sub> | <sub>false</sub> | <sub>true</sub> | <sub>[]</sub> | <sub>['']</sub> | <sub>0</sub> | <sub>1</sub> | <sub>-1</sub> | <sub>'0'</sub> | <sub>'1'</sub> | <sub>'-1'</sub> | <sub>''</sub> | <sub>' '</sub> | <sub>'null'</sub> | <sub>'false'</sub> | <sub>'true'</sub> | <sub>'str'</sub> | <sub>[0,1]</sub> | <sub>[0]</sub> | <sub>{}</sub> | <sub>un.known.property</sub> | <sub>(()=>un.known.property)</sub> |
731
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
732
+ | <sub>undefined</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
733
+ | <sub>null</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
734
+ | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
735
+ | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
736
+ | <sub>[]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
737
+ | <sub>['']</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
738
+ | <sub>0</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
739
+ | <sub>1</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
740
+ | <sub>-1</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
741
+ | <sub>'0'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
742
+ | <sub>'1'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
743
+ | <sub>'-1'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
744
+ | <sub>''</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>true</sub> | <sub>true</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
745
+ | <sub>' '</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
746
+ | <sub>'null'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
747
+ | <sub>'false'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
748
+ | <sub>'true'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
749
+ | <sub>'str'</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
750
+ | <sub>[0,1]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
751
+ | <sub>[0]</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>false</sub> | <sub>error</sub> | <sub>false</sub> |
752
+ | <sub>{}</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>true</sub> | <sub>error</sub> | <sub>false</sub> |
753
+ | <sub>un.known.property</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> | <sub>error</sub> |
754
+ | <sub>(()=>un.known.property)</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>false</sub> | <sub>error</sub> | <sub>true</sub> |