Make the notes sticky!
authoraroben <aroben@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Oct 2007 10:30:45 +0000 (10:30 +0000)
committeraroben <aroben@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Oct 2007 10:30:45 +0000 (10:30 +0000)
         Reviewed by Mark.

         * misc/DatabaseExample.html:
         * misc/deleteButton.tiff: Added.
         * misc/deleteButtonPressed.tiff: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@26817 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitSite/ChangeLog
WebKitSite/misc/DatabaseExample.html
WebKitSite/misc/deleteButton.tiff [new file with mode: 0644]
WebKitSite/misc/deleteButtonPressed.tiff [new file with mode: 0644]

index f71daa785228dcefa2c9fd586fc60232178bd03d..a7b3602f15438f227a47452f437f5582587c8dc6 100644 (file)
@@ -1,3 +1,13 @@
+2007-10-20  Adam Roben  <aroben@apple.com>
+
+        Make the notes sticky!
+
+        Reviewed by Mark.
+
+        * misc/DatabaseExample.html:
+        * misc/deleteButton.tiff: Added.
+        * misc/deleteButtonPressed.tiff: Added.
+
 2007-10-19  Timothy Hatcher  <timothy@apple.com>
 
         Reviewed by Mark Rowe.
index ea2f5bb13091a2f940983ddbffe97c003eecf22f..9d4fedee3c0baa8183ebc9e94196ebec2d2bd44c 100644 (file)
@@ -1,12 +1,52 @@
+<!doctype html>
 <html>
+<head>
+<title>WebKit HTML 5 SQL Storage Notes Demo</title>
 <style>
-#oddNote { background-color: White; }
-#evenNote { background-color: LightCyan; }
-#note { border: 2px dashed blue; padding: 2px; }
-</style>
+body {
+    font-family: 'Lucida Grande', 'Helvetica', sans-serif;
+}
 
-<script>
+.note {
+    background-color: rgb(255, 240, 70);
+    height: 250px;
+    padding: 10px;
+    position: absolute;
+    width: 200px;
+    -webkit-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5);
+}
+
+.closebutton {
+    background-image: url(deleteButton.tiff);
+    height: 30px;
+    position: absolute;
+    left: -15px;
+    top: -15px;
+    width: 30px;
+}
+
+.closebutton:active {
+    background-image: url(deleteButtonPressed.tiff);
+}
 
+.edit {
+    outline: none;
+}
+
+.timestamp {
+    position: absolute;
+    left: 0px;
+    right: 0px;
+    bottom: 0px;
+    font-size: 9px;
+    background-color: #db0;
+    color: white;
+    border-top: 1px solid #a80;
+    padding: 2px 4px;
+    text-align: right;
+}
+</style>
+<script>
 var db;
 try {
     db = openDatabase("NoteTest", "1.0");
@@ -16,82 +56,259 @@ if (!db) {
     alert("Failed to open the database on disk.  Are you using a WebKit nightly with this feature enabled?");
 }
 
-function insertNote(note, timestamp)
+try {
+    db.executeSql("CREATE TABLE WebKitStickyNotes (id REAL UNIQUE, note TEXT, timestamp REAL, left TEXT, top TEXT, zindex REAL)", [], function (result) {});
+} catch(e) { }
+
+var captured = null;
+var highestZ = 0;
+var highestId = 0;
+
+function Note()
 {
-    db.executeSql("INSERT INTO WebKitNotes VALUES (?, ?)", [note, timestamp], function(result) {
-        if (result.errorCode)
-            alert("Failed to save note in database");
-        else
-            appendNote(note, timestamp);
-    });
+    var self = this;
+
+    var note = document.createElement('div');
+    note.className = 'note';
+    note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
+    note.addEventListener('click', function() { return self.onNoteClick() }, false);
+    this.note = note;
+
+    var close = document.createElement('div');
+    close.className = 'closebutton';
+    close.addEventListener('click', function() { return self.close() }, false);
+    note.appendChild(close);
+
+    var edit = document.createElement('div');
+    edit.className = 'edit';
+    edit.setAttribute('contenteditable', true);
+    edit.addEventListener('keyup', function() { return self.onKeyUp() }, false);
+    note.appendChild(edit);
+    this.editField = edit;
+
+    var ts = document.createElement('div');
+    ts.className = 'timestamp';
+    ts.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
+    note.appendChild(ts);
+    this.lastModified = ts;
+
+    document.body.appendChild(note);
+    return this;
 }
 
-function saveNote()
-{    
-    if (!db)
-        return;
-
-    var note = document.getElementById("note").innerText;
-    var timestamp = new Date();
-    timestamp = timestamp.getTime();
-
-    // This CREATE TABLE might throw if the table already exists, so ignore that.
-    try {
-        db.executeSql("CREATE TABLE WebKitNotes (note TEXT, timestamp REAL)", [], function(result) {
-            insertNote(note, timestamp);
-        });
-    } catch(err) {
-        // The table already exists, so try an insert.
-        insertNote(note, timestamp);
-    }
+Note.prototype = {
+    get id()
+    {
+        if (!("_id" in this))
+            this._id = 0;
+        return this._id;
+    },
+
+    set id(x)
+    {
+        this._id = x;
+    },
+
+    get text()
+    {
+        return this.editField.innerHTML;
+    },
+
+    set text(x)
+    {
+        this.editField.innerHTML = x;
+    },
+
+    get timestamp()
+    {
+        if (!("_timestamp" in this))
+            this._timestamp = 0;
+        return this._timestamp;
+    },
+
+    set timestamp(x)
+    {
+        if (this._timestamp == x)
+            return;
+
+        this._timestamp = x;
+        var date = new Date();
+        date.setTime(parseFloat(x));
+        this.lastModified.textContent = modifiedString(date);
+    },
+
+    get left()
+    {
+        return this.note.style.left;
+    },
+
+    set left(x)
+    {
+        this.note.style.left = x;
+    },
+
+    get top()
+    {
+        return this.note.style.top;
+    },
+
+    set top(x)
+    {
+        this.note.style.top = x;
+    },
+
+    get zIndex()
+    {
+        return this.note.style.zIndex;
+    },
+
+    set zIndex(x)
+    {
+        this.note.style.zIndex = x;
+    },
+
+    close: function()
+    {
+        this.killSaveTimer();
+
+        db.executeSql("DELETE FROM WebKitStickyNotes WHERE id = ?", [this.id], function(result) {});
+        document.body.removeChild(this.note);
+    },
+
+    saveSoon: function()
+    {
+        this.cancelPendingSave();
+        var self = this;
+        this._saveTimer = setTimeout(function() { self.save() }, 200);
+    },
+
+    cancelPendingSave: function()
+    {
+        if (!("_saveTimer" in this))
+            return;
+        clearTimeout(this._saveTimer);
+        delete this._saveTimer;
+    },
+
+    save: function()
+    {
+        this.cancelPendingSave();
+
+        if ("dirty" in this) {
+            this.timestamp = new Date().getTime();
+            delete this.dirty;
+        }
+
+        db.executeSql("UPDATE WebKitStickyNotes SET note = ?, timestamp = ?, left = ?, top = ?, zindex = ? WHERE id = ?", [this.text, this.timestamp, this.left, this.top, this.zIndex, this.id], function(result) {});
+    },
+
+    saveAsNew: function()
+    {
+        this.timestamp = new Date().getTime();
+        db.executeSql("INSERT INTO WebKitStickyNotes (id, note, timestamp, left, top, zindex) VALUES (?, ?, ?, ?, ?, ?)", [this.id, this.text, this.timestamp, this.left, this.top, this.zIndex], function(result) {});
+    },
+
+    onMouseDown: function(e)
+    {
+        captured = this;
+        this.startX = e.clientX - this.note.offsetLeft;
+        this.startY = e.clientY - this.note.offsetTop;
+        this.zIndex = ++highestZ;
+
+        var self = this;
+        if (!("mouseMoveHandler" in this)) {
+            this.mouseMoveHandler = function(e) { return self.onMouseMove(e) }
+            this.mouseUpHandler = function(e) { return self.onMouseUp(e) }
+        }
+
+        document.addEventListener('mousemove', this.mouseMoveHandler, true);
+        document.addEventListener('mouseup', this.mouseUpHandler, true);
+
+        return false;
+    },
+
+    onMouseMove: function(e)
+    {
+        if (this != captured)
+            return true;
+
+        this.left = e.clientX - this.startX + 'px';
+        this.top = e.clientY - this.startY + 'px';
+        return false;
+    },
+
+    onMouseUp: function(e)
+    {
+        document.removeEventListener('mousemove', this.mouseMoveHandler, true);
+        document.removeEventListener('mouseup', this.mouseUpHandler, true);
+
+        this.save();
+        return false;
+    },
+
+    onNoteClick: function(e)
+    {
+        this.editField.focus();
+        getSelection().collapseToEnd();
+    },
+
+    onKeyUp: function()
+    {
+        this.dirty = true;
+        this.saveSoon();
+    },
 }
 
-var added = 0;
-var noteIDs = new Array();
-noteIDs[0] = "oddNote";
-noteIDs[1] = "evenNote";
+function loaded()
+{
+    db.executeSql("SELECT id, note, timestamp, left, top, zindex FROM WebKitStickyNotes", [], function(result) {
+        if (result.errorCode) {
+            alert('Failed to retrieve notes from database');
+            return;
+        }
 
-function appendNote(note, timestamp)
+        for (var i = 0; i < result.rows.length; ++i) {
+            var row = result.rows.item(i);
+            var note = new Note();
+            note.id = row['id'];
+            note.text = row['note'];
+            note.timestamp = row['timestamp'];
+            note.left = row['left'];
+            note.top = row['top'];
+            note.zIndex = row['zindex'];
+
+            if (row['id'] > highestId)
+                highestId = row['id'];
+            if (row['zindex'] > highestZ)
+                highestZ = row['zindex'];
+        }
+
+        if (!result.rows.length)
+            newNote();
+    });
+}
+
+function modifiedString(date)
 {
-    if (!db)
-        return;
-
-    var previousNotes = document.getElementById("previousNotes");
-    
-    var date = new Date();
-    date.setTime(parseFloat(timestamp));
-
-    var newdiv = document.createElement('div');
-    newdiv.setAttribute('id', noteIDs[added++ % 2]);
-    newdiv.innerText = date + ": " + note;
-    
-    previousNotes.appendChild(newdiv);
+    return 'Last Modified: ' + date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
 }
 
-function loaded()
+function newNote()
 {
-    if (!db)
-        return;
-
-    try {
-        db.executeSql("SELECT note, timestamp FROM WebKitNotes ORDER BY timestamp", [], function(result) {
-            if (result.errorCode) {
-                alert("Failed to retrieve previous notes from database");
-                return;
-            }
-            for (var i = 0; i < result.rows.length; ++i) {
-                var row = result.rows.item(i);
-                appendNote(row["note"], row["timestamp"]);
-            }
-        });
-    } catch(err) { }
+    var note = new Note();
+    note.id = ++highestId;
+    note.timestamp = new Date().getTime();
+    note.left = Math.round(Math.random() * 400) + 'px';
+    note.top = Math.round(Math.random() * 500) + 'px';
+    note.zIndex = ++highestZ;
+    note.saveAsNew();
 }
 
+addEventListener('load', loaded, false);
 </script>
-
-<body onload="loaded()">
-<div id="note" contenteditable>Enter your note here</div>
-<input type=button onclick="saveNote()" value="Save Note">
-<div id="previousNotes"></div>
+</head>
+<body>
+<p>This page demonstrates the use of the <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/section-sql.html">HTML 5 Client-side Database Storage API</a>. Any notes you create will be saved in a database on your local hard drive, and will be reloaded from that database the next time you visit this page. To try it out, use a <a href="http://nightly.webkit.org/">WebKit Nightly Build</a>.</p>
+<button onclick="newNote()">New Note</button>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/WebKitSite/misc/deleteButton.tiff b/WebKitSite/misc/deleteButton.tiff
new file mode 100644 (file)
index 0000000..bf4347e
Binary files /dev/null and b/WebKitSite/misc/deleteButton.tiff differ
diff --git a/WebKitSite/misc/deleteButtonPressed.tiff b/WebKitSite/misc/deleteButtonPressed.tiff
new file mode 100644 (file)
index 0000000..6232484
Binary files /dev/null and b/WebKitSite/misc/deleteButtonPressed.tiff differ