Mercurial > genshi > mirror
changeset 625:abad7c2ebe15 trunk
GenshiTutorial: implemented AJAX commenting.
author | cmlenz |
---|---|
date | Fri, 31 Aug 2007 17:01:00 +0000 |
parents | dc657447f352 |
children | 1fc90c02e2d8 |
files | examples/tutorial/geddit/controller.py examples/tutorial/geddit/lib/ajax.py examples/tutorial/geddit/lib/template.py examples/tutorial/geddit/model.py examples/tutorial/geddit/templates/_comment.html examples/tutorial/geddit/templates/_form.html examples/tutorial/geddit/templates/comment.html examples/tutorial/geddit/templates/index.html examples/tutorial/geddit/templates/info.html examples/tutorial/geddit/templates/submit.html |
diffstat | 10 files changed, 109 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/tutorial/geddit/controller.py +++ b/examples/tutorial/geddit/controller.py @@ -10,7 +10,7 @@ from genshi.filters import HTMLFormFiller from geddit.form import LinkForm, CommentForm -from geddit.lib import template +from geddit.lib import ajax, template from geddit.model import Link, Comment @@ -77,14 +77,20 @@ try: data = form.to_python(data) comment = link.add_comment(**data) - raise cherrypy.HTTPRedirect('/info/%s' % link.id) + if not ajax.is_xhr(): + raise cherrypy.HTTPRedirect('/info/%s' % link.id) + return template.render('_comment.html', comment=comment, + num=len(link.comments)) except Invalid, e: errors = e.unpack_errors() else: errors = {} - return template.render(link=link, comment=None, - errors=errors) | HTMLFormFiller(data=data) + if ajax.is_xhr(): + stream = template.render('_form.html', link=link, errors=errors) + else: + stream = template.render(link=link, comment=None, errors=errors) + return stream | HTMLFormFiller(data=data) def main(filename):
new file mode 100644 --- /dev/null +++ b/examples/tutorial/geddit/lib/ajax.py @@ -0,0 +1,5 @@ +import cherrypy + +def is_xhr(): + requested_with = cherrypy.request.headers.get('X-Requested-With') + return requested_with and requested_with.lower() == 'xmlhttprequest'
--- a/examples/tutorial/geddit/lib/template.py +++ b/examples/tutorial/geddit/lib/template.py @@ -5,6 +5,8 @@ from genshi.output import encode, get_serializer from genshi.template import Context, TemplateLoader +from geddit.lib import ajax + loader = TemplateLoader( os.path.join(os.path.dirname(__file__), '..', 'templates'), auto_reload=True @@ -18,9 +20,10 @@ def decorate(func): def wrapper(*args, **kwargs): cherrypy.thread_data.template = loader.load(filename) - if method == 'html': - options.setdefault('doctype', 'html') - serializer = get_serializer(method, **options) + opt = options.copy() + if not ajax.is_xhr() and method == 'html': + opt.setdefault('doctype', 'html') + serializer = get_serializer(method, **opt) stream = func(*args, **kwargs) if not isinstance(stream, Stream): return stream
--- a/examples/tutorial/geddit/model.py +++ b/examples/tutorial/geddit/model.py @@ -15,7 +15,9 @@ return '<%s %r>' % (type(self).__name__, self.title) def add_comment(self, username, content): - self.comments.append(Comment(username, content)) + comment = Comment(username, content) + self.comments.append(comment) + return comment class Comment(object): @@ -26,4 +28,4 @@ self.time = datetime.utcnow() def __repr__(self): - return '<%s>' % (type(self).__name__) + return '<%s by %r>' % (type(self).__name__, self.username)
new file mode 100644 --- /dev/null +++ b/examples/tutorial/geddit/templates/_comment.html @@ -0,0 +1,4 @@ +<li id="comment$num"> + <strong>${comment.username}</strong> at ${comment.time.strftime('%x %X')} + <blockquote>${comment.content}</blockquote> +</li>
new file mode 100644 --- /dev/null +++ b/examples/tutorial/geddit/templates/_form.html @@ -0,0 +1,23 @@ +<form xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + class="comment" action="${url('/comment/%s/' % link.id)}" method="post"> + <table summary=""><tbody><tr> + <th><label for="username">Your name:</label></th> + <td> + <input type="text" id="username" name="username" /> + <span py:if="'username' in errors" class="error">${errors.username}</span> + </td> + </tr><tr> + <th><label for="comment">Comment:</label></th> + <td> + <textarea id="comment" name="content" rows="6" cols="50"></textarea> + <span py:if="'content' in errors" class="error"><br />${errors.content}</span> + </td> + </tr><tr> + <td></td> + <td> + <input type="submit" value="Submit" /> + <input type="submit" name="cancel" value="Cancel" /> + </td> + </tr></tbody></table> +</form>
--- a/examples/tutorial/geddit/templates/comment.html +++ b/examples/tutorial/geddit/templates/comment.html @@ -13,24 +13,6 @@ at ${comment.time.strftime('%x %X')}: <blockquote>${comment.content}</blockquote> </p> - <form action="" method="post"> - <table summary=""><tbody><tr> - <th><label for="username">Your name:</label></th> - <td> - <input type="text" id="username" name="username" /> - <span py:if="'username' in errors" class="error">${errors.username}</span> - </td> - </tr><tr> - <th><label for="comment">Comment:</label></th> - <td> - <textarea id="comment" name="content" rows="6" cols="50"></textarea> - <span py:if="'content' in errors" class="error"><br />${errors.content}</span> - </td> - </tr></tbody></table> - <div> - <input type="submit" value="Submit" /> - <input type="submit" name="cancel" value="Cancel" /> - </div> - </form> + <xi:include href="_form.html" /> </body> </html>
--- a/examples/tutorial/geddit/templates/index.html +++ b/examples/tutorial/geddit/templates/index.html @@ -10,7 +10,6 @@ </head> <body> <h1>News</h1> - <p><a class="action" href="${url('/submit/')}">Submit new link</a></p> <ol py:if="links" class="links"> <li py:for="link in links"> @@ -23,5 +22,7 @@ </div> </li> </ol> + + <p><a class="action" href="${url('/submit/')}">Submit new link</a></p> </body> </html>
--- a/examples/tutorial/geddit/templates/info.html +++ b/examples/tutorial/geddit/templates/info.html @@ -5,22 +5,60 @@ <xi:include href="layout.html" /> <head> <title>${link.title}</title> - <link rel="alternate" type="application/atom+xml" title="Geddit: ${link.title}" - href="${url('/feed/%s/' % link.id)}" /> + <link rel="alternate" title="Geddit: ${link.title}" + type="application/atom+xml" href="${url('/feed/%s/' % link.id)}" /> + <script type="text/javascript"> + function loadCommentForm(a) { + $.get("${url('/comment/%s/' % link.id)}", {}, function(html) { + var form = a.hide().parent().after(html).next(); + function closeForm() { + form.slideUp("fast", function() { a.fadeIn(); form.remove() }); + return false; + } + function initForm() { + form.find("input[@name='cancel']").click(closeForm); + form.submit(function() { + var data = form.find("input[@type='text'], textarea").serialize(); + $.post("${url('/comment/%s/' % link.id)}", data, function(html) { + var elem = $(html).get(0); + if (/form/i.test(elem.tagName)) { + form.after(elem).remove(); + form = $(elem); + initForm(); + } else { + if ($("ul.comments").length == 0) { + a.parent().before('<ul class="comments"></ul>'); + } + $("ul.comments") + .find("li.hilite").removeClass("hilite").end() + .append($(elem).addClass("hilite")).slideDown(); + closeForm(); + } + }); + return false; + }); + } + initForm(); + }); + } + $(document).ready(function() { + $("a.action").click(function() { + loadCommentForm($(this)); + return false; + }); + }); + </script> </head> <body> <h1>${link.title}</h1> <a href="${link.url}">${link.url}</a><br /> posted by ${link.username} at ${link.time.strftime('%x %X')}<br /> - <p><a class="action" href="${url('/comment/%s/' % link.id)}">comment</a></p> - <ul py:if="link.comments" class="comments"> - <li py:for="idx, comment in enumerate(link.comments)" id="comment$idx"> - <strong>${comment.username}</strong> - at ${comment.time.strftime('%x %X')} - <blockquote>${comment.content}</blockquote> - </li> + <xi:include href="_comment.html" + py:for="num, comment in enumerate(link.comments)" /> </ul> + + <p><a class="action" href="${url('/comment/%s/' % link.id)}">comment</a></p> </body> </html>
--- a/examples/tutorial/geddit/templates/submit.html +++ b/examples/tutorial/geddit/templates/submit.html @@ -21,18 +21,19 @@ <input type="text" id="url" name="url" /> <span py:if="'url' in errors" class="error">${errors.url}</span> </td> - </tr> - <tr> + </tr><tr> <th><label for="title">Title:</label></th> <td> <input type="text" name="title" /> <span py:if="'title' in errors" class="error">${errors.title}</span> </td> + </tr><tr> + <td></td> + <td> + <input type="submit" value="Submit" /> + <input type="submit" name="cancel" value="Cancel" /> + </td> </tr></tbody></table> - <div> - <input type="submit" value="Submit" /> - <input type="submit" name="cancel" value="Cancel" /> - </div> </form> </body> </html>