> For the complete documentation index, see [llms.txt](https://maksimdan.gitbook.io/javascript/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://maksimdan.gitbook.io/javascript/intro_to_javascript/section_8.md).

# Section 8 - Examining Famous Frameworks and Libraries

### Building Our own Framework

#### Requirements

* Name: Greetr
* Generates form and informal greetings
* Reusable, and non interfearing
* English and Spanish
* Easy to Type structure
  * $G&#x20;
* Support Jquery

#### Structuring safe code

```
    ...


    (function (global, $){

    })(window, $)
```

* What happened:
  * Immediately invoked function that creates a new execution context, keeping our variables safe.
  * 2 global objects where passed that we're going to work with.

#### Part 2

```
    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }
    }
```

* Greetr is a function, that when invoked, returns a new object, so that we do have to use the keyword ourselves.
* Init is not yet defined, but is a common keyword used to handle initialization.&#x20;

```
    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }

        Greetr.prototype = {};

        Greetr.init = function(first, last, lang) {
            this.firstname = first || '[users first name]';
            this.lastname = last || '[users last name]';
            this.language = lang || 'en';

            // defined later -> checks if language is supported
            this.validate();
        }

        Greetr.init.prototype = Greetr.prototype;

    })(window, $)
```

* Next we implement our object constructor.
  * Unique variable primitive to our library are defined as a properties to each respected object.
    * Default variables are invocated by coersion.&#x20;
* We defined a new object as a prototype (inheritance) to each object.
  * Save memory space by not passing it into the constructor.
  * Empty for now
* Because objects where constructed with .init (seperate execution context), we want all Greetr/prototype objects to point to Greetr.init.prototype.
  * Allows us to define methods in Greetr.prototype more cleanly.&#x20;

```
        global.Greetr = global.$G = Greetr;
```

* One last thing before we finish. To establish a neat alias, all we have to set our object function constructor as part of the global window.
* Now, we can treat Greetr, and $G equivalently as constructors.

```
    var g = $G('dan','mak');
    console.log(g); // G…r.init {firstname: "dan", lastname: "mak", language: "en"}
```

### Part 3

```
    var supportedLang = ['en', 'es'];

        Greetr.prototype = {

    };
```

* The next part is really cool. Its just like constructing classes in C++.
* Each unique object will have access to methods defined without our prototype, thanks to our pointer fix.
* Variables constructed WITHIN the immediately invoked function will remain 'private' to the methods within the prototype.
  * That way, our framework is defined where it needs to be, and does not mess around with any global context.
  * Our prototype, however - maintains access to these variables because of closure.

```
    var greetings = {
        en: 'Hello',
        es: 'Hola'
    };

    var formalGreetings = {
        en: 'Greetings',
        es: 'Saludos'
    };

    var logMessages = {
        en: 'Logged In',
        es: 'Inicio sesion'
    };
```

* Next, we define a few reference variables for our prototype methods.

```
    fullname: function() {
        return this.firstname + ' ' + this.lastname;
    },

    validate: function() {
        if (supportedLang.indexOf(this.language) === -1) {
            throw "Invalid language";
        }
        else {
            console.log("Valid language");
        }
    },

    greeting: function() {
        return greetings[this.language] + ' ' + this.firstname + '!';
    },

    formalGreeting: function() {
        return formalGreetings[this.language] + ' ' + this.fullname();
    },

    greet: function(formal) {
        var msg;

        if (formal) {
            msg = this.formalGreeting();
        }

        else {
            msg = this.greeting();
        }

        //show whats happening
        if (console) {
            console.log(msg);
        }

        return this;
    },

    log: function() {
        //Internet explore check if console is open
        if (console) {
            console.log(logMessages[this.language] + ' ' + this.fullname());
        }

        //chainable
        return this;
    },

    setLang: function(lang) {
        this.language = lang;
        this.validate();
        return this;
    } 
```

* Each of these functions will reference with a uniquely constructed new object.
* This is why the keyword this becomes so important.
* validate searches through our index of supported languages with this.language, - the current language supplied to an object.
  * throws and error if the language is invalid.
* function greet is not required, but it grants chainable methods to our library. It also simplifies two methods with a single invocation
  * Optional boolean variable passed in to invoke a formal greeting.&#x20;
* At first I thought it was strange that setLand first let the language, and then validated it, but then I realized something.
  * Even if we change the language of an object to something that is not supported, it does not matter because it of this.validate().
  * If an error is thrown, then the setLand does not return, so it wouldn't allow it to pass through.
* Testing so far

```
    var a = g.fullname();
    console.log(a); // dan mak

    g.validate(); // Valid language

    var b = g.greeting(); 
    console.log(b); // Hello dan!

    var c = g.formalGreeting();
    console.log(c); // Greetings dan!

    g.greet(); // Hello dan!

    g.log(); // Logged In dan mak

    g.setLang('germen');
    g.validate(); //Uncaught Invalid language
```

### Part 3

* Adding jQuery support

&#x20;EnglishSpanish&#x20;

```
    HTMLGreeting: function(selector, formal) {
        if (!$) {
            throw 'Jquery not loaded';
        }

        if (!selector) {
            throw 'Missing Jquery selector';
        }

        var msg;
        if (formal) {
            msg = this.formalGreeting();
        }
        else {
            msg = this.greeting();
        }

        $(selector).html(msg);
        return this;
    }
```

* This function will be used to modify our html page once all of our variables are taken into account. The selector is a jQuery element.
  * Everything else references variables that are already known in the constructed object.
  * We also have a bit of jQuery code on the bottom, that is used to modify any html attribute.
* It is always best to commenet up your code once you finish. It may be understood now, but in time - the memory of your intents may be lost.&#x20;
* It also helps other coders.
* Since I've documented my thoughts here, I wont bother.

```
    $('#login').click(function() {
        var g = $G('dan','mak');
        var loginGreeter = g;

        $('#logindiv').hide();
        loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
    });
```

* Finally, its time to finish up our project by adding jQuery functionality to our html.
* That long chained method looks complecated, but lets break it down:
  * Using our constructed object, we set our variable property using a jQuery selector on the html element.
  * The next function call can be thought of as being executed on a new line.

## The Final Library/Framework

```
    //HTML
    <html>
    <head>

    </head>
    <body>
        <div id="logindiv">
            <select id="lang">
                <option value="en">English</option> 
                <option value="es">Spanish</option> 
            </select>
            <input type="button" value="Login" id="login">
        </div>

        <h1 id="greeting"></h1>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="Greetr.js"></script>
        <script src="app.js"></script>
    </body>                                            
    </html>


    //Greetr.js
    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }

        var supportedLang = ['en', 'es'];

        var greetings = {
            en: 'Hello',
            es: 'Hola'
        };

        var formalGreetings = {
            en: 'Greetings',
            es: 'Saludos'
        };

        var logMessages = {
            en: 'Logged In',
            es: 'Inicio sesion'
        };

        Greetr.prototype = {
            fullname: function() {
                return this.firstname + ' ' + this.lastname;
            },

            validate: function() {
                if (supportedLang.indexOf(this.language) === -1) {
                    throw "Invalid language";
                }
                else {
                    console.log("Valid language");
                }
            },

            greeting: function() {
                return greetings[this.language] + ' ' + this.firstname + '!';
            },

            formalGreeting: function() {
                return formalGreetings[this.language] + ' ' + this.fullname();
            },

            greet: function(formal) {
                var msg;

                if (formal) {
                    msg = this.formalGreeting();
                }

                else {
                    msg = this.greeting();
                }

                //show whats happening
                if (console) {
                    console.log(msg);
                }

                return this;
            },

            log: function() {
                //Internet explore check if console is open
                if (console) {
                    console.log(logMessages[this.language] + ' ' + this.fullname());
                }

                //chainable
                return this;
            },

            setLang: function(lang) {
                this.language = lang;
                this.validate();
                return this;
            },

            HTMLGreeting: function(selector, formal) {
                if (!$) {
                    throw 'Jquery not loaded';
                }

                if (!selector) {
                    throw 'Missing Jquery selector';
                }

                var msg;
                if (formal) {
                    msg = this.formalGreeting();
                }
                else {
                    msg = this.greeting();
                }

                $(selector).html(msg);
                return this;
            }

        };

        Greetr.init = function(first, last, lang) {
            this.firstname = first || '[users first name]';
            this.lastname = last || '[users last name]';
            this.language = lang || 'en';

            // check language
            this.validate();
        }

        Greetr.init.prototype = Greetr.prototype;

        global.Greetr = global.$G = Greetr;

    })(window, $)



    //app.js


    $('#login').click(function() {
        var g = $G('dan','mak');
        var loginGreeter = g;

        $('#logindiv').hide();
        loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
    });
```
