Create a Posticks (Sticky Notes) app with HTML5, CSS3 and jQuery

While I was on vacation in the Dominican Republic, I had some free time to work in a small application that creates Posticks notes, or sticky notes, in the browsers and save it in the localStorage of the browser. If you want to know what I am talking about you can visit the demo. In addition, I would like to recommend reading about the following topics: HTML5, CSS3, contenteditable, and localStorage.

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Posticks</title>
  <link rel="stylesheet" rev="stylesheet" href="styles.css" />
  <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.3/themes/base/jquery-ui.css" type="text/css" media="all" />
</head>
<body>
  <header>
  	<h1>posticks</h1>
        <input type="button" value="Add Postick" id="btn-addNote" />
  </header>
<div id="board"></div>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script>
  <script type="text/javascript" src="js/scripts.js"></script>
</body>
</html>

The HTML code is very simple. We just create a HTML5 document that includes a header tag at the top of the page, including a h1 title and a button to create/add new postick notes to the board. Next, a div with “board” as an id attribute that is going to contains the posticks created. Also, there are references the following CSS and JavaScript files:

  • styles.css: saved locally to style the html.
  • jquery-ui.css: hosted in google and it is only used as a helper by the jquery-ui to add the drag event to the posticks.
  • jquery.min.js: jQuery hosted by google.
  • jquery-ui.min.js: hosted in google and it adds the drag functionality to the posticks.
  • scripts.js: hosted locally and it is where we add our code.

The HTML code for the posticks it is as follow:

<div class="postick">
  <div class="toolbar"><span class="delete" title="Close">x</span></div>
  <div contenteditable class="editable"></div>
</div>

Where each postick would have a class named “postick”, then would have a subdiv called “toolbar” containing a close button within a span. Also, the postick would have another with the class “editable,” which it will contain the text of the each postick.

CSS

/************ Tags ************/
 
/* Just some basic reset for the body tag */
body {
	background:#F1C387;
	padding:0;
	margin:0;
	font-family: Helvetica, Verdana, Geneva, sans-serif
}
 
header {
	padding-left:20px;
	height:50px;
	display:block;
	background:#0E0300;
	-webkit-box-shadow:0px 2px 5px gray;
	-moz-box-shadow:0px 2px 5px gray;
	box-shadow:0px 2px 5px gray;
	text-align:right;
}
 
h1 {
        color:white;	
        display:inline;
        font-size:210%;	
        padding:15px 10px 0px 0px;
	text-shadow: 1px -1px 0px #999; 
        text-transform:capitalize;
}
 
 
input[type="button"] {
        background:#EFE4DC;
        border:1px solid black;
        -moz-border-radius:5px;
        border-radius:5px;
        color:black;
        font-weight:bold;
        float:left;	
        padding:10px;
	margin:5px 10px 0 0;
        text-shadow: 1px 1px 0px white;
}
 
input[type="button"]:hover {
	background:#E03A00;
	color:white;
	text-shadow: 1px 1px 0px black;
	cursor:pointer;
}
 
/************ Classes ************/
 
.postick {
	border:1px solid gray;
	width:200px;
	height:200px;
	padding:4px;
	font-size:85%;
	background:#FFFC7F;
	-moz-box-shadow:2px 2px 2px #999999;
	-webkit-box-shadow:2px 2px 2px #999999;
	box-shadow:2px 2px 2px #999999;
	position:absolute;
}
 
.toolbar {
	text-align:right;
	font-weight:bold;
}
 
/* Postick's button "delete" */
.delete {
	cursor:pointer;
	font-size:120%;
}
 
/* Content to be editable inside the postick */
.editable {
	cursor:pointer;
	height:180px;
	marging:0 auto;
	width:100%;
	overflow:hidden;
	position:relative;
	-moz-text-shadow: 1px 1px 0px white;
	text-shadow: 1px 1px 0px white;
}
 
.editable:hover{
	border:1px dotted gray;
}

The CSS code is very simple; we just reset a little the body tag, user the input[type] selector to select all the buttons (In this case it is only one, but I encourage you to add more buttons like, remove all, clean all, etc.) Additionally, we have the class postick which style each of the postick created, the class toolbar, and delete that were described before and the class editable, which it would have a hover effect to let the user know what part of the element to click to start editing.

JavaScript

The JavaScript file it is very self-explanatory. If you have any questions about how it works, please leave a comment.

(function ($, $S) {
    //$ jQuery
    //$S window.localStorage
    //Variables Declaration
    var $board = $('#board'),
        //Board where the Posticks are sticked
        Postick, //Singleton Object containing the Functions to work with the LocalStorage
        len = 0, //Length of Objects in the LocalStorage 
        currentNotes = '', //Storage the html construction of the posticks
        o; //Actual Postick data in the localStorage
 
 
 
    //Manage the Posticks in the Local Storage
	//Each postick is saved in the localStorage as an Object  
    Postick = {
        add: function (obj) {
            obj.id = $S.length;
            $S.setItem(obj.id, JSON.stringify(obj));
        },
 
        retrive: function (id) {
            return JSON.parse($S.getItem(id));
        },
 
        remove: function (id) {
            $S.removeItem(id);
        },
 
        removeAll: function () {
            $S.clear();
        }
 
    };
 
    //If exist any postick, Create it/them
    len = $S.length;
    if (len) {
        for (var i = 0; i < len; i++) {
            //Create all posticks saved in localStorage
            var key = $S.key(i);
            o = Postick.retrive(key);
            currentNotes += '<div class="postick"';
            currentNotes += ' style="left:' + o.left;
            currentNotes += 'px; top:' + o.top;
			//data-key is the attribute to know what item delete in the localStorage
            currentNotes += 'px"><div class="toolbar"><span class="delete" data-key="' + key;
            currentNotes += '">x</span></div><div contenteditable="true" class="editable">';
            currentNotes += o.text;
            currentNotes += '</div>';
        }
 
        //Append all the posticks to the board
        $board.html(currentNotes);
    }
 
    //When the document is ready, make all posticks Draggable
    $(document).ready(function () {
        $(".postick").draggable({
            cancel: '.editable',
          "zIndex": 3000,
          "stack" : '.postick'
        });
    });
 
    //Remove Postick
    $('span.delete').live('click', function () {
        if (confirm('Are you sure you want to delete this Note?')) {
            var $this = $(this);
			//data-key is the attribute to know what item delete in the localStorage
            Postick.remove($this.attr('data-key'));
            $this.closest('.postick').fadeOut('slow', function () {
                $(this).remove();
            });
        }
    });
 
    //Create postick
    $('#btn-addNote').click(function () {
        $board.append('<div class="postick" style="left:20px;top:70px"><div class="toolbar"><span class="delete" title="Close">x</span></div><div contenteditable class="editable"></div></div>');
        $(".postick").draggable({
            cancel: '.editable'
        });
    });
 
    //Save all the posticks when the user leaves the page
    window.onbeforeunload = function () {
        //Clean the localStorage
        Postick.removeAll();
        //Then insert each postick into the LocalStorage
		//Saving their position on the page, in order to position them when the page is loaded again
        $('.postick').each(function () {
            var $this = $(this);
            Postick.add({
                top: parseInt($this.position().top),
                left: parseInt($this.position().left),
                text: $this.children('.editable').text()
            });
        });
    }
})(jQuery, window.localStorage);

Demo

Please review the demo at JSFiddle.net.

Teylor Feliz
Teylor Feliz

Teylor is a seasoned generalist that enjoys learning new things. He has over 20 years of experience wearing different hats that include software engineer, UX designer, full-stack developer, web designer, data analyst, database administrator, and others. He is the founder of Haketi, a small firm that provides services in design, development, and consulting.

Over the last ten years, he has taught hundreds of students at an undergraduate and graduate levels. He loves teaching and mentoring new designers and developers to navigate the rapid changing field of UX design and engineering.

Articles: 182