Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit ab58f28707bc30d3e23d4729211cace873ad7878 0 parents
@daleharvey authored
BIN  _attachments/delete.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 _attachments/index.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CouchNotes</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>
+ <link rel="stylesheet" href="style/main.css" type="text/css">
+ </head>
+
+ <body>
+
+ <div id="content"></div>
+
+ <script type="text/html" id="home_tpl">
+ <header>
+ <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="date"><a href="#!/{{id}}/">{{date}}</a></td>
+ <td class="arrow"><a href="#!/{{id}}/">&gt;</a></td>
+ </tr>
+ {{/notes}}
+ </table>
+ {{^notes}}<div class="none">No Notes :(</div>{{/notes}}
+
+ </script>
+
+ <script type="text/html" id="create_tpl">
+ <header>
+
+ <a id="back" class="left">Back</a>
+
+ <h1>{{title}}</h1>
+
+ <a class="right hide" id="save">Save</a>
+ <a href="{{editLink}}" id="edit" class="right hide">Edit</a>
+
+ </header>
+
+ <div id="notes"><textarea id="notestext">{{{notes}}}</textarea></div>
+
+ <footer>
+ <form action="#delete">
+ <input type="hidden" value="" />
+ <input type="submit" id="delete" value="" />
+ </form>
+ </footer>
+
+ </script>
+
+ </body>
+
+ <script src="../../../_utils/script/jquery.js"></script>
+ <script src="../../../_utils/script/jquery.couch.js"></script>
+ <script src="../../../_utils/script/sha1.js"></script>
+
+ <script src="./md5.js"></script>
+ <script src="./mustache.js"></script>
+ <script src="./utils.js"></script>
+ <script src="./notes.js"></script>
+
+</html>
379 _attachments/md5.js
@@ -0,0 +1,379 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
+var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
+function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
+function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
+function hex_hmac_md5(k, d)
+ { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function b64_hmac_md5(k, d)
+ { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
+function any_hmac_md5(k, d, e)
+ { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+ return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of a raw string
+ */
+function rstr_md5(s)
+{
+ return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data (raw strings)
+ */
+function rstr_hmac_md5(key, data)
+{
+ var bkey = rstr2binl(key);
+ if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
+
+ var ipad = Array(16), opad = Array(16);
+ for(var i = 0; i < 16; i++)
+ {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+
+ var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
+ return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
+}
+
+/*
+ * Convert a raw string to a hex string
+ */
+function rstr2hex(input)
+{
+ try { hexcase } catch(e) { hexcase=0; }
+ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+ var output = "";
+ var x;
+ for(var i = 0; i < input.length; i++)
+ {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F)
+ + hex_tab.charAt( x & 0x0F);
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to a base-64 string
+ */
+function rstr2b64(input)
+{
+ try { b64pad } catch(e) { b64pad=''; }
+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ var output = "";
+ var len = input.length;
+ for(var i = 0; i < len; i += 3)
+ {
+ var triplet = (input.charCodeAt(i) << 16)
+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
+ for(var j = 0; j < 4; j++)
+ {
+ if(i * 8 + j * 6 > input.length * 8) output += b64pad;
+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
+ }
+ }
+ return output;
+}
+
+/*
+ * Convert a raw string to an arbitrary string encoding
+ */
+function rstr2any(input, encoding)
+{
+ var divisor = encoding.length;
+ var i, j, q, x, quotient;
+
+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
+ var dividend = Array(Math.ceil(input.length / 2));
+ for(i = 0; i < dividend.length; i++)
+ {
+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
+ }
+
+ /*
+ * Repeatedly perform a long division. The binary array forms the dividend,
+ * the length of the encoding is the divisor. Once computed, the quotient
+ * forms the dividend for the next step. All remainders are stored for later
+ * use.
+ */
+ var full_length = Math.ceil(input.length * 8 /
+ (Math.log(encoding.length) / Math.log(2)));
+ var remainders = Array(full_length);
+ for(j = 0; j < full_length; j++)
+ {
+ quotient = Array();
+ x = 0;
+ for(i = 0; i < dividend.length; i++)
+ {
+ x = (x << 16) + dividend[i];
+ q = Math.floor(x / divisor);
+ x -= q * divisor;
+ if(quotient.length > 0 || q > 0)
+ quotient[quotient.length] = q;
+ }
+ remainders[j] = x;
+ dividend = quotient;
+ }
+
+ /* Convert the remainders to the output string */
+ var output = "";
+ for(i = remainders.length - 1; i >= 0; i--)
+ output += encoding.charAt(remainders[i]);
+
+ return output;
+}
+
+/*
+ * Encode a string as utf-8.
+ * For efficiency, this assumes the input is valid utf-16.
+ */
+function str2rstr_utf8(input)
+{
+ var output = "";
+ var i = -1;
+ var x, y;
+
+ while(++i < input.length)
+ {
+ /* Decode utf-16 surrogate pairs */
+ x = input.charCodeAt(i);
+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
+ {
+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
+ i++;
+ }
+
+ /* Encode output as utf-8 */
+ if(x <= 0x7F)
+ output += String.fromCharCode(x);
+ else if(x <= 0x7FF)
+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0xFFFF)
+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ else if(x <= 0x1FFFFF)
+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
+ 0x80 | ((x >>> 12) & 0x3F),
+ 0x80 | ((x >>> 6 ) & 0x3F),
+ 0x80 | ( x & 0x3F));
+ }
+ return output;
+}
+
+/*
+ * Encode a string as utf-16
+ */
+function str2rstr_utf16le(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
+ (input.charCodeAt(i) >>> 8) & 0xFF);
+ return output;
+}
+
+function str2rstr_utf16be(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length; i++)
+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
+ input.charCodeAt(i) & 0xFF);
+ return output;
+}
+
+/*
+ * Convert a raw string to an array of little-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+function rstr2binl(input)
+{
+ var output = Array(input.length >> 2);
+ for(var i = 0; i < output.length; i++)
+ output[i] = 0;
+ for(var i = 0; i < input.length * 8; i += 8)
+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
+ return output;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2rstr(input)
+{
+ var output = "";
+ for(var i = 0; i < input.length * 32; i += 8)
+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
+ return output;
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length.
+ */
+function binl_md5(x, len)
+{
+ /* append padding */
+ x[len >> 5] |= 0x80 << ((len) % 32);
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+ var a = 1732584193;
+ var b = -271733879;
+ var c = -1732584194;
+ var d = 271733878;
+
+ for(var i = 0; i < x.length; i += 16)
+ {
+ var olda = a;
+ var oldb = b;
+ var oldc = c;
+ var oldd = d;
+
+ a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+ d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+ c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
+ b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+ a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+ d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
+ c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+ b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+ a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
+ d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+ c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+ b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+ a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
+ d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+ c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+ b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
+
+ a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+ d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+ c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
+ b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+ a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+ d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
+ c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+ b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+ a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
+ d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+ c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+ b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
+ a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+ d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+ c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
+ b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+ a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+ d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+ c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
+ b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+ a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+ d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
+ c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+ b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+ a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
+ d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+ c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+ b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
+ a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+ d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+ c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
+ b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+ a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+ d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
+ c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+ b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+ a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
+ d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+ c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+ b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+ a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
+ d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+ c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+ b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
+ a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+ d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+ c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
+ b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ }
+ return Array(a, b, c, d);
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+ return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+ return (num << cnt) | (num >>> (32 - cnt));
+}
324 _attachments/mustache.js
@@ -0,0 +1,324 @@
+/*
+ mustache.js — Logic-less templates in JavaScript
+
+ See http://mustache.github.com/ for more info.
+*/
+
+var Mustache = function() {
+ var Renderer = function() {};
+
+ Renderer.prototype = {
+ otag: "{{",
+ ctag: "}}",
+ pragmas: {},
+ buffer: [],
+ pragmas_implemented: {
+ "IMPLICIT-ITERATOR": true
+ },
+ context: {},
+
+ render: function(template, context, partials, in_recursion) {
+ // reset buffer & set context
+ if(!in_recursion) {
+ this.context = context;
+ this.buffer = []; // TODO: make this non-lazy
+ }
+
+ // fail fast
+ if(!this.includes("", template)) {
+ if(in_recursion) {
+ return template;
+ } else {
+ this.send(template);
+ return;
+ }
+ }
+
+ template = this.render_pragmas(template);
+ var html = this.render_section(template, context, partials);
+ if(in_recursion) {
+ return this.render_tags(html, context, partials, in_recursion);
+ }
+
+ this.render_tags(html, context, partials, in_recursion);
+ },
+
+ /*
+ Sends parsed lines
+ */
+ send: function(line) {
+ if(line != "") {
+ this.buffer.push(line);
+ }
+ },
+
+ /*
+ Looks for %PRAGMAS
+ */
+ render_pragmas: function(template) {
+ // no pragmas
+ if(!this.includes("%", template)) {
+ return template;
+ }
+
+ var that = this;
+ var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
+ this.ctag);
+ return template.replace(regex, function(match, pragma, options) {
+ if(!that.pragmas_implemented[pragma]) {
+ throw({message:
+ "This implementation of mustache doesn't understand the '" +
+ pragma + "' pragma"});
+ }
+ that.pragmas[pragma] = {};
+ if(options) {
+ var opts = options.split("=");
+ that.pragmas[pragma][opts[0]] = opts[1];
+ }
+ return "";
+ // ignore unknown pragmas silently
+ });
+ },
+
+ /*
+ Tries to find a partial in the curent scope and render it
+ */
+ render_partial: function(name, context, partials) {
+ name = this.trim(name);
+ if(!partials || partials[name] === undefined) {
+ throw({message: "unknown_partial '" + name + "'"});
+ }
+ if(typeof(context[name]) != "object") {
+ return this.render(partials[name], context, partials, true);
+ }
+ return this.render(partials[name], context[name], partials, true);
+ },
+
+ /*
+ Renders inverted (^) and normal (#) sections
+ */
+ render_section: function(template, context, partials) {
+ if(!this.includes("#", template) && !this.includes("^", template)) {
+ return template;
+ }
+
+ var that = this;
+ // CSW - Added "+?" so it finds the tighest bound, not the widest
+ var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
+ "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
+ "\\s*", "mg");
+
+ // for each {{#foo}}{{/foo}} section do...
+ return template.replace(regex, function(match, type, name, content) {
+ var value = that.find(name, context);
+ if(type == "^") { // inverted section
+ if(!value || that.is_array(value) && value.length === 0) {
+ // false or empty list, render it
+ return that.render(content, context, partials, true);
+ } else {
+ return "";
+ }
+ } else if(type == "#") { // normal section
+ if(that.is_array(value)) { // Enumerable, Let's loop!
+ return that.map(value, function(row) {
+ return that.render(content, that.create_context(row),
+ partials, true);
+ }).join("");
+ } else if(that.is_object(value)) { // Object, Use it as subcontext!
+ return that.render(content, that.create_context(value),
+ partials, true);
+ } else if(typeof value === "function") {
+ // higher order section
+ return value.call(context, content, function(text) {
+ return that.render(text, context, partials, true);
+ });
+ } else if(value) { // boolean section
+ return that.render(content, context, partials, true);
+ } else {
+ return "";
+ }
+ }
+ });
+ },
+
+ /*
+ Replace {{foo}} and friends with values from our view
+ */
+ render_tags: function(template, context, partials, in_recursion) {
+ // tit for tat
+ var that = this;
+
+ var new_regex = function() {
+ return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
+ that.ctag + "+", "g");
+ };
+
+ var regex = new_regex();
+ var tag_replace_callback = function(match, operator, name) {
+ switch(operator) {
+ case "!": // ignore comments
+ return "";
+ case "=": // set new delimiters, rebuild the replace regexp
+ that.set_delimiters(name);
+ regex = new_regex();
+ return "";
+ case ">": // render partial
+ return that.render_partial(name, context, partials);
+ case "{": // the triple mustache is unescaped
+ return that.find(name, context);
+ default: // escape the value
+ return that.escape(that.find(name, context));
+ }
+ };
+ var lines = template.split("\n");
+ for(var i = 0; i < lines.length; i++) {
+ lines[i] = lines[i].replace(regex, tag_replace_callback, this);
+ if(!in_recursion) {
+ this.send(lines[i]);
+ }
+ }
+
+ if(in_recursion) {
+ return lines.join("\n");
+ }
+ },
+
+ set_delimiters: function(delimiters) {
+ var dels = delimiters.split(" ");
+ this.otag = this.escape_regex(dels[0]);
+ this.ctag = this.escape_regex(dels[1]);
+ },
+
+ escape_regex: function(text) {
+ // thank you Simon Willison
+ if(!arguments.callee.sRE) {
+ var specials = [
+ '/', '.', '*', '+', '?', '|',
+ '(', ')', '[', ']', '{', '}', '\\'
+ ];
+ arguments.callee.sRE = new RegExp(
+ '(\\' + specials.join('|\\') + ')', 'g'
+ );
+ }
+ return text.replace(arguments.callee.sRE, '\\$1');
+ },
+
+ /*
+ find `name` in current `context`. That is find me a value
+ from the view object
+ */
+ find: function(name, context) {
+ name = this.trim(name);
+
+ // Checks whether a value is thruthy or false or 0
+ function is_kinda_truthy(bool) {
+ return bool === false || bool === 0 || bool;
+ }
+
+ var value;
+ if(is_kinda_truthy(context[name])) {
+ value = context[name];
+ } else if(is_kinda_truthy(this.context[name])) {
+ value = this.context[name];
+ }
+
+ if(typeof value === "function") {
+ return value.apply(context);
+ }
+ if(value !== undefined) {
+ return value;
+ }
+ // silently ignore unkown variables
+ return "";
+ },
+
+ // Utility methods
+
+ /* includes tag */
+ includes: function(needle, haystack) {
+ return haystack.indexOf(this.otag + needle) != -1;
+ },
+
+ /*
+ Does away with nasty characters
+ */
+ escape: function(s) {
+ s = String(s === null ? "" : s);
+ return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
+ switch(s) {
+ case "&": return "&amp;";
+ case "\\": return "\\\\";
+ case '"': return '\"';
+ case "<": return "&lt;";
+ case ">": return "&gt;";
+ default: return s;
+ }
+ });
+ },
+
+ // by @langalex, support for arrays of strings
+ create_context: function(_context) {
+ if(this.is_object(_context)) {
+ return _context;
+ } else {
+ var iterator = ".";
+ if(this.pragmas["IMPLICIT-ITERATOR"]) {
+ iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
+ }
+ var ctx = {};
+ ctx[iterator] = _context;
+ return ctx;
+ }
+ },
+
+ is_object: function(a) {
+ return a && typeof a == "object";
+ },
+
+ is_array: function(a) {
+ return Object.prototype.toString.call(a) === '[object Array]';
+ },
+
+ /*
+ Gets rid of leading and trailing whitespace
+ */
+ trim: function(s) {
+ return s.replace(/^\s*|\s*$/g, "");
+ },
+
+ /*
+ Why, why, why? Because IE. Cry, cry cry.
+ */
+ map: function(array, fn) {
+ if (typeof array.map == "function") {
+ return array.map(fn);
+ } else {
+ var r = [];
+ var l = array.length;
+ for(var i = 0; i < l; i++) {
+ r.push(fn(array[i]));
+ }
+ return r;
+ }
+ }
+ };
+
+ return({
+ name: "mustache.js",
+ version: "0.3.1-dev",
+
+ /*
+ Turns a template and view into HTML
+ */
+ to_html: function(template, view, partials, send_fun) {
+ var renderer = new Renderer();
+ if(send_fun) {
+ renderer.send = send_fun;
+ }
+ renderer.render(template, view, partials);
+ if(!send_fun) {
+ return renderer.buffer.join("\n");
+ }
+ }
+ });
+}();
143 _attachments/notes.js
@@ -0,0 +1,143 @@
+var Notes = (function () {
+
+ var dbName = 'couchnotes',
+ router = new Router(),
+ db = $.couch.db(dbName),
+ currentDoc = null;
+
+ router.get(/^(!)?$/, function () {
+ db.view(dbName + '/notes', {
+ descending : true,
+ success : function (data) {
+ var i, rows = [];
+ for (i=0; i < data.total_rows; i++) {
+ rows.push({
+ id : data.rows[i].id,
+ title : data.rows[i].key[1],
+ date : formatDate(data.rows[i].key[0])
+ });
+ }
+ render("#home_tpl", {notes:rows});
+ }
+ });
+ });
+
+ router.get('!/:id/edit/', function (id) {
+ showNote(id, true);
+ });
+
+ router.get('!/:id/', function (id) {
+ showNote(id, false);
+ });
+
+ router.post('delete', function () {
+ db.removeDoc(currentDoc, {
+ success: function () {
+ document.location.href = "#!";
+ }
+ });
+ });
+
+
+ function showNote(id, edit) {
+ db.openDoc(id, {
+ error : function (data) {
+ currentDoc = null;
+ renderNote({title:"New Note"}, edit);
+ },
+ success : function (data) {
+ currentDoc = data;
+ data.created = formatDate(data.created);
+ data.editLink = '#!/' + data._id + '/edit/';
+ renderNote(data, edit);
+ }
+ });
+ };
+
+ function renderNote(data, edit) {
+ render("#create_tpl", data);
+ if (edit) {
+ $("#notes textarea")[0].focus();
+ } else {
+ stopEditing();
+ }
+ };
+
+ function startEditing() {
+ $("#edit").hide();
+ $("#save").show();
+ };
+
+ function stopEditing() {
+ $("#edit").show();
+ $("#save").hide();
+ };
+
+ function saveNote(callback) {
+
+ var notes = $("#notes textarea").val(),
+ title = notes.split('\n')[0];
+
+ if (notes === "" || title === "") {
+ return false;
+ }
+
+ var doc = {
+ _id : new Date().getTime() + "",
+ title : title,
+ type : 'note',
+ notes : notes,
+ created : new Date()
+ };
+
+ if (currentDoc) {
+ doc._id = currentDoc._id;
+ doc._rev = currentDoc._rev;
+ }
+
+
+ db.saveDoc(doc, {
+ success : function (data) {
+ if (!currentDoc) {
+ currentDoc = doc;
+ }
+ currentDoc._rev = data.rev;
+ if (typeof callback === "function") {
+ callback(doc);
+ }
+ }
+ });
+
+ return title;
+ };
+
+ function formatDate(date) {
+ return prettyDate(new Date(date));
+ };
+
+ function render(tpl, data) {
+ data = data || {};
+ $('#content').html(Mustache.to_html($(tpl).html(), data));
+ };
+
+ // 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 () {
+ saveNote(function (doc) {
+ document.location.href = '#!';
+ });
+ });
+ $("#save").live("click", function () {
+ saveNote(function (doc) {
+ document.location.href = '#!/' + doc._id +'/';
+ });
+ });
+ };
+
+ bindDomEvents();
+ router.init();
+
+})();
154 _attachments/style/main.css
@@ -0,0 +1,154 @@
+/* add styles here */
+
+* {
+ margin:0px;
+ padding:0px;
+}
+
+body {
+ font:1em Helvetica, sans-serif;
+}
+
+header {
+ display:block;
+ position:fixed;
+ top:0px;
+ width:100%;
+ background:-moz-linear-gradient(center top , #4C5861, #384147)
+ repeat scroll 0 0 transparent;
+ background : -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#4C5861),
+ color-stop(100%,#384147));
+ color:white;
+ text-align:center;
+ padding:10px 0px;
+ border-bottom:2px solid #000;
+}
+
+header form, header a {
+ cursor:pointer;
+ position:absolute;
+ top:5px;
+}
+
+header a, header input {
+ display:block;
+ margin:5px;
+ -moz-border-radius:5px;
+ border:1px solid black;
+ color:white;
+ text-decoration:none;
+ line-height:27px;
+ height:27px;
+ text-shadow:1px 1px 1px #000;
+ background:rgba(0,0,0,0.2);
+ font-size:13px;
+ padding:0px 8px;
+}
+
+.right {
+ right:10px;
+}
+.left {
+ left:10px;
+}
+
+.plus {
+ font-size:18px;
+ padding:0px;
+ width:25px;
+}
+
+h1 {
+ text-shadow:1px 1px 1px #000;
+ font-size:26px;
+ font-weight:normal;
+}
+
+#notes {
+ display:block;
+ position:absolute;
+ top:50px;
+ left:0px;
+ right:0px;
+ bottom:20px;
+}
+
+#notes textarea {
+ outline:none;
+ font-family: 'Reenie Beanie', arial, serif;
+ /* font-size:26px; */
+ width:100%;
+ height:100%;
+ border:0px;
+ padding:10px 0px 10px 10px;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+}
+
+.hide {
+ display:none;
+}
+
+footer {
+ position:absolute;
+ bottom:0px;
+}
+
+.notes a {
+ display:block;
+ font-size:18px;
+ color:#666;
+ height:100%;
+ text-decoration:none;
+ padding:10px;
+ outline:none;
+}
+
+.notes {
+ margin-top:50px;
+ width:100%;
+}
+
+.notes td {
+ border-bottom:1px solid #DDD;
+}
+
+.arrow {
+ font-weight:bold;
+ width:50px;
+ text-align:center;
+}
+
+.notes .date {
+ width:150px;
+ text-align:right;
+}
+.notes .date a {
+ text-align:right;
+}
+.notes .date a, .notes .arrow a {
+ color:#BBB;
+ font-size:14px;
+}
+
+#delete {
+ display:block;
+ height:48px;
+ width:48px;
+ border:0px;
+ background:url(../delete.png);
+ text-indent:-9999;
+}
+
+input[type=submit] {
+ cursor:pointer;
+}
+
+.none {
+ font:24px Times New Roman, serif;
+ font-style:italic;
+ text-align:center;
+ color:#999;
+ margin:20px 0px;
+}
751 _attachments/style/mobile.css
@@ -0,0 +1,751 @@
+html, body {
+ padding : 0px;
+ margin : 0px;
+ height : 100%;
+}
+
+body {
+ background : #E5E5E5;
+ font : 1em sans-serif;
+ overflow-y : scroll;
+ padding-bottom : 30px;
+}
+
+h1 {
+ margin : 0px;
+}
+h3 {
+ margin-top:0px;
+}
+
+a img {
+ border: 0px;
+}
+
+input[name="name"] {
+ margin-bottom:10px;
+}
+
+#account form {
+ background : #EEE;
+ padding : 10px;
+}
+input[type="text"], input[type="email"], input[type="password"] {
+ padding : 2px;
+ font-size : 90%;
+ border : 1px solid #999;
+}
+
+fieldset {
+ padding : 0px;
+ margin-bottom : 10px;
+ border : 0px;
+ overflow : auto;
+}
+
+label {
+ display : block;
+}
+
+#items, #active {
+ width : 100%;
+}
+
+ul {
+ list-style : none;
+ margin : 0;
+ padding : 0;
+}
+
+#items {
+ border-top : 1px solid #AAA;
+}
+#items li {
+ border-bottom : 1px solid #AAA;
+}
+
+div.none {
+ border-top : 1px solid #AAA;
+ border-bottom : 1px solid #AAA;
+}
+
+.users { margin-top:20px; }
+
+#items .users {
+ border-top : none;
+}
+
+li .message {
+ padding : 2px;
+}
+
+li .state {
+ display:block;
+ height:60px;
+ float : right;
+}
+
+.user a {
+ display : block;
+ padding : 5px;
+ height : 50px;
+ outline : none;
+ line-height : 50px;
+ text-decoration : none;
+ overflow : hidden;
+ color : darkblue;
+ background : -moz-linear-gradient(top, #C0CFE8 0%, #B1C9DD 100%);
+ background : -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#C0CFE8),
+ color-stop(100%,#B1C9DD));
+}
+
+.user, .item {
+ background : #EEE;
+ position : relative;
+ min-height : 40px;
+ overflow : auto;
+ cursor : pointer;
+}
+.item {
+ padding : 5px;
+}
+.details {
+ float:right;
+ padding : 4px;
+}
+
+#editheader {
+ height:45px;
+}
+.btn.back {
+ display:block;
+ margin:10px 0px;
+ float:left;
+ font-size:90%;
+ padding:4px;
+}
+
+#profile .item {
+ background : #EEE;
+ padding : 8px;
+ border-bottom : 1px solid #CCC;
+ overflow : hidden;
+ min-height : 0px;
+ height : 30px;
+}
+
+.item {
+ background : white;
+ color : #222;
+}
+
+.later {
+ background: -moz-linear-gradient(top, #C0CFE8 0%, #B1C9DD 100%);
+ background: -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#C0CFE8),
+ color-stop(100%,#B1C9DD));
+}
+
+.now, .active {
+ background: -moz-linear-gradient(top, #BEE5CC 0%, #B1DBCE 100%);
+ background: -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#BEE5CC),
+ color-stop(100%,#B1DBCE));
+}
+.done {
+ background: -moz-linear-gradient(top, #FFF 0%, #EEE 100%);
+ background: -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#FFF),
+ color-stop(100%,#EEE));
+}
+
+.selected {
+ background: -moz-linear-gradient(top, #666 0%, #333 100%);
+ background: -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#FFF),
+ color-stop(100%,#EEE));
+ color:#eee !important;
+}
+
+.blocked {
+ background-color : #fb8;
+ border-top : 2px solid #f00;
+ border-bottom : 2px solid #f00;
+}
+
+#profile label {
+ display : block;
+}
+
+.ava {
+ float : left;
+ width : 60px;
+ margin-right : 4px;
+ text-align : center;
+ padding : 4px 4px 0px 4px;
+ overflow : hidden;
+}
+
+.ava img {
+ display : block;
+ margin : 0px auto;
+}
+
+.small {
+ font-size : 0.8em;
+}
+
+div.avatar {
+ padding : 2px;
+ padding-bottom : 0;
+ margin-right : 4px;
+ float : left;
+ font-size : 0.78em;
+ width : 60px;
+ height : 60px;
+ text-align : center;
+}
+
+div.avatar .name {
+ padding-top : 2px;
+ position : absolute;
+ top : 0;
+ color : #999;
+ right : 0;
+}
+
+div.avatar img {
+ margin : 0 auto;
+ padding : 0;
+ width : 40px;
+ height : 40px;
+}
+
+#messagewrapper {
+ position : absolute;
+ right : 87px;
+ left : 9px;
+ top : 8px;
+ height : 30px;
+}
+
+#message {
+ height:100%;
+ width:100%;
+ margin : 0px;
+ font-size : 90%;
+ padding : 5px;
+ -webkit-box-sizing : border-box;
+ -moz-box-sizing : border-box;
+ -webkit-border-radius:0px;
+}
+
+select {
+ padding : 2px;
+}
+
+#notify {
+ position : fixed;
+ bottom : 40px;
+ left : 20px;
+ right : 20px;
+ padding : 20px 10px;
+ text-align : center;
+ background : #000;
+ color : white;
+ display : none;
+ opacity : 0.9;
+ z-index : 200;
+ -webkit-box-shadow :2px 2px 6px #000;
+ -webkit-border-radius :5px;
+ -moz-box-shadow :2px 2px 6px #000;
+ -moz-border-radius :5px;
+}
+
+#createbtn {
+ width:80px;
+ position : absolute;
+ right : 8px;
+ top : 8px;
+ z-index : 100;
+ margin : 0px;
+ height : 30px;
+ font-size : 90%;
+ padding : 4px;
+ z-index : 300;
+ text-align:center
+}
+
+.clearfix:after {
+ content : ".";
+ display : block;
+ height : 0;
+ clear : both;
+ visibility : hidden;
+}
+
+.cancel {
+ position : absolute;
+ bottom : 10px;
+ right : 10px;
+ display : none;
+}
+
+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;
+}
+
+.btn {
+ padding : 5px 5px;
+ margin : 0px 10px;
+ 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;
+ -moz-border-radius : 3px;
+ -webkit-border-radius : 3px;
+ text-decoration : none;
+ cursor : pointer;
+ color:black;
+}
+
+.cover {
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 100%;
+ height : 100%;
+ background : black;
+ opacity : 0.8;
+ z-index : 100;
+}
+
+.dialog {
+ margin-top : 5px;
+ position : absolute;
+ z-index : 200;
+ width : 220px;
+ left : 50%;
+ margin-left : -110px;
+}
+
+.save {
+ display : block;
+ margin-top : 20px;
+}
+
+.delete {
+ color : red;
+}
+
+.confirm {
+ color : green;
+}
+
+.warning {
+ margin : 5px;
+ background : red;
+ color : white;
+ padding : 5px 0px;
+ font-weight : bold;
+ text-align : center;
+}
+
+textarea[name="message"] {
+ width : 100%;
+ height : 60px;
+ margin-bottom : 10px;
+ -webkit-box-sizing : border-box;
+ -moz-box-sizing : border-box;
+}
+
+label.checkbox {
+ background : #FEFEFE;
+ border : 1px solid #CCC;
+ -moz-border-radius : 3px;
+ -webkit-border-radius : 3px;
+ padding : 3px;
+ margin : 10px 0px;
+}
+
+.desc, .tags, .mentions {
+ padding: 0px 10px;
+}
+.tags li, .mentions li {
+ display:inline;
+}
+.tags a, .mentions a {
+ text-decoration : none;
+ margin : 0px 10px 10px 10px;
+ color : darkblue;
+}
+.tags a:hover, .mentions a:hover {
+ color : lightblue;
+}
+
+.name {
+ font-size : 60%;
+ color : #333;
+}
+
+#navigation {
+ overflow : auto;
+ border-bottom : 1px solid #111;
+ background :
+ -webkit-gradient(linear, 0% 40%, 0% 70%, from(#4C5861), to(#384147));
+ background :
+ -moz-linear-gradient(center top, #4C5861, #384147)
+ repeat scroll 0 0 transparent;
+}
+#navigation li {
+ float : left;
+ width : 20%;
+}
+#navigation li a {
+ text-align : center;
+ text-decoration : none;
+ color : #EEE;
+ padding : 8px 0px;
+ line-height : 100%;
+ display : block;
+ outline : none;
+ border-left : 1px solid #666;
+ border-right : 1px solid #000;
+ text-shadow : 1px 1px 1px #000;
+ background :
+ -webkit-gradient(linear, 0% 40%, 0% 70%, from(#4C5861), to(#384147));
+ background :
+ -moz-linear-gradient(center top, #4C5861, #384147)
+ repeat scroll 0 0 transparent;
+}
+#navigation li:first-child a {
+ border-left:0px;
+}
+#navigation li:last-child a {
+ border-right:0px;
+}
+#navigation li a.selected {
+ background : -moz-linear-gradient(top, #C0CFE8 0%, #B1C9DD 100%);
+
+ background : -webkit-gradient(linear, left top, left bottom,
+ color-stop(0%,#C0CFE8),
+ color-stop(100%,#B1C9DD));
+ color : white;
+ border-left : 0px;
+ border-right : 0px;
+}
+
+#mainstate {
+ display:none;
+}
+
+#footer {
+ display:none !important;
+ background : white;
+ padding : 10px;
+ color : #999;
+ font-size : 80%;
+ border-top : 1px solid #AAA;
+}
+
+.modalform {
+ position : relative;
+ background : white;
+ margin : 20px auto;
+ padding : 30px;
+ width : 220px;
+ -moz-box-shadow : 0px 0px 5px #333;
+ -moz-border-radius : 5px;
+ -webkit-box-shadow : 0px 0px 5px #333;
+ -webkit-border-radius : 5px;
+}
+
+.modalform label span {
+ font-size : 80%;
+ display : block;
+ color : #999;
+}
+
+.modalform label {
+ display : block;
+ margin-bottom : 20px;
+}
+.modalform label input {
+ display : block;
+ width : 100%;
+}
+
+#content {
+ margin : 0px 0px 20px 0px;
+}
+
+#create {
+ display : block;
+ background : #384147;
+ padding : 5px 5px 2px 5px;
+ position : relative;
+ min-height : 40px;
+ overflow : auto;
+ outline : none;
+ z-index : 200;
+}
+#editform {
+ padding:0px 10px;
+}
+
+h2 {
+ font-weight : normal;
+ text-align : center;
+ margin-bottom : 20px;
+ font-weight : bold;
+ color : #2786C2;
+ text-shadow : 1px 1px 1px rgba(0, 0, 0, 0.1);
+}
+
+h3 #content {
+ text-indent : 20px;
+}
+
+.edit {
+ outline:none;
+}
+
+.now {
+ color:#222;
+}
+.status {
+ margin-top:3px;
+ line-height:20px;
+ font-size:90%;
+ display:block;
+ width:60px;
+ height:20px;
+ color:#333;
+ font-weight:bold;
+ text-indent:20px;
+}
+.public {
+ text-align:center;
+ width:20px;
+ height:35px;
+ overflow:hidden;
+ display : block;
+ width : 60px;
+ margin-top : 0px;
+}
+.public {
+ opacity:0.2;
+}
+.published .public {
+ opacity:0.6;
+}
+
+.isNotSelf .public {
+ display:none;
+}
+
+.now .status {
+ background:url(../hammer.png) no-repeat;
+}
+.later .status {
+ background:url(../ticket.png) no-repeat;
+}
+.done .status {
+ background:url(../star.png) no-repeat;
+}
+
+.none {
+ padding : 10px 0px;
+ text-align : center;
+ color : #999;
+ font-style : italic;
+ background : white;
+ font-family : serif;
+}
+
+.profileheader {
+ margin-top : 10px;
+ padding-left : 20px;
+}
+.profileheader h2 {
+ display : inline;
+ padding-left : 10px;
+}
+.profileheader img {
+ vertical-align:middle
+}
+
+.loading {
+ min-height : 100px;
+ background : url(../loading.gif) no-repeat center center;
+}
+
+.mainform label {
+ line-height : 50px;
+ height:50px;
+ float : left;
+ font-weight : bold;
+ width:100%;
+ position:relative;
+ display:block;
+}
+.first select {
+ position:relative;
+ top:-15px;
+}
+.mainform label span {
+ display:block;
+ float:right;
+}
+#syncform {
+ padding:0px 10px;
+}
+.mainform fieldset {
+ border-bottom : 1px solid #AAA;
+ border-top : 1px solid #FFF;
+ margin : 0px;
+}
+
+#editform div img {
+ vertical-align : middle;
+}
+
+.btns {
+ margin:20px 0px;
+ text-align:center;
+}
+.btns .btn {
+ margin:0px;
+ width:45%;
+ -webkit-box-sizing : border-box;
+ -moz-box-sizing : border-box;
+}
+.btns .btn:first-child {
+ margin-right:5%;
+}
+
+.gravatar {
+ width : 39px;
+ height : 39px;
+}
+
+.mainform .last {
+ border-bottom:0px;
+}
+.mainform .first {
+ border-top:0px;
+}
+
+header, #footer {
+ display:none;
+}
+.err404 {
+ margin:0px 20px;
+}
+.editing header {
+ display:none !important;
+}
+.details {
+ font-size : 80%;
+ font-style : italic;
+ color : #999;
+ margin : 5px 0px;
+ text-align : right;
+ font-family : serif;
+}
+
+.fullbtn {
+ width:100%;
+ display:block;
+}
+
+.startsync {
+ padding:10px;
+}
+
+.syncstatus {
+ width:100%;
+ text-align:left;
+ display:block;
+ -webkit-box-sizing : border-box;
+ -moz-box-sizing : border-box;
+ outline:none;
+}
+.syncstatus div {
+ outline:none;
+ text-indent:30px;
+}
+.working div {
+ background: url(../loadingsmall.gif) no-repeat 5px center !important;
+}
+.paused div {
+ background: url(../control-pause.png) no-repeat 5px center;
+}
+.running div {
+ background: url(../tick.png) no-repeat 5px center !important;
+}
+.paddedform {
+ padding: 0px 10px;
+}
+
+#gravatar_preview {
+ position:absolute;
+ top:15px;
+ right:25px;
+}
+
+button::-moz-focus-inner,
+input[type="reset"]::-moz-focus-inner,
+input[type="button"]::-moz-focus-inner,
+input[type="submit"]::-moz-focus-inner,
+input[type="file"] > input[type="button"]::-moz-focus-inner {
+ border: none;
+}
+
+.main {
+ padding:0px 10px;
+}
+
+#syncbtns button {
+ text-indent:20px;
+ width:33%;
+ float:left;
+ display:block;
+}
+#syncbtns button:last-child {
+ -moz-border-radius-topleft:0px;
+ -moz-border-radius-bottomleft:0px;
+ -webkit-border-radius-topleft:0px;
+ -webkit-border-radius-bottomleft:0px;
+}
+#syncbtns button:first-child {
+ -moz-border-radius-topright:0px;
+ -moz-border-radius-bottomright:0px;
+ -webkit-border-radius-topright:0px;
+ -webkit-border-radius-bottomright:0px;
+}
+
+#syncbtns {
+ overflow:auto;
+}
+#syncbtns .middle {
+ border-width:1px 0 1px 0;
+ -moz-border-radius:0px;
+ -webkit-border-radius:0px;
+ width:34%;
+}
BIN  _attachments/tick.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
308 _attachments/utils.js
@@ -0,0 +1,308 @@
+// Err a little NIH, some of the regex stuff is from sammy, but I only
+// wanted the routing, and the way sammy implemented routing isnt
+// great for my cpu (it polls by default even when the hashchange
+// is supported)
+var Router = (function() {
+
+ var PATH_REPLACER = "([^\/]+)",
+ PATH_MATCHER = /:([\w\d]+)/g,
+ preRouterFun = null,
+ fun404 = null,
+ routes = {GET: [], POST: []};
+
+ // Needs namespaced and decoupled and stuff
+ function init() {
+ $(window).bind("hashchange", urlChanged).trigger("hashchange");
+ $(document).bind("submit", formSubmitted);
+ };
+
+ function get(path, cb) {
+ route("GET", path, cb);
+ };
+
+ function post(path, cb) {
+ route("POST", path, cb);
+ };
+
+ function refresh(maintainScroll) {
+ urlChanged(maintainScroll);
+ };
+
+ function preRouter(fun) {
+ preRouterFun = fun;
+ };
+
+ function error404(fun) {
+ fun404 = fun;
+ };
+
+ function go(url) {
+ document.location.hash = url;
+ window.scrollTo(0,0);
+ };
+
+ function toRegex(path) {
+ return (path.constructor == String)
+ ? new RegExp("^"+path.replace(PATH_MATCHER, PATH_REPLACER)+"$")
+ : path;
+ };
+
+ function route(verb, path, cb) {
+ routes[verb].push({
+ path : toRegex(path),
+ callback : cb
+ });
+ };
+
+ function urlChanged(maintainScroll) {
+ trigger("GET", window.location.hash.slice(1));
+ if (maintainScroll !== true) {
+ window.scrollTo(0,0);
+ }
+ };
+
+ function formSubmitted(e) {
+
+ e.preventDefault();
+ var action = e.target.getAttribute("action");
+
+ if (action[0] === "#") {
+ trigger("POST", action.slice(1), e, serialize(e.target));
+ }
+ }
+
+ function trigger(verb, url, ctx, data) {
+ if (preRouterFun) {
+ if (!preRouterFun(verb, url, ctx)) {
+ return;
+ }
+ }
+ var match = matchPath(verb, url);
+ if (match) {
+ var args = match.match.slice(1);
+ if (verb === "POST") {
+ args.unshift(data);
+ args.unshift(ctx);
+ }
+ match.details.callback.apply(this, args);
+ } else {
+ if (fun404) {
+ fun404(verb, url);
+ }
+ }
+ };
+
+ function matchesCurrent(needle) {
+ return window.location.hash.slice(1).match(toRegex(needle));
+ };
+
+ function matchPath(verb, path) {
+ var i, tmp, arr = routes[verb];
+ for (i = 0; i < arr.length; i += 1) {
+ tmp = path.match(arr[i].path);
+ if (tmp) {
+ return {"match":tmp, "details":arr[i]};
+ }
+ }
+ return false;
+ };
+
+ function serialize(obj) {
+ var o = {};
+ var a = $(obj).serializeArray();
+ $.each(a, function() {
+ if (o[this.name]) {
+ if (!o[this.name].push) {
+ o[this.name] = [o[this.name]];
+ }
+ o[this.name].push(this.value || '');
+ } else {
+ o[this.name] = this.value || '';
+ }
+ });
+ return o;
+ };
+
+ return {
+ go : go,
+ get : get,
+ post : post,
+ init : init,
+ matchesCurrent : matchesCurrent,
+ pre : preRouter,
+ refresh : refresh,
+ error404 : error404
+ };
+
+});
+
+function linkUp(body, person_prefix, tag_prefix) {
+
+ //body = Mustache.escape(body);
+ person_prefix = person_prefix || "#!/mentions/";
+ tag_prefix = tag_prefix || "#!/tags/";
+
+ var tmp = body.replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi,function(a) {
+ return '<a target="_blank" href="'+a+'">'+a+'</a>';
+ });
+
+ function transformText(str) {
+ return str.replace(/\@([\w\-]+)/g, function(user,name) {
+ return '<a href="'+person_prefix+encodeURIComponent(name)+'">'+user+'</a>';
+ }).replace(/\#([\w\-\.]+)/g,function(word,tag) {
+ return '<a href="'+tag_prefix+encodeURIComponent(tag)+'">'+word+'</a>';
+ });
+ };
+
+ function replaceTags(dom) {
+ var i, tmp;
+ for (i = 0; i < dom.childNodes.length; i++) {
+ tmp = (dom.childNodes[i].nodeType === 3 &&
+ $(dom.childNodes[i]).parents("a").length === 0)
+ ? $("<span>"+transformText(dom.childNodes[i].textContent)+"</span>")[0]
+ : replaceTags(dom.childNodes[i]);
+
+ dom.replaceChild(tmp, dom.childNodes[i]);
+ }
+ return dom;
+ };
+
+ var div = document.createElement("div");
+ div.innerHTML = tmp;
+ return replaceTags(div).innerHTML;
+
+ //return tmp;
+};
+
+var dateFormat = function () {
+ var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+ timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+ timezoneClip = /[^-+\dA-Z]/g,
+ pad = function (val, len) {
+ val = String(val);
+ len = len || 2;
+ while (val.length < len) val = "0" + val;
+ return val;
+ };
+
+ // Regexes and supporting functions are cached through closure
+ return function (date, mask, utc) {
+ var dF = dateFormat;
+
+ // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+ if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
+ mask = date;
+ date = undefined;
+ }
+
+ // Passing date through Date applies Date.parse, if necessary
+ date = date ? new Date(date) : new Date;
+ if (isNaN(date)) throw SyntaxError("invalid date");
+
+ mask = String(dF.masks[mask] || mask || dF.masks["default"]);
+
+ // Allow setting the utc argument via the mask
+ if (mask.slice(0, 4) == "UTC:") {
+ mask = mask.slice(4);
+ utc = true;
+ }
+
+ var _ = utc ? "getUTC" : "get",
+ d = date[_ + "Date"](),
+ D = date[_ + "Day"](),
+ m = date[_ + "Month"](),
+ y = date[_ + "FullYear"](),
+ H = date[_ + "Hours"](),
+ M = date[_ + "Minutes"](),
+ s = date[_ + "Seconds"](),
+ L = date[_ + "Milliseconds"](),
+ o = utc ? 0 : date.getTimezoneOffset(),
+ flags = {
+ d: d,
+ dd: pad(d),
+ ddd: dF.i18n.dayNames[D],
+ dddd: dF.i18n.dayNames[D + 7],
+ m: m + 1,
+ mm: pad(m + 1),
+ mmm: dF.i18n.monthNames[m],
+ mmmm: dF.i18n.monthNames[m + 12],
+ yy: String(y).slice(2),
+ yyyy: y,
+ h: H % 12 || 12,
+ hh: pad(H % 12 || 12),
+ H: H,
+ HH: pad(H),
+ M: M,
+ MM: pad(M),
+ s: s,
+ ss: pad(s),
+ l: pad(L, 3),
+ L: pad(L > 99 ? Math.round(L / 10) : L),
+ t: H < 12 ? "a" : "p",
+ tt: H < 12 ? "am" : "pm",
+ T: H < 12 ? "A" : "P",
+ TT: H < 12 ? "AM" : "PM",
+ Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+ o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+ S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+ };
+
+ return mask.replace(token, function ($0) {
+ return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+ });
+ };
+}();
+
+// Some common format strings
+dateFormat.masks = {
+ "default": "ddd mmm dd yyyy HH:MM:ss",
+ shortDate: "m/d/yy",
+ mediumDate: "mmm d, yyyy",
+ longDate: "mmmm d, yyyy",
+ fullDate: "dddd, mmmm d, yyyy",
+ shortTime: "h:MM TT",
+ mediumTime: "h:MM:ss TT",
+ longTime: "h:MM:ss TT Z",
+ isoDate: "yyyy-mm-dd",
+ isoTime: "HH:MM:ss",
+ isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
+ isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+};
+
+// Internationalization strings
+dateFormat.i18n = {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ]
+};
+
+// For convenience...
+Date.prototype.format = function (mask, utc) {
+ return dateFormat(this, mask, utc);
+};
+
+// Takes an ISO time and returns a string representing how
+// long ago the date represents.
+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 && (
+ diff < 60 && "just now" ||
+ diff < 120 && "1 minute ago" ||
+ diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
+ diff < 7200 && "1 hour ago" ||
+ diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
+ day_diff == 1 && "Yesterday" ||
+ day_diff < 7 && day_diff + " days ago" ||
+ day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago" ||
+ day_diff < 365 && Math.ceil( day_diff / 31) + " months ago";
+};
1  _id
@@ -0,0 +1 @@
+_design/couchnotes
5 views/notes/map.js
@@ -0,0 +1,5 @@
+function(doc) {
+ if (doc.type && doc.type === 'note') {
+ emit([doc.created, doc.title], null);
+ }
+};
Please sign in to comment.
Something went wrong with that request. Please try again.