19 |
├── .gitignore ├── README.md ├── TODO.txt ├── _attachments ├── app.html ├── apps.html ├── images │ ├── couchapp.png │ ├── icon.png │ └── tile.png ├── index.html ├── script │ ├── app.js │ ├── jquery.scrollTo.js │ └── md5.js └── style │ └── main.css ├── couchapp.json ├── evently ├── apps │ └── _init │ │ ├── data.js │ │ ├── mustache.html │ │ ├── query.json │ │ └── render.txt ├── garden │ └── _init │ │ ├── after.js │ │ ├── async.js │ │ ├── data.js │ │ └── mustache.html ├── installs │ ├── load │ │ ├── after.js │ │ ├── path.txt │ │ └── xasync.js │ └── render │ │ ├── data.js │ │ ├── mustache.html │ │ └── selectors │ │ └── a.share │ │ └── click.js └── shares │ └── render │ ├── after.js │ ├── data.js │ ├── mustache.html │ ├── query.js │ ├── render.txt │ └── selectors │ └── form │ ├── change.js │ └── submit.js ├── lib └── garden.js ├── vendor └── couchapp │ ├── README.md │ ├── _attachments │ ├── docs.css │ ├── docs.html │ ├── docs.js │ ├── jquery.couch.app.js │ ├── jquery.couch.app.util.js │ ├── jquery.evently.js │ ├── jquery.mustache.js │ └── jquery.pathbinder.js │ ├── docs │ ├── account.md │ ├── couchapp.md │ ├── docs.md │ ├── evently.md │ ├── pathbinder.md │ └── profile.md │ ├── evently │ ├── account │ │ ├── _init.js │ │ ├── adminParty.js │ │ ├── doLogin.js │ │ ├── doLogout.js │ │ ├── doSignup.js │ │ ├── loggedIn │ │ │ ├── after.js │ │ │ ├── data.js │ │ │ ├── mustache.html │ │ │ └── selectors.json │ │ ├── loggedOut │ │ │ ├── mustache.html │ │ │ └── selectors.json │ │ ├── loginForm │ │ │ ├── after.js │ │ │ ├── mustache.html │ │ │ └── selectors │ │ │ │ ├── a[href=#signup].json │ │ │ │ └── form │ │ │ │ └── submit.js │ │ └── signupForm │ │ │ ├── after.js │ │ │ ├── mustache.html │ │ │ └── selectors │ │ │ ├── a[href=#login].json │ │ │ └── form │ │ │ └── submit.js │ ├── docs │ │ ├── index │ │ │ ├── data.js │ │ │ ├── mustache.html │ │ │ └── path.txt │ │ └── topic │ │ │ ├── after.js │ │ │ ├── data.js │ │ │ ├── edit │ │ │ └── _init │ │ │ │ ├── fun.js │ │ │ │ └── selectors │ │ │ │ ├── a.edit │ │ │ │ └── click.js │ │ │ │ └── a.run │ │ │ │ └── click.js │ │ │ ├── mustache.html │ │ │ └── path.txt │ └── profile │ │ ├── loggedIn.js │ │ ├── loggedOut │ │ ├── after.js │ │ └── mustache.html │ │ ├── noProfile │ │ ├── data.js │ │ ├── mustache.html │ │ └── selectors │ │ │ └── form │ │ │ └── submit.js │ │ └── profileReady │ │ ├── after.js │ │ ├── data.js │ │ └── mustache.html │ ├── lib │ ├── atom.js │ ├── cache.js │ ├── docform.js │ ├── list.js │ ├── markdown.js │ ├── path.js │ └── redirect.js │ └── metadata.json └── views └── apps └── map.js /.gitignore: -------------------------------------------------------------------------------- 1 | .couchapprc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CouchApp Garden 2 | 3 | I thought it would be fun to have a way to see all my installed CouchApps, so I made this. 4 | 5 | I hope you like it. 6 | 7 | If it doesn't run on your system, let me know -- it's pretty basic, so it should be easy to figure out. 8 | 9 | I'm following the #evently hashtag on twitter if people need assistance. 10 | 11 | Requires CouchDB 0.11 12 | 13 | Screenshot: 14 | 15 | [Screenshot of a list of CouchApps with icons and links](http://github.com/jchris/garden/blob/master/_attachments/images/icon.png) 16 | 17 | Patches welcome! 18 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | share this app! (Can do without query) 2 | shared_by should be profile 3 | copy app to garden db 4 | install this app 5 | pick a db 6 | copy to ddoc 7 | record install rev for noticing edits 8 | 9 | make index info as semantic html in a list function 10 | 11 | evently shared templates 12 | 13 | replication manager / db 14 | 15 | elsewhere: 16 | jchrisa.net 17 | plok.org 18 | couchapp.org 19 | etc 20 | +1 new 21 | 22 | for each: 23 | replicate 24 | app (push / pull) 25 | data (push / pull) 26 | 27 | 28 | versions: 29 | drl 1-rev 30 | sofa 2-rev 31 | 32 | 33 | 34 | Sofa, running in: 35 | 36 | [Daytime Running Lights](db.html#/db/drl) 37 | [jchris/sofa](source username when self rev match -- unedited) 38 | [Old Drl](db.html#/db/drl-old) 39 | [jchris/sofa]() update (when unedited but not same as same-users-shared) 40 | [Couchio Talk](db.html#/db/talk) 41 | [couchio/sofa]() 42 | [Sofa](db.html#/db/sofa) 43 | [sofa]() share (if rev no match) 44 | 45 | function db_link_username() { 46 | unedited 47 | username 48 | edited 49 | if (usename == me) 50 | me 51 | else 52 | remove username 53 | end 54 | } 55 | 56 | update() { 57 | unedited && shared[username].rev != my rev 58 | } 59 | 60 | edited() { 61 | install_rev != ddoc_rev 62 | // store in install record 63 | (could we use rev prefix?) 64 | } 65 | 66 | share() { 67 | edited || !doc.garden 68 | } 69 | 70 | Shared Versions: 71 | 72 | [couchio/sofa](shared/couchio/_design/sofa) 73 | Install 74 | [jchris/sofa](shared/jchris/_design/sofa) 75 | Install 76 | on click 77 | to which db? 78 | drl 79 | drl-old 80 | sofa 81 | + other / new 82 | 83 | 84 | [oreillymedia/sofa](shared/oreillymedia/_design/sofa) 85 | Install 86 | [benoit/sofa](shared/benoit/_design/sofa) 87 | Install -------------------------------------------------------------------------------- /_attachments/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |Install these CouchApps.
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /_attachments/images/couchapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchris/garden/7238b9b182b56e3d3311419cb9673f9ea9709ccb/_attachments/images/couchapp.png -------------------------------------------------------------------------------- /_attachments/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchris/garden/7238b9b182b56e3d3311419cb9673f9ea9709ccb/_attachments/images/icon.png -------------------------------------------------------------------------------- /_attachments/images/tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchris/garden/7238b9b182b56e3d3311419cb9673f9ea9709ccb/_attachments/images/tile.png -------------------------------------------------------------------------------- /_attachments/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Easy access to all your CouchApps. Browse available apps.
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /_attachments/script/app.js: -------------------------------------------------------------------------------- 1 | $.couch.app(function() { 2 | var app = this; 3 | 4 | // $("#garden").evently(app.ddoc.evently.garden, app); 5 | // $("#replicate").evently(app.ddoc.evently.replicate, app); 6 | $("#account").evently(app.ddoc.vendor.couchapp.evently.account, app); 7 | 8 | // $.pathbinder.begin("/"); 9 | 10 | 11 | 12 | 13 | // give an option to copy those ddocs to the garden db for sharing 14 | 15 | // ability to replicate remote gardens into the local garden 16 | 17 | // bookmark remote gardens info in the garden, so that that info also replicates 18 | // remote garden bookmarks should have non-uuid docids to prevent duplicate entries for popular sources? 19 | 20 | // ability to install ddocs in the local garden into local databases 21 | // this should have a warning! 22 | }); -------------------------------------------------------------------------------- /_attachments/script/jquery.scrollTo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.ScrollTo - Easy element scrolling using jQuery. 3 | * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com 4 | * Dual licensed under MIT and GPL. 5 | * Date: 9/11/2008 6 | * @author Ariel Flesler 7 | * @version 1.4 8 | * 9 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html 10 | */ 11 | ;(function(h){var m=h.scrollTo=function(b,c,g){h(window).scrollTo(b,c,g)};m.defaults={axis:'y',duration:1};m.window=function(b){return h(window).scrollable()};h.fn.scrollable=function(){return this.map(function(){var b=this.parentWindow||this.defaultView,c=this.nodeName=='#document'?b.frameElement||b:this,g=c.contentDocument||(c.contentWindow||c).document,i=c.setInterval;return c.nodeName=='IFRAME'||i&&h.browser.safari?g.body:i?g.documentElement:this})};h.fn.scrollTo=function(r,j,a){if(typeof j=='object'){a=j;j=0}if(typeof a=='function')a={onAfter:a};a=h.extend({},m.defaults,a);j=j||a.speed||a.duration;a.queue=a.queue&&a.axis.length>1;if(a.queue)j/=2;a.offset=n(a.offset);a.over=n(a.over);return this.scrollable().each(function(){var k=this,o=h(k),d=r,l,e={},p=o.is('html,body');switch(typeof d){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(d)){d=n(d);break}d=h(d,this);case'object':if(d.is||d.style)l=(d=h(d)).offset()}h.each(a.axis.split(''),function(b,c){var g=c=='x'?'Left':'Top',i=g.toLowerCase(),f='scroll'+g,s=k[f],t=c=='x'?'Width':'Height',v=t.toLowerCase();if(l){e[f]=l[i]+(p?0:s-o.offset()[i]);if(a.margin){e[f]-=parseInt(d.css('margin'+g))||0;e[f]-=parseInt(d.css('border'+g+'Width'))||0}e[f]+=a.offset[i]||0;if(a.over[i])e[f]+=d[v]()*a.over[i]}else e[f]=d[i];if(/^\d+$/.test(e[f]))e[f]=e[f]<=0?0:Math.min(e[f],u(t));if(!b&&a.queue){if(s!=e[f])q(a.onAfterFirst);delete e[f]}});q(a.onAfter);function q(b){o.animate(e,j,a.easing,b&&function(){b.call(this,r,a)})};function u(b){var c='scroll'+b,g=k.ownerDocument;return p?Math.max(g.documentElement[c],g.body[c]):k[c]}}).end()};function n(b){return typeof b=='object'?b:{top:b,left:b}}})(jQuery); -------------------------------------------------------------------------------- /_attachments/script/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 17 | 18 | /* 19 | * These are the functions you'll usually want to call 20 | * They take string arguments and return either hex or base-64 encoded strings 21 | */ 22 | function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} 23 | function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} 24 | function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} 25 | function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } 26 | function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } 27 | function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } 28 | 29 | /* 30 | * Perform a simple self-test to see if the VM is working 31 | */ 32 | function md5_vm_test() 33 | { 34 | return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; 35 | } 36 | 37 | /* 38 | * Calculate the MD5 of an array of little-endian words, and a bit length 39 | */ 40 | function core_md5(x, len) 41 | { 42 | /* append padding */ 43 | x[len >> 5] |= 0x80 << ((len) % 32); 44 | x[(((len + 64) >>> 9) << 4) + 14] = len; 45 | 46 | var a = 1732584193; 47 | var b = -271733879; 48 | var c = -1732584194; 49 | var d = 271733878; 50 | 51 | for(var i = 0; i < x.length; i += 16) 52 | { 53 | var olda = a; 54 | var oldb = b; 55 | var oldc = c; 56 | var oldd = d; 57 | 58 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); 59 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); 60 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); 61 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); 62 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); 63 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); 64 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); 65 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); 66 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); 67 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); 68 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); 69 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); 70 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); 71 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); 72 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); 73 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); 74 | 75 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); 76 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); 77 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); 78 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); 79 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); 80 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); 81 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); 82 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); 83 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); 84 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); 85 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); 86 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); 87 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); 88 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); 89 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); 90 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); 91 | 92 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); 93 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); 94 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); 95 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); 96 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); 97 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); 98 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); 99 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); 100 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); 101 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); 102 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); 103 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); 104 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); 105 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); 106 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); 107 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); 108 | 109 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); 110 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); 111 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); 112 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); 113 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); 114 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); 115 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); 116 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); 117 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); 118 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); 119 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); 120 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); 121 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); 122 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); 123 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); 124 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); 125 | 126 | a = safe_add(a, olda); 127 | b = safe_add(b, oldb); 128 | c = safe_add(c, oldc); 129 | d = safe_add(d, oldd); 130 | } 131 | return Array(a, b, c, d); 132 | 133 | } 134 | 135 | /* 136 | * These functions implement the four basic operations the algorithm uses. 137 | */ 138 | function md5_cmn(q, a, b, x, s, t) 139 | { 140 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); 141 | } 142 | function md5_ff(a, b, c, d, x, s, t) 143 | { 144 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 145 | } 146 | function md5_gg(a, b, c, d, x, s, t) 147 | { 148 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 149 | } 150 | function md5_hh(a, b, c, d, x, s, t) 151 | { 152 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 153 | } 154 | function md5_ii(a, b, c, d, x, s, t) 155 | { 156 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 157 | } 158 | 159 | /* 160 | * Calculate the HMAC-MD5, of a key and some data 161 | */ 162 | function core_hmac_md5(key, data) 163 | { 164 | var bkey = str2binl(key); 165 | if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); 166 | 167 | var ipad = Array(16), opad = Array(16); 168 | for(var i = 0; i < 16; i++) 169 | { 170 | ipad[i] = bkey[i] ^ 0x36363636; 171 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 172 | } 173 | 174 | var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); 175 | return core_md5(opad.concat(hash), 512 + 128); 176 | } 177 | 178 | /* 179 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 180 | * to work around bugs in some JS interpreters. 181 | */ 182 | function safe_add(x, y) 183 | { 184 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 185 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 186 | return (msw << 16) | (lsw & 0xFFFF); 187 | } 188 | 189 | /* 190 | * Bitwise rotate a 32-bit number to the left. 191 | */ 192 | function bit_rol(num, cnt) 193 | { 194 | return (num << cnt) | (num >>> (32 - cnt)); 195 | } 196 | 197 | /* 198 | * Convert a string to an array of little-endian words 199 | * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. 200 | */ 201 | function str2binl(str) 202 | { 203 | var bin = Array(); 204 | var mask = (1 << chrsz) - 1; 205 | for(var i = 0; i < str.length * chrsz; i += chrsz) 206 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); 207 | return bin; 208 | } 209 | 210 | /* 211 | * Convert an array of little-endian words to a string 212 | */ 213 | function binl2str(bin) 214 | { 215 | var str = ""; 216 | var mask = (1 << chrsz) - 1; 217 | for(var i = 0; i < bin.length * 32; i += chrsz) 218 | str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); 219 | return str; 220 | } 221 | 222 | /* 223 | * Convert an array of little-endian words to a hex string. 224 | */ 225 | function binl2hex(binarray) 226 | { 227 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 228 | var str = ""; 229 | for(var i = 0; i < binarray.length * 4; i++) 230 | { 231 | str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + 232 | hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); 233 | } 234 | return str; 235 | } 236 | 237 | /* 238 | * Convert an array of little-endian words to a base-64 string 239 | */ 240 | function binl2b64(binarray) 241 | { 242 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 243 | var str = ""; 244 | for(var i = 0; i < binarray.length * 4; i += 3) 245 | { 246 | var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) 247 | | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) 248 | | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); 249 | for(var j = 0; j < 4; j++) 250 | { 251 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 252 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 253 | } 254 | } 255 | return str; 256 | } 257 | -------------------------------------------------------------------------------- /_attachments/style/main.css: -------------------------------------------------------------------------------- 1 | /* add styles here */ 2 | 3 | pre { 4 | background:#eee; 5 | } 6 | 7 | body { 8 | font:1em Helvetica, sans-serif; 9 | padding:4px; 10 | background:url(../images/tile.png); 11 | } 12 | 13 | h1, h3 { 14 | margin:0; 15 | padding:0; 16 | } 17 | 18 | ul { 19 | list-style-type: none; 20 | margin:0; padding:0; 21 | } 22 | 23 | #account { 24 | float:right; 25 | } 26 | 27 | #garden h4 { 28 | padding:0; 29 | margin:0 0 8px 0; 30 | } 31 | 32 | li { 33 | margin:8px; 34 | padding:8px; 35 | border:4px dotted #bbc; 36 | } 37 | 38 | #shares .icon img { 39 | border:2px solid #bbc; 40 | } 41 | 42 | li.app { 43 | float:left; 44 | width:200px; 45 | height:200px; 46 | border:4px solid #55b; 47 | background:#eef; 48 | overflow:hidden; 49 | text-align:center; 50 | } 51 | 52 | #garden li.app h3 { 53 | padding:0; 54 | margin:0; 55 | font-size:1em; 56 | } 57 | 58 | #garden li.app h4 { 59 | font-size:0.8em; 60 | color:#555; 61 | text-align:left; 62 | } 63 | 64 | #shares { 65 | width:40%; 66 | float:left; 67 | } 68 | 69 | #installs { 70 | width:40%; 71 | float:left; 72 | } 73 | 74 | div.icon { 75 | max-height:150px; 76 | overflow:hidden; 77 | } 78 | 79 | .icon img { 80 | width:150px; 81 | } 82 | 83 | .info { 84 | float:right; 85 | font-size:0.75em; 86 | } 87 | 88 | div.screen { 89 | float:left; 90 | margin-right:8px; 91 | } 92 | 93 | .clear { 94 | clear:left; 95 | } -------------------------------------------------------------------------------- /couchapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CouchApp Garden", 3 | "description": "Tells you all the local CouchApps, allows you to share them!" 4 | } -------------------------------------------------------------------------------- /evently/apps/_init/data.js: -------------------------------------------------------------------------------- 1 | function(row) { 2 | var info = row.value.shared.info; 3 | info.shared_by = row.value.shared.by; 4 | info.icon = info.icon || "images/couchapp.png"; 5 | info.shared_doc_id = row.id; 6 | return info; 7 | }; -------------------------------------------------------------------------------- /evently/apps/_init/mustache.html: -------------------------------------------------------------------------------- 1 |{{#shared_by}}Shared by: {{shared_by}}/{{/shared_by}}{{name}}
9 | {{#share}} 10 | share 11 | {{/share}} 12 | {{#update}} 13 | update 14 | {{/update}} 15 | 16 |from db: {{#from_db}}{{from_db}}{{/from_db}}
7 | 24 | 25 |Installing into ' + db + '...
'); 10 | garden.installApp(app, db, shared_doc_id, { 11 | success : function() { 12 | $(".progress:last",form).text("Installed into "+db); 13 | } 14 | }); 15 | } 16 | 17 | if (db == "_other") { 18 | db = $("[name=other]", form).val(); 19 | var create = $("[name=create]", form).is(':checked'); 20 | if (create) { 21 | $.couch.db(db).create({ 22 | success : installApp, 23 | error : installApp 24 | }); 25 | } else { 26 | installApp(); 27 | } 28 | } else { 29 | installApp(); 30 | } 31 | 32 | return false; 33 | }; -------------------------------------------------------------------------------- /lib/garden.js: -------------------------------------------------------------------------------- 1 | function couchAppName(ddoc) { 2 | var name; 3 | name = ddoc.couchapp && ddoc.couchapp.name; 4 | if (name && name != "Name of your CouchApp") { 5 | return name; 6 | } else { 7 | name = ddoc._id.split('/'); 8 | name.shift(); 9 | return name.join('/'); 10 | } 11 | } 12 | 13 | function couchAppSlug(ddoc) { 14 | var slug = ddoc._id.split('/'); 15 | slug.shift(); 16 | return slug.join('/'); 17 | } 18 | 19 | 20 | function couchAppIcon(db, ddoc) { 21 | if (ddoc._attachments && ddoc._attachments["images/icon.png"]) { 22 | return ['', db, ddoc._id, "images/icon.png"].join('/'); 23 | } 24 | } 25 | 26 | function couchAppPath(db, ddoc) { 27 | var index, path; 28 | index = ddoc.couchapp && ddoc.couchapp.index; 29 | if (index) { 30 | path = ['', db, ddoc._id, index].join('/'); 31 | } else if (ddoc._attachments && ddoc._attachments["index.html"]) { 32 | path = ['', db, ddoc._id, "index.html"].join('/'); 33 | } 34 | return path; 35 | } 36 | 37 | function installId(db, ddoc) { 38 | return [db, ddoc._id].join("/"); 39 | } 40 | 41 | function edited(ddoc) { 42 | return false; 43 | } 44 | 45 | function share(ddoc) { 46 | return (!ddoc.garden || edited(ddoc)); 47 | }; 48 | 49 | function couchAppSharedBy(ddoc) { 50 | if (ddoc.garden && ddoc.garden.shared) {return ddoc.garden.shared.shared_by;} 51 | }; 52 | 53 | // update must be called at render time, when shares are known 54 | // function update(ddoc) { 55 | // return !edited() && shared[username].rev != my rev 56 | // } 57 | 58 | // todo use this in map fun 59 | function appInfo(db, ddoc) { 60 | var info = { 61 | name : couchAppName(ddoc), 62 | shared_by : couchAppSharedBy(ddoc), 63 | slug : couchAppSlug(ddoc), 64 | path : couchAppPath(db, ddoc), 65 | icon : couchAppIcon(db, ddoc), 66 | db : db, 67 | install_id : installId(db, ddoc), 68 | share : share(ddoc) 69 | } 70 | if (info.path) { 71 | return info; 72 | } 73 | }; 74 | 75 | function appInfos(db, rows) { 76 | var app_infos = []; 77 | for (var i=0; i < rows.length; i++) { 78 | var row = rows[i]; 79 | var app_info = appInfo(db, row.doc); 80 | if (app_info) { 81 | app_infos.push(app_info); 82 | } 83 | } 84 | return app_infos; 85 | } 86 | 87 | function findApps(dbs, app_infos, cb) { 88 | var db = dbs.pop(); 89 | if (db) { 90 | $.couch.db(db).allDesignDocs({ 91 | include_docs : true, 92 | success : function(resp) { 93 | findApps(dbs, app_infos.concat(appInfos(db, resp.rows)), cb); 94 | }, 95 | error : function(resp) { 96 | findApps(dbs, app_infos, cb); 97 | } 98 | }); 99 | } else { // did the last db 100 | cb(app_infos); 101 | } 102 | } 103 | 104 | function localApps(cb) { 105 | $.couch.allDbs({ 106 | success : function(dbs) { 107 | findApps(dbs, [], function(apps) { 108 | cb(apps); 109 | }); 110 | } 111 | }); 112 | } 113 | 114 | exports.localApps = localApps; 115 | 116 | function cachedApps(app, fun) { 117 | var cache = app.require("vendor/couchapp/lib/cache"); 118 | cache.get(app.db, "local_apps_cache", function(value_cb) { 119 | localApps(function(apps) { 120 | value_cb(apps.map(function(a) { 121 | a.icon = a.icon || "images/couchapp.png"; 122 | return a; 123 | })); 124 | }); 125 | }, fun); 126 | }; 127 | exports.cachedApps = cachedApps; 128 | 129 | exports.installedApps = function(app, name, fun) { 130 | cachedApps(app, function(apps) { 131 | var installs = []; 132 | apps.forEach(function(a) { 133 | if (a.slug == name) { 134 | installs.push(a) 135 | } 136 | }); 137 | fun(installs) 138 | }); 139 | } 140 | 141 | function clearCache(app) { 142 | var cache = app.require("vendor/couchapp/lib/cache"); 143 | cache.clear(app.db, "local_apps_cache"); 144 | }; 145 | 146 | exports.installApp = function(app, db, shared_doc_id, opts) { 147 | // load the doc 148 | var target_db = $.couch.db(db); 149 | var userSuccess = opts.success; 150 | opts.success = function() { 151 | clearCache(app); 152 | userSuccess.apply(this, arguments); 153 | }; 154 | app.db.openDoc(shared_doc_id, { 155 | attachments : true, 156 | success : function(shared) { 157 | // get install id 158 | var install_id = shared.garden.shared.id; 159 | target_db.openDoc(install_id, { 160 | success : function(target) { 161 | shared._rev = target._rev; 162 | shared._id = target._id; 163 | target_db.saveDoc(shared, opts); 164 | }, 165 | error : function() { 166 | shared._id = install_id; 167 | delete shared._rev; 168 | target_db.saveDoc(shared, opts); 169 | } 170 | }); 171 | } 172 | }); 173 | 174 | }; 175 | 176 | exports.shareApp = function(app, userName, path, opts) { 177 | // load the ddoc from the path, save it to app.db, call success 178 | var parts = path.split('/'); 179 | var db = parts.shift(); 180 | var ddoc_id = parts.join('/'); 181 | $.couch.db(db).openDoc(ddoc_id, { 182 | attachments : true, 183 | success : function(doc) { 184 | doc.garden = doc.garden || {}; 185 | // use appInfo? 186 | doc.garden.shared = { 187 | id : doc._id, 188 | rev : doc._rev, 189 | info : appInfo(db, doc), 190 | at : new Date(), 191 | by : userName 192 | }; 193 | var garden_id = ["shared", userName, doc._id].join('/'); 194 | doc._id = garden_id; 195 | app.db.openDoc(garden_id, { 196 | success : function(shared) { 197 | doc._rev = shared._rev; 198 | app.db.saveDoc(doc, opts); 199 | }, 200 | error : function() { 201 | delete doc._rev; 202 | app.db.saveDoc(doc, opts); 203 | } 204 | }); 205 | } 206 | }); 207 | }; 208 | -------------------------------------------------------------------------------- /vendor/couchapp/README.md: -------------------------------------------------------------------------------- 1 | ## CouchApp - more than just a filesystem mapper 2 | 3 | This is where documentation will go for the client and server JavaScript parts of CouchApp. -------------------------------------------------------------------------------- /vendor/couchapp/_attachments/docs.css: -------------------------------------------------------------------------------- 1 | body { 2 | font:1em Helvetica, sans-serif; 3 | margin:0; 4 | padding:4px; 5 | } 6 | 7 | h1 { 8 | margin:0.5em; 9 | } 10 | 11 | h2 { 12 | color:#222; 13 | } 14 | 15 | pre { 16 | padding:4px; 17 | margin:4px; 18 | background:#bbb; 19 | } 20 | 21 | #content { 22 | padding:4px; 23 | margin:2px; 24 | } 25 | 26 | #sidebar { 27 | float:right; 28 | width:34%; 29 | } 30 | 31 | #docs { 32 | -moz-box-shadow:0 0 2em #000; 33 | -webkit-box-shadow:0 0 2em #000; 34 | width:58%; 35 | padding:8px; 36 | margin:4px; 37 | } 38 | 39 | .example { 40 | background:#ffd; 41 | padding:4px; 42 | margin:4px; 43 | position:absolute; 44 | } 45 | 46 | textarea.code { 47 | width:100%; 48 | } 49 | 50 | .edit { 51 | float:right; 52 | font-size:0.8em; 53 | } 54 | -------------------------------------------------------------------------------- /vendor/couchapp/_attachments/docs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Not much to see here
" 162 | }, 163 | loggedIn : { 164 | mustache : "loggedIn was triggered from another widget, {{name}}.
", 165 | data : function(e, r) { 166 | return { name : r.userCtx.name }; 167 | } 168 | } 169 | }); 170 | 171 | Be sure to run the above example code before the next one, otherwise there won't be anything to link to. 172 | 173 | This next block of code demonstrates how to link two widgets together. First we create a normal account widget on the `#link_source` element, then we tell Evently to connect it to the `#link_target` element. Now whenever the `loggedIn` evenr is triggered on the source, it will be triggered on the target. 174 | 175 | $.couch.app(function(app){ 176 | $("#link_source").evently(app.ddoc.vendor.couchapp.evently.account); 177 | // link the source to the target, for the loggedIn event 178 | $.evently.connect($("#link_source"), $("#link_target"), ["loggedIn"]); 179 | }); 180 | 181 | ## Conclusion 182 | 183 | If you are writing a CouchApp that will have users logging and and logging out, you'd do well to use the account widget. It's customizable and linkable. And what's more, it's code that's already written. 184 | 185 | Enjoy! 186 | 187 | -------------------------------------------------------------------------------- /vendor/couchapp/docs/couchapp.md: -------------------------------------------------------------------------------- 1 | # Docs for $.couch.app 2 | 3 | The simplest use of CouchApp in the browser is to get access to information about the database you are running in. 4 | 5 | $.couch.app(function(app) { 6 | $("#dbinfo").evently({ 7 | _init : { 8 | mustache : 'The db name is {{name}}
', 9 | data : app.db 10 | } 11 | }); 12 | }); 13 | 14 | Yay couchapp. 15 | 16 | The `$.couch.app()` function also loads the current design document so that it is available for templates etc. That is how the words you are reading were loaded. This file is included in the CouchApp application library. Let's look at the design doc: 17 | 18 | $.couch.app(function(app) { 19 | $("#ddoc").evently({ 20 | _init : { 21 | mustache : 'Click to show the full doc source:
{{ddoc}}', 22 | data : { 23 | ddoc : JSON.stringify(app.ddoc, null, 2).slice(0,100) + '...' 24 | } 25 | }, 26 | click : { 27 | mustache : '
The full doc source (rerun to hide):
{{ddoc}}', 28 | data : { 29 | ddoc : JSON.stringify(app.ddoc, null, 2) 30 | } 31 | } 32 | }); 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /vendor/couchapp/docs/docs.md: -------------------------------------------------------------------------------- 1 | # Docs for the docs system. 2 | 3 | You are encouraged to use the couchapp docs system to write documentation for your plugins and applications. Extra bonus points because it's fun. 4 | 5 | Docs automatically make divs based on `$("#foo")` pattern matching. That is, we regex the code looking for the first id we see referenced. Remember ids need to be unique on a page. For doc examples you only get one id. 6 | 7 | Example Code: 8 | 9 | $("#hide_foo").hide("slow"); 10 | 11 | That's all it takes. You only get one div in each example for now. Have fun! -------------------------------------------------------------------------------- /vendor/couchapp/docs/evently.md: -------------------------------------------------------------------------------- 1 | # Evently Docs 2 | 3 | Evently is an declarative framework for evented jQuery applications. You write your code as widgets made up of templates and callbacks, while Evently handles the busywork of linking them together. 4 | 5 | Evently has special handlers for CouchDB views and `_changes` feeds, and could be easily extended for other server-side frameworks. 6 | 7 | ## Hello World 8 | 9 | At it's simplest an Evently widget is a set of events connected to a single DOM element. 10 | 11 | JavaScript: 12 | 13 | $("#hello").evently({ 14 | _init : { 15 | mustache : "
Hello world
", 16 | }, 17 | click : { 18 | mustache : "What a crazy world!
", 19 | } 20 | }); 21 | 22 | You can also do some more interesting things: 23 | 24 | $("#heyjane").evently({ 25 | _init : { 26 | mustache : '', 27 | selectors : { 28 | 'a[href=#joan]' : { 29 | click : 'hiJoan' 30 | }, 31 | 'a[href=#jane]' : { 32 | click : 'hiJane' 33 | } 34 | } 35 | }, 36 | hiJoan : { 37 | mustache : 'Hello Joan!
' 38 | }, 39 | hiJane : { 40 | mustache : "Darn, it's Jane...
", 41 | after : function() { 42 | setTimeout(function() { 43 | // automatically trigger the "janeRocks" event after 2 seconds. 44 | $("#heyjane").trigger("janeRocks"); 45 | }, 2000); 46 | } 47 | }, 48 | janeRocks : { 49 | render : "append", 50 | mustache : "Actually Jane is awesome.
" 51 | } 52 | }); 53 | 54 | 55 | The imporant thing about this is that the widget is defined by an JavaScript object. This means we can save it as files on our hard drive and `couchapp` will handle saving it as a JSON object for us. 56 | 57 | [screenshot of the above code in textmate's file drawer] 58 | 59 | When we let CouchApp package our evently apps we get to work on them in individual files, instead of as a great big giant mess of JavaScript. This means HTML is HTML, JSON is JSON, and JavaScript is JavaScript. Yay! 60 | 61 | ## Ajax Hello World 62 | 63 | Let's do a little Ajax. We'll just load the version of the CouchDB instance we happen to be serving our HTML from: 64 | 65 | $("#ajax").evently({ 66 | _init : { 67 | mustache : 'Loading CouchDB server info.
', 68 | after : function() { 69 | var widget = $(this); 70 | $.ajax({ 71 | url : '/', 72 | complete : function(req) { 73 | var resp = $.httpData(req, "json"); 74 | widget.trigger("version", [resp]); 75 | } 76 | }) 77 | } 78 | }, 79 | version : { 80 | mustache : "Running CouchDB version {{version}}
", 81 | data : function(e, resp) { 82 | return resp; 83 | } 84 | } 85 | }); 86 | 87 | Explain `mustache` and `data` 88 | 89 | -- triggering other events 90 | -- selectors 91 | -- create a doc 92 | 93 | ## Evently and CouchApp together 94 | 95 | Evently makes it easy to write decoupled JavaScript code, but as the examples above show, Evently widgets can turn into a lot of JSON to look at all on one screen. Because Evently code is declarative, and each handler and callback stands on its own (instead of being wrapped in a common closure), it can be broken out into individual files. 96 | 97 | CouchApp provides a mechanism for mapping between individual files and JSON structures. In this model a directory structure is mapped to a JSON object. So if you have a directory structure like: 98 | 99 | _init/ 100 | mustache.html 101 | selectors/ 102 | form/ 103 | submit.js 104 | input.name/ 105 | change.js 106 | a.cancel/ 107 | click.txt 108 | cancelled/ 109 | mustache.html 110 | selectors/ 111 | a.continue/ 112 | click.txt 113 | 114 | It will appear within your CouchApp design document as: 115 | 116 | { 117 | _init : { 118 | mustache : "contents of mustache.html", 119 | selectors { 120 | form : { 121 | submit : "function() { ... }" 122 | }, 123 | "input.name" { 124 | change : "function() { ... }" 125 | }, 126 | "a.cancel" { 127 | click : "cancelled" 128 | } 129 | } 130 | }, 131 | cancelled : { 132 | mustache : "contents of mustache.html", 133 | selectors : { 134 | "a.continue" : { 135 | click : "_init" 136 | } 137 | } 138 | } 139 | } 140 | 141 | This makes Evently and CouchApp a natural fit for each other. I swear I didn't plan this when I started writing Evently, it just turned out to be an awesome side effect of trying to stay as close to JSON as possible. 142 | 143 | In the [account widget tutorial](#/topic/account) we see the details of the account widget. What isn't discussed much there, is how the code is edited on your filesystem. 144 | 145 | If you are writing an Evently CouchApp widget you can edit the individual pieces on your filesystem. This has the added advantage of giving you native syntax highlighting for all the code. Instead of editing everything as JSON or JavaScript, the templates can be treated as HTML, the paths as text, etc. 146 | 147 | ## Evently Queries 148 | 149 | Evently understands CouchDB in a couple of very simple ways. If you know CouchDB, you're probably familiar with its Map Reduce views. Evently lets you specify view queries in a declarative way, and even takes care of the Ajax request. All you have to do is write code to handle the returned data. 150 | 151 | -- new rows, etc 152 | 153 | -- run a query 154 | 155 | -- connect to changes 156 | 157 | -- links to example apps 158 | 159 | ## Freeform Asynchronous Actions 160 | 161 | Watch out, you're dangerous! Evently allows you to make any old asyncronous action you want, with the `widget.async` member. The callback is the first argument to the `async` function. Check it out: 162 | 163 | $("#async").evently({ 164 | _init : { 165 | mustache : "How many databases on the local host?
Answer: {{number_of_dbs}}
Other stuff: {{args}}
More: {{allArgs}}
", 166 | async : function(cb) { 167 | var ag = Array.prototype.slice.call(arguments).map(function(a){return a.toSource ? a.toSource() : a}); 168 | $.couch.allDbs({ 169 | success : function(resp) { 170 | cb(resp.length, ag); 171 | } 172 | }) 173 | }, 174 | data : function(count, args) { 175 | return { 176 | number_of_dbs : count, 177 | args : JSON.stringify(args), 178 | allArgs : JSON.stringify(Array.prototype.slice.call(arguments)) 179 | }; 180 | } 181 | }, 182 | click : { 183 | mustache : "What a crazy world!
", 184 | } 185 | }); -------------------------------------------------------------------------------- /vendor/couchapp/docs/pathbinder.md: -------------------------------------------------------------------------------- 1 | # Docs about $.pathbinder 2 | 3 | Pathbinder is a tiny framework for triggering events based on paths in URL hash. For example, you might want to render one panel when the user clicks a link to `#/foo` and another when the URL hash changes to `#/bar`. If you've never used URL hashes for application state in an Ajax app before, prepare to be happy. 4 | 5 | There are two big advantages to having the state in the URL-hash. One is that users can bookmark screens they may have reached by navigating within your app. The other is that the back button will continue to work. 6 | 7 | The page you are on has a URL hash of `#/topic/pathbinder` right now. You can follow links to other "pages" within this application, and Pathbinder takes care of triggering the proper events. 8 | 9 | ## A simple example 10 | 11 | $("#basic_path").html(''); 12 | $("#basic_path").bind("foo", function() { 13 | $(this).html("you went to foo
"); 14 | }); 15 | $("#basic_path").pathbinder("foo", "/foo"); 16 | 17 | This code sets up the `#basic_path` div with some initial content, including a link to `#/foo`. If you click the link to foo, you'll see the URL change. It is the changed URL which Pathbinder sees and uses to trigger any running code. You can experiment by manually entering the `#/foo` URL hash, instead of clicking the link, and you'll see that it also triggers the `foo` event. 18 | 19 | ## Using path parameters 20 | 21 | Pathbinder was inspired by the path handling in [Sammy.js](http://github.com/aq/sammy.js). Like Sammy, you can use it to pull parameters from the URL-hash. This page can be linked [using a path that has "pathbinder" as a parameter](#/topic/pathbinder). Let's explore how you can pull parameters out of a path. 22 | 23 | $("#param_path").html(''); 24 | $("#param_path").bind("foo", function(e, params) { 25 | $(this).html("you went to foo - "+params.id+"
"); 26 | }); 27 | $("#param_path").pathbinder("foo", "/foo/:id"); 28 | 29 | When you click the link to super foo, you'll see the param is passed through the event. You can also edit the URL to see that "super" is not hard coded and can be replaced with other values. 30 | 31 | ## Pathbinder with Evently 32 | 33 | It should be no suprise that Pathbinder and Evently play well together. The gist of it is that Evently looks for a key called `path` and if it finds it, uses Pathbinder to connect that event handler to the path. Let's try it out: 34 | 35 | $("#evently_path").evently({ 36 | _init : { 37 | path : '/index', 38 | mustache : 'the index. more cowbell!
' 39 | }, 40 | cowbell : { 41 | path : '/cowbell', 42 | mustache : 'Now that is a lot of cowbell. back to the index
' 43 | } 44 | }); 45 | 46 | Note that when you use an Evently path, Evently also takes care to visit the path when the corresponding event is triggered. So running the above example code (which automatically triggers the `_init` event) will set the hash to `#/index`. If you were to trigger the `cowbell` event through non-path means, you'd see that it changes the path to `#/cowbell` anyway. 47 | 48 | ### Too many widgets 49 | 50 | One thing worth noting: there is only one URL hash for any given page, so be aware that if you have multiple widgets competing for the real-estate, they could conflict with each other. Pathbinder won't do anything when presented with a path it doesn't care about (go ahead, try out some non-sense ones on this page). 51 | 52 | This means that if you have a few widgets all using the path, the page should still behave in a useful way. However, this breaks down if you intend people to be able to use the URL hash to link to page state. Since there can be only one URL hash, whichever action they took last will be reflected in the bookmarked URL. For this reason it makes sense to limit yourself to one path-based Evently widget per page. 53 | -------------------------------------------------------------------------------- /vendor/couchapp/docs/profile.md: -------------------------------------------------------------------------------- 1 | # docs for the profile evently widget 2 | 3 | This widget makes it easy to give users a profile for your application. -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/_init.js: -------------------------------------------------------------------------------- 1 | function() { 2 | var elem = $(this); 3 | $.couch.session({ 4 | success : function(r) { 5 | var userCtx = r.userCtx; 6 | if (userCtx.name) { 7 | elem.trigger("loggedIn", [r]); 8 | } else if (userCtx.roles.indexOf("_admin") != -1) { 9 | elem.trigger("adminParty"); 10 | } else { 11 | elem.trigger("loggedOut"); 12 | }; 13 | } 14 | }); 15 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/adminParty.js: -------------------------------------------------------------------------------- 1 | function() { 2 | alert("Admin party! Fix this in Futon before proceeding."); 3 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/doLogin.js: -------------------------------------------------------------------------------- 1 | function(e, name, pass) { 2 | var elem = $(this); 3 | $.couch.login({ 4 | name : name, 5 | password : pass, 6 | success : function(r) { 7 | elem.trigger("_init") 8 | } 9 | }); 10 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/doLogout.js: -------------------------------------------------------------------------------- 1 | function() { 2 | var elem = $(this); 3 | $.couch.logout({ 4 | success : function() { 5 | elem.trigger("_init"); 6 | } 7 | }); 8 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/doSignup.js: -------------------------------------------------------------------------------- 1 | function(e, name, pass) { 2 | var elem = $(this); 3 | $.couch.signup({ 4 | name : name 5 | }, pass, { 6 | success : function() { 7 | elem.trigger("doLogin", [name, pass]); 8 | } 9 | }); 10 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedIn/after.js: -------------------------------------------------------------------------------- 1 | // todo move to template 2 | function(e, r) { 3 | $(this).attr("data-name", r.userCtx.name); 4 | $$(this).userCtx = r.userCtx; 5 | } 6 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedIn/data.js: -------------------------------------------------------------------------------- 1 | function(e, r) { 2 | return { 3 | name : r.userCtx.name, 4 | uri_name : encodeURIComponent(r.userCtx.name), 5 | auth_db : encodeURIComponent(r.info.authentication_db) 6 | }; 7 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedIn/mustache.html: -------------------------------------------------------------------------------- 1 | Welcome 2 | {{name}}! 3 | Logout? 4 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedIn/selectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "a[href=#logout]" : {"click" : ["doLogout"]} 3 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedOut/mustache.html: -------------------------------------------------------------------------------- 1 | Signup or Login -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loggedOut/selectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "a[href=#signup]" : {"click" : ["signupForm"]}, 3 | "a[href=#login]" : {"click" : ["loginForm"]} 4 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loginForm/after.js: -------------------------------------------------------------------------------- 1 | function() { 2 | $("input[name=name]", this).focus(); 3 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loginForm/mustache.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loginForm/selectors/a[href=#signup].json: -------------------------------------------------------------------------------- 1 | {"click" : ["signupForm"]} -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/loginForm/selectors/form/submit.js: -------------------------------------------------------------------------------- 1 | function(e) { 2 | var name = $('input[name=name]', this).val(), 3 | pass = $('input[name=password]', this).val(); 4 | $(this).trigger('doLogin', [name, pass]); 5 | return false; 6 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/signupForm/after.js: -------------------------------------------------------------------------------- 1 | function() { 2 | $("input[name=name]", this).focus(); 3 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/signupForm/mustache.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/signupForm/selectors/a[href=#login].json: -------------------------------------------------------------------------------- 1 | {"click" : ["loginForm"]} -------------------------------------------------------------------------------- /vendor/couchapp/evently/account/signupForm/selectors/form/submit.js: -------------------------------------------------------------------------------- 1 | function(e) { 2 | var name = $('input[name=name]', this).val(), 3 | pass = $('input[name=password]', this).val(); 4 | $(this).trigger('doSignup', [name, pass]); 5 | return false; 6 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/docs/index/data.js: -------------------------------------------------------------------------------- 1 | function() { 2 | var docs = $$(this).app.ddoc.vendor.couchapp.docs; 3 | var dnames = []; 4 | $.forIn(docs, function(d) { 5 | dnames.push({ 6 | title: d, 7 | href : "#/topic/"+encodeURIComponent(d) 8 | }); 9 | }); 10 | return {docs:dnames}; 11 | }; -------------------------------------------------------------------------------- /vendor/couchapp/evently/docs/index/mustache.html: -------------------------------------------------------------------------------- 1 |Error running #', id, 5 | ' code block:
', 6 | (y.toSource ? y.toSource() : JSON.stringify(y)), 7 | ''].join('')); 8 | } 9 | var id = e.data.args[1]; 10 | var example = $("#code-"+id); 11 | var js = $('textarea',example).val() || $('pre',example).text(); 12 | $('#'+id).unbind(); 13 | try { 14 | eval(js); 15 | } catch (y) { 16 | err(y, id); 17 | } 18 | } catch(x) { 19 | err(x, id); 20 | } 21 | return false; 22 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/docs/topic/mustache.html: -------------------------------------------------------------------------------- 1 |
Please log in to see your profile.
-------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/noProfile/data.js: -------------------------------------------------------------------------------- 1 | function(e, userCtx) { 2 | return userCtx; 3 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/noProfile/mustache.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/noProfile/selectors/form/submit.js: -------------------------------------------------------------------------------- 1 | function() { 2 | // TODO this can be cleaned up with docForm? 3 | 4 | var name = $("input[name=userCtxName]",this).val(); 5 | var newProfile = { 6 | rand : Math.random().toString(), 7 | nickname : $("input[name=nickname]",this).val(), 8 | email : $("input[name=email]",this).val(), 9 | url : $("input[name=url]",this).val() 10 | }, widget = $(this); 11 | 12 | // setup gravatar_url 13 | if (typeof hex_md5 == "undefined") { 14 | alert("creating a profile requires md5.js to be loaded in the page"); 15 | return; 16 | } 17 | 18 | newProfile.gravatar_url = 'http://www.gravatar.com/avatar/'+hex_md5(newProfile.email || newProfile.rand)+'.jpg?s=40&d=identicon'; 19 | 20 | // store the user profile on the user account document 21 | $.couch.userDb(function(db) { 22 | var userDocId = "org.couchdb.user:"+name; 23 | db.openDoc(userDocId, { 24 | success : function(userDoc) { 25 | userDoc["couch.app.profile"] = newProfile; 26 | db.saveDoc(userDoc, { 27 | success : function() { 28 | newProfile.name = userDoc.name; 29 | $$(widget).profile = newProfile; 30 | widget.trigger("profileReady", [newProfile]); 31 | } 32 | }); 33 | } 34 | }); 35 | }); 36 | return false; 37 | } -------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/profileReady/after.js: -------------------------------------------------------------------------------- 1 | function(e, p) { 2 | $$(this).profile = p; 3 | }; -------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/profileReady/data.js: -------------------------------------------------------------------------------- 1 | function(e, p) { 2 | return { 3 | nickname : p.nickname, 4 | name : p.name, 5 | avatar_url : p.gravatar_url 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /vendor/couchapp/evently/profile/profileReady/mustache.html: -------------------------------------------------------------------------------- 1 |Hello {{nickname}}!
8 | -------------------------------------------------------------------------------- /vendor/couchapp/lib/atom.js: -------------------------------------------------------------------------------- 1 | // atom feed generator 2 | // requries E4X support. 3 | 4 | function f(n) { // Format integers to have at least two digits. 5 | return n < 10 ? '0' + n : n; 6 | } 7 | 8 | function rfc3339(date) { 9 | return date.getUTCFullYear() + '-' + 10 | f(date.getUTCMonth() + 1) + '-' + 11 | f(date.getUTCDate()) + 'T' + 12 | f(date.getUTCHours()) + ':' + 13 | f(date.getUTCMinutes()) + ':' + 14 | f(date.getUTCSeconds()) + 'Z'; 15 | }; 16 | 17 | exports.header = function(data) { 18 | var f =s around 197 | // "paragraphs" that are wrapped in non-block-level tags, such as anchors, 198 | // phrase emphasis, and spans. The list of tags we're looking for is 199 | // hard-coded: 200 | var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" 201 | var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" 202 | 203 | // First, look for nested blocks, e.g.: 204 | //
tags around block-level tags.
351 | text = _HashHTMLBlocks(text);
352 | text = _FormParagraphs(text);
353 |
354 | return text;
355 | }
356 |
357 |
358 | var _RunSpanGamut = function(text) {
359 | //
360 | // These are all the transformations that occur *within* block-level
361 | // tags like paragraphs, headers, and list items.
362 | //
363 |
364 | text = _DoCodeSpans(text);
365 | text = _EscapeSpecialCharsWithinTagAttributes(text);
366 | text = _EncodeBackslashEscapes(text);
367 |
368 | // Process anchor and image tags. Images must come first,
369 | // because ![foo][f] looks like an anchor.
370 | text = _DoImages(text);
371 | text = _DoAnchors(text);
372 |
373 | // Make links out of things like ` Just type tags
1029 | //
1030 |
1031 | // Strip leading and trailing lines:
1032 | text = text.replace(/^\n+/g,"");
1033 | text = text.replace(/\n+$/g,"");
1034 |
1035 | var grafs = text.split(/\n{2,}/g);
1036 | var grafsOut = new Array();
1037 |
1038 | //
1039 | // Wrap tags.
1040 | //
1041 | var end = grafs.length;
1042 | for (var i=0; i ");
1052 | str += "
\n");
382 |
383 | return text;
384 | }
385 |
386 | var _EscapeSpecialCharsWithinTagAttributes = function(text) {
387 | //
388 | // Within tags -- meaning between < and > -- encode [\ ` * _] so they
389 | // don't conflict with their use in Markdown for code, italics and strong.
390 | //
391 |
392 | // Build a regex to find HTML tags and comments. See Friedl's
393 | // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
394 | var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
395 |
396 | text = text.replace(regex, function(wholeMatch) {
397 | var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
398 | tag = escapeCharacters(tag,"\\`*_");
399 | return tag;
400 | });
401 |
402 | return text;
403 | }
404 |
405 | var _DoAnchors = function(text) {
406 | //
407 | // Turn Markdown link shortcuts into XHTML tags.
408 | //
409 | //
410 | // First, handle reference-style links: [link text] [id]
411 | //
412 |
413 | /*
414 | text = text.replace(/
415 | ( // wrap whole match in $1
416 | \[
417 | (
418 | (?:
419 | \[[^\]]*\] // allow brackets nested one level
420 | |
421 | [^\[] // or anything else
422 | )*
423 | )
424 | \]
425 |
426 | [ ]? // one optional space
427 | (?:\n[ ]*)? // one optional newline followed by spaces
428 |
429 | \[
430 | (.*?) // id = $3
431 | \]
432 | )()()()() // pad remaining backreferences
433 | /g,_DoAnchors_callback);
434 | */
435 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
436 |
437 | //
438 | // Next, inline-style links: [link text](url "optional title")
439 | //
440 |
441 | /*
442 | text = text.replace(/
443 | ( // wrap whole match in $1
444 | \[
445 | (
446 | (?:
447 | \[[^\]]*\] // allow brackets nested one level
448 | |
449 | [^\[\]] // or anything else
450 | )
451 | )
452 | \]
453 | \( // literal paren
454 | [ \t]*
455 | () // no id, so leave $3 empty
456 | (.*?)>? // href = $4
457 | [ \t]*
458 | ( // $5
459 | (['"]) // quote char = $6
460 | (.*?) // Title = $7
461 | \6 // matching quote
462 | [ \t]* // ignore any spaces/tabs between closing quote and )
463 | )? // title is optional
464 | \)
465 | )
466 | /g,writeAnchorTag);
467 | */
468 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
469 |
470 | //
471 | // Last, handle reference-style shortcuts: [link text]
472 | // These must come last in case you've also got [link test][1]
473 | // or [link test](/foo)
474 | //
475 |
476 | /*
477 | text = text.replace(/
478 | ( // wrap whole match in $1
479 | \[
480 | ([^\[\]]+) // link text = $2; can't contain '[' or ']'
481 | \]
482 | )()()()()() // pad rest of backreferences
483 | /g, writeAnchorTag);
484 | */
485 | text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
486 |
487 | return text;
488 | }
489 |
490 | var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
491 | if (m7 == undefined) m7 = "";
492 | var whole_match = m1;
493 | var link_text = m2;
494 | var link_id = m3.toLowerCase();
495 | var url = m4;
496 | var title = m7;
497 |
498 | if (url == "") {
499 | if (link_id == "") {
500 | // lower-case and turn embedded newlines into spaces
501 | link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
502 | }
503 | url = "#"+link_id;
504 |
505 | if (g_urls[link_id] != undefined) {
506 | url = g_urls[link_id];
507 | if (g_titles[link_id] != undefined) {
508 | title = g_titles[link_id];
509 | }
510 | }
511 | else {
512 | if (whole_match.search(/\(\s*\)$/m)>-1) {
513 | // Special case for explicit empty url
514 | url = "";
515 | } else {
516 | return whole_match;
517 | }
518 | }
519 | }
520 |
521 | url = escapeCharacters(url,"*_");
522 | var result = "" + link_text + "";
531 |
532 | return result;
533 | }
534 |
535 |
536 | var _DoImages = function(text) {
537 | //
538 | // Turn Markdown image shortcuts into tags.
539 | //
540 |
541 | //
542 | // First, handle reference-style labeled images: ![alt text][id]
543 | //
544 |
545 | /*
546 | text = text.replace(/
547 | ( // wrap whole match in $1
548 | !\[
549 | (.*?) // alt text = $2
550 | \]
551 |
552 | [ ]? // one optional space
553 | (?:\n[ ]*)? // one optional newline followed by spaces
554 |
555 | \[
556 | (.*?) // id = $3
557 | \]
558 | )()()()() // pad rest of backreferences
559 | /g,writeImageTag);
560 | */
561 | text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
562 |
563 | //
564 | // Next, handle inline images: 
565 | // Don't forget: encode * and _
566 |
567 | /*
568 | text = text.replace(/
569 | ( // wrap whole match in $1
570 | !\[
571 | (.*?) // alt text = $2
572 | \]
573 | \s? // One optional whitespace character
574 | \( // literal paren
575 | [ \t]*
576 | () // no id, so leave $3 empty
577 | (\S+?)>? // src url = $4
578 | [ \t]*
579 | ( // $5
580 | (['"]) // quote char = $6
581 | (.*?) // title = $7
582 | \6 // matching quote
583 | [ \t]*
584 | )? // title is optional
585 | \)
586 | )
587 | /g,writeImageTag);
588 | */
589 | text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
590 |
591 | return text;
592 | }
593 |
594 | var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
595 | var whole_match = m1;
596 | var alt_text = m2;
597 | var link_id = m3.toLowerCase();
598 | var url = m4;
599 | var title = m7;
600 |
601 | if (!title) title = "";
602 |
603 | if (url == "") {
604 | if (link_id == "") {
605 | // lower-case and turn embedded newlines into spaces
606 | link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
607 | }
608 | url = "#"+link_id;
609 |
610 | if (g_urls[link_id] != undefined) {
611 | url = g_urls[link_id];
612 | if (g_titles[link_id] != undefined) {
613 | title = g_titles[link_id];
614 | }
615 | }
616 | else {
617 | return whole_match;
618 | }
619 | }
620 |
621 | alt_text = alt_text.replace(/"/g,""");
622 | url = escapeCharacters(url,"*_");
623 | var result = "
";
635 |
636 | return result;
637 | }
638 |
639 |
640 | var _DoHeaders = function(text) {
641 |
642 | // Setext-style headers:
643 | // Header 1
644 | // ========
645 | //
646 | // Header 2
647 | // --------
648 | //
649 | text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
650 | function(wholeMatch,m1){return hashBlock("
" + _RunSpanGamut(m1) + "
");});
651 |
652 | text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
653 | function(matchFound,m1){return hashBlock("" + _RunSpanGamut(m1) + "
");});
654 |
655 | // atx-style headers:
656 | // # Header 1
657 | // ## Header 2
658 | // ## Header 2 with closing hashes ##
659 | // ...
660 | // ###### Header 6
661 | //
662 |
663 | /*
664 | text = text.replace(/
665 | ^(\#{1,6}) // $1 = string of #'s
666 | [ \t]*
667 | (.+?) // $2 = Header text
668 | [ \t]*
669 | \#* // optional closing #'s (not counted)
670 | \n+
671 | /gm, function() {...});
672 | */
673 |
674 | text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
675 | function(wholeMatch,m1,m2) {
676 | var h_level = m1.length;
677 | return hashBlock("` blocks.
835 | //
836 |
837 | /*
838 | text = text.replace(text,
839 | /(?:\n\n|^)
840 | ( // $1 = the code block -- one or more lines, starting with a space/tab
841 | (?:
842 | (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
843 | .*\n+
844 | )+
845 | )
846 | (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
847 | /g,function(){...});
848 | */
849 |
850 | // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
851 | text += "~0";
852 |
853 | text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
854 | function(wholeMatch,m1,m2) {
855 | var codeblock = m1;
856 | var nextChar = m2;
857 |
858 | codeblock = _EncodeCode( _Outdent(codeblock));
859 | codeblock = _Detab(codeblock);
860 | codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
861 | codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
862 |
863 | codeblock = "
";
864 |
865 | return hashBlock(codeblock) + nextChar;
866 | }
867 | );
868 |
869 | // attacklab: strip sentinel
870 | text = text.replace(/~0/,"");
871 |
872 | return text;
873 | }
874 |
875 | var hashBlock = function(text) {
876 | text = text.replace(/(^\n+|\n+$)/g,"");
877 | return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
878 | }
879 |
880 |
881 | var _DoCodeSpans = function(text) {
882 | //
883 | // * Backtick quotes are used for " + codeblock + "\n
spans.
884 | //
885 | // * You can use multiple backticks as the delimiters if you want to
886 | // include literal backticks in the code span. So, this input:
887 | //
888 | // Just type ``foo `bar` baz`` at the prompt.
889 | //
890 | // Will translate to:
891 | //
892 | //
foo `bar` baz
at the prompt.`bar`
...
905 | //
906 |
907 | /*
908 | text = text.replace(/
909 | (^|[^\\]) // Character before opening ` can't be a backslash
910 | (`+) // $2 = Opening run of `
911 | ( // $3 = The code block
912 | [^\r]*?
913 | [^`] // attacklab: work around lack of lookbehind
914 | )
915 | \2 // Matching closer
916 | (?!`)
917 | /gm, function(){...});
918 | */
919 |
920 | text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
921 | function(wholeMatch,m1,m2,m3,m4) {
922 | var c = m3;
923 | c = c.replace(/^([ \t]*)/g,""); // leading whitespace
924 | c = c.replace(/[ \t]*$/g,""); // trailing whitespace
925 | c = _EncodeCode(c);
926 | return m1+""+c+"
";
927 | });
928 |
929 | return text;
930 | }
931 |
932 |
933 | var _EncodeCode = function(text) {
934 | //
935 | // Encode/escape certain characters inside Markdown code runs.
936 | // The point is that in code, these characters are literals,
937 | // and lose their special Markdown meanings.
938 | //
939 | // Encode all ampersands; HTML entities are not
940 | // entities within a Markdown code span.
941 | text = text.replace(/&/g,"&");
942 |
943 | // Do the angle bracket song and dance:
944 | text = text.replace(//g,">");
946 |
947 | // Now, escape characters that are magic in Markdown:
948 | text = escapeCharacters(text,"\*_{}[]\\",false);
949 |
950 | // jj the line above breaks this:
951 | //---
952 |
953 | //* Item
954 |
955 | // 1. Subitem
956 |
957 | // special char: *
958 | //---
959 |
960 | return text;
961 | }
962 |
963 |
964 | var _DoItalicsAndBold = function(text) {
965 |
966 | // must go first:
967 | text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
968 | "$2");
969 |
970 | text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
971 | "$2");
972 |
973 | return text;
974 | }
975 |
976 |
977 | var _DoBlockQuotes = function(text) {
978 |
979 | /*
980 | text = text.replace(/
981 | ( // Wrap whole match in $1
982 | (
983 | ^[ \t]*>[ \t]? // '>' at the start of a line
984 | .+\n // rest of the first line
985 | (.+\n)* // subsequent consecutive lines
986 | \n* // blanks
987 | )+
988 | )
989 | /gm, function(){...});
990 | */
991 |
992 | text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
993 | function(wholeMatch,m1) {
994 | var bq = m1;
995 |
996 | // attacklab: hack around Konqueror 3.5.4 bug:
997 | // "----------bug".replace(/^-/g,"") == "bug"
998 |
999 | bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0"); // trim one level of quoting
1000 |
1001 | // attacklab: clean up hack
1002 | bq = bq.replace(/~0/g,"");
1003 |
1004 | bq = bq.replace(/^[ \t]+$/gm,""); // trim whitespace-only lines
1005 | bq = _RunBlockGamut(bq); // recurse
1006 |
1007 | bq = bq.replace(/(^|\n)/g,"$1 ");
1008 | // These leading spaces screw with content, so we need to fix that:
1009 | bq = bq.replace(
1010 | /(\s*
[^\r]+?<\/pre>)/gm,
1011 | function(wholeMatch,m1) {
1012 | var pre = m1;
1013 | // attacklab: hack around Konqueror 3.5.4 bug:
1014 | pre = pre.replace(/^ /mg,"~0");
1015 | pre = pre.replace(/~0/g,"");
1016 | return pre;
1017 | });
1018 |
1019 | return hashBlock("
\n" + bq + "\n
");
1020 | });
1021 | return text;
1022 | }
1023 |
1024 |
1025 | var _FormParagraphs = function(text) {
1026 | //
1027 | // Params:
1028 | // $text - string to process with html