iDev: CSS inheritance sequence

CSS inheritance sequence

Starting today, I will also write about a few things CSS apart from Google Maps Javascript API and Jquery Mobile. I will cover some really interesting things in CSS and keep updating this blog as and when I learn something new and think its worth sharing with you all.

Today we will look at a very common mostly known thing in CSS – the inheritance sequence of CSS. Most of you reading this post must be aware that there are 3 ways in which you can include CSS into your web application.

  • External Stylesheet
  • Internal Stylesheet
  • Inline Styles
 
External Style Sheet
    An external style sheet is ideal when you are writing a style that would be applied across multiple pages. The external style sheet gives the developer lot of control over the look and feel of the entire website or web application. The external style sheet is included using the the “link” tag which is included in the head section.
<link rel=”stylesheet” href=”styles/default.css” />
Internal Style Sheet
    An internal style sheet is used usually when a single document has unique style. The internal styles are written as part of the “style” tag which is again included in the “head” section.
<style>
    p{
        font-size: 20px;
        color: #a123bb;
    }
</style>
Inline Style
    An inline style loses many of the advantages of style sheets by mixing the content with the presentation. Inline styles should generally be avoided and be used when absolutely necessary and unavoidable!
<p style=”font-size: 20px; color: #a123bb;”></p>
    As we know and/or have learned from experience, that these styles cascade into one, let’s say a “virtual” style sheet which gets applied on the entire web site/application. This cascade follows the following sequence to override each other and create one final style sheet. Number #4 in the following list has the highest priority in the cascade.
  1. Browser default styles
  2. External style sheet
  3. Internal style sheet
  4. Inline styles
    So an inline styles has the highest priority, meaning that it will override a style defined inside the “head” tag, or in an external style sheet or the default browser styles. However, there are a few cases where this sequence of cascade can change!
Case #1: Usage of the !important keyword
    In case there is the “!important” keyword associated with an of the styles, then that style would get applied irrespective of whether it is part of the internal or the external style sheet.
Case #2: Javascript
    When styles are applied through javascript, these styles will override all styles included as part of the internal or external style sheet or even the inline styles and the ones with even the “!important” keyword associated with them.
Case #3: Sequence of inclusion of stylesheets
    If the link to the external style sheet is placed after the internal style sheet in the “head” tag, the external style sheet will override the internal stye sheet!
    Hope you have enjoyed this post and learned a few new things. Do let me know in case you want me to include a topic as part of the blog and I would be happy to write about it! Till then keep reading and keep sharing.
Reference : Here
Advertisements

iDev : A DOM Manipulation Class in 100 Lines of JavaScript

Hi Friends

A DOM Manipulation Class in 100 Lines of JavaScript By Krasimir Tsonev

If you build web applications you probably deal with the DOM a lot. Accessing and manipulating DOM elements is a common requirement of nearly every web application. Very often we collect information from different controls, we need to set values, change the content of div or span tags. Of course there are a lot of libraries that help handle these actions, with the most popular being jQuery, of course, which is the de factor standard. However, sometimes you don’t need everything that jQuery provides, so in this article we will take a look at how to build your own class for managing DOM elements.

The API

As developers we make decisions every day. I believe in the test-driven development and one of the things which I really like is the fact that it forces you to make design decisions before you start the actual coding. Along those lines, here is what I want the DOM management class’s API to look like in the end:

// returns DOM element dom(‘.selector’).el // returns the value/content of the element dom(‘.selector’).val()  // sets the value/content of the element dom(‘.selector’).val(‘value’)

This should cover most of the possible use cases. However it would be even better if we could manipulate several objects at once. And it would be great if we could generate a JavaScript object.

// generates an object containing DOM elements dom({     structure: {         propA: ‘.selector’,         propB: ‘.selector’     },     propC: ‘.selector’ })

Once we have our elements stored we could easily execute the val method for all of them.

// retrieving the values of several DOM elements dom({     structure: {         propA: ‘.selector’,         propB: ‘.selector’     },     propC: ‘.selector’ }).val()

This will be aneffective method for translating data from the DOM directly into a JavaScript object.

Now that we have an idea of what our API should look like, our class starts with the following code:

var dom = function(el) {     var api = { el: null }     api.val = function(value) {         // …     }     return api; }

Scoping

It is clear that we are going to use methods like getElementById, querySelector or querySelectorAll. Typically, you might access the DOM like this:

var header = document.querySelector(‘.header’);

What is really interesting here is that querySelector, for example, is not just a method of the document object, but also of any other DOM element. This means that we are able to run the query in specific context. For example:

<header>     <p>Big</p> </header> <footer>     <p>Small</p> </footer>  var header = document.querySelector(‘header’); var footer = document.querySelector(‘footer’); console.log(header.querySelector(‘p’).textContent); // Big console.log(footer.querySelector(‘p’).textContent); // Small

We are able to operate within specific part of the DOM tree and our class should support the passing of a scope. So, together with a selector it would be good if it accepts a parent element.

var dom = function(el, parent) {     var api = { el: null }     api.val = function(value) {         // …     }     return api; }

Reaching the DOM element

As we said above, we are going to use querySelector and querySelectorAll to reach the DOM elements. Let’s create two shortcuts for these functions.

var qs = function(selector, parent) {     parent = parent || document;     return parent.querySelector(selector); }; var qsa = function(selector, parent) {     parent = parent || document;     return parent.querySelectorAll(selector); };

After that we should use the passed el argument. Normally this will be a string (selector) but we should also support:

  • A DOM element – the val method of the class will be pretty handy so we may need to use the class with already referenced element;
  • A JavaScript object – in order to create JavaScript object containing multiple DOM elements.

The following switch will cover both cases:

switch(typeof el) {     case ‘string’:         parent = parent && typeof parent === ‘string’ ? qs(parent) : parent;         api.el = qs(el, parent);     break;     case ‘object’:          if(typeof el.nodeName != ‘undefined’) {             api.el = el;         } else {             var loop = function(value, obj) {                 obj = obj || this;                 for(var prop in obj) {                     if(typeof obj[prop].el != ‘undefined’) {                         obj[prop] = obj[prop].val(value);                     } else if(typeof obj[prop] == ‘object’) {                         obj[prop] = loop(value, obj[prop]);                     }                 }                 delete obj.val;                 return obj;             }             var res = { val: loop };             for(var key in el) {                 res[key] = dom.apply(this, [el[key], parent]);             }             return res;         }     break; }

The first case is executed if the developer passes a string. We prepare the parent and call the querySelector shortcut. The second part of the statement is for the cases where we have a DOM element sent or a JavaScript object. We are checking if the object has nodeName property, and, if it does, then we directly apply it as a value of the api.el property. If it doesn’t, then we go through all the parts of the object and initialize a class instance for every property. Here are some test cases involving the following markup:

<p>text</p> <header>     <p>Big</p> </header> <footer>     <p>Small</p> </footer>

Accessing the first paragraph:

dom(‘p’).el

Accessing the paragraph in the header node:

dom(‘p’, ‘header’).el

Passing a DOM element:

dom(document.querySelector(‘header’)).el

Passing a JavaScript object:

var els = dom({     footer: ‘footer’,     paragraphs: {         header: ‘header p’,         footer: ‘footer p’     } })) // At the end we have again JavaScript object. // It’s properties are actually results // of dom function execution. For example, to get // the paragraph in the footer: els.paragraphs.footer.el

Getting or setting the value of an element

The value of the form elements like input or select could be retrieved easily – we can use the value property of the element. We already have an access to the DOM element – it is stored in api.el. However, it is a little bit tricky when we are working with radio or check boxes. For the other HTML nodes like divs, sections or spans for example we need to get the value of the textContent property. If there is no textContent defined then innerHTML will produce similar results. Let’s use another switch statement:

api.val = function(value) {     if(!this.el) return null;     var set = !!value;     var useValueProperty = function(value) {         if(set) { this.el.value = value; return api; }         else { return this.el.value; }     }     switch(this.el.nodeName.toLowerCase()) {         case ‘input’:         break;         case ‘textarea’:         break;         case ‘select’:                       break;         default:     }     return set ? api : null; }

First of all we need to have api.el defined. The variable set is a boolean telling us if we are retrieving or setting the value of the element. There is a helper method defined for those elements which have .value property. The switch will contain the actual logic of the method. At the end we are returning the API itself in order to chain the methods of the class. Of course we are doing this only if we are using the function as a setter.

Let’s see how to handle the different types of elements. For example the input node:

case ‘input’:     var type = this.el.getAttribute(‘type’);     if(type == ‘radio’ || type == ‘checkbox’) {         var els = qsa(‘[name=”‘ + this.el.getAttribute(‘name’) + ‘”]’, parent);         var values = [];         for(var i=0; i<els.length; i++) {             if(set && els[i].checked && els[i].value !== value) {                 els[i].removeAttribute(‘checked’);             } else if(set && els[i].value === value) {                 els[i].setAttribute(‘checked’, ‘checked’);                 els[i].checked = ‘checked’;             } else if(els[i].checked) {                 values.push(els[i].value);             }         }         if(!set) { return type == ‘radio’ ? values[0] : values; }     } else {         return useValueProperty.apply(this, [value]);     } break;

This is may be the most interesting case. There are two types of elements which need to be processed differently – radio and check boxes. These elements are grouped into sets and we need to keep this in mind. That’s why we are using querySelectorAll to fetch the whole group and find out which one is selected/checked. It’s even more complex, because a group of check boxes could have more then one value. The method above successfully handles all these situations.

The processing of a textarea element is pretty simple thanks to the helper we wrote above.

case ‘textarea’:      return useValueProperty.apply(this, [value]);  break;

Here’s how we handle a drop down (select):

case ‘select’:     if(set) {         var options = qsa(‘option’, this.el);         for(var i=0; i<options.length; i++) {             if(options[i].getAttribute(‘value’) === value) {                 this.el.selectedIndex = i;             } else {                 options[i].removeAttribute(‘selected’);             }         }     } else {         return this.el.value;     } break;

And this will process everything else:

default:      if(set) {         this.el.innerHTML = value;     } else {         if(typeof this.el.textContent != ‘undefined’) {             return this.el.textContent;         } else if(typeof this.el.innerText != ‘undefined’) {             return typeof this.el.innerText;         } else {             return this.el.innerHTML;         }     } break;

With these lines of code we have finished our val method. Here is a short HTML form and its corresponding test:

<form>     <input type=”text” value=”sample text” />     <input type=”radio” name=”options” value=”A”>     <input type=”radio” name=”options” checked value=”B”>     <select>         <option value=”10″></option>         <option value=”20″></option>         <option value=”30″ selected></option>     </select>     <footer>version: 0.3</footer> </form>

If we use the following code:

dom({     name: ‘[type=”text”]’,     data: {         options: ‘[type=”radio”]’,         count: ‘select’     },     version: ‘footer’ }, ‘form’).val();

We will get:

{     data: {         count: “30”,         options: “B”     },     name: “sample text”,     version: “version: 0.3” }

This method could be really helpful if you want to translate a data from HTML form into JavaScript object. This is a pretty common task that many of us need to accomplish almost every day.

Final result

The finished class is only 100 lines of code but it still gives us what we need to access DOM elements and to get or set their value/content.

var dom = function(el, parent) {     var api = { el: null }     var qs = function(selector, parent) {         parent = parent || document;         return parent.querySelector(selector);     };     var qsa = function(selector, parent) {         parent = parent || document;         return parent.querySelectorAll(selector);     };     switch(typeof el) {         case ‘string’:             parent = parent && typeof parent === ‘string’ ? qs(parent) : parent;             api.el = qs(el, parent);         break;         case ‘object’:              if(typeof el.nodeName != ‘undefined’) {                 api.el = el;             } else {                 var loop = function(value, obj) {                     obj = obj || this;                     for(var prop in obj) {                         if(typeof obj[prop].el != ‘undefined’) {                             obj[prop] = obj[prop].val(value);                         } else if(typeof obj[prop] == ‘object’) {                             obj[prop] = loop(value, obj[prop]);                         }                     }                     delete obj.val;                     return obj;                 }                 var res = { val: loop };                 for(var key in el) {                     res[key] = dom.apply(this, [el[key], parent]);                 }                 return res;             }         break;     }     api.val = function(value) {         if(!this.el) return null;         var set = !!value;         var useValueProperty = function(value) {             if(set) { this.el.value = value; return api; }             else { return this.el.value; }         }         switch(this.el.nodeName.toLowerCase()) {             case ‘input’:                 var type = this.el.getAttribute(‘type’);                 if(type == ‘radio’ || type == ‘checkbox’) {                     var els = qsa(‘[name=”‘ + this.el.getAttribute(‘name’) + ‘”]’, parent);                     var values = [];                     for(var i=0; i<els.length; i++) {                         if(set && els[i].checked && els[i].value !== value) {                             els[i].removeAttribute(‘checked’);                         } else if(set && els[i].value === value) {                             els[i].setAttribute(‘checked’, ‘checked’);                             els[i].checked = ‘checked’;                         } else if(els[i].checked) {                             values.push(els[i].value);                         }                     }                     if(!set) { return type == ‘radio’ ? values[0] : values; }                 } else {                     return useValueProperty.apply(this, [value]);                 }             break;             case ‘textarea’:                  return useValueProperty.apply(this, [value]);              break;             case ‘select’:                 if(set) {                     var options = qsa(‘option’, this.el);                     for(var i=0; i<options.length; i++) {                         if(options[i].getAttribute(‘value’) === value) {                             this.el.selectedIndex = i;                         } else {                             options[i].removeAttribute(‘selected’);                         }                     }                 } else {                     return this.el.value;                 }             break;             default:                  if(set) {                     this.el.innerHTML = value;                 } else {                     if(typeof this.el.textContent != ‘undefined’) {                         return this.el.textContent;                     } else if(typeof this.el.innerText != ‘undefined’) {                         return typeof this.el.innerText;                     } else {                         return this.el.innerHTML;                     }                 }             break;         }         return set ? api : null;     }     return api; }

I’ve created a JSBin example that you can play with to see how the class works.

Summary

The class I discussed above is part of the AbsurdJS client-side components. The full documentation for the module could be found here. The aim of the code is not to replace jQuery or the dozens of popular libraries available for DOM access. The idea of the function is to be independent, to do only one thing and to do it well. Which is the main concept behind AbsurdJS and its build-in modules like the router or Ajax wrapper.

iPhonegap: Developing a PhoneGap Application

Tutorial: Developing a PhoneGap Application

Reference : Here

In this tutorial, you create a fully functional employee directory application with PhoneGap. You will learn:

  • How to use different local data storage strategies.
  • How to use several PhoneGap APIs such as Geolocation, Contacts, and Camera.
  • How to handle specific mobile problems such as touch events, scrolling, styling, page transitions, etc.
  • How to build an application using a single page architecture and HTML templates.
  • How to build (compile and package) an application for 6 platforms using PhoneGap Build.

To complete this tutorial, all you need is a code editor, a modern browser, and a connection to the Internet. A working knowledge of HTML and JavaScript is assumed, but you don’t need to be a JavaScript guru.

Setting Up

  1. Download the assets for the workshop here.
  2. Unzip the file anywhere on your file system.
  3. If your code editor allows you to “open a directory”, open the phonegap-workshop-master directory.
  4. Follow the instructions below.
Step-by-step solution files are also available here.

Part 1: Choosing a Local Storage Option


Step 1: Explore different persistence mechansisms

Open the following files in phonegap-workshop-master/js/storage, and explore the different persistence stores they define:

  1. memory-store.js (MemoryStore)
  2. ls-store.js (LocalStorageStore)
  3. websql-store.js (WebSqlStore)

Step 2: Test the application with different persistence mechanisms

To change the local persistence mechanism for the application:

  1. In index.html: add a script tag for the corresponding .js file: memory-store.jsls-store.js, or websql-store.js.
  2. In js/main.js: Instantiate the specific store in the initialize() function of the app object: MemoryStoreLocalStorageStore, or WebSqlStore.
  3. To test the application, open index.html in your browser, or simply double-click index.html on your file system. Type a few characters in the search box to search employees by name. Clicking an employee link doesn’t produce any result at this time.

Part 2: Building with PhoneGap Build


  1. If you don’t already have one, create an account on http://build.phonegap.com.
  2. Click the “new app” button to create a new application on PhoneGap Build.
  3. Either point to a GitHub repository where you push your code for this workshop, or zip up your phonegap-workshop directory and upload it to PhoneGap Build.
  4. Click the Ready to build button.
    The iOS button will immediately turn red because the iOS build requires that you upload your Apple Developer certificate and an application provisioning profile. You can find more information here if you haven’t already signed up for the Apple Developer Program. If you don’t have an iOS device, or if you are not ready to upload your developer certificate, you can skip step 5 and keep running the application in the browser or a non iOS device.
  5. To upload your Apple developer certificate and your application provisioning profile:
    • Click the red iOS button.
    • Select “add a key” in the “No key selected” dropdown.
    • Provide a title for your developer certificate/provisioning profile combination (for example: EmployeeDirectory), select your developer certificate and provisioning profile, enter your developer certificate password, and click “submit key”.
    • Go back to the list of apps. Click the iOS button for your application again. Select your newly added key in the iOS dropdown. The iOS build will start automatically.
  6. When the build process completes, use a QR Code reader app to install the Employee Directory application on your device.

To fine tune your build preferences:

  1. In the phonegap-workshop directory, create a file namedconfig.xml file defined as follows (make the necessary adjustments for id, author, etc.):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8"?>
    <widget xmlns       = "http://www.w3.org/ns/widgets"
            xmlns:gap   = "http://phonegap.com/ns/1.0"
            id          = "org.coenraets.employeedirectory"
            versionCode = "10"
            version     = "1.1.0">
        <name>Employee Directory</name>
        <description>
            A simple employee directory application
        </description>
        <author href="http://coenraets.org" email="ccoenraets@gmail.com">
            Christophe Coenraets
        </author>
        <feature name="http://api.phonegap.com/1.0/camera"/>
        <feature name="http://api.phonegap.com/1.0/contacts"/>
        <feature name="http://api.phonegap.com/1.0/file"/>
        <feature name="http://api.phonegap.com/1.0/geolocation"/>
        <feature name="http://api.phonegap.com/1.0/media"/>
        <feature name="http://api.phonegap.com/1.0/network"/>
    </widget>
  2. If you used the GitHub approach, sync with GitHub and click the Update Code button in PhoneGap Build.
    If you used the zip file approach, zip up your phonegap-workshop directory and upload the new version to PhoneGap Build
There are many other parameters you can specify in config.xml to configure the build process. See the documentation for config.xmlhere.

Part 3: Using Native Notification


A default webview alert gives away the fact that your application is not native. In this section, we set up the basic infrastructure to display native alerts when the application is running on a device, and fall back to default browser alerts when running in the browser.

  1. In index.html, add the following script tag (as the first script tag at the bottom of the body):
    1
    <script src="phonegap.js"></script>

    This instructs PhoneGap Build to inject a platform specific version of phonegap.js at build time. In other words, phonegaps.js doesn’t need to be (and shouldn’t be) present in your project folder.

  2. In main.js, define a function named showAlert() inside the app object. If navigator.notification is available, use its alert() function. Otherwise, use the default browser alert() function.
    1
    2
    3
    4
    5
    6
    7
    showAlert: function (message, title) {
        if (navigator.notification) {
            navigator.notification.alert(message, null, title, 'OK');
        } else {
            alert(title ? (title + ": " + message) : message);
        }
    },
  3. Test the notification logic by displaying a message when the application store has been initialized: Pass an anonymous callback function as an argument to the constructor of the persistence store (the store will call this function after it has successfully initialized). In the anonymous function, invoke the showAlert() function.
    1
    2
    3
    4
    5
    6
    7
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            self.showAlert('Store Initialized', 'Info');
        });
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    }
  4. Test the application: When you run the application in the browser, you should see a standard browser alert. When you run the application on your device, you should see a native alert.

Part 4: Setting Up a Single Page Application


A single page application is a web application that lives within a single HTML page. The “views” of the application are injected into- and removed from the DOM as needed as the user navigates through the app. A single page application architecture is particularly well suited for mobile apps:

  • The absence of continual page refreshes provides a more fluid / closer to native experience.
  • The UI is entirely created at the client-side with no dependency on a server to create the UI, making it an ideal architecture for applications that work offline.

In this section, we set up the basic infrastructure to turn Employee Directory into a single page application.

  1. In index.html: remove the HTML markup inside the body tag (with the exception of the script tags).
  2. In main.js, define a function named renderHomeView() inside the app object. Implement the function to programmatically add the Home View markup to the body element.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    renderHomeView: function() {
        var html =
                "<div class='header'><h1>Home</h1></div>" +
                "<div class='search-view'>" +
                "<input class='search-key'/>" +
                "<ul class='employee-list'></ul>" +
                "</div>"
        $('body').html(html);
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    },
  3. Modify the initialize() function of the app object. In the anonymous callback function of the store constructor, call the renderHomeView() function to programmatically display the Home View.
    1
    2
    3
    4
    5
    6
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            self.renderHomeView();
        });
    }

Part 5: Using Handlebar Templates


Writing HTML fragments in JavaScript and programmatically inserting them into the DOM is tedious. It makes your application harder to write and harder to maintain. HTML templates address this issue by decoupling the UI definition (HTML markup) from your code. There are a number of great HTML template solutions: Mustache.js, Handlebar.js, and Underscore.js to name a few.

In this section, we create two templates to streamline the code of the Employee Directory application. We use Handlebar.js but the smae result can be achieved using the other HTML template solutions.

Modify index.html as follows:

  1. Add a script tag to include the handlebar.js library:
    1
    <script src="lib/handlebars.js"></script>
  2. Create an HTML template to render the Home View. Add this script tag as the first child of the body tag:
    1
    2
    3
    4
    5
    <script id="home-tpl" type="text/x-handlebars-template">
        <div class='header'><h1>Home</h1></div>
        <div class='search-bar'><input class='search-key' type="text"/></div>
        <ul class='employee-list'></ul>
    </script>
  3. Create an HTML template to render the employee list items. Add this script tag immediately after the previous one:
    1
    2
    3
    4
    5
    <script id="employee-li-tpl" type="text/x-handlebars-template">
        {{#.}}
        <li><a href="#employees/{{this.id}}">{{this.firstName}} {{this.lastName}}<br/>{{this.title}}</a></li>
        {{/.}}
    </script>

Modify main.js as follows:

  1. In the initialize() function of the app object, add the code to compile the two templates defined above:
    1
    2
    this.homeTpl = Handlebars.compile($("#home-tpl").html());
    this.employeeLiTpl = Handlebars.compile($("#employee-li-tpl").html());
  2. Modify renderHomeView() to use the homeTpl template instead of the inline HTML:
    1
    2
    3
    4
    renderHomeView: function() {
        $('body').html(this.homeTpl());
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    },
  3. Modify findByName() to use the employeeLiTpl template instead of the inline HTML:
    1
    2
    3
    4
    5
    6
    findByName: function() {
        var self = this;
        this.store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(self.employeeLiTpl(employees));
        });
    },
  4. Test the application.

Part 6: Creating a View Class


It’s time to provide our application with some structure. If we keep adding all the core functions of the application to the app object, it will very quickly grow out of control. In this section we create a HomeView object that encapsulates the logic to create and render the Home view.

Step 1: Create the HomeView Class

  1. Create a file called HomeView.js in the js directory, and define a HomeView class implemented as follows:
    1
    2
    3
    4
    var HomeView = function(store) {
    }
  2. Add the two templates as static members of HomeView.
    1
    2
    3
    4
    5
    6
    7
    var HomeView = function(store) {
    }
    HomeView.template = Handlebars.compile($("#home-tpl").html());
    HomeView.liTemplate = Handlebars.compile($("#employee-li-tpl").html());
  3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view-related events. Invoke the initialize() function inside the HomeView constructor function.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var HomeView = function(store) {
        this.initialize = function() {
            // Define a div wrapper for the view. The div wrapper is used to attach events.
            this.el = $('<div/>');
            this.el.on('keyup', '.search-key', this.findByName);
        };
        this.initialize();
    }
    HomeView.template = Handlebars.compile($("#home-tpl").html());
    HomeView.liTemplate = Handlebars.compile($("#employee-li-tpl").html());
  4. Move the renderHomeView() function from the app object to the HomeView class. To keep the view reusable, attach the html to the div wrapper (this.el) instead of the document body. Because the function is now encapsulated in the HomeView class, you can also rename it from renderHomeView() to just render().
    1
    2
    3
    4
    this.render = function() {
        this.el.html(HomeView.template());
        return this;
    };
  5. Move the findByName() function from the app object to the HomeView class.
    1
    2
    3
    4
    5
    this.findByName = function() {
        store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(HomeView.liTemplate(employees));
        });
    };

Step 2: Using the HomeView class

  1. In index.html, add a script tag to include HomeView.js (just before the script tag for main.js):
    1
    <script src="js/HomeView.js"></script>
  2. Remove the renderHomeView() function from the app object.
  3. Remove the findByName() function from the app object.
  4. Modify the initialize function() to display the Home View using the HomeView class:
    1
    2
    3
    4
    5
    6
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            $('body').html(new HomeView(self.store).render().el);
        });
    }

Part 7: Adding Styles and Touch-Based Scrolling


Step 1: Style the Application

  1. Add the Source Sans Pro font definition to the head of index.html
    1
    <script src="css/source-sans-pro.js"></script>

    Source Sans Pro is part of the free Adobe Edge Web Fonts.

  2. Add styles.css to the head of index.html
    1
    <link href="css/styles.css" rel="stylesheet">
  3. In index.html, modify the home-tpl template: change the search-key input type from text to search.
  4. Test the application. Specifically, test the list behavior when the list is bigger than the browser window (or the screen)

Step 2: Native Scrolling Approach

  1. Modify the home-tpl template in index.html. Add a div wrapper with a scroll class around the ul element with a scroll:
    1
    2
    3
    4
    5
    <script id="home-tpl" type="text/x-handlebars-template">
        <div class='header'><h1>Home</h1></div>
        <div class='search-bar'><input class='search-key' type="search"/></div>
        <div class="scroll"><ul class='employee-list'></ul></div>
    </script>
  2. Add the following class definition to css/styles.css:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .scroll {
        overflow: auto;
        -webkit-overflow-scrolling: touch;
        position: absolute;
        top: 84px;
        bottom: 0px;
        left: 0px;
        right: 0px;
    }
If the platforms you target support touch-based scrolling of fixed regions, this approach is all you need (you can skip step 3 below). If not, you’ll need to implement a programmatic approach, typically with the help of a library such as iScroll.

Step 3: iScroll Approach

  1. Add a script tag to include the iscroll.js library:
    1
    <script src="lib/iscroll.js"></script>
  2. In HomeView.js, modify the findByName() function: Instantiate an iScroll object to scroll the list of employees returned. If the iScroll object already exists (), simply refresh it to adapt it to the new size of the list.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    this.findByName = function() {
        store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(HomeView.liTemplate(employees));
            if (self.iscroll) {
                console.log('Refresh iScroll');
                self.iscroll.refresh();
            } else {
                console.log('New iScroll');
                self.iscroll = new iScroll($('.scroll', self.el)[0], {hScrollbar: false, vScrollbar: false });
            }
        });
    };
More information on iScroll is available here.

Part 8: Highlighting Tapped or Clicked UI Elements


  1. In styles.css, add a tappable-active class definition for tapped or clicked list item links. The class simply highlights the item with a blue background:
    1
    2
    3
    4
    li>a.tappable-active {
        color: #fff;
        background-color: #4286f5;
    }
  2. In main.js, define a registerEvents() function inside the app object. Add a the tappable_active class to the selected (tapped or clicked) list item:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    registerEvents: function() {
        var self = this;
        // Check of browser supports touch events...
        if (document.documentElement.hasOwnProperty('ontouchstart')) {
            // ... if yes: register touch event listener to change the "selected" state of the item
            $('body').on('touchstart', 'a', function(event) {
                $(event.target).addClass('tappable-active');
            });
            $('body').on('touchend', 'a', function(event) {
                $(event.target).removeClass('tappable-active');
            });
        } else {
            // ... if not: register mouse events instead
            $('body').on('mousedown', 'a', function(event) {
                $(event.target).addClass('tappable-active');
            });
            $('body').on('mouseup', 'a', function(event) {
                $(event.target).removeClass('tappable-active');
            });
        }
    },
  3. Invoke the registerEvents() function from within the app object’s initialize() function.
  4. Test the application.

Part 9: View Routing


In this section, we add an employee details view. Since the application now has more than one view, we also add a simple view routing mechanism that uses the hash tag to determine whether to display the home view or the details view for a specific employee.

Step 1: Create the employee template

Open index.html and add a template to render a detailed employee view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script id="employee-tpl" type="text/x-handlebars-template">
    <div class='header'><a href='#' class="button header-button header-button-left">Back</a><h1>Details</h1></div>
    <div class='details'>
        <img class='employee-image' src='img/{{firstName}}_{{lastName}}.jpg' />
        <h1>{{firstName}} {{lastName}}</h1>
        <h2>{{title}}</h2>
        <span class="location"></span>
        <ul>
            <li><a href="tel:{{officePhone}}">Call Office<br/>{{officePhone}}</a></li>
            <li><a href="tel:{{cellPhone}}">Call Cell<br/>{{cellPhone}}</a></li>
            <li><a href="sms:{{cellPhone}}">SMS<br/>{{cellPhone}}</a></li>
        </ul>
    </div>
</script>

Step 2: Create the EmployeeView class

  1. Create a file called EmployeeView.js in the js directory, and define an EmployeeView class implemented as follows:
    1
    2
    3
    4
    var EmployeeView = function() {
    }
  2. Add the template as a static member of EmployeeView.
    1
    2
    3
    4
    5
    6
    var EmployeeView = function() {
    }
    EmployeeView.template = Handlebars.compile($("#employee-tpl").html());
  3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view related events. Invoke the initialize() function inside the HomeView constructor function.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var EmployeeView = function(employee) {
        this.initialize = function() {
            this.el = $('<div/>');
        };
        this.initialize();
     }
    EmployeeView.template = Handlebars.compile($("#employee-tpl").html());
  4. Define a render() function implemented as follows:
    1
    2
    3
    4
    this.render = function() {
        this.el.html(EmployeeView.template(employee));
        return this;
    };
  5. In index.html, add a script tag to include EmployeeView.js (just before the script tag for main.js):
    1
    <script src="js/EmployeeView.js"></script>

Step 3: Implement View Routing

  1. In the app’s initialize() function, define a regular expression that matches employee details urls.
    1
    this.detailsURL = /^#employees\/(\d{1,})/;
  2. In the app’s registerEvents() function, add an event listener to listen to URL hash tag changes:
    1
    $(window).on('hashchange', $.proxy(this.route, this));
  3. In the app object, define a route() function to route requests to the appropriate view:
    • If there is no hash tag in the URL: display the HomeView
    • If there is a has tag matching the pattern for an employee details URL: display an EmployeeView for the specified employee.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    route: function() {
        var hash = window.location.hash;
        if (!hash) {
            $('body').html(new HomeView(this.store).render().el);
            return;
        }
        var match = hash.match(app.detailsURL);
        if (match) {
            this.store.findById(Number(match[1]), function(employee) {
                $('body').html(new EmployeeView(employee).render().el);
            });
        }
    }
  4. Modify the initialize() function to call the route() function:
    1
    2
    3
    4
    5
    6
    7
    8
    initialize: function() {
        var self = this;
        this.detailsURL = /^#employees\/(\d{1,})/;
        this.registerEvents();
        this.store = new MemoryStore(function() {
            self.route();
        });
    }
  5. Test the application.

Part 10: Using the Location API


In this section, we add the ability to tag an employee with his/her location information. In this sample application, we display the raw information (longitude/latitude) in the employee view. In a real-life application, we would typically save the location in the database as part of the employee information and show it on a map.

The code below works when running the application as a PhoneGap app on your device. It should also work in Chrome on the desktop when the page is served with the http:// protocol, and in Firefox, regardless of the protocol (http:// or file://).
  1. In index.html, add the following list item to the employee-tpl template:
    1
    <li><a href="#" class="add-location-btn">Add Location</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Add Location list item:
    1
    this.el.on('click', '.add-location-btn', this.addLocation);
  3. In EmployeeView, define the addLocation event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    this.addLocation = function(event) {
        event.preventDefault();
        console.log('addLocation');
        navigator.geolocation.getCurrentPosition(
            function(position) {
                $('.location', this.el).html(position.coords.latitude + ',' + position.coords.longitude);
            },
            function() {
                alert('Error getting location');
            });
        return false;
    };
  4. Test the Application

Part 11: Using the Contacts API


In this section, we use the PhoneGap Contacts API to provide the user with the ability to add an employee to the device’s contact list.

The code below only works when running the application on your device as a PhoneGap app. In other words, you can’t test it in a browser on the desktop.
  1. In index.html, add the following list item to the employee template:
    1
    <li><a href="#" class="add-contact-btn">Add to Contacts</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Add to Contacts list item:
    1
    this.el.on('click', '.add-contact-btn', this.addToContacts);
  3. In EmployeeView, define the addToContacts event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    this.addToContacts = function(event) {
        event.preventDefault();
        console.log('addToContacts');
        if (!navigator.contacts) {
            app.showAlert("Contacts API not supported", "Error");
            return;
        }
        var contact = navigator.contacts.create();
        contact.name = {givenName: employee.firstName, familyName: employee.lastName};
        var phoneNumbers = [];
        phoneNumbers[0] = new ContactField('work', employee.officePhone, false);
        phoneNumbers[1] = new ContactField('mobile', employee.cellPhone, true); // preferred number
        contact.phoneNumbers = phoneNumbers;
        contact.save();
        return false;
    };
  4. Test the Application

Part 12: Using the Camera API


In this section, we use the PhoneGap Camera API to provide the user with the ability to take a picture of an employee, and use that picture as the employee’s picture in the application. We do not persist that picture in this sample application.

The code below only works when running the application on your device as a PhoneGap app. In other words, you can’t test it in a browser on the desktop.
  1. In index.html, add the following list item to the employee template:
    1
    <li><a href="#" class="change-pic-btn">Change Picture</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Change Picture list item:
    1
    this.el.on('click', '.change-pic-btn', this.changePicture);
  3. In EmployeeView, define the changePicture event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    this.changePicture = function(event) {
        event.preventDefault();
        if (!navigator.camera) {
            app.showAlert("Camera API not supported", "Error");
            return;
        }
        var options =   {   quality: 50,
                            destinationType: Camera.DestinationType.DATA_URL,
                            sourceType: 1,      // 0:Photo Library, 1=Camera, 2=Saved Photo Album
                            encodingType: 0     // 0=JPG 1=PNG
                        };
        navigator.camera.getPicture(
            function(imageData) {
                $('.employee-image', this.el).attr('src', "data:image/jpeg;base64," + imageData);
            },
            function() {
                app.showAlert('Error taking picture', 'Error');
            },
            options);
        return false;
    };
  4. Test the Application

Part 13: Sliding Pages with CSS Transitions


  1. Add the following classes to styles.css:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    .page {
        position: absolute;
        width: 100%;
        height: 100%;
        -webkit-transform:translate3d(0,0,0);
    }
    .stage-center {
        top: 0;
        left: 0;
    }
    .stage-left {
        left: -100%;
    }
    .stage-right {
        left: 100%;
    }
    .transition {
        -moz-transition-duration: .375s;
        -webkit-transition-duration: .375s;
        -o-transition-duration: .375s;
    }
  2. Inside the app object, define a slidePage() function implemented as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    slidePage: function(page) {
        var currentPageDest,
            self = this;
        // If there is no current page (app just started) -> No transition: Position new page in the view port
        if (!this.currentPage) {
            $(page.el).attr('class', 'page stage-center');
            $('body').append(page.el);
            this.currentPage = page;
            return;
        }
        // Cleaning up: remove old pages that were moved out of the viewport
        $('.stage-right, .stage-left').not('.homePage').remove();
        if (page === app.homePage) {
            // Always apply a Back transition (slide from left) when we go back to the search page
            $(page.el).attr('class', 'page stage-left');
            currentPageDest = "stage-right";
        } else {
            // Forward transition (slide from right)
            $(page.el).attr('class', 'page stage-right');
            currentPageDest = "stage-left";
        }
        $('body').append(page.el);
        // Wait until the new page has been added to the DOM...
        setTimeout(function() {
            // Slide out the current page: If new page slides from the right -> slide current page to the left, and vice versa
            $(self.currentPage.el).attr('class', 'page transition ' + currentPageDest);
            // Slide in the new page
            $(page.el).attr('class', 'page stage-center transition');
            self.currentPage = page;
        });
    },
  3. Modify the route() function as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    route: function() {
        var self = this;
        var hash = window.location.hash;
        if (!hash) {
            if (this.homePage) {
                this.slidePage(this.homePage);
            } else {
                this.homePage = new HomeView(this.store).render();
                this.slidePage(this.homePage);
            }
            return;
        }
        var match = hash.match(this.detailsURL);
        if (match) {
            this.store.findById(Number(match[1]), function(employee) {
                self.slidePage(new EmployeeView(employee).render());
            });
        }
    },

    Thanks , Keep Coding 🙂

iConcept : What is DOM ?

 

What is DOM (Document Object Model): Tree and Node Structure of HTML Page

The Document Object Model (DOM) defines a standard way for accessing and manipulating HTML documents. The DOM presents an HTML document as a TREE-STRUCTURE. The DOM is a W3C (World Wide Web Consortium) standard. The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a document.

The Document Object Model (DOM) is the model that describes how all elements in an HTML page, like input fields, images, paragraphs etc., are related to the topmost structure: the document itself.
DOM: The Tree and Node Structure
The HTML DOM views an HTML document as a tree-structure. The tree structure is called a node-tree. In the DOM, everything in an HTML document is a node. All nodes can be accessed through the tree. Their contents can be modified or deleted, and new elements can be created.
Note: The Root Node of DOM Tree is DOCUMENT.
document.documentElement – returns the root node of the document
document.body – gives direct access to the <body> tag
The nodes in the node tree have a hierarchical relationship to each other. On the basis of hierarchy, Nodes can be divided into three categories:
1. Parent Nodes
2. Child Nodes
3. Sibling Nodes:
  Child Nodes on the same level are called siblings (brothers or sisters).
Example:
<p>This is a paragraph</p>
Here “p” is parent node and ‘This is a paragraph’ is a child node.
Note:
1. In a node tree, the top node is called the root
2. Every node, except the root, has exactly one parent node
3. A node can have any number of children
4. A leaf is a node with no children
5. Siblings are nodes with the same parent
Nodes can also be classified as:
1. Element Nodes: Every HTML element is an element node
2. Text Nodes: The text in the HTML elements are text nodes. In the HTML DOM the value of the text node can be accessed by the innerHTML property.
3. Attribute Nodes: Every HTML attribute is an attribute node
4. Comment Nodes: Comments are also treated as nodes in DOM.
5. Document Node: It is the parent node of DOM.. The entire document is a document node
Example:
<p align=”right”>This is a paragraph</p>
Here “p” is element node, ‘This is a paragraph” is a text node and “align” is the attribute node.
Node Properties
In the HTML DOM, each node is an object.Objects have methods and properties that can be accessed and manipulated by JavaScript. Three important node properties are:
1. nodeName
2. nodeValue
3. nodeType
The nodeName Property
The nodeName property specifies the name of a node.
1. nodeName is read-only
2. nodeName of an element node is the same as the tag name
3. nodeName of an attribute node is the attribute name
4. nodeName of a text node is always #text
5. nodeName of the document node is always #document
Note: nodeName always contains the uppercase tag name of an HTML element.
The nodeValue Property
1. The nodeValue property specifies the value of a node.
2. nodeValue for element nodes is undefined
3. nodeValue for text nodes is the text itself
4. nodeValue for attribute nodes is the attribute value
The nodeType Property
The nodeType property returns the type of node. nodeType is read only.
The most important node types are: Element Node, Text Node, Attribute Node, Comment Node and Document Node
HTML DOM Methods:
x.getElementById(id) – get the element with a specified id
x.getElementsByTagName(name) – get all elements with a specified tag name
x.appendChild(node) – insert a child node to x
x.removeChild(node) – remove a child node from x
Note: In the list above, x is a node object (HTML element or node, say document).
HTML DOM Properties
x.innerHTML – the text value of x
x.nodeName – the name of x
x.nodeValue – the value of x
x.parentNode – the parent node of x
x.childNodes – the child nodes of x
x.attributes – the attributes nodes of x
Note: In the list above, x is a node object (HTML element or node, say <p>).
Reference : Click Here

 

iConcept: GET vs POST

 GET vs POST: Which one is better? A 10 point comparison
1. Data Size Restriction in GET: There is a character restriction of 255 in the URL. This is mostly the old browsers restriction and new ones can handle more than that. But we can’t be sure that all our visitors are using new browsers. So when we show a text area or a text box asking users to enter some data, then there will be a problem if more data is entered. This restriction is not there in POST method. We can transfer unlimited data using POST. In PHP by default 8MB of data can be transferred. (can be changed by setting the post_max_size in the php.ini file)
2. Data Type Restriction in GET: As the data transfers through address bar ( URL ) there are some restrictions in using space, some characters like ampersand ( & ) etc in the GET method of posting data. We have to take special care for encoding (while sending) and decoding (while receiving) data if such special characters are present.
3. Security: In GET method data gets transferred to the processing page in name value pairs as a query string in URL, so it is exposed and can be easily traced by visiting history pages of the browser. Data is always submitted in the form of text. So any login details with password should never be posted by using GET method. On the other hand, POST is much more secure. In case of POST, all the name value pairs are submitted in the Message Body of the request.
4. Speed: GET is faster than POST.
5. Bookmarking: There are some special cases where advantage of using GET method is, one can store the name value pairs as bookmark and directly use them by bypassing the form. But you cannot bookmark using POST method.
6. If POST method is used and if the page is refreshed it would prompt before the request is resubmitted but it would not prompt if GET method is used.
7. Uploading files through input type file is possible in POST but not with GET method.
8. There are chances for data lost after server encoding in GET method but no data loss occurs in case of POST method.
9. GET uses STACK method for passing form variables while POST method uses HEAP method for passing form variables.
10. GET can store up to 18 form variables but there is no limit in case of POST method.
Reference : Click Here
Thanks :), Keep Coding:)