├── README.md └── js ├── sortNumberArray.js ├── stringBoolToBool.js ├── getElementsByClassName.js ├── domWalk.js ├── arrayMerge.js ├── matchesSelector.js ├── getAbsoluteUrl.js ├── fnParamsFromArray.js ├── deepFreeze.js ├── getUrlParam.js ├── once.js ├── createTable.js ├── publish-subscribe.js ├── insertRuleCSS.js ├── throttle.js ├── relativeTimeValue.js ├── objectIterator.js ├── debounce.js ├── poll.js ├── filterMapReduce.js ├── timers.js ├── lazyLoadImages.js ├── domTreeTraversal.js ├── measureSitePerformance.js ├── flattenNestedArray.js └── vanillahelpers.js /README.md: -------------------------------------------------------------------------------- 1 | # JS Utils 2 | 3 | Utility functions in JavaScript -------------------------------------------------------------------------------- /js/sortNumberArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sort numeric Array 3 | */ 4 | (function () { 5 | var arr = [2, 5, 1, 19, 26, 7]; 6 | 7 | arr.sort(function (a, b) { 8 | return a - b; 9 | }); 10 | })(); -------------------------------------------------------------------------------- /js/stringBoolToBool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert string values 'true'/'false' to boolean true/false. 3 | * 4 | */ 5 | 6 | (function () { 7 | // BASIC TECHIQUE 8 | 9 | // This will work only if the string values are only one of the either ('true'/'false') 10 | // Will return misleading results if the string value is different 11 | var a = 'true'; 12 | var boolVal = (a === true); // Returns true 13 | 14 | // TRICK 15 | var b = 'true'; 16 | var boolVal = JSON.parse(b); // Returns true.. throws an error if we use any other string other than 'true' or 'false' 17 | 18 | })(); -------------------------------------------------------------------------------- /js/getElementsByClassName.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Native JavaScript implementation of getElementsByClassName() -- Polyfill 3 | * 4 | * @param node 5 | * @param classname 6 | * @returns {*} 7 | */ 8 | 9 | function getElementsByClassName(classname) { 10 | var results = []; 11 | var elemsUnderCurrNode = this.getElementsByTagName("*"); // 'this' value is the current node referenced 12 | var r = new RegExp('\\b' + classname + '\\b'); // \b is word separator 13 | 14 | for (var i = 0; i < elemsUnderCurrNode.length; i++) { 15 | var classNames = elemsUnderCurrNode[i].className; 16 | if (classNames && r.test(classNames)) { 17 | results[results.length] = elemsUnderCurrNode[i]; 18 | } 19 | } 20 | return results; 21 | } -------------------------------------------------------------------------------- /js/domWalk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Walk through all elements in the DOM 3 | * 4 | * @Reference: 5 | * https://www.kirupa.com/html5/traversing_the_dom.htm 6 | * 7 | * @param node 8 | */ 9 | 10 | function walkTheDOM(node) { 11 | if (node.nodeType == 1) { 12 | //console.log(node.tagName); 13 | node = node.firstChild; 14 | 15 | while (node) { 16 | walkTheDOM(node); 17 | node = node.nextSibling; 18 | } 19 | } 20 | } 21 | 22 | // Example usage: Process all Text nodes on the page 23 | walkTheDOM(document.body, function (node) { 24 | if (node.nodeType === 3) { // Is it a Text node? 25 | var text = node.data.trim(); 26 | if (text.length > 0) { // Does it have non white-space text content? 27 | // process text 28 | } 29 | } 30 | }); -------------------------------------------------------------------------------- /js/arrayMerge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Merge 2 arrays into one. 3 | * 4 | * - Using concat() -- Create a new toArray. 5 | * - Using Array push() -- Modifies existing array. 6 | */ 7 | 8 | (function () { 9 | // Using concat() - CREATES A NEW ARRAY 10 | var alpha = ['a', 'b', 'c']; 11 | var numeric = [1, 2, 3]; 12 | 13 | var alphaNumeric = alpha.concat(numeric); 14 | 15 | console.log(alphaNumeric); 16 | // Result: ['a', 'b', 'c', 1, 2, 3] 17 | 18 | 19 | // Using Array prototye push (Efficient): DOES NOT CREATE A NEW ARRAY 20 | var a1 = [1, 2, 3]; 21 | var a2 = [4, 5, 6]; 22 | 23 | Array.prototype.push.apply(a1, a2); 24 | console.log(a1); 25 | // Result: [1, 2, 3, 4, 5, 6] 26 | 27 | 28 | // array_merge() as a function 29 | var array_merge = Function.prototype.apply.bind(Array.prototype.push); 30 | // USAGE 31 | array_merge(a1, a2); 32 | 33 | })(); 34 | -------------------------------------------------------------------------------- /js/matchesSelector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * matchesSelector() 3 | * 4 | * Oftentimes we validate input before moving forward; ensuring a truthy value, ensuring forms data is valid, etc. 5 | * But how often do we ensure an element qualifies for moving forward? You can use a matchesSelector function to 6 | * validate if an element is of a given selector match. 7 | * 8 | */ 9 | 10 | (function () { 11 | function matchesSelector(el, selector) { 12 | var p = Element.prototype; 13 | var f = 14 | p.matches || 15 | p.webkitMatchesSelector || 16 | p.mozMatchesSelector || 17 | p.msMatchesSelector || 18 | function (s) { 19 | return [].indexOf.call(document.querySelectorAll(s), this) !== -1; 20 | }; 21 | return f.call(el, selector); 22 | } 23 | 24 | // Usage 25 | matchesSelector(document.getElementById('myDiv'), 'div.someSelector[some-attribute=true]'); 26 | 27 | })(); -------------------------------------------------------------------------------- /js/getAbsoluteUrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * getAbsoluteUrl() 3 | * 4 | * Dealing with URL formats can be a real nightmare. Think of how just a few characters can effect a URL's absolute endpoint: 5 | * starting or not starting with / 6 | * starting with // 7 | * starting with ? 8 | * starting with #...and so on 9 | * What if you want an absolute URL though? One that starts with http or https? 10 | * You can use an A element to get that absolute URL 11 | * 12 | * @Reference: 13 | * http://davidwalsh.name/get-absolute-url 14 | * 15 | */ 16 | 17 | (function () { 18 | var getAbsoluteUrl = (function () { 19 | var a; 20 | 21 | return function (url) { 22 | if (!a) { 23 | a = document.createElement('a'); 24 | a.href = url; 25 | 26 | return a.href; 27 | } 28 | }; 29 | })(); 30 | 31 | // Usage 32 | getAbsoluteUrl('/something'); // http://localhost:3000/something 33 | 34 | })(); -------------------------------------------------------------------------------- /js/fnParamsFromArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A function has 3 params. 3 | * The values to be passed to the params, are in an array. 4 | * 5 | * What is a simple trick to pass the parameters to the function from an array 6 | * 7 | * Short Answer: Use fn.apply(null, array); 8 | * 9 | */ 10 | 11 | // In ES5 -- You can use fn.apply() 12 | (function () { 13 | var arr = [1, 2, 3]; // The array values need to passed to params a, b, c. 14 | function testFn(a, b, c) { 15 | // Some logic 16 | } 17 | 18 | // Use apply() to pass array values as parameters. 19 | testFn.apply(null, arr); 20 | 21 | })(); 22 | 23 | // In ES6 -- You can use the spread operator (..var) 24 | (function() { 25 | var arr = [1, 2, 3]; // The array values need to passed to params a, b, c. 26 | function testFn(a, b, c) { 27 | // Some logic 28 | } 29 | 30 | // Use the spread operator (...) in ES6 to pass array values as parameters. 31 | testFn(...arr); 32 | })(); -------------------------------------------------------------------------------- /js/deepFreeze.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Object.freze() is shallow. 3 | * Let's make a deepFreeze() function 4 | */ 5 | 6 | obj1 = { 7 | internal: {} 8 | }; 9 | 10 | Object.freeze(obj1); 11 | obj1.internal.a = 'aValue'; 12 | 13 | console.log(obj1.internal.a); // aValue 14 | 15 | // To make the object fully immutable, freeze each object in obj1 16 | function deepFreeze(obj) { 17 | // Retrieve the property names defined on obj 18 | var propNames = Object.getOwnPropertyNames(obj); 19 | 20 | // Freeze properties before freezing self 21 | propNames.forEach(function (name) { 22 | var prop = obj[name]; 23 | 24 | // Freeze prop if it is an object 25 | if (typeof prop == 'object' && prop !== null && !Object.isFrozen(prop)) { 26 | deepFreeze(prop); 27 | } 28 | }); 29 | 30 | // Freeze self 31 | return Object.freeze(obj); 32 | } 33 | 34 | // Test deepFreeze 35 | var obj2 = { 36 | internal: {} 37 | }; 38 | 39 | deepFreeze(obj2); 40 | obj2.internal.a = 'anotherValue'; 41 | console.log(obj2.internal.a); // undefined 42 | -------------------------------------------------------------------------------- /js/getUrlParam.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get param value from the url 3 | * 4 | * window.location.search 5 | * Returns the query string part of the url, including the leading question mark (?). It's supported across all browsers. 6 | * 7 | * encodeURIComponent() - encodes a URI component. 8 | * decodeURIComponent() - decodes a URI component. 9 | * 10 | * encodeUR() - encodes the complete url. 11 | * decodeUR() - decodes the complete url. 12 | */ 13 | 14 | 15 | (function () { 16 | function getQueryParam(paramName) { 17 | // We apply substring(1) on the queryString to remove the leading question mark(?) 18 | var query = window.location.search.substring(1); 19 | var vars = query.split('&'); 20 | for (var i = 0; i < vars.length; i++) { 21 | var pair = vars[i].split('='); 22 | if (pair[0] === paramName) { 23 | return decodeURIComponent(pair[1]); 24 | } 25 | } 26 | // If param name is not found in the query string, return false. 27 | return false; 28 | } 29 | 30 | // If the url is https://www.vasanthk.com?user=vasa 31 | // getqueryParam(user) returns 'vasa' 32 | })(); -------------------------------------------------------------------------------- /js/once.js: -------------------------------------------------------------------------------- 1 | /** 2 | * once() 3 | * 4 | * The function ensure that a given function can be called once and only once, thus preventing duplicate initialization 5 | * 6 | * Link: http://sinonjs.org/ 7 | */ 8 | 9 | // Implementation 1 10 | (function () { 11 | function once(fn) { 12 | var returnValue, called = false; 13 | return function () { 14 | if (!called) { 15 | called = true; 16 | returnValue = fn.apply(this, arguments); 17 | } 18 | return returnValue; 19 | }; 20 | } 21 | 22 | // Usage 23 | var canOnlyFireOnce = once(function () { 24 | console.log('Fired!'); 25 | }); 26 | 27 | canOnlyFireOnce(); // Fired! 28 | canOnlyFireOnce(); // undefined 29 | })(); 30 | 31 | // Implementation 2 32 | (function () { 33 | function once(fn, context) { 34 | var result; 35 | 36 | return function () { 37 | if (fn) { 38 | fn.apply(context || this, arguments); 39 | fn = null; 40 | } 41 | return result; 42 | }; 43 | } 44 | 45 | // Usage 46 | var canOnlyFireOnce = once(function () { 47 | console.log('Fired!'); 48 | }); 49 | 50 | canOnlyFireOnce(); // Fired! 51 | canOnlyFireOnce(); // undefined 52 | 53 | })(); 54 | -------------------------------------------------------------------------------- /js/createTable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate table 3 | */ 4 | 5 | function generate_table() { 6 | // get the reference for the body 7 | var body = document.getElementsByTagName("body")[0]; 8 | 9 | // creates a element and a element 10 | var tbl = document.createElement("table"); 11 | var tblBody = document.createElement("tbody"); 12 | 13 | // creating all cells 14 | for (var i = 0; i < 2; i++) { 15 | // creates a table row 16 | var row = document.createElement("tr"); 17 | 18 | for (var j = 0; j < 2; j++) { 19 | // Create a in the
element and a text node, make the text 20 | // node the contents of the , and put the at 21 | // the end of the table row 22 | var cell = document.createElement("td"); 23 | var cellText = document.createTextNode("cell in row " + i + ", column " + j); 24 | cell.appendChild(cellText); 25 | row.appendChild(cell); 26 | } 27 | 28 | // add the row to the end of the table body 29 | tblBody.appendChild(row); 30 | } 31 | 32 | // put the
33 | tbl.appendChild(tblBody); 34 | // appends
into 35 | body.appendChild(tbl); 36 | // sets the border attribute of tbl to 2; 37 | tbl.setAttribute("border", "2"); 38 | } -------------------------------------------------------------------------------- /js/publish-subscribe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Publish-Subscribe 3 | * 4 | * @Reference: 5 | * https://davidwalsh.name/pubsub-javascript 6 | * 7 | */ 8 | 9 | // Pub-Sub module to help you publish to a topic and anyone can subscribe. 10 | var events = (function() { 11 | var topics = {}; 12 | 13 | return { 14 | subscribe: function(topic, listener) { 15 | // Create the topic's object if not created. 16 | if(!topics.hasOwnProperty(topic)) topics[topic] = []; 17 | 18 | // Add the listener to queue 19 | var index = topics[topic].push(listener) - 1; 20 | 21 | // Provide handle back for removal of topic 22 | return { 23 | remove: function() { 24 | delete topics[topic][index]; 25 | } 26 | } 27 | }, 28 | publish: function(topic, info) { 29 | // If the topic doesn't exist, or there's no listeners in queue, just leave 30 | if(!topics.hasOwnProperty(topic)) return; 31 | 32 | // Cycle through topics queue, fire! 33 | topics[topic].forEach(function(item) { 34 | item(info != undefined ? info : {}); 35 | }) 36 | } 37 | } 38 | })(); 39 | 40 | 41 | // Publishing to a topic 42 | events.publish('/page/load', { 43 | url: '/some/url/path' // any argument 44 | }); 45 | 46 | 47 | // ...and subscribing to said topic in order to be notified of events: 48 | var subscription = events.subscribe('/page.load', function(obj) { 49 | // Do something now that the event has occurred. 50 | }); 51 | 52 | // ..sometime later where I no longer want subscription... 53 | subscription.remove(); -------------------------------------------------------------------------------- /js/insertRuleCSS.js: -------------------------------------------------------------------------------- 1 | /** 2 | * We all know that we can grab a NodeList from a selector (via document.querySelectorAll) and give each of them a style, 3 | * but what's more efficient is setting that style to a selector (like you do in a stylesheet) 4 | * 5 | * This is especially useful when working on a dynamic, AJAX-heavy site. If you set the style to a selector, 6 | * you don't need to account for styling each element that may match that selector (now or in the future). 7 | * 8 | * @Reference: 9 | * http://davidwalsh.name/add-rules-stylesheets 10 | * 11 | */ 12 | 13 | (function () { 14 | var sheet = (function () { 15 | // Create