Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added basic sync screen

  • Loading branch information...
commit f42930d921b5b6ba921225e41a8638b3c1996587 1 parent ab58f28
@daleharvey authored
View
57 _attachments/index.html
@@ -2,7 +2,7 @@
<html>
<head>
<title>CouchNotes</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="style/main.css" type="text/css">
</head>
@@ -12,13 +12,15 @@
<script type="text/html" id="home_tpl">
<header>
+ <a id="sync" href="#!/sync/" class="left">Sync</a>
<h1>CouchNotes</h1>
<a href="#!/new/edit/" class="right plus">+</a>
</header>
+
<table class="notes" cellspacing="0">
{{#notes}}
<tr>
- <td><a href="#!/{{id}}/">{{title}}</a></td>
+ <td class="title"><a href="#!/{{id}}/">{{title}}</a></td>
<td class="date"><a href="#!/{{id}}/">{{date}}</a></td>
<td class="arrow"><a href="#!/{{id}}/">&gt;</a></td>
</tr>
@@ -27,8 +29,55 @@
{{^notes}}<div class="none">No Notes :(</div>{{/notes}}
</script>
+
+ <script type="text/html" id="sync_tpl">
+ <header>
+ <a class="left" href="#!">Back</a>
+ <h1>Sync</h1>
+ </header>
+
+ <div id="notes">
+
+ <div id="feedback">No Current Tasks</div>
+
+ <form action="#sync" id="syncform" class="mainform">
+ <fieldset>
+ <label>User Name
+ <span><input type="text" name="username" value="{{username}}"
+ id="username" placeholder="johndoe" /></span>
+ </label>
+ </fieldset>
+ <fieldset>
+ <label>Password
+ <span><input type="password" value="{{password}}"
+ id="password" name="password" /></span>
+ </label>
+ </fieldset>
+ <fieldset>
+ <label>Server
+ <span><input type="text" name="server" value="{{server}}"
+ id="server" placeholder="http://example.com" /></span>
+ </label>
+ </fieldset>
+ <fieldset>
+ <label>Database
+ <span><input type="text" name="database" value="{{database}}"
+ id="database" placeholder="mywork" /></span>
+ </label>
+ </fieldset>
+
+ <input type="hidden" name="action" id="syncaction" />
+
+ <div id="syncbtns">
+ <button class="syncbtn" id="push"><div>Push</div></button>
+ <button class="syncbtn" id="pull"><div>Pull</div></button>
+ </div>
+ </form>
+ </div>
+ </script>
<script type="text/html" id="create_tpl">
+
<header>
<a id="back" class="left">Back</a>
@@ -40,7 +89,9 @@
</header>
- <div id="notes"><textarea id="notestext">{{{notes}}}</textarea></div>
+ <div id="notes">
+ <textarea id="notestext">{{{notes}}}</textarea>
+ </div>
<footer>
<form action="#delete">
View
124 _attachments/notes.js
@@ -1,12 +1,16 @@
var Notes = (function () {
- var dbName = 'couchnotes',
+ var mainDb = document.location.pathname.split("/")[1],
+ ctrlDb = mainDb + "-ctrl",
+ storageKey = "syncDetails",
+ details = jsonStorage(storageKey),
router = new Router(),
- db = $.couch.db(dbName),
+ $db = $.couch.db(mainDb),
+ $ctrl = $.couch.db(ctrlDb),
currentDoc = null;
-
+
router.get(/^(!)?$/, function () {
- db.view(dbName + '/notes', {
+ $db.view('couchnotes/notes', {
descending : true,
success : function (data) {
var i, rows = [];
@@ -21,7 +25,11 @@ var Notes = (function () {
}
});
});
-
+
+ router.get('!/sync/', function () {
+ render("#sync_tpl", details);
+ });
+
router.get('!/:id/edit/', function (id) {
showNote(id, true);
});
@@ -38,9 +46,52 @@ var Notes = (function () {
});
});
+ function _changesListener(dbName, since) {
+ $.ajax({
+ method : "GET",
+ url : "/" + dbName + "/_changes",
+ data : {since: since, feed:"longpoll", include_docs: true},
+ contentType : "application/json",
+ dataType : "json",
+ "success": function (data) {
+ for( var i = 0; i < data.results.length; i++) {
+ var doc = data.results[i].doc;
+ if (doc.result && doc.status && doc.status === "complete") {
+ $("#feedback").text("Replication Complete");
+ }
+ }
+ _changesListener(dbName, data.last_seq);
+ }
+ });
+ };
+
+ function changesListener(dbName) {
+ $ctrl.info({
+ "success": function (data) {
+ _changesListener(dbName, data.update_seq);
+ },
+ error : function () {
+ $ctrl = false;
+ }
+ });
+ };
+
+ changesListener(ctrlDb);
+
+ function saveDetails() {
+
+ details = {
+ "username" : $("#username").val(),
+ "password" : $("#password").val(),
+ "server" : $("#server").val(),
+ "database" : $("#database").val()
+ };
+ jsonStorage(storageKey, details);
+ };
+
function showNote(id, edit) {
- db.openDoc(id, {
+ $db.openDoc(id, {
error : function (data) {
currentDoc = null;
renderNote({title:"New Note"}, edit);
@@ -79,7 +130,7 @@ var Notes = (function () {
title = notes.split('\n')[0];
if (notes === "" || title === "") {
- return false;
+ return callback();
}
var doc = {
@@ -87,16 +138,15 @@ var Notes = (function () {
title : title,
type : 'note',
notes : notes,
- created : new Date()
+ created : new Date().getTime()
};
if (currentDoc) {
doc._id = currentDoc._id;
doc._rev = currentDoc._rev;
}
-
- db.saveDoc(doc, {
+ $db.saveDoc(doc, {
success : function (data) {
if (!currentDoc) {
currentDoc = doc;
@@ -120,9 +170,20 @@ var Notes = (function () {
$('#content').html(Mustache.to_html($(tpl).html(), data));
};
+ function jsonStorage(key, val) {
+ if (val) {
+ localStorage[key] = JSON.stringify(val);
+ return true;
+ } else {
+ return localStorage && localStorage[key] &&
+ JSON.parse(localStorage[key]) || false;
+ }
+ };
+
// I dont like these global events, they are bound to the page permanently
// so may cause conflicts
function bindDomEvents() {
+
$("#notes textarea").live("focus", startEditing);
$("#back").live("click", function () {
@@ -130,12 +191,53 @@ var Notes = (function () {
document.location.href = '#!';
});
});
+
$("#save").live("click", function () {
saveNote(function (doc) {
- document.location.href = '#!/' + doc._id +'/';
+ if (doc) {
+ document.location.href = '#!/' + doc._id +'/';
+ }
});
});
};
+
+ function createUrlFromDetails() {
+ if (details.username === "") {
+ return "http://" + details.server + "/" + details.database;
+ } else {
+ return "http://" + details.username + ":" + details.password + "@"
+ + details.server + "/" + details.database;
+ }
+ };
+
+ function doReplication(obj) {
+ $.ajax({
+ "url": "/" + ctrlDb,
+ "type": 'POST',
+ "data": JSON.stringify(obj),
+ contentType : "application/json",
+ dataType : "json",
+ "success": function () {
+ $("#feedback").text("Starting Replication");
+ }
+ });
+ };
+
+ $("#push").live("click", function (obj) {
+ saveDetails();
+ doReplication({
+ "target" : createUrlFromDetails(),
+ "source" : mainDb
+ });
+ });
+
+ $("#pull").live("click", function () {
+ saveDetails();
+ doReplication({
+ "target" : mainDb,
+ "source" : createUrlFromDetails()
+ });
+ });
bindDomEvents();
router.init();
View
115 _attachments/style/main.css
@@ -1,8 +1,9 @@
/* add styles here */
-* {
+* {
margin:0px;
padding:0px;
+ border:0p;x
}
body {
@@ -23,6 +24,7 @@ header {
text-align:center;
padding:10px 0px;
border-bottom:2px solid #000;
+ height:28px;
}
header form, header a {
@@ -34,6 +36,7 @@ header form, header a {
header a, header input {
display:block;
margin:5px;
+ border-radius:5px;
-moz-border-radius:5px;
border:1px solid black;
color:white;
@@ -60,30 +63,40 @@ header a, header input {
}
h1 {
+ display:block;
+ position:absolute;
+ left:70px;
+ right:70px;
text-shadow:1px 1px 1px #000;
font-size:26px;
font-weight:normal;
+ white-space:nowrap;
+ overflow:hidden;
+ text-overflow: ellipsis;
}
-#notes {
+#notes {
+ /* padding-top:50px; */
display:block;
position:absolute;
top:50px;
left:0px;
right:0px;
- bottom:20px;
+ bottom:4px;
}
-#notes textarea {
+#notes textarea {
+ -webkit-appearance:none;
outline:none;
font-family: 'Reenie Beanie', arial, serif;
- /* font-size:26px; */
width:100%;
height:100%;
- border:0px;
+ border:1px solid transparent;
padding:10px 0px 10px 10px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ resize: none;
}
.hide {
@@ -96,15 +109,20 @@ footer {
}
.notes a {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
display:block;
font-size:18px;
color:#666;
height:100%;
text-decoration:none;
- padding:10px;
+ padding:10px 0;
outline:none;
}
+.title {
+ padding-left:10px;
+}
+
.notes {
margin-top:50px;
width:100%;
@@ -116,12 +134,25 @@ footer {
.arrow {
font-weight:bold;
- width:50px;
+ width:30px;
text-align:center;
}
+.arrow a {
+ display:block;
+ width:16px;
+ height:16px;
+ padding:0px;
+ line-height:16px;
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ background:#DDD;
+ color:white !important;;
+ margin:0px auto;
+}
+
.notes .date {
- width:150px;
+ width:100px;
text-align:right;
}
.notes .date a {
@@ -129,7 +160,7 @@ footer {
}
.notes .date a, .notes .arrow a {
color:#BBB;
- font-size:14px;
+ font-size:12px;
}
#delete {
@@ -151,4 +182,68 @@ input[type=submit] {
text-align:center;
color:#999;
margin:20px 0px;
+}
+
+
+fieldset {
+ border: 0 none;
+ border-bottom: 1px solid #DDD;
+ overflow: auto;
+ padding: 0;
+}
+
+
+label {
+ display: block;
+ float: left;
+ font-weight: bold;
+ height: 50px;
+ line-height: 50px;
+ position: relative;
+ width: 100%;
+}
+
+label span {
+ display: block;
+ float: right;
+}
+
+form {
+ padding: 0 10px;
+}
+
+input[type="password"],
+input[type="text"] {
+ border: 1px solid #999999;
+ font-size: 90%;
+ padding: 2px;
+}
+
+input[type="submit"], input[type="button"], button {
+ padding : 5px 5px;
+ background :
+ -webkit-gradient(linear, 0% 40%, 0% 70%, from(#F9F9F9), to(#E3E3E3));
+ background :
+ -moz-linear-gradient(center top , #F9F9F9, #E3E3E3)
+ repeat scroll 0 0 transparent;
+ border : 1px solid #666;
+ border-radius : 3px;
+ text-decoration : none;
+ cursor : pointer;
+ -moz-border-radius : 3px;
+ -webkit-border-radius : 3px;
+}
+
+#syncbtns button {
+ display:block;
+ width:100%;
+ margin-top:20px;
+ font-size:100%;
+ padding:10px;
+}
+
+#feedback {
+ margin : 20px;
+ background: #EEE;
+ padding:12px;
}
View
14 _attachments/utils.js
@@ -62,7 +62,9 @@ var Router = (function() {
};
function formSubmitted(e) {
-
+
+ console.log(e);
+
e.preventDefault();
var action = e.target.getAttribute("action");
@@ -291,14 +293,14 @@ Date.prototype.format = function (mask, utc) {
function prettyDate(date){
var diff = (((new Date()).getTime() - date.getTime()) / 1000),
day_diff = Math.floor(diff / 86400);
-
+
if ( isNaN(day_diff) || day_diff < 0 )
return;
-
- return day_diff == 0 && (
+
+ return day_diff == 0 && (
diff < 60 && "just now" ||
- diff < 120 && "1 minute ago" ||
- diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
+ diff < 120 && "1 min ago" ||
+ diff < 3600 && Math.floor( diff / 60 ) + " min ago" ||
diff < 7200 && "1 hour ago" ||
diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
day_diff == 1 && "Yesterday" ||
Please sign in to comment.
Something went wrong with that request. Please try again.