Todo from the url bar

by brennan

HTML

<script src="http://fonts.googleapis.com/css?family=Source+Sans+Pro"></script>
<div class="list">
    <img class="list-image" src="https://si0.twimg.com/profile_images/1509269555/316646_10150268132246996_514031995_8131645_3022929_n_reasonably_small.jpg">
    <h1>Todo List</h1>
    <ol class="todos">
        <li data-id="0">
            <input id="cb0" type="checkbox" checked />
            <label for="cb0">Do this</label>
        </li>
        <li data-id="1">
            <input id="cb1" type="checkbox" />
            <label for="cb1">Or this</label>
        </li>
    </ol>
</div>
<div class="addTodo">
    <form>
        <input type="text" placeholder="Add Todo..."/>
        <button type="submit">+</button>
    </form>
</div>

CSS

html{
    background:#ccc url(http://subtlepatterns.subtlepatterns.netdna-cdn.com/patterns/low_contrast_linen.png);
    font-family: 'Source Sans Pro', sans-serif;
}
.list{
    position:relative;
    margin:50px auto 0;
    width:400px;
    background: white url(http://subtlepatterns.subtlepatterns.netdna-cdn.com/patterns/retina_dust.png);
    border-radius:3px;
    border-bottom:2px solid #aaa;
    box-shadow:0 2px 5px rgba(0,0,0,0.6),
               0 3px 10px 5px rgba(0,0,0,0.3);
}
    .list-image{
        position:absolute;
        top:0px;left:50%;
        display:block;
        width:60px;
        height:60px;
        margin:-25px 0 0 -30px;
        border-radius:60px;
        box-shadow:0 2px 5px rgba(0,0,0,0.3),
               0 2px 10px 5px rgba(0,0,0,0.1);
    }
.list h1{
    background: -webkit-linear-gradient(top, rgba(0,0,0,0) 40%,rgba(0,0,0,0.2) 100%); /* Chrome10+,Safari5.1+ */
    height:65px;
    line-height:100px;
    font-size:20px;
    text-shadow:0 1px 2px rgba(0,0,0,0.5),
                0 1px 6px rgba(0,0,0,0.3);
    text-align:center;
    color:#fff;
}
.list .todos{
    background:#f8f8f8;
    border-bottom-right-radius:3px;
    border-bottom-left-radius:3px;
}
.list .todos li{
    padding:2px 10px;
    border-top:1px solid #fff;
    border-bottom:1px solid #ddd;
    line-height:28px;
}
.list .todos li:last-child{
    border-bottom:0;
}
.list .todos li input{
    float:left;
    margin-top:8px
}
.list .todos li label{
    margin-left:10px;
    text-shadow:0 1px 0 #fff;
}
.list .todos li input:checked + label{
    text-decoration: line-through;
    text-shadow:none;
    color:#999;
}


.addTodo{
    position:relative;
    display:block;
    padding:3px;
    margin:20px auto 0;
    width:350px;
    height:28px;
    background:-webkit-linear-gradient(top, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0) 100%);
    border-radius:5px;
    border-bottom:1px solid #444;
    box-shadow:inset 0 2px 3px rgba(0,0,0,0.3);
}

.addTodo button[type="submit"]{
   ...

JavaScript

var data = null;
if(location.hash){
    data = JSON.parse(location.hash.substr(1))
}

var todos = data || {
    0: {title:'Do this', checked: true},
    1: {title:'Or this', checked: false}
};

$('body').on('click', 'input[type="checkbox"]', function(){
    var id = $(this).closest('li').attr('data-id');
    todos[id].checked = $(this).is(':checked');
    saveTodos();
});

$('form').submit(function(e){
    e.preventDefault();
    
    todos[Object.keys(todos).length] = {
        title: $(this).find('input').val(),
        checked: false
    };
    
    $(this).find('input').val('');

    renderTodos();
});

function renderTodos(){
    var html = '';
    $.each(todos, function(id, todo){
        var checked = '';
        if(todo.checked){
            checked = 'checked';
        }
        
        html += '<li data-id="'+id+'">'+
                    '<input id="cb'+id+'" type="checkbox" '+checked+' />'+
                    '<label for="cb'+id+'">'+todo.title+'</label>'+
                '</li>';
        
    });
    
    $('.todos').html(html);
    saveTodos();
}

function saveTodos(){
    location.hash = JSON.stringify(todos);
}
    
    
renderTodos();