Wednesday, October 3, 2018

Write a Javascript Library From Scratch

Almost every web developer has encountered use of jQuery in daily life coding. Today we will write a custom javascript library from scratch and learn how we can write our own custom library like jquery from scratch.

Write a Javascript Library From Scratch
Obviously its going to be a basic simple library just to illustrate working model of jquery. First we are going to create an object and I am going to use _$$ as object name. So lets define our object using self-invoking function which accepts a selector as a parameter.

(function (win, doc) {
    function _$$(selector) {
        // Initiate the object if it hasn't been initiated
        if (!(this instanceof _$$)) {
            return new _$$(selector);
        }

        this.length = 0;
        var elements = [];
        if(selector instanceof HTMLElement || selector == window || selector == document){
            elements = [selector];
        }else if(typeof selector === "string"){
            elements = doc.querySelectorAll(selector);
        }
        // Push all elements to object
        if (elements.length) {
            this.length = elements.length;
            for (var i = 0; i < this.length; i++) {
                this[i] = elements[i];
            }
        }
        return this;
    }
    // Append object to window object
    win._$$ = _$$;
})(window, document);

So what have we achieved so far now? We can select elements like jQuery using_$$("p"), _$$(window), _$$(document) etc. Now that we can select element let's add some functions to our object using prototypes.

_$$.prototype = {
    each: function (callback) {
        for (var i = 0; i < this.length; i++) {
            callback.call(this[i], this, i);
        }
        return this;
    },
    ready:function(callback){
        return this.each(function(){
            win.addEventListener("DOMContentLoaded",callback,false);
        });
    },
    on: function (name, callback) {
        return this.each(function () {
            return this.addEventListener(name, callback, false);
        });
    },
    hide:function(speed,callback){
        return this.each(function(ob){
            return ob.css("display","none") && ob;
        });
    },
    show:function(speed,callback){
        return this.each(function(ob){
            return ob.css("display","block");
        });
    },
    toggle:function(speed,callback){
        return this.each(function(ob){
            if(!ob.is(":visible")){
                return ob.css("display","block");
            }else{
                return ob.css("display","none");
            }
        });
    },
    is:function(prop){
        switch(prop){
            case ":visible":
                return this[0].clientHeight > 0 && this[0].clientWidth > 0 ? true : false;
                break;
        }
    },
    css:function(param1,param2){
        this.each(function(){
            if(typeof param1 === "object"){
                for(x in param1){
                   this.style[x] = param1[x];
                }
            }
            else if(typeof param1 === "string" && typeof param2 === "string"){
                this.style[param1] = param2;
            }
        });
        return window.getComputedStyle(this[0]).getPropertyValue(param1);
    },
    addClass:function(className){
        return this.each(function(){
            return this.classList.add(className);
        });
    },
    removeClass:function(className){
        return this.each(function(){
            return this.classList.remove(className);
        });
    },
    toggleClass:function(className){
        return this.each(function(){
           if(this.classList.contains(className)){
               return this.classList.remove(className);
           }else{
               return this.classList.add(className);
           }
        });
    }
};

Notice that our prototype function each: does all the heavy lifting for library. What it actually does is it takes the function from other prototypes calling it. It then calls that function on every element present in object and passes three values (the current element, the object itself, current index). Now that our library is ready lets use it in our demo.

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Write a Javascript Library From Scratch</title>
        <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
        <script type="text/javascript" src="js/library.js"></script>
        <script type="text/javascript" src="js/javascript.js"></script>
        <link rel="stylesheet" href="css/style.css" />
    </head>
    <body>
        <div class="main-container">
            <div class="section">
                <div>
                        <button class="btn btn-default hidebtn">Hide</button>
                        <button class="btn btn-default showbtn">Show</button>
                        <button class="btn btn-default togglebtn">Toggle</button>
                        Hide, Show or Toggle paragraph below:
                </div>
                <div class="p-wrapper">
                    <p class="hide-show-toggle">
                        Lorem Ipsum is simply dummy text of the printing and typesetting industry.
                        Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
                        It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.
                        It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
                    </p>
                </div>
            </div>

            <div class="section">
                <div>
                    <button class="btn btn-default add-class">Add Class</button>
                    <button class="btn btn-default remove-class">Remove Class</button>
                    <button class="btn btn-default toggle-class">Toggle Class</button>
                    Add, Remove or Toggle class on paragraph below:
                </div>

                <p class="add-remove-toggle-class">
                    Lorem Ipsum is simply dummy text of the printing and typesetting industry.
                    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
                    It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.
                    It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
                </p>
            </div>
        </div>
    </body>
</html>

style.css

*{
    box-sizing: border-box;
}
html,body{
    margin: 0px;
    padding: 0px;
}
body{
    background: #f0f0f0;
    font: normal normal 14px Open Sans,Verdana, Arial;
}
a:link {
    text-decoration: none;
    color: #3778cd;
}
.section{
    padding: 15px;
}
.main-container{
    max-width: 1024px;
    margin: 0px auto;
}
.btn{
    display: inline-block;
    padding: 5px 10px;
    border: 1px solid #ddd;
    cursor: pointer;
    background: #fff;
}
.bg-color {
    background: #006cad;
    color: #fff;
}

javascript.js

_$$(document).ready(function(){

    _$$(".hidebtn").on("click",function(){
        _$$(".hide-show-toggle").hide();
    });
     _$$(".showbtn").on("click",function(){
        _$$(".hide-show-toggle").show();
    });

    _$$(".togglebtn").on("click",function(){
        _$$(".hide-show-toggle").toggle();
    });

     _$$(".add-class").on("click",function(){
        _$$(".add-remove-toggle-class").addClass("bg-color");
    });
     _$$(".remove-class").on("click",function(){
        _$$(".add-remove-toggle-class").removeClass("bg-color");
    });

    _$$(".toggle-class").on("click",function(){
        _$$(".add-remove-toggle-class").toggleClass("bg-color");
    });
});