From fd215812087d7e3ceb8c31d754a5cda7bb7e8e9b Mon Sep 17 00:00:00 2001
From: Emily O'Leary <lotusecho@ThinkLotus>
Date: Sun, 24 Mar 2013 21:42:42 -0400
Subject: [PATCH 1/4] Added comment preview functionality to user pages. It
works by passing the comment's value as a JSON string
to a new handler that lives at /ajax/comment/preview.
The query string is decoded, unquoted, and has its
leading and trailing quotes removed to match the input
that cleaned_markdown_conversion expects.
It does this in real time with a 500ms lag by using a timer. Initially I tried the onChange handler but you need to lose focus for that to process. The javascript timer is only invoked if the add comment button is pressed. A request is only sent if the comment box is not empty and the current value is not the same as the last value.
---
mediagoblin/static/js/comment_show.js | 12 ++++++++++++
.../templates/mediagoblin/user_pages/media.html | 2 ++
mediagoblin/user_pages/forms.py | 2 +-
mediagoblin/user_pages/routing.py | 4 ++++
mediagoblin/user_pages/views.py | 19 ++++++++++++++++++-
5 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js
index c5ccee6..cb69fcc 100644
a
|
b
|
|
15 | 15 | * You should have received a copy of the GNU Affero General Public License |
16 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 | */ |
| 18 | var content=""; |
18 | 19 | |
| 20 | function previewComment(){ |
| 21 | if ($('#comment_content').val() && (content != $('#comment_content').val())) { |
| 22 | content = $('#comment_content').val(); |
| 23 | $.getJSON($('#previewURL').val(),JSON.stringify($('#comment_content').val()), |
| 24 | function(data){ |
| 25 | $('#comment_preview').replaceWith("<div id=comment_preview><h3>Comment Preview</h3><br />" + decodeURIComponent(data) + |
| 26 | "<hr style='border: 1px solid #333;' /></div>"); |
| 27 | }); |
| 28 | } |
| 29 | } |
19 | 30 | $(document).ready(function(){ |
20 | 31 | $('#form_comment').hide(); |
21 | 32 | $('#button_addcomment').click(function(){ |
22 | 33 | $(this).fadeOut('fast'); |
23 | 34 | $('#form_comment').slideDown(function(){ |
| 35 | setInterval("previewComment()",500); |
24 | 36 | $('#comment_content').focus(); |
25 | 37 | }); |
26 | 38 | }); |
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index b77c12b..28573d3 100644
a
|
b
|
|
102 | 102 | <input type="submit" value="{% trans %}Add this comment{% endtrans %}" class="button_action" /> |
103 | 103 | {{ csrf_token }} |
104 | 104 | </div> |
| 105 | <input type="hidden" value="{{ request.urlgen('mediagoblin.user_pages.media_preview_comment') }}" id="previewURL" /> |
105 | 106 | </form> |
| 107 | <div id="comment_preview"></div> |
106 | 108 | {% endif %} |
107 | 109 | <ul style="list-style:none"> |
108 | 110 | {% for comment in comments %} |
diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py
index e9746a6..fe6fccf 100644
a
|
b
|
class MediaCommentForm(wtforms.Form):
|
23 | 23 | _('Comment'), |
24 | 24 | [wtforms.validators.Required()], |
25 | 25 | description=_(u'You can use ' |
26 | | u'<a href="http://daringfireball.net/projects/markdown/basics">' |
| 26 | u'<a href="http://daringfireball.net/projects/markdown/basics" target=new>' |
27 | 27 | u'Markdown</a> for formatting.')) |
28 | 28 | |
29 | 29 | class ConfirmDeleteForm(wtforms.Form): |
diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py
index 9cb665b..b1dde39 100644
a
|
b
|
add_route('mediagoblin.user_pages.media_post_comment',
|
32 | 32 | '/u/<string:user>/m/<int:media_id>/comment/add/', |
33 | 33 | 'mediagoblin.user_pages.views:media_post_comment') |
34 | 34 | |
| 35 | add_route('mediagoblin.user_pages.media_preview_comment', |
| 36 | '/ajax/comment/preview/', |
| 37 | 'mediagoblin.user_pages.views:media_preview_comment') |
| 38 | |
35 | 39 | add_route('mediagoblin.user_pages.user_gallery', |
36 | 40 | '/u/<string:user>/gallery/', |
37 | 41 | 'mediagoblin.user_pages.views:user_gallery') |
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index c611daa..c50d801 100644
a
|
b
|
|
16 | 16 | |
17 | 17 | import logging |
18 | 18 | import datetime |
| 19 | import json |
| 20 | import urllib |
19 | 21 | |
20 | 22 | from mediagoblin import messages, mg_globals |
21 | 23 | from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, |
22 | 24 | CollectionItem, User) |
23 | 25 | from mediagoblin.tools.response import render_to_response, render_404, redirect |
| 26 | from mediagoblin.tools.text import cleaned_markdown_conversion |
24 | 27 | from mediagoblin.tools.translate import pass_to_ugettext as _ |
25 | 28 | from mediagoblin.tools.pagination import Pagination |
26 | 29 | from mediagoblin.user_pages import forms as user_forms |
27 | 30 | from mediagoblin.user_pages.lib import send_comment_email |
28 | | |
| 31 | from mediagoblin.meddleware.csrf import render_csrf_form_token |
29 | 32 | from mediagoblin.decorators import (uses_pagination, get_user_media_entry, |
30 | 33 | get_media_entry_by_id, |
31 | 34 | require_active_login, user_may_delete_media, user_may_alter_collection, |
32 | 35 | get_user_collection, get_user_collection_item, active_user_from_url) |
33 | 36 | |
34 | 37 | from werkzeug.contrib.atom import AtomFeed |
| 38 | from werkzeug.wrappers import Response |
35 | 39 | |
36 | 40 | |
37 | 41 | _log = logging.getLogger(__name__) |
… |
… |
def media_post_comment(request, media):
|
157 | 161 | comment = request.db.MediaComment() |
158 | 162 | comment.media_entry = media.id |
159 | 163 | comment.author = request.user.id |
| 164 | print request.form['comment_content'] |
160 | 165 | comment.content = unicode(request.form['comment_content']) |
161 | 166 | |
162 | 167 | if not comment.content.strip(): |
… |
… |
def media_post_comment(request, media):
|
180 | 185 | return redirect(request, location=media.url_for_self(request.urlgen)) |
181 | 186 | |
182 | 187 | |
| 188 | |
| 189 | def media_preview_comment(request): |
| 190 | |
| 191 | comment = unicode(urllib.unquote(request.query_string).decode('string_escape')) |
| 192 | if comment.startswith('"') and comment.endswith('"'): |
| 193 | comment = comment[1:-1] |
| 194 | print comment |
| 195 | #decoderRing = json.JSONDecoder() |
| 196 | #comment = decoderRing.decode(request.query_string) |
| 197 | |
| 198 | return Response(json.dumps(cleaned_markdown_conversion(comment))) |
| 199 | |
183 | 200 | @get_media_entry_by_id |
184 | 201 | @require_active_login |
185 | 202 | def media_collect(request, media): |
--
1.7.10.4
From 1e2720a25acc7408ab6eb0d498fc389a1fc73e6b Mon Sep 17 00:00:00 2001
From: Emily O'Leary <lotusecho@ThinkLotus>
Date: Sun, 24 Mar 2013 22:16:12 -0400
Subject: [PATCH 2/4] Added i18n to my javascript changes as per trac #417
---
mediagoblin/static/js/comment_show.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js
index cb69fcc..35183be 100644
a
|
b
|
function previewComment(){
|
22 | 22 | content = $('#comment_content').val(); |
23 | 23 | $.getJSON($('#previewURL').val(),JSON.stringify($('#comment_content').val()), |
24 | 24 | function(data){ |
25 | | $('#comment_preview').replaceWith("<div id=comment_preview><h3>Comment Preview</h3><br />" + decodeURIComponent(data) + |
| 25 | $('#comment_preview').replaceWith("<div id=comment_preview><h3>{% trans -%}Comment Preview{%- endtrans %}</h3><br />" + decodeURIComponent(data) + |
26 | 26 | "<hr style='border: 1px solid #333;' /></div>"); |
27 | 27 | }); |
28 | 28 | } |
--
1.7.10.4
From 53576b3f233c83bc54b7ec0d6791141ed89ec026 Mon Sep 17 00:00:00 2001
From: Emily O'Leary <lotusecho@ThinkLotus>
Date: Mon, 25 Mar 2013 14:13:09 -0400
Subject: [PATCH 3/4] Changed the target of the markdown links for opening in
a new tab as suggested by joar.
---
mediagoblin/user_pages/forms.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py
index fe6fccf..7c04c9d 100644
a
|
b
|
class MediaCommentForm(wtforms.Form):
|
23 | 23 | _('Comment'), |
24 | 24 | [wtforms.validators.Required()], |
25 | 25 | description=_(u'You can use ' |
26 | | u'<a href="http://daringfireball.net/projects/markdown/basics" target=new>' |
| 26 | u'<a href="http://daringfireball.net/projects/markdown/basics" target="_blank">' |
27 | 27 | u'Markdown</a> for formatting.')) |
28 | 28 | |
29 | 29 | class ConfirmDeleteForm(wtforms.Form): |
… |
… |
class MediaCollectForm(wtforms.Form):
|
47 | 47 | collection_description = wtforms.TextAreaField( |
48 | 48 | _('Description of this collection'), |
49 | 49 | description=_("""You can use |
50 | | <a href="http://daringfireball.net/projects/markdown/basics"> |
| 50 | <a href="http://daringfireball.net/projects/markdown/basics" target="_blank"> |
51 | 51 | Markdown</a> for formatting.""")) |
--
1.7.10.4
From d1b23937078582864f842b075f24c8263e513c59 Mon Sep 17 00:00:00 2001
From: Emily O'Leary <Emma.C.Echo@gmail.com>
Date: Tue, 6 Aug 2013 18:22:51 -0400
Subject: [PATCH 4/4] Changed how the comment was encoded/read. Fixed CSRF +
Post with comment preview. Merged with latest master
---
mediagoblin/static/js/comment_show.js | 19 ++++++++++---------
.../templates/mediagoblin/user_pages/media.html | 1 +
mediagoblin/user_pages/views.py | 12 ++++--------
3 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js
index 35183be..42a2181 100644
a
|
b
|
|
18 | 18 | var content=""; |
19 | 19 | |
20 | 20 | function previewComment(){ |
21 | | if ($('#comment_content').val() && (content != $('#comment_content').val())) { |
22 | | content = $('#comment_content').val(); |
23 | | $.getJSON($('#previewURL').val(),JSON.stringify($('#comment_content').val()), |
24 | | function(data){ |
25 | | $('#comment_preview').replaceWith("<div id=comment_preview><h3>{% trans -%}Comment Preview{%- endtrans %}</h3><br />" + decodeURIComponent(data) + |
26 | | "<hr style='border: 1px solid #333;' /></div>"); |
27 | | }); |
28 | | } |
| 21 | if ($('#comment_content').val() && (content != $('#comment_content').val())) { |
| 22 | content = $('#comment_content').val(); |
| 23 | $.post($('#previewURL').val(),$('#form_comment').serialize(), |
| 24 | function(data){ |
| 25 | preview = JSON.parse(data) |
| 26 | $('#comment_preview').replaceWith("<div id=comment_preview><h3>" + $('#previewText').val() +"</h3><br />" + preview.content + |
| 27 | "<hr style='border: 1px solid #333;' /></div>"); |
| 28 | }); |
| 29 | } |
29 | 30 | } |
30 | 31 | $(document).ready(function(){ |
31 | 32 | $('#form_comment').hide(); |
32 | 33 | $('#button_addcomment').click(function(){ |
33 | 34 | $(this).fadeOut('fast'); |
34 | 35 | $('#form_comment').slideDown(function(){ |
35 | | setInterval("previewComment()",500); |
| 36 | setInterval("previewComment()",500); |
36 | 37 | $('#comment_content').focus(); |
37 | 38 | }); |
38 | 39 | }); |
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index 39a5eec..3acd835 100644
a
|
b
|
|
108 | 108 | {{ csrf_token }} |
109 | 109 | </div> |
110 | 110 | <input type="hidden" value="{{ request.urlgen('mediagoblin.user_pages.media_preview_comment') }}" id="previewURL" /> |
| 111 | <input type="hidden" value="{% trans %}Comment Preview{% endtrans %}" id="previewText"/> |
111 | 112 | </form> |
112 | 113 | <div id="comment_preview"></div> |
113 | 114 | {% endif %} |
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index 66d8fc5..a087851 100644
a
|
b
|
def media_post_comment(request, media):
|
198 | 198 | |
199 | 199 | |
200 | 200 | def media_preview_comment(request): |
| 201 | """Runs a comment through markdown so it can be previewed.""" |
| 202 | comment = unicode(request.form['comment_content']) |
| 203 | cleancomment = { "content":cleaned_markdown_conversion(comment)} |
201 | 204 | |
202 | | comment = unicode(urllib.unquote(request.query_string).decode('string_escape')) |
203 | | if comment.startswith('"') and comment.endswith('"'): |
204 | | comment = comment[1:-1] |
205 | | print comment |
206 | | #decoderRing = json.JSONDecoder() |
207 | | #comment = decoderRing.decode(request.query_string) |
208 | | |
209 | | return Response(json.dumps(cleaned_markdown_conversion(comment))) |
| 205 | return Response(json.dumps(cleancomment)) |
210 | 206 | |
211 | 207 | @get_media_entry_by_id |
212 | 208 | @require_active_login |