Friday 9 August 2013

Automatically log users into your website using HTML5 Local Storage

So your users has been registered. They have gone through the pain of logging in on a mobile phone and you want them to authenticate more easily next time round, so that they don't give up on using your web app.

The solution : HTML5 Local Storage. In the code below, I take the username and password, and put them in localstorage variables. When the (login) page is visited again, I check to see if those localstorage variables exist. If they do, I add them as values to the username and password field, and perform a submit.

Enjoy!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>HTML5 Save Password</title>
<!--[if IE]>
<script src="html5.js"></script>
<![endif]-->
<script src="jquery.min.js"></script>
</head>
<body>
<form method="POST" action="set.php">
<label for"username">Username</label>
<input name="username" type="email" />
<label for"password">Password</label>
<input name="password" type="password" />
<input type="submit" />
</form>
<script>
(function()
{
u = false;
p = false;
if(localStorage.getItem('username') != null)
{
$('form input[name=username]').val(localStorage.getItem('username'));
u = true;
}
if(localStorage.getItem('password') != null)
{
$('form input[name=password]').val(localStorage.getItem('password'));
p = true;
}
if((u == true) && (p == true))
{
$('form').submit();
}
$('form').submit(function()
{
localStorage.username = $('form input[name=username]').val();
localStorage.password = $('form input[name=password]').val();
});
})();
</script>
</body>
</html>

Thursday 1 August 2013

HTML5 contenteditable save, re-save and save again

The HTML5 contenteditable attribute is really useful, but when you've got my typing skills, you'd really like to keep saving as you go. In the example below I'm writing to a text file for simplicity. I've got a few things going on.

  • If the text file exists or has data in there, I use it. Otherwise, the editable paragraph holds a default string.
  • I use a form submit to kick off a jQuery event.
  • The jQuery function calls a PHP script to write the contents of my editable paragraph to the file.

This way I can keep pressing the submit button as I go, which will just update the text file with the current editable paragraph contents.

Here's the code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Editable jQuery save</title>
<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" href="http://meyerweb.com/eric/tools/css/reset/reset.css" />
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
</script>
</head>
<body>
<p id="content" contenteditable="true">
<?php
$text = file_get_contents('test.txt');
if(!empty($text))
{
echo $text;
}
else
{
echo 'Put some text here.';
}
?>
</p>
<form>
<input type="submit" />
</form>
<script>
(function()
{
$('form').submit(function()
    {
        $.post('set.php',
        {
            content:$('#content').text()
        }, function(data)
        {
        if(data)
        {
        console.log(data)
        }    
        });
        return false;
    });
})();
</script>
</body>
</html>

And set.php

<?php
if(isset($_POST['content']))
{
file_put_contents('test.txt', $_POST['content']);
}
else
{
echo 'write was not successful';
}
?>

Heredoc in PHP to reduce a lot of echo calls

Heredoc is a way of building strings for output. Funnily enough I found there was a mistake in some of the coding on the Wikipedia page, but I won't hold that against them. Also, in some of the examples I've come across on the web, they don't seem to recognise an important feature of heredoc. That is, it also provides HTML output.

Below is some example PHP code with the correct syntax, use of variables and HTML. That should speed things up a bit.

<?php
$recipient = 'Mick';
$sender = 'Johnnie';
$x = <<<EOF
Dear $recipient,
I wish you to leave Sunnydale and never return.<br />
Not Quite Love,
$sender
EOF;
echo $x;
?>

Wednesday 17 July 2013

HTML5 Data methods

Here are various ways you can use data through HTML5. The code is larger than usual, that's because I've provided code for 8 different methods of storing and using data. I have tried to highlight the related code and method using colours. To run this, you'll need 3 files:

  • index.php
  • twittieserver.php
  • webworker.plugin.js

The code for all of these files is below. So, let's start with index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML5 Localstorage</title>
<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" href="http://meyerweb.com/eric/tools/css/reset/reset.css" />
<style>
body
{
font:0.9em/1.1em Sans-serif;
color:#808080;
}
.column
{
float:left;
width:440px;
}
form, section
{
margin:10px;
padding:10px;
width:400px;
border:2px solid #808080;
}
p.description, section article ul
{
margin:4px 4px 8px 0px;
padding:4px;
}
section article ul
{
background:#F5DA55;
}
p.description
{
background:#F5F555;
}
h1, h2
{
font:1.4em/1.5em Georgia, Serif;
}
h1
{
margin:14px 0 10px 10px;
}
strong
{
font-weight:bold;
}
</style>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
</script>
</head>
<body>
<h1>HTML5 Data Options</h1>
<div class="column">
<form>
<h2>Input</h2>
<p class="description">This form will be used to add content to the sessionStorage, localStorage and Web SQL Objects.</p>
<input type="text" id="one" /><br />
<button>Save</button>
</form>
<section id="customdataattribute">
<h2>Custom Data attributes</h2>
<p class="description">Allows you to hold data values within a selector.<p>
<p class="description">E.g &lt;li data-no="20"&gt;<br />Can therefore be called through jQuery as $('li').data('no');<p>
<article>
<ul>
<li data-no="22">This value is 22<li>
<li data-no="33">This value is 33<li>
</ul>
</article>
</section>
<section id="sessionstorage">
<h2>sessionStorage</h2>
<p class="description">This data will be lost when the browser is closed.<p>
<article></article>
</section>
<section id="localstorage">
<h2>localStorage</h2>
<p class="description">This data will be retained after the browser is closed. It persists until deleted by user through browser settings or by this application.<p>
<article></article>
</section>
</div>
<div class="column">
<section id="cachemanifest">
<h2>cache-manifest</h2>
<p class="description">A file which tells the browser what to cache, and not cache. <br /><strong>CACHE MANIFEST</strong> entries will be cached after they are downloaded for the first time.
<br /><strong>NETWORK</strong> entries require a connection to the server, and will not be cached.
<br /><strong>FALLBACK</strong> are fallback pages, if a page is unavailable.
<br />Instructions below:</p>
<article>
<p>First create a .htaccess file for your site (if you are using a proper web server) and add to it the following line:</p>
<p>AddType text/cache-manifest    .manifest</p>
<p>Next, create a file called cache.manifest. In this file, add the lines:</p>
<p><strong>CACHE MANIFEST</strong></p>
<p>index.html</p>
<p><strong>NETWORK</strong>:</p>
<p>login.html</p>
<p><strong>FALLBACK</strong>:</p>
<p>/html/ /offline.html</p>
</article>
</section>
<section id="sse">
<h2>Server-Sent Events</h2>
<p class="description">Allows this application to get data updates from a server. In this example I've simulated a twittie server using a PHP script called twittieserver.php. This data will be lost when the browser is closed.</p>
<article>
<ul>
</ul>
</article>
</section>
<section id="webworker">
<h2>Web Worker</h2>
<p class="description">A piece of JavaScript or jQuery running in the background, without affecting the performance of this application.</p>
<article></article>
</section>
<section id="websql">
<h2>Web SQL</h2>
<p class="description">Allows an application such as this to build a SQL database at the client end. It is also possible to synchronise this data at the server end. This supports applications which ahve both and online and offline state. It persists until deleted by user through browser settings or by this application.</p>
<article>
<ul>
</ul>
</article>
</section>
</div>
<script>
/* Calculates the custom data attributes and appends them to the result of a selector */
$.fn.calculatecustomattributes = function()
{
lis = $(this).children('li');
res = 0;
ve = 0;
$(lis).each(function()
{
ve = parseInt($(this).data('no'));
if(!isNaN(ve))
{
res += ve;
}
});
$(this).append('<li>Result is '+res+'</li>');
};

/* Sets the form contents which were stored in the sessionStorage object to the calling selector */
$.fn.displaysessionstorage = function()
{
$(this).html('<p>Content is '+sessionStorage.getItem('one')+'</p>');
};

/* Sets the form contents which were stored in the localStorage object to the calling selector */
$.fn.displaylocalstorage = function()
{
$(this).html('<p>Content is '+localStorage.one+'</p>');
};

/* Lists contents of the Web SQL object in the calling selector */
$.fn.displaywebsql = function(db)
{
container = $(this);
db.transaction(function(tx)
{
tx.executeSql('SELECT * FROM jimmy', [], function(tx, results)
{
  var len = results.rows.length, i;
for (i = 0; i < len; i++)
{
$(container).append('<li>'+results.rows.item(i).text+'</li>');
}
});
});
};

/* This function is called when the 'Save' button is clicked */
$.fn.saveit = function(db)
{
/* Put the value of the form input in a variable */
one = $('form #one').val();

/* Create an item in the sessionStorage object and apply the value of our variable */
sessionStorage.setItem('one', one);

/* Create an item in the localStorage object and apply the value of our variable */
localStorage.one = one;

/* Insert the value of our variable into the Web SQL object */
db.transaction(function(tx)
{
tx.executeSql('INSERT INTO jimmy (text) VALUES (?)',[one]);
});

/* Refresh the contents of our containers */
$('#sessionstorage article').displaysessionstorage();
$('#localstorage article').displaylocalstorage();
$('#websql article ul').displaywebsql(db);
};

(function()
{
/* Check to see if web storage is supported */
if(typeof(Storage) == 'undefined')
        {
            alert('Sorry! No web storage support..');
        };

        /* Check to see if web workers are supported */
        if(typeof(Worker) == 'undefined')
{
    alert('Sorry! No web worker support..');
}

/* Check to see if Server-Sent Events are supported */
if(typeof(EventSource) =='undefined')
{
alert('Sorry! No server-sent events support..');
}

/* Calculate custom attibutes */
$('#customdataattribute article ul').calculatecustomattributes();

/* Create a Web SQL object */
var db = openDatabase('mydb', '1.0', 'jimmy database', 2 * 1024 * 1024);
db.transaction(function(tx)
{
tx.executeSql('CREATE TABLE jimmy (id unique, text)');
});

/* Refresh the contents of our containers */
$('#sessionstorage article').displaysessionstorage();
$('#localstorage article').displaylocalstorage();
$('#websql article ul').displaywebsql(db);

/* Call the saveit function when the button is clicked */
$('button').click(function()
{
$(document).saveit(db);
});

/* Get updates for a server, here I've simulated the server with a PHP script */
var feed = new EventSource('twittieserver.php');
feed.onmessage = function(event)
{
/* Add new articles to the top of the list and limit the list to 4, thus removing the fourth item from the list */
$('#sse article ul').prepend(event.data);
if($('#sse article ul > li').size() == 4)
{
$('#sse article ul li:last-child').remove();
}
};

/* Get updates from a JavaScript, simply replacing the contents of the container with each new value returned */
w = new Worker("webworker.plugin.js");
w.onmessage = function(event)
{
$('#webworker article').html(event.data);
};
})();
</script>
</body>
</html>

Now twittieserve.php
<?php
header('Content-Type:text/event-stream');
header('Cache-Control:no-cache');
$seconds = date('s');
echo 'data:<li>Item '.$seconds.'</li>'.PHP_EOL.PHP_EOL;
flush();
?>

And finally, webworker.plugin.js
var i=0;
function timedCount()
{
i=i+1;
postMessage(i);
setTimeout("timedCount()",500);
}
timedCount();

Enjoy!

Friday 12 July 2013

Form changer jQuery plugin

Websites I work on often include the need to add a login, password reset and self-registration form. This requirement can either take up too much space on the page, or require a refresh to load each form. They could all easily be put in a container like a div and called upon (or shown) only when needed. This is what I've done with the example below.
The 'data-location' anchor attributes must correspond to the form ID's they are requesting.
First, I've hidden all the things not required to be visible on load and just spaced the links out (in blue).
Second, I've created the container, forms and links I need (in red).
Third, I've called my plugin to handle the interaction (in green).
Below the HTML, I present the plugin code. There is a little catch all at the top, just in case anyone creates a container with either an ID, class or neither.
Enjoy!
<!DOCTYPE html>
<html lang="en">
<head>
<title>Form changer</title>
<style>
#formholder #resetpassword, #formholder #selfregister, #formholder a[data-location="login"]
{
display:none;
}
#formholder a
{
margin:0.2em;
}
</style>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
</script>
</head>
<body>
<div id="formholder">
<form id="login">
<p>Hello from login</p>
</form>
<form id="resetpassword">
<p>Hello from reset password</p>
</form>
<form id="selfregister">
<p>Hello from self-register</p>
</form>
<a href="#" data-location="login">Login</a><a href="#" data-location="resetpassword">Reset password</a><a href="#" data-location="selfregister">Self-register</a>
</div>
<script src="formchanger.plugin.js"></script>
<script>
(function()
{
$('#formholder a').formchanger();
})();
</script>
</body>
</html>

Now the plugin code:
(function($)
{
$.fn.formchanger = function()
{
id = $(this).parent().attr('id');
clas = $(this).parent().attr('class');
tag = $(this).parent().get(0).tagName;
if(id != null)
{
container = '#'+id;
}
else if(clas != null)
{
container = '.'+clas;
}
else
{
container = tag;
}
anchors = $(container).children('a');
forms = $(container).children('form');
$(this).click(function()
{
$(anchors).show();
$(forms).hide();
$(container+' #'+$(this).data('location')).show();
$(this).hide();
});
};
})(jQuery);

Thursday 11 July 2013

Cross browser box shadows (yet again)

A client recently asked me to make their site a 'copy' (don't ask) of another website. The site needing to be copied had employed one of those shadows using a very long image with a drop shadow at either end and repeated on the Y axis as a background. Plus, top and bottom shadow images to give the 360 degree effect.  This wasn't going to be possible to use with the site which I had developed, since my site was responsive. So I had to return to the old chestnut of drop shadows in IE. If my client was asking for a 'copy' of another site, there was a good chance they were IE users and I couldn't assume I'd get away with providing standard solutions (I can say this, we have a good relationship) .
See below.

.container
{
  margin-top:20px;
  box-shadow:3px 3px 10px 5px #666666;
  -moz-box-shadow:3px 3px 10px 5px #666666;
  -webkit-box-shadow:3px 3px 10px 5px #666666;
  filter:
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=0,strength=5),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=45,strength=2),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=90,strength=5),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=135,strength=5),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=180,strength=10),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=225,strength=5),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=270,strength=5),
  progid:DXImageTransform.Microsoft.Shadow(color=#666666,direction=315,strength=2);
}

Wednesday 3 July 2013

Onload alerts with foundation.js

I was recently asked to help on a website which had been designed using the foundation framework. Naturally, I had to sift through lots of code to find how the site actually worked, but it's not a bad framework. One of the requirements was to create a message alert only when a text string had been passed to the page.

Below is an example of how I did it using PHP. There are 2 elements highlighted in red. Crucial code which was not highlighted in the online documentation. Code which I have added to do the job.

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" ><![endif]-->
<!--[if gt IE 8]><!--><html class="no-js" lang="en" ><!--<![endif]-->
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Foundation test</title>
<link rel="stylesheet" href="css/foundation.css" />
<script src="js/vendor/jquery.js"></script>
<script src="js/vendor/custom.modernizr.js"></script>
</head>
<body>
<div id="myModal" class="reveal-modal">
<h2>Alert!</h2>
<?php
echo '<p>'.urldecode($_GET['message']).'</p>';
?>
<a class="close-reveal-modal">&#215;</a>
</div>
<script src="js/foundation/foundation.js"></script>
<script src="js/foundation/foundation.reveal.js"></script>
<script>
$(document).foundation();
<?php
if(isset($_GET['message']))
{
?>
$('#myModal').foundation('reveal', 'open');
<?php
}
?>
</script>
</body>
</html>