Showing posts with label html. Show all posts
Showing posts with label html. Show all posts

Apr 11, 2014

Extending the JavaScript HTML5 Canvas object

I have been playing with JavaScript, trying to find new and interesting way to use it in browsers. I have found the wonder that is CANVAS, which allows you to do a whole lot of drawing and animation tasks.

The problem is that the features are low-level, meaning you need to write a lot of code to make anything useful or interesting. A nice technique is to use the prototyping feature of JavaScript to extend the features of canvas. Here are some examples:

if (window.CanvasRenderingContext2D) {
    /**
     * Rounded Rectangle
     */
    CanvasRenderingContext2D.prototype.roundedRect = function(x, y, width, height, radius, colour, border, lineWidth, alpha) {
        // if certain values are not set just exit
        if(!x || !y || !width || !height) { return true; }
        // Set other values
        if (!radius) { radius = 5; }
        if (!alpha) { alpha=1; }
        // Start drawing the rounded rectangle
        this.beginPath();
        this.moveTo(x + radius, y);
        this.lineTo(x + width - radius, y);
        this.quadraticCurveTo(x + width, y, x + width, y + radius);
        this.lineTo(x + width, y + height - radius);
        this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
        this.lineTo(x + radius, y + height);
        this.quadraticCurveTo(x, y + height, x, y + height - radius);
        this.lineTo(x, y + radius);
        this.quadraticCurveTo(x, y, x + radius, y);
        // Colour it in
        if (colour) {
            this.globalAlpha = alpha;
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.lineWidth = (lineWidth) ? linewidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
        // Reset Alpha if it was changed
        this.globalAlpha = 1;
        this.closePath();
    };
    /**
     * Ellipse
     */
    CanvasRenderingContext2D.prototype.ellipse = function(x, y, width, height, colour, border, lineWidth, alpha) {
        // if certain values are not set just exit
        if (!x || !y || !width || !height) { return true; }
        if (!alpha) { alpha=1; }
        // Calculate some points
        var xLeft = x - (width / 2);
        var xRight = x + (width / 2);
        var yTop = y - (height / 2);
        var yBot = y + (height / 2);
        // Draw the ellipse
        this.beginPath();
        // NOTE: The moveTo() is needed to start the drawing from the correct spot
        this.moveTo(x, yTop);
        // Start drawing two bezier curves to create an ellipse
        this.bezierCurveTo(xRight, yTop, xRight, yBot, x, yBot);
        this.bezierCurveTo(xLeft, yBot, xLeft, yTop, x, yTop);
        // Colour it in
        if (colour) {
            this.globalAlpha = alpha;
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.lineWidth = (lineWidth) ? linewidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
        // Reset Alpha if it was changed
        this.globalAlpha = 1;
        // Finish the drawing
        this.closePath();
    };
    /**
     * Rounded arcs and circles
     */
    CanvasRenderingContext2D.prototype.circularArc = function(x, y, radius, startAng, endAng, colour, border, lineWidth, enclosed, direction, alpha) {
        // if certain values are not set just exit
        if (!x || !y || !radius) { return true; }
        // Set other values
        if (!alpha) { alpha=1; }
        if (!startAng) { startAng = 0; }
        if (!endAng) { endAng = Math.PI; }
        if (!direction) { direction = false; }
        // Start drawing
        this.beginPath();
        this.arc(x, y, radius, startAng, endAng, direction);
        if (enclosed) {
            this.closePath();
        }
        // Colour it in
        if (colour) {
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.globalAlpha = alpha;
            this.lineWidth = (lineWidth) ? lineWidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
     // Reset Alpha if it was changed
        this.globalAlpha = 1;
        // Finish the drawing
        this.closePath();
    };
}

References

Sep 7, 2013

AJAX with JQuery and Google App Engine: Python

This is an adaption of AJAX with JQuery and PHP. It is a continuation of my Python 2.7 and Google App Engine series, and portions of the code builds upon my earlier work.

A first example...

AJAX stands for Asynchronous JavaScript And XML, and allows us to make our websites seem more dynamic. Let's start with the JavaScript side of things...

Create a file called static.html and add the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
       <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
       <title>Ajax With Jquery</title>

       <!-- Grab the JQuery API from the Google servers -->
       <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript" charset="utf-8"></script>

       <!-- Our own JQuery code to do the AJAX-y stuff -->
       <script type="text/javascript" charset="utf-8">

          $(document).ready(function(){
             $('#txtValue').keyup(function(){
                 $('#display').html($(this).val());
             });
          });

       </script>
    </head>

    <body>
       <label for="txtValue">Enter a value : </label>
       <input type="text" name="txtValue" value="" id="txtValue">

        <div id="display"></div>
    </body>
</html>

Create a file called app.yaml and add the following:
application: almightynassar
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: /(.*).html
  static_files: \1.html
  upload: (.*).html

The above will simply serve ALL html page requests directly (which is enough for this example).

Now, if you are using Eclipse just right click on the project, select 'Run As' and choose the 'PyDev: Google App Run' option. Depending on how you configured your Google SDK, it will start up a server on your machine on port 8080. Open up a new tab and navigate to http://localhost:8080/static.html. You should now see a text box; when you type into the box it will automatically display the text in the space below.

Something a little more AJAX - The HTML

So our original example just showed how we could manipulate the DOM (Document Object Model) of the browser during run-time, without a page refresh. How can we use this knowledge utilizing the power of Google App Engine? Well, first let us edit static.html to something we can manipulate:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
       <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
       <title>Ajax With Jquery</title>
     
       <!-- Grab the JQuery API from the Google servers -->
       <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript" charset="utf-8"></script>

       <!-- Our own JQuery code to do the AJAX-y stuff -->
       <script type="text/javascript" charset="utf-8">
       $(document).ready(function(){
            // This will run when the item of class 'button' is clicked
            $(".button").click(function() {
               
                // Grabs the text input
                var name = $("input#txtValue").val();
        
                var dataString = 'txtValue='+ name;  
                // This creates the AJAX connection
                $.ajax({
                    type: "POST",
                    url: "/tutorial",
                    data: dataString,
                    success: function(data) {
                        $('#display').html(data.text);
                    }
                });
            return false;
            });
        });
       </script>
    </head>

    <body>
         <form name="contact" method="post" action="">
            <label for="txtValue">Enter a value : </label>
            <input type="text" name="txtValue" value="" id="txtValue">
            <input type="submit" name="submit" class="button" id="submit_btn" value="Send" />
         </form>
         <div id="display">
         </div>
   </body>
</html> 

Our JavaScript now sends some data to an external URL (in this case /tutorial) and inserts the returned data into the display div. Now all we need to do is code our Python script....

Our Python webapp

Create a file called tutorial.py and add the following code:

# The webapp2 framework
import webapp2

# The JSON library
import json

# Our JSON handler class
class JsonPage(webapp2.RequestHandler):
    # The POST handler
    def post(self):
        # Our POST Input
        txtinput = self.request.get('txtValue')
       
        # Create an array
        array = {'text': txtinput}
       
        # Output the JSON
        self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(json.dumps(array))

# URL map the JSON function
app = webapp2.WSGIApplication([('/tutorial', JsonPage)], debug=True)

Now we just need to edit app.yaml so it can serve up our tutorial script:

application: almightynassar
version: 1
runtime: python27
api_version: 1
threadsafe: no

handlers:
- url: /(.*).html
  static_files: \1.html
  upload: (.*).html

- url: /(.*)
  script: tutorial.app

Open up a new tab and navigate to http://localhost:8080/static.html. You should now see a text box with a button called 'Send'. Typing into this box and then clicking 'Send' will transmit the text to our tutorial script and then display the text in the space below.

References:

Aug 23, 2013

Coursera Notes: Stanford 'Start-up Engineering' (Lectures 5-8)

These are just some of my notes from Coursera's 'Start-up Engineering' course, taught by Balaji Srinivasan from Stanford.

This is a continuation of my existing series of notes.

Market Research, Wire-framing and Design

  • Idea \ne Mock-up
    Mock-up \ne Prototype
    Prototype \ne Program
    Program \ne Product
    Product \ne Business
    Business \ne Profit
  • Execution! It is not the idea, but the execution that matters. Sales rather than technology is what builds a business.
  • Market! Market will draw a product from a team, whether or not it is quality or the team is good.
  • An idea exists within a maze. A simple sentence is not enough to describe an idea; an idea is defined by the regulations, markets, and competition.
  • Execution mindset. This is essentially writing a to-do list and regularly checking off items. Rinse and repeat.
  • Market Research:
    1. News coverage and research papers. Google Books, SEC filings and Wikipedia.
    2. Back-of-envelope estimate of market size. Look for relevant statistics.
    3. Validate. Google keyword planner and Facebook advertiser tools help determine if there is actually a market need.
    4. Do a basic launch page with basic SEO. Use wireframes.
    5. Ad-word to discover the market. The launch page will then gauge market interest.
  • MVP or Minimum Viable Product.
  • Remember, a start-up aims to be very ambitious and scale rapidly.
  • Two features of successful start-ups:
    1. Exhibit economies of scale. Cost of production per unit decreases as more units are built (but revenue stays the same). We can then determine a break-even point and therefore the minimal capital required.
    2. Attack/Pursue large markets. Different pricing will attract different markets, but low price points require automation and industrial efficiency to make profits (because customer service is expensive). It may be better to charge higher initially to counter risks. Market sizing calculations should be done early and often.
  • Once a market and broad perspective has been set, versions and features need to be prioritized. Remember, it is execution and sales that matter!
  • Rough guide to prioritizing versions and features:
    • How much are they willing to pay for certain features or versions?
    • Which features are required in each version? What features make sense to bundle together?
    • Estimate the time and cost to build each feature. Is it feasible to implement the feature now, or wait for more funding?
    • Find the most popular features.
    • Calculate the market size for each feature.
  • Wireframing tools: omnigraffle, lucid chart, jet strap and popapp.
  • Copy-writing:
    • Home-page message must allow a customer to immediately figure out what the product is. This is a priority if this is going to be a major source of potential customers.
    • Work backwards from the press release (write the release then build the product). This allows you to figure out which features are making the news and which are not.
    • Find your competitors and explain why they are terrible options. Use this insight when explaining the benefits of your product.
    • Simple, factual and concise statements.
    • Call to action. Allow the customer to do something once they visit your website.
  • Vector graphics are better to work with.
  • In design remember Alignment, Repetition, Contrast and Proximity.
  • Start with a font heavy design (it is easier to do and images can always come later)

Mobile

  • Assumption behind the mobile phenomenon is that everything is going to be on the internet. The internet is going from a novelty to a utility.
  • Build for HTML5 and then move to native apps. HTML5 ensure your application works on all devices (and Android will soon utilise HTML5 and Javascript instead of native applications).
  • Internet of Things is the idea that every device will have it's own IP address. This offers a huge potential market.
  • Quantified self is the measuring of human beings and our actions. This is the collection of metrics that may revolutionize diagnosis and medicine.
  • One way to build mobile-aware applications is user-agent sniffing. This approach has the problems that a client can fake their own user-agent, and that the user-agent is inherently unreliable.
  • CSS media queries and Responsive web design allows the application of conditional styles depending on screen size. This is much more reliable, but does not have ubiquitous support (yet).
  • Some constraints with mobile include:
    • Unreliable networks (the fallacies of distributed computing)
    • Debugging requires logging (and bug reporting)
    • Minimization of user input (difficult problem to solve; how to collect everything you need without overwhelming the user)
    • Minimize the time to result (if you take too long the user will go elsewhere)

HTML / CSS / Javascript

  • HTML is the skeleton of a web application. It provides the structure of a page and the semantics. It is a set of finite elements with attributes.
  • CSS is the look and layout of a web application. It edits the element and attributes for styling and formatting.
  • Javascript is the dynamics and behavior of a web application. It allows you to provide client-side validation, pulling in content, playing games and much more.
  • Some useful tools include jsfiddle.net and Chrome Developer Tools.

Deployment, DNS and Custom Domains

  • Your code production environments should be along the lines of Development -> Staging -> Production
  • Separating environments bring the following benefits:
    • Testing of features before they reach the customer
    • Roll back of code in case of major bugs
    • Restore code or data in case of catastrophic crashes of the server
    • Incorporate contributions from multiple engineers
    • Perform AB testing of features
  • DNS (Domain Name System) converts IP address into human readable hostnames. The system first looks locally in a program, then the OS, then the ISP and then finally a trusted internet DNS server.

Nov 12, 2012

Get page width dynamically with Javascript (or JQuery)

This quick script will display the current width of your browser window (useful for creating responsive web designs).

The HTML

Simply make a <div> element, which we will be used by JQuery to print out the window width:
<html>
  <body>
    <div id="dimensions">
      <span class="width"></span>
    </div>
  </body>
</html>

JQuery method

If you already use JQuery, then this is for you. If you aren't using it, you should consider it; it makes programming in Javascript a breeze!

To use this snippet, just download the JQuery library, link it into your page and add the following script:

<script>
  $("#dimensions .width").html($(window).width());
  $(window).resize(function(){
    $("#dimensions .width").html($(window).width());
  });

</script>

Javascript method

If you don't have JQuery this should work equally well:

<script>
  window.onresize = displayWindowSize;
  window.onload = displayWindowSize;
  function displayWindowSize() {
    // your size calculation code here
    document.getElementById("dimensions").innerHTML = myWidth + "x" + myHeight;
  };
</script>

Further reading

You can also browse my other content such as:

Aug 31, 2012

HTML5 and CSS3 drop-down menu

Don't forget to visit more of CSS3 tips and tricks!

The HTML5

All you will need is a simple menu structure using <nav> and nested <ul> tags, like this:
<nav>
    <ul>
        <li><a href="/">Home</a>
            <ul>
                <li><a href="/about">About</a></li>
                <li><a href="/contact">Contact</a></li>
            </ul>
        </li>
        <li><a href="/service">Services</a>
            <ul>
                <li><a href="/service/transport">Transport</a></li>
            </ul>
        </li>
        <li><a href='/welcome/language'>Change Language</a></li>
    </ul>
</nav>

The CSS3

I am just going to comment the CSS code; hopefully that is enough explanation for you...
/********************* Nav elements ****************************/

/* Navigation menu HTML5 tag*/
nav
{
    /* No border*/
    border:none;
    border:0px;
   
    /* Ensures the text is aligned properly*/
    text-align: left;
   
    /* Margins and padding*/
    margin:0px;
    padding:0px;
}

/* Our top menu list */
nav ul
{
    /* Set's how the element will interact with adjacent elements */
    display:block;
   
    /* Sets the height of the element (needs to be larger than the text) */
    height: 35px;
   
    /* Buffer space between other containers */
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 1%;
    margin: 0;
   
    /* Does not insert bullet points*/
    list-style:none;
}

/* Float all <li> elements */
nav li{
    float:left;
}

/* Display top menu <li> items as inline */
nav ul li
{
    /* Set's how the element will interact with adjacent elements */
    display:inline;
}

/* The main menu link */
nav ul li a
{
    /* Changes the text to bold and uppercase */
    font-weight: bold;
    text-decoration:none;
    text-transform: uppercase;
   
    /* Default text colour */
    color:#CCCCCC;
   
    /* Pads the text so that it is not right up against the parent element*/
    padding: 5px;
   
    /* Specifies the line-height of the text */
    line-height:30px;
   
    /* Background colour */
    background-color: #FFFFFF;
   
    /* Border colour */
    border: 2px solid #CCCCCC;
   
        /* CSS3 Rounded Border */
    -webkit-border-radius: 8px; /* Saf3-4, iOS 1-3.2, Android ≤1.6 */
        -moz-border-radius: 8px; /* FF1-3.6 */
        border-radius: 8px; /* Opera 10.5, IE9, Saf5, Chrome, FF4, iOS 4, Android 2.1+ */

      /* useful if you don't want a bg color from leaking outside the border: */
      -moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}

/* When we hover over (or for mobile devices, click on the element) */
nav ul li a:focus, nav ul li:focus a, nav ul li a:hover, nav ul li:hover a
{
    /* Underlines the text when we hover over it*/
    text-decoration:underline;
   
    /* Change the background colour*/
    background-color: #CCCCCC;
   
    /* Default text colour */
    color:#336666;
   
    /* Border colour */
    border: 2px solid #336666;
}

/* Our sub menus */
nav li ul
{
    /* Our background colour */
    background-color: #CCCCCC;
   
    /* HIDES the element until needed! */
    display:none;
   
    /* Let the browser determine the element height */
    height:auto;
   
    /* No padding or margins required */
    padding:0px;
    margin:0px;
   
    /* Minimum width of 120px */   
    min-width: 120px;
    width: auto;
   
    /* Use the absolute positioning method*/
    position:absolute;
   
    /* Stack this element right at the front of all elements*/
    z-index:200;
   
    /* Default text colour */
    color:#336666;
   
    /* Border colour */
    border: 2px solid #FFFFFF;
   
    /* CSS3 Rounded Border */
    -webkit-border-radius: 8px; /* Saf3-4, iOS 1-3.2, Android ≤1.6 */
        -moz-border-radius: 8px; /* FF1-3.6 */
        border-radius: 8px; /* Opera 10.5, IE9, Saf5, Chrome, FF4, iOS 4, Android 2.1+ */

      /* useful if you don't want a bg color from leaking outside the border: */
      -moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}
nav li:focus ul, nav li:hover ul
{
    /* Set's how the element will interact with adjacent elements */
    display:block;
}
nav li li
{
    /* Set's how the element will interact with adjacent elements */
    display:block;
   
    /* Do not allow the element to float around */
    float:none;
   
    /* Do not set margin */
    margin: 0;
   
    /* Take up all space given by parent element*/
    /*width:100%;*/
   
    /* Border colour */
    border: none;
}
nav li:focus li a, nav li:hover li a
{
    /* Turn off the background */
    background:none;
    border:none;
    text-decoration:none;
}
nav li ul a
{
    /* Set's how the element will interact with adjacent elements */
    display:block;
   
    /* Sets the height of the element (needs to be larger than the text) */
    /*height:35px;*/
   
    /* No margin */
    margin:0px;
    /*line-height: 20px;*/
   
    /* No border or underlines*/
    text-decoration:none;
    border:none;
   
    /* Default text colour */
    color:#CCCCCC;
}
nav li ul a:hover, nav ul li ul li:hover a
{
    /* Underlines the text when we hover over it*/
    text-decoration:underline;
   
    /* Change the background colour*/
    background-color: #336666;
   
    color: #CCCCCC;
}
nav p
{
    /* No floating elements are allowed to the left of this element */
    clear:left;
}

Jul 18, 2012

AJAX, JQuery, CodeIgniter and PHP

This is an extension of an earlier blog of mine, but this time I have built it using the CodeIgniter PHP framework. I have also spiced it up with a dynamic JQuery form (kudos to Charlie Griefer and this blog post for the code!)

If you want to get your hands dirty doing something a little harder then I suggest you check out my earlier blog on creating a login system with CodeIgniter.

If you are just getting started, have a look at my other blog posts, 'Ubuntu, LAMP and CodeIgniter' and the 'Extended JQuery Tutorial'.

Getting started

I am going to assume that you are working with a fresh installation of CodeIgniter that simply displays the welcome message. I am going to start from there so we don't get into any confusion!

First, unzip the CodeIgniter source into your web-server's root directory (if you followed my LAMP guide above, this will default to /var/www/). Rename the extracted folder to test (so in the default example, the CodeIgniter framework will be stored in /var/www/test/).

Now delete ALL the php files in /var/www/test/application/controllers and /var/www/test/application/views. We are going to start completely fresh!

The final step is to configure the framework to use our new controller (once we create it...), so edit the file /var/www/test/application/config/routes.php with the following line:
$route['default_controller'] = "home";
Now to make our main controller....

The Home page controller

  1. Create a file in /var/www/test/application/controllers named home.php
  2. Add in the following code:
    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

    class Home extends CI_Controller {

        /**
         * Index Page for the home controller.
         *
         * Maps to the following URL
         *         http://example.com/
    index.php
         *    - or - 
         *         http://example.com/index.php/home
         *    - or -
         * Since this controller is set as the default controller in
         * config/routes.php, it's displayed at http://example.com/
         *
         * So any other public methods not prefixed with an underscore will
         * map to /index.php/home/<method_name>
         * @see http://codeigniter.com/user_guide/general/urls.html
         */
        public function index()
        {
            $this->load->view('view');
        }
    }

    /* End of file ajax.php */
    /* Location: ./application/controllers/home.php */
  3. That's it. All this does is load up our view, which is our next step.

The Home page view

  1. Create a file in /var/www/test/application/views named view.php
  2. Add in the following code:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>Test</title>

    <!-- JQuery code hosted by Google -->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>

    <!-- Adding and Deleting form buttons -->
    <script type="text/javascript" src="form.js"></script>

    <!-- AJAX functionality -->
    <script type="text/javascript" src="ajax.js"></script>
    </head>

    <body>

    <form id="myForm">
    <div id="input1" style="margin-bottom:4px;" class="clonedInput">
    Name: <input type="text" class="name" name="name1" id="name1" />
    </div>

    <div>
    <input type="button" id="btnAdd" value="add another name" />
    <input type="button" id="btnDel" value="remove name" />
    <input type="button" name="submit" class="button" id="submit" value="Send" />
    </div>

    <div id="display">
    </div>
    </form>

    </body>
    </html>
  3. Our basic HTML page includes three JavaScript files (One is the JQuery API, the other two we write ourselves; see below). We have a form with an input text box and three buttons. The first two buttons add and remove input boxes from our form, while the last button performs our AJAX operation.

form.js - Dynamically adding form elements

  1. Create a file called form.js in /var/www/test/
  2. Add the following code:
    $(document).ready(function() {
                $('#btnAdd').click(function() {
                   

                    // how many "duplicatable" input fields we currently have

                    var num     = $('.clonedInput').length;                // the numeric ID of the new input field being added
                    var newNum  = new Number(num + 1);
     
                    // create the new element via clone(),
                    // and manipulate it's ID using newNum value
                    var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);
     
                    // manipulate the name/id values of the input inside the new element
                    newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
     
                    // insert the new element after the last "duplicatable" input field
                    $('#input' + num).after(newElem);
     
                    // enable the "remove" button
                    $('#btnDel').attr('disabled','');
     
                    // business rule: you can only add 5 names
                    if (newNum == 5)
                        $('#btnAdd').attr('disabled','disabled');
                });
     
                $('#btnDel').click(function() {
                   
    // how many "duplicatable" input fields we currently have
                    var num = $('.clonedInput').length;

                   
    // remove the last element
                    $('#input' + num).remove();
     
                    // enable the "add" button
                    $('#btnAdd').attr('disabled','');
     
                    // if only one element remains, disable the "remove" button
                    if (num-1 == 1)
                        $('#btnDel').attr('disabled','disabled');
                });
     
                $('#btnDel').attr('disabled','disabled');
            });
  3. This function attaches a JavaScript function to the add and remove button. The code is pretty well commented by Charlie Griefer, so if you want to know more I suggest you go visit his blog post.

ajax.js - AJAX with JQuery

  1.  Create a file called ajax.js in /var/www/test/
  2. Add the following code:
    $(document).ready(function() {
        // This will run when the item of id 'submit' is clicked
        $("#submit").click(function() {

        // Grabs the text input
    from the form
        var name = [];
        $(".name").each(function() { name.push($(this).val()) });

        // Create the key-value pair for POST

        var dataString = 'string=' + name.join(' ') + '';

        // This creates the AJAX connection
        $.ajax({
           type: "POST",
           url: "index.php/ajax",
           data: dataString,
           dataType: 'json',
           success: function(obj) {
              $('#display').html(obj.message);
           }
        });
        return false;
        });
    });
  3. This will send all of our dynamically generated form elements to index.php/ajax (which we will now create). Hopefully the code and comments are self explanatory; if you have any problems just shout out in the comments!

The AJAX controller

  1. Create a file in /var/www/test/application/controllers named ajax.php
  2. Add the following code:
    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

    class Ajax extends CI_Controller {


       /**

        * Index Page for this controller.
        *
        * Maps to the following URL
        * http://example.com/index.php/ajax
        * - or -
        * http://example.com/index.php/ajax/index
        *
        * So any other public methods not prefixed with an underscore will
        * map to /index.php/ajax/<method_name>
        * @see http://codeigniter.com/user_guide/general/urls.html
       */
       public function index()
       {
           $txtValue = "We have recieved: " . $this->input->post('string');

           echo json_encode(array('message' => $txtValue));

       }
    }

    /* End of file ajax.php */

    /* Location: ./application/controllers/ajax.php */
  3. You should now be able to run this on your web-server and have a dynamic form that sends and recieves AJAX!

References:

Jun 9, 2012

Parsing HTML with lxml and Google App Engine: Python

This is a continuation of my Python 2.7 and Google App Engine series. If you are just starting out I suggest you start reading Getting Started and First App. If you are after parsing XML files please see my post 'Parsing XML with Google App Engine: Python'.

We are going to assume you will be using Eclipse and a fresh project. In this example we are going to use Triple J Unearthed's Top 100 charts HTML page to parse.

Adding lxml to Google App Engine

The first thing we need to do is add the lxml library to our app.yaml configuration file. In your Eclipse project add a new file called app.yaml and add the following:

application: almightynassar
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: triplej.app

libraries:
- name: lxml
  version: latest

Most of these fields were covered in Getting Started, but we now have a new field: libraries. This is where we declare all third party libraries not included in GAE default python environment.

Using lxml

Create a new file called triplej.py and add the following code:

# The webapp2 framework
import webapp2

# lxml parser for XML and HTML
from lxml import etree

# The URL Fetch library
from google.appengine.api import urlfetch

# Fetches an XML document and parses it
class MainPage(webapp2.RequestHandler):
    # Respond to a HTTP GET request
    def get(self):
            # Grabs the HTML
            url = urlfetch.fetch('http://www.triplejunearthed.com/Charts/')
           
            # Parses the HTML
            tree   = etree.HTML(url.content)

            # Converts the DOM into a string       
            result = etree.tostring(tree, pretty_print=True, method="html")

           
           # Output the results onto the screen
           self.response.out.write(str(result))
   
       
# Create our application instance that maps the root to our
# MainPage handler
app = webapp2.WSGIApplication([('/*', MainPage)], debug=True)

If you run this code you will notice that all it does is simply download the HTML page, parses it, and then outputs the page exactly as it was downloaded (minus all the images and CSS styling). Nothing impressive, but we proved the concept works. Now on to something a little more beefy....

Parsing, Extracting and Cleaning the HTML

In this example we will perform multiple functions that will only extract the chart from the Triple J Unearthed website. Replace the triplej.py code with the following:

# The webapp2 framework
import webapp2

# lxml parser for XML and HTML
from lxml import html

# HTML cleaner
from lxml.html.clean import Cleaner

# The URL Fetch library
from google.appengine.api import urlfetch

# Fetches an XML document and parses it
class MainPage(webapp2.RequestHandler):
    # Respond to a HTTP GET request
    def get(self):
        # Grabs the HTML
        url = 'http://www.triplejunearthed.com/Charts/'
        website = urlfetch.fetch(url)
       
        # Saves our content as a string
        page = str(website.content)

        # Parses the HTML
        tree = html.fromstring(page)

        # The ID string of the table element we want          # NOTE: This is bound to change!!! Double check the HTML source first!!!
        elementID = "ctl00_ctl00_ctl00_ctl00_MainBody_ContentPlaceHolder1_ContentPlaceHolder1_ContentPlaceHolder1_GridView1"
       
        # Grab the chart element
        #
        # style: removes styling
        # links: removes links
        # add_nofollow: adds rel="nofollow" to anchor tags
        # page_structure: removes <html>, <head>, and <title> tages
        # safe_attrs_only: only allows safe element attributes
        # javascript: removes embedded javascript
        # scripts: remove script tags
        # kill_tags: remove the element and content
        # remove_tags: remove only the element, but not the content
        #
        # There are more available. See the API reference for lxml
        cleaner = Cleaner(style=True, links=True, add_nofollow=True,
                          page_structure=True, safe_attrs_only=True,

                          javascript=True, scripts=True, kill_tags = set(['img','th']),
                          remove_tags = (['div']))

       
        # Grab only our chart (but scrub it clean first!)
        chart = cleaner.clean_html(tree.get_element_by_id(elementID))
       
        # Change all relative links into absolute links based on the url
        chart.make_links_absolute(url)
       
        # Converts the DOM element into a string
        result = html.tostring(chart)
       
        # Output the results onto the screen
        self.response.out.write(result)        
       
# Create our application instance that maps the root to our
# MainPage handler
app = webapp2.WSGIApplication([('/*', MainPage)], debug=True)

Running this code should result in a sanitized version of the Triple J Top 100 chart!

References

Apr 19, 2012

Extended Jquery tutorial

This tutorial is an extension of the basic JQuery tutorial. We will not cover the same stuff here, so if you want a quick and easy primer on JQuery please click on that link. Instead, this offers some extra background information that help put the code examples into context.

You might also want to check out my other posts such as the JQuery Slideshow or AJAX with JQuery and PHP.

What is JQuery?

JQuery is a client-side JavaScript library that can do a wide variety of tasks. This includes browser effects, AJAX, and interact with the DOM. Despite the introduction of CSS3 (which will elegantly handle browser effects and limited DOM manipulation), JQuery still has alot to offer the web developer. It has also been around for longer which means, for the moment, it has better cross-browser support.

JQuery is not meant to be used as an application framework. It does not provide a blueprint around which a developer can build a website. Instead, it offers a wide set of tools to make development much, MUCH easier.

Getting started...

Getting started with jQuery is easy; download the library script from the website and include it in your web-application as you would any other JavaScript file. Alternatively, Google provides live hosting of the jQuery so you could link to that to save on your bandwidth.

<!-- Include the JQuery Library code... JQuery will not work without this -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>


Selectors

JQuery works best by manipulating the DOM (the fancy, technical name given to the HTML page displayed by the browser), but to do this it needs a way of finding the elements to manipulate. To do this jQuery sports a CSS selector engine, meaning you just use standard CSS nomenclature to select an element.

For instance, if we had a div element with an id set to foo, in CSS we would write #foo {} to declare the style for that id. In JQuery, to search for and manipulate element foo you would write:

$('#foo').function()

Make sure the DOM is ready!

A common problem new developers have with jQuery is they start querying the DOM before it is ready. Browsers sometimes execute JavaScript before they have completely parsed the DOM, and this leads to errors where you manipulate the #foo class but it has not loaded on the page yet.

This problem is solved by calling the jQuery function that waits until the DOM has completely loaded:

$(document).ready(function {
      $('#foo').css('colour', 'red');
});

References:

Apr 5, 2012

CSS tips and tricks

As someone with a background in developing electronics and embedded systems, it is no shock that when it comes to pretty UX interfaces I suck. My interfaces is the definition of 'total suckage'. But nevertheless, the job market demands that I at least attempt to make pretty interfaces for clients; the critical criteria for modern web applications seem to lie in the appearance instead of the substance. But alas, I digress...

I have been doing research into CSS as it is the dominant method of creating nice structured web interfaces (yes, JavaScript can do that too but I prefer to stick to using JS for behavioural coding). So I have come across a HEAP of useful tutorials that will help turn your steaming pile of crap into glistening gold!

Rounded Borders

Rounded borders looks awesome on anything. Here is the code:

.roundBorder
{
     border: 2px solid #505050;
     /* Rounded Border */
    -webkit-border-radius: 8px; /* Saf3-4, iOS 1-3.2, Android ≤1.6 */
    -moz-border-radius: 8px; /* FF1-3.6 */
    border-radius: 8px; /* Opera 10.5, IE9, Saf5, Chrome, FF4, iOS 4, Android 2.1+ */

    /* useful if you don't want a bg color from leaking outside the border: */
    -moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}


Background Gradient

You can read more about this here, but for now here is some code for you to play with:

.gradient
{
    /* Background Gradient */
    background-color: #69aef1;
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #69aef1), color-stop(100%, #ffffff));
    background-image: -webkit-linear-gradient(top, #69aef1, #fff); /* Chrome 10+, Saf5.1+, iOS 5+ */
    background-image: -moz-linear-gradient(top, #69aef1, #fff); /* FF3.6 */
    background-image: -ms-linear-gradient(top, #69aef1, #fff); /* IE10 */
    background-image: -o-linear-gradient(top, #69aef1, #fff); /* Opera 11.10+ */
    background-image: linear-gradient(to bottom, #69aef1, #fff);
}


Word Wrapping/Breaking

This piece of CSS should provide nicer looking word-breaking/hyphenation:

    /* CSS3 word break */
    -ms-word-break: break-all;
    word-break: break-all;
    word-break: break-word;
    -webkit-hyphens: auto;
    -moz-hyphens: auto; 


Centre Tables (and Elements)

I used this code to make a table centre properly in one of my elements. I'm sure it could find uses elsewhere though:

.center
{
      /* Reset margins for the elements (defaults to centered( */
    margin-left:auto;
    margin-right:auto;
}


CSS toggled accordion

This effect is created using a simple unordered list with added radio button functionality. Here is the code:

/* Clean up the lists styles */
ul.accordion {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Hide the radio buttons */
/* These are what allow us to toggle content panes */
ul.accordion label + input[type='radio'] {
    display: none;
}

/* Give each content pane some styles */
ul.accordion li {
    background-color: #CCCCCC;
    border-bottom: 1px solid #DDDDDD;
}

/* Make the main tab look more clickable */
ul.accordion label {
    background-color: #666666;
    color: #FFFFFF;
    display: block;
    padding: 10px;
}

ul.accordion label:hover {
    cursor: pointer;
}

/* Set up the div that will show and hide */
ul.accordion div.content {
    overflow: hidden;
    padding: 0 10px;
    display: none;
}

/* Show the content boxes when the radio buttons are checked */
ul.accordion label + input[type='radio']:checked + div.content {
    display: block;
}


So our HTML code will then be:

<ul class='accordion'>
    <li>
        <label for='cp-1'>Content pane 1</label>
        <input type='radio' name='a' id='cp-1' checked='checked'>
        <div class='content'>
            <p>text</p>
        </div>
    </li>
   
    <li>
        <label for='cp-2'>Content pane 2</label>
        <input type='radio' name='a' id='cp-2'>
        <div class='content'>
            <p>text2</p>
        </div>
    </li>
</ul>


References:

  • This website is an absolute must! 'CSS3 Please!' lists a whole heap of cross-browser compatible CSS3 techniques that you can just copy and paste into your website!
  • Blog post by Kenneth Auchenberg on how to achieve word wrapping in pure CSS
  • Blog post by Scott Granneman on how to centre a table in CSS
  • Blog post by Mike Cherim on the different types of web page layouts; fixed, fluid/liquid, and elastic.
  • Another post about the three types of web page layouts (fixed, fluid, and elastic) by Extend Studio
  • w3schools CSS reference
  • Pure CSS toggle accordian implementation by Oliver Caldwell
  • CSS Menu Maker provides a range of open source css menus
  • A list of CSS tutorials by Design Festival

Mar 29, 2012

CodeIgniter: PHP web app authentication

I have recently begun using CodeIgniter as my PHP framework for quickly whipping up web applications. And as a continuation on my web application blog posts (such as my AJAX with JQuery and PHP tricks) I have decided to whip this one up about how to use the CodeIgniter framework to create a site wide authentication system.

This tutorial assumes some knowledge in database administration and basic knowledge of CodeIgniter (time of writing I was using version 2.1.0) and PHP (version 5.3.10).

Model

First we will need to know the data we will be saving. The following SQL script was created using MySQL, but you should be able to configure with some minor modifications:

CREATE TABLE IF NOT EXISTS `users` (
  `userID` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT COMMENT 'The unique ID',
  `username` varchar(64) NOT NULL COMMENT 'A unique username',
  `password` varchar(128) NOT NULL COMMENT 'The password with embedded salt',
  `personID` int(10) unsigned zerofill NOT NULL COMMENT 'Foreign key to person data',
  `active` tinyint(1) NOT NULL COMMENT 'Whether the user is activated',
  `creationDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'The date the user was created',
  PRIMARY KEY (`userID`),
  UNIQUE KEY `username` (`username`),
  KEY `personID` (`personID`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;



Now that we know what data we are storing, we can create our model in CodeIgniter. In the folder 'application/models/', create a file called auth_model.php.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Login Authentication Model Class
 *
 * This is the model that will access authentication data (and provide some
 * functions).
 *
 * @package        Application
 * @subpackage    Models
 * @category    Models
 * @author         Almighty Olive
 * @copyright    Copyright (c) 2012, olivecodex.blogspot.com.au
 */

class Auth_model extends CI_Model
{
    /**
     * Modified constructor class
     */
    function __construct()
        {
            parent::__construct();
       
        // Ensure that sessions are loaded
        $this->load->library('session');
    }

    /**
     * Secure hash generation function.
     *     $input - the data to be hashed
     *     $salt - OPTIONAL: the salt to be used in the hashing function
     *
     * For more info about hashing, please see http://crackstation.net/hashing-security.html
     */
    function createHash($input, $salt = null)
    {
        // If no salt is passed then generate it
        if ($salt === null)   
        {
            //get 256 random bits in hex
            $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
        }

        //Prepend the salt, then hash
        $hash = hash("sha256", $salt . $input);
   
        //store the salt and hash in the same string, so only 1 DB column is needed
        $final = $salt . $hash;
   
        return $final;
    }


    /**
     * De-hash function (provided it has been hashed like above)
     * Returns true if the hashed input matches what is stored in the database
     *
     *     $salthash - the salt and hash created by authed_hash (stored in your DB)
     *     $input    - the data to verify
     *     returns   - true if the password is valid, false otherwise.
     *
     * For more info about hashing, please see http://crackstation.net/hashing-security.html
     */
    function validate($input, $salthash)
    {
        // Extract the salt and hash from the stored string
        $salt = substr($salthash, 0, 64); //get the salt from the front of the hash
        $validHash = substr($salthash, 64, 64); //the SHA256

        // Create a hash using the input and salt
        $testHash = hash("sha256", $salt . $input); //hash the password being tested
   
        //If the hashes are exactly the same, the password is valid
        return $testHash === $validHash;
    }
   
    /**
     * For a given username and password combination, this function
     * will look-up the database and determine if the user can access
     * the system
     *     $username = the passed username
     *    $password = the passed password
     *    returns true if the user is active
     */
    function checkAuth($username,$password)
    {
        // Sets up the query parameters
        $this->db->select("*");
        $this->db->where("username",$username);
        $this->db->where("active",'1');

        // Executes the specified query
        $query = $this->db->get("users");

        // Checks that only one row exists
        if(($query->num_rows()>0) && ($query->num_rows()<2))
        {
            $data = array();

            // Grab the resulting row
                $data = $query->row();

            // Checks to see if the password is correct
            if ( $this->validate($password, $data->password))
            {
                    // Create a data array to save to the session session
                    $sessionArray = array( 'userID'=>$data->userID,
                        'username'=>$data->username,
                        'personID'=>$data->personID,
                        'main'=>array(),
                        'logged_in'=>'TRUE');
                    $this->session->set_userdata($sessionArray);

                    // Return from the function
                    return TRUE;
            }
        }

        // If we have arrived here, it means we were not successful
        return FALSE;
    }

    /**
     * Check if a session has already been created
     *    returns true if a session exists
     */
    public function check_session()
    {
        if ($this->session->userdata('userID') AND $this->session->userdata('logged_in')=='TRUE')
        {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    /**
     * Deletes all session data
     *    returns true if a session exists
     */
    public function logout()
    {
        $this->session->unset_userdata('userID');
        $this->session->unset_userdata('logged_in');
        session_destroy();
    }
}
?>


Custom Controller Class

CodeIgniter uses the MVC design pattern, so most of our processing will be through our Controllers. To make our application automatically check if a user has logged in (and redirect them to the login screen if they haven't), we will create a new parent controller class. ALL pages that need authentication will be required to be a child of our new class!

Create a new file in 'application/core/' called 'MY_Controller.php' (change MY_ to whatever you have set it in your config file).

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Application Controller Class
 *
 * This class object is a super class
 *
 * @package        CodeIgniter
 * @subpackage    Libraries
 * @category    Libraries
 * @author        ExpressionEngine Dev Team
 * @link        http://codeigniter.com/user_guide/general/controllers.html
 */

class MY_Controller extends CI_Controller
{
    function __construct()
    {
    // Performs all the initilisation for a controller
        parent::__construct();

    // Ensure that sessions are loaded
    $this->load->helper('url');

    // Ensure that sessions are loaded
    $this->load->library('session');

    // Load our Authentication Model
    $this->load->model('Auth_model');

    // Check our session to see if we are logged in or not
    if(!$this->Auth_model->check_session()){
        redirect('/auth/login');
    }
    }
}

// END Controller class

/* End of file MY_Controller.php */
/* Location: ./application/core/MY_Controller.php */


Login page controller

Now we need to create a login controller. Note that this controller is NOT derived from our custom class! The custom class redirects to our Login page, so if you do this then you will just end up with a continuous loop!

Create a new file under 'application/controllers/auth/' (create the folder if necessary) called 'login.php'. Note that I am using three view files; header.php, footer.php and login.php. I won't bother making these files as they should be pretty straightforward; you just need a simple form (that redirects to the login page) with a username field, a password field and a submit button.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Login extends CI_Controller {

    /**
     * Constructor for this controller.
     *
     * Load up some common modules
     *
     * @see http://codeigniter.com/user_guide/general/urls.html
     */
    function __construct()
        {
        // Performs all the initilisation for a controller
            parent::__construct();

        // Loads the URL helper (redirection)
        $this->load->helper('url');

        // Ensure that sessions are loaded
        $this->load->library('session');

        // Load our Authentication Model
        $this->load->model('Auth_model');
        }

    /**
     * Index Page for this controller.
     *
     * Maps to the following URL
     *         http://example.com/auth/login
     *    - or - 
     *         http://example.com/auth/login/index
     *
     * @see http://codeigniter.com/user_guide/general/urls.html
     */
    public function index()
    {
        // Loads the form helper
        $this->load->helper('form');

        // Loads the form validation library
        $this->load->library('form_validation');

        // Check our session to see if we are logged in
        if($this->Auth_model->check_session())
        {
            redirect('/');
        }

        // Set the validation rules for the form
        $this->form_validation->set_rules('username', 'Username', 'trim|required|min_length[3]|xss_clean');
        $this->form_validation->set_rules('password', 'Password', 'required');

        // Run Validation check
        if($this->form_validation->run() == TRUE){
            // Grab our submitted data
            $username = $this->input->post('username');
            $password = $this->input->post('password');

            // Check if the user details matches that in our database
            if( $this->Auth_model->checkAuth($username,$password))
            {
                // Authentication is successful
                redirect('/');
            }
        }

        // If we are here it means authentication has failed... load up the error page
        $this->load->view('slair_header');
        $this->load->view('slair_login');
        $this->load->view('slair_footer');
    }

    /**
     * Logout Page for this controller.
     *
     * Maps to the following URL
     *         http://example.com/auth/login/logout
     *
     * @see http://codeigniter.com/user_guide/general/urls.html
     */
    public function logout()
    {   
        // Perform the logout functions
        $this->Auth_model->logout();

        //Goes back to the login screen
        redirect('/auth/login/');
    }
}

/* End of file slair.php */
/* Location: ./application/controllers/slair.php */


Conclusion

You should now be able to just do the following on any controller that requires authentication to access:

class CLASSNAME extends MY_Controller {

     ....

}


The MY_Controller will automatically redirect to the Login page if no session has been detected, otherwise we have a valid user so it will continue processing the rest of the PHP script.

Enjoy!

References:

  • Blog post from Afruj Jahan about writing a simple Login authentication system in CodeIgniter
  • CodeIgniter website
  • List of useful CodeIgniter Tutorials
  • Article about why we should ALWAYS salt our passwords
  • Article about the best way to secure your passwords from Cracked Station