Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

fixup stuff that got broke by my revert party

  • Loading branch information...
commit b5acfddc0b1137ff63e4e7575137bab9854963c7 1 parent 543a6ed
@jchris jchris authored
View
6 README.md
@@ -5,7 +5,11 @@ I was tired of all the complicated wikis that required some kind of application
To deploy this you need to point a DNS name at your Couch (or use `/etc/hosts`), and then configure your CouchDB to have a vhost like:
[vhosts]
- mydnsname.com:5984 = /pages/_design/pages/_rewrite
+ mydnsname.com = /pages/_design/pages/_rewrite
+
+You can also add this configuration option with curl:
+
+ curl -X PUT http://localhost:5984/_config/vhosts/mydnsname.com -d '"/pages/_design/pages/_rewrite"'
This app requires that it be deployed to a database called `pages`. I'd like to make that more dynamic, but I haven't quite gotten around to it yet (maybe I never will, that's where *you* come in.)
View
27 _attachments/style/main.css
@@ -7,7 +7,15 @@ body {
h1 {
margin:0;
font-weight:normal;
- font-size:2em;
+ font-size:2.2em;
+}
+
+h2 {
+ font-size:1.7em;
+}
+
+a.missing {
+ color : #d00;
}
#header {
@@ -49,10 +57,19 @@ p.menu a {
max-width:35%;
}
-#wiki {
+#wiki .wiki {
+ width:65%;
margin:8px;
}
+#wiki pre {
+ background:#ddd;
+ padding:4px;
+}
+#wiki code {
+ background:#ddd;
+}
+
#comments {
margin:4px;
padding:4px;
@@ -84,9 +101,9 @@ p.menu a {
padding:8px;
}
-.markdown-help {
- float:left;
- margin-left:20px;
+.preview {
+ float:right;
+ font-size:80%;
width:37%;
}
View
9 evently/comments/_init/mustache.html
@@ -5,12 +5,12 @@
<div class="avatar">
{{#gravatar_url}}<img src="{{gravatar_url}}"/>{{/gravatar_url}}
<div class="name">
- {{nickname}}
+ {{by}}
</div>
</div>
-
- <p>{{{comment}}}</p>
- <em><span class="date">{{at}}</span></em>
+ <p>{{{comment}}}</p>
+ <em><span class="date">{{at}}</span></em>
+ <div class="clear"></div>
</li>
{{/comments}}
</ul>
@@ -21,5 +21,4 @@
<textarea name="comment" rows="4" cols="60"></textarea>
<input type="hidden" name="topic" value="{{topic}}">
<p><input type="submit" value="Save Comment"></p>
- <p><em>* I'd be happy to make this Markdown instead if someone patches <a href="http://attacklab.net/showdown/">Showdown</a> to have a safe mode.</em></p>
</form>
View
5 evently/comments/_init/query.js
@@ -2,8 +2,7 @@ function() {
var docid = $$("#wiki").docid;
return {
view : "recent-comments",
- startkey : [docid, {}],
- endkey : [docid],
- descending : true
+ endkey : [docid, {}],
+ startkey : [docid]
};
};
View
6 evently/profile/loggedOut/all.html
@@ -1,3 +1,5 @@
<p class="menu">
- <a href="/pages/recent">Recent Changes</a>
-</p>
+ <a href="/page/index">Home</a>
+ <a href="/pages/recent">Changes</a>
+ <a href="/pages/comments">Comments</a>
+</p>
View
6 evently/profile/loggedOut/mustache.html
@@ -1,3 +1,5 @@
<p class="menu">
- <a href="/pages/recent">Recent Changes</a>
-</p>
+ <a href="/page/index">Home</a>
+ <a href="/pages/recent">Changes</a>
+ <a href="/pages/comments">Comments</a>
+</p>
View
5 evently/profile/profileReady/all.html
@@ -3,6 +3,7 @@
</div>
<p class="menu">
<a href="/page/index">Home</a>
- <a href="/pages/recent">Recent Changes</a>
+ <a href="/pages/recent">Changes</a>
+ <a href="/pages/comments">Comments</a>
</p>
-<div style="clear:left;"></div>
+<div style="clear:left;"></div>
View
5 evently/profile/profileReady/mustache.html
@@ -6,6 +6,7 @@
<a href="#/history">History</a>
<a href="#/upload">Upload File</a>
<a href="/page/index">Home</a>
- <a href="/pages/recent">Recent Changes</a>
+ <a href="/pages/recent">Changes</a>
+ <a href="/pages/comments">Comments</a>
</p>
-<div style="clear:left;"></div>
+<div style="clear:left;"></div>
View
29 evently/wiki/_init.js
@@ -0,0 +1,29 @@
+function() {
+ var wiki = $(this), app = $$(wiki).app, m, pages = {}, keys = [];
+ $("a",wiki).each(function() {
+ m = this.href.match(/.*\/page\/([^\/]+)$/);
+ if (m && m[1]) {
+ pages[m[1]] = true;
+ }
+ });
+ // unique keys will be faster on big pages
+ for (m in pages) {
+ keys.push(m);
+ }
+ if (keys.length > 0) {
+ app.view("all-pages", {
+ keys : keys,
+ success : function(resp) {
+ var i, p;
+ for (i=0; i < resp.rows.length; i++) {
+ p = resp.rows[i].key;
+ delete pages[p];
+ }
+ for (m in pages) {
+ $("a[href='"+m+"']", wiki).addClass("missing");
+ }
+ },
+ error : function() {}
+ });
+ }
+};
View
5 evently/wiki/edit/mustache.html
@@ -8,10 +8,9 @@
<textarea name="markdown" rows="30" cols="70">{{markdown}}</textarea>
<p><label>Optional description: <input size="60" type="text" name="note" value="{{note}}"></label>
<input type="submit" value="Save Changes">
- <input type="button" name="preview" value="Preview">
</p>
- <div class="preview"></div>
-</div>
{{>help}}
+</div>
+<div class="preview"></div>
<div class="clear"></div>
</form>
View
7 evently/wiki/edit/selectors/input[name=preview]/click.js
@@ -1,7 +0,0 @@
-function() {
- var form = $(this).parents("form"), app = $$(form).app,
- f = form.serializeObject(),
- markdown = app.require("vendor/couchapp/lib/markdown");
- $.log(f)
- $(".preview", form).html(markdown.encode(f.markdown));
-};
View
6 evently/wiki/edit/selectors/textarea[name=markdown]/_init.js
@@ -0,0 +1,6 @@
+function() {
+ var ta = $(this);
+ setTimeout(function() {
+ ta.trigger("keyup");
+ },50);
+};
View
1  evently/wiki/edit/selectors/textarea[name=markdown]/_init.txt
@@ -1 +0,0 @@
-keyup
View
16 evently/wiki/edit/selectors/textarea[name=markdown]/keyup.js
@@ -1,7 +1,15 @@
function() {
- var form = $(this).parents("form"), app = $$(this).app,
+ var form = $(this).parents("form"), prev = $(".preview", form), app = $$(this).app,
f = form.serializeObject(),
markdown = app.require("vendor/couchapp/lib/markdown");
- $.log(f)
- $(".preview", form).html(markdown.encode(f.markdown));
-};
+ if ($$(prev).markdown != f.markdown) {
+ $$(prev).markdown = f.markdown;
+ $(prev).html(markdown.encode(f.markdown));
+ if (!$$(prev).timeout) {
+ $$(prev).timeout = setTimeout(function() {
+ $("#wiki").trigger("_init");
+ $$(prev).timeout = false;
+ }, 1100);
+ }
+ }
+}
View
18 lists/comments.js
@@ -0,0 +1,18 @@
+function() {
+ var row, ddoc = this,
+ mustache = require("vendor/couchapp/lib/mustache"),
+ markdown = require("vendor/couchapp/lib/markdown"),
+ data = {
+ title : "All Comments",
+ site_title : this.couchapp.name,
+ path : "/pages/comments",
+ comments : []
+ };
+ provides("html", function() {
+ while (row = getRow()) {
+ log(row);
+ data.comments.push(row.value)
+ }
+ send(mustache.to_html(ddoc.templates.comments, data, ddoc.templates.partials));
+ });
+};
View
9 rewrites.json
@@ -38,7 +38,14 @@
}
},
{
+ "from" : "/pages/comments",
+ "to" : "_list/comments/all-comments",
+ "query" : {
+ "descending" : true
+ }
+ },
+ {
"from" : "pages/*",
"to" : "../../*"
}
-]
+]
View
29 templates/comments.html
@@ -0,0 +1,29 @@
+{{>header}}
+<ul>
+ {{#comments}}
+ <li>
+ <span class="date">{{at}}</span>:
+ {{#by}}{{name}} {{/by}}
+ {{^by}}Unknown {{/by}}
+ (<a href="/page/{{topic}}">{{topic}}</a>)
+ <span class="idontknow">{{comment}}</span>
+ </li>
+ {{/comments}}
+</ul>
+ </body>
+ <script src="/script/myloader.js"></script>
+ <script src="/_utils/script/base64.js"></script>
+ <script type="text/javascript" charset="utf-8">
+ $.couch.app(function(app) {
+ $(".date").prettyDate();
+ $("#account").evently("account", app);
+ var pr = app.ddoc.evently.profile.profileReady;
+ pr.mustache = pr.all; // mod the template for this page
+ $("#profile").evently("profile", app);
+ $.evently.connect("#account","#profile", ["loggedIn","loggedOut"]);
+ },{
+ db : "pages",
+ design : "pages"
+ });
+ </script>
+</html>
View
2  templates/page.html
@@ -1,6 +1,6 @@
{{>header}}
<div id="tools"></div>
- <div id="wiki">{{{body}}}</div>
+ <div id="wiki"><div class="wiki">{{{body}}}</div></div>
<div id="comments"></div>
{{#has_atts}}
<div id="files">
View
2  templates/partials/header.html
@@ -8,6 +8,6 @@
<body>
<div id="header">
<div id="account"></div>
- <h1><strong>{{site_title}}:</strong> <a href="{{path}}">{{title}}</a></h1>
+ <h1><strong><a href="/page/index">{{site_title}}</a>:</strong> <a href="{{path}}">{{title}}</a></h1>
</div>
<div id="profile"></div>
View
29 validate_doc_update.js
@@ -0,0 +1,29 @@
+function (newDoc, oldDoc, userCtx, secObj) {
+ var v = require("vendor/couchapp/lib/validate").init(newDoc, oldDoc, userCtx, secObj);
+
+ if (v.isAdmin()) {
+ return true; // admin can do anything
+ }
+
+ if (!userCtx.name) {
+ // this could be configurable based on secObj
+ v.unauthorized("please login to make changes");
+ }
+
+ // only admin may delete
+ if (newDoc._deleted) {
+ v.unauthorized("only admin may delete docs");
+ }
+
+ // attached versions must be preserved
+ if (oldDoc && oldDoc._attachments) {
+ for (var n in oldDoc._attachments) {
+ if (n.indexOf("rev") == 0) {
+ if (!(newDoc._attachments && newDoc._attachments[n]
+ && newDoc._attachments[n].stub === true)) {
+ v.forbidden("old versions may not be deleted")
+ }
+ }
+ }
+ }
+}
View
53 vendor/couchapp/lib/validate.js
@@ -0,0 +1,53 @@
+// a library for validations
+// over time we expect to extract more helpers and move them here.
+exports.init = function(newDoc, oldDoc, userCtx, secObj) {
+ var v = {};
+
+ v.forbidden = function(message) {
+ throw({forbidden : message});
+ };
+
+ v.unauthorized = function(message) {
+ throw({unauthorized : message});
+ };
+
+ v.assert = function(should, message) {
+ if (!should) v.forbidden(message);
+ }
+
+ v.isAdmin = function() {
+ return userCtx.roles.indexOf('_admin') != -1
+ };
+
+ v.isRole = function(role) {
+ return userCtx.roles.indexOf(role) != -1
+ };
+
+ v.require = function() {
+ for (var i=0; i < arguments.length; i++) {
+ var field = arguments[i];
+ message = "The '"+field+"' field is required.";
+ if (typeof newDoc[field] == "undefined") v.forbidden(message);
+ };
+ };
+
+ v.unchanged = function(field) {
+ if (oldDoc && oldDoc[field] != newDoc[field])
+ v.forbidden("You may not change the '"+field+"' field.");
+ };
+
+ v.matches = function(field, regex, message) {
+ if (!newDoc[field].match(regex)) {
+ message = message || "Format of '"+field+"' field is invalid.";
+ v.forbidden(message);
+ }
+ };
+
+ // this ensures that the date will be UTC, parseable, and collate correctly
+ v.dateFormat = function(field) {
+ message = "Sorry, '"+field+"' is not a valid date format. Try: 2010-02-24T17:00:03.432Z";
+ v.matches(field, /\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}(\.\d*)?Z/, message);
+ }
+
+ return v;
+};
View
5 views/all-comments/map.js
@@ -0,0 +1,5 @@
+function(doc) {
+ if (doc.type == "comment" && doc.comment) {
+ emit(doc.at, doc);
+ }
+};
View
5 views/all-pages/map.js
@@ -0,0 +1,5 @@
+function(doc) {
+ if (doc.title && doc.markdown) {
+ emit(doc._id, 1);
+ }
+};
Please sign in to comment.
Something went wrong with that request. Please try again.