diff options
-rw-r--r-- | askbot/doc/source/changelog.rst | 1 | ||||
-rw-r--r-- | askbot/media/images/delete.png | bin | 434 -> 431 bytes | |||
-rw-r--r-- | askbot/media/images/edit2.png | bin | 498 -> 571 bytes | |||
-rw-r--r-- | askbot/media/images/flag.png | bin | 515 -> 519 bytes | |||
-rw-r--r-- | askbot/media/images/link.png | bin | 601 -> 513 bytes | |||
-rw-r--r-- | askbot/media/images/sprites.png | bin | 15025 -> 18549 bytes | |||
-rw-r--r-- | askbot/media/style/style.less | 53 | ||||
-rw-r--r-- | askbot/models/post.py | 30 | ||||
-rw-r--r-- | askbot/models/question.py | 7 | ||||
-rw-r--r-- | askbot/templates/question.html | 93 | ||||
-rw-r--r-- | askbot/templates/question/answer_controls.html | 92 | ||||
-rw-r--r-- | askbot/templates/question/javascript.html | 1 | ||||
-rw-r--r-- | askbot/templates/question/question_controls.html | 28 | ||||
-rw-r--r-- | askbot/urls.py | 15 | ||||
-rw-r--r-- | askbot/views/readers.py | 1 | ||||
-rw-r--r-- | askbot/views/writers.py | 27 |
16 files changed, 257 insertions, 91 deletions
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index 031a3e64..888ad286 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -7,6 +7,7 @@ Development version Danish, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese (requires package textsearch_ja), Norwegian, Portugese, Romanian, Russian, Spanish, Swedish, Turkish. +* repost answer as a comment under the previous (older) answer 0.7.48 (Jan 28, 2013) diff --git a/askbot/media/images/delete.png b/askbot/media/images/delete.png Binary files differindex 9263eae3..90349e69 100644 --- a/askbot/media/images/delete.png +++ b/askbot/media/images/delete.png diff --git a/askbot/media/images/edit2.png b/askbot/media/images/edit2.png Binary files differindex f142a68c..e683fddf 100644 --- a/askbot/media/images/edit2.png +++ b/askbot/media/images/edit2.png diff --git a/askbot/media/images/flag.png b/askbot/media/images/flag.png Binary files differindex fc302335..f9d8f0c0 100644 --- a/askbot/media/images/flag.png +++ b/askbot/media/images/flag.png diff --git a/askbot/media/images/link.png b/askbot/media/images/link.png Binary files differindex 6ad60f5e..7dd90f10 100644 --- a/askbot/media/images/link.png +++ b/askbot/media/images/link.png diff --git a/askbot/media/images/sprites.png b/askbot/media/images/sprites.png Binary files differindex 78eea747..4f23e088 100644 --- a/askbot/media/images/sprites.png +++ b/askbot/media/images/sprites.png diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less index 0510b398..f5fc98ef 100644 --- a/askbot/media/style/style.less +++ b/askbot/media/style/style.less @@ -2101,7 +2101,8 @@ ul#related-tags li { margin-top:10px; margin-bottom:8px; - a { + a, + span.dropdown-toggle { color: #777; padding: 0px 7px 3px 18px; cursor: pointer; @@ -2110,17 +2111,51 @@ ul#related-tags li { font-family:@body-font; text-decoration: none; height:18px; - display:block; - float:right; line-height:18px; margin-top:-2px; margin-left:4px; } - a:hover { + a:hover, + span.dropdown-toggle:hover { background-color: #f5f0c9; + } + span.dropdown-toggle { + background: url(../images/sprites.png) no-repeat -7px -242px; .rounded-corners(3px); - + position: relative; + } + span.dropdown-toggle:hover { + padding-right: 0; + background: url(../images/sprites.png) no-repeat -7px -274px; + form { + margin: 0; + } + input { + display: block !important; + height: 20px !important; + line-height: 20px !important; + margin: 0; + padding: 0 5px; + .rounded-corners(0); + width: 100% !important; + } + .dropdown-menu { + display: block; + padding: 5px 0; + right: -5px !important; + left: auto; + li, + li:hover { + display: block !important; + margin: 0; + padding: 0; + width: 100% !important; + } + li:hover { + background-color: #f5f0c9; + } + } } .sep { color: #ccc; @@ -2131,11 +2166,11 @@ ul#related-tags li { } .post-controls, .answer-controls{ .question-delete{ - background: url(../images/delete.png) no-repeat left 2px; + background: url(../images/delete.png) no-repeat left -1px; padding-left:11px; } .question-flag{ - background: url(../images/flag.png) no-repeat center left; + background: url(../images/flag.png) no-repeat 2px 0; } .answer-publish{ background: url(../images/publish.png) no-repeat center left; @@ -2144,7 +2179,7 @@ ul#related-tags li { background: url(../images/unpublish.png) no-repeat 2px center; } .question-edit{ - background: url(../images/edit2.png) no-repeat 2px center; + background: url(../images/edit2.png) no-repeat 3px 1px; } .question-retag{ background: url(../images/retag.png) no-repeat center left; @@ -2153,7 +2188,7 @@ ul#related-tags li { background: url(../images/close.png) no-repeat center left; } .permant-link{ - background: url(../images/link.png) no-repeat center left; + background: url(../images/link.png) no-repeat 2px 1px; } .answer-convert{ diff --git a/askbot/models/post.py b/askbot/models/post.py index 625d262b..57cc309d 100644 --- a/askbot/models/post.py +++ b/askbot/models/post.py @@ -579,6 +579,11 @@ class Post(models.Model): def is_reject_reason(self): return self.post_type == 'reject_reason' + def get_last_edited_date(self): + """returns date of last edit or date of creation + if there were no edits""" + return self.last_edited_at or self.added_at + def get_moderators(self): """returns query set of users who are site administrators and moderators""" @@ -587,10 +592,27 @@ class Post(models.Model): user_filter = user_filter & models.Q(groups__in=self.groups.all()) return User.objects.filter(user_filter) - def get_last_edited_date(self): - """returns date of last edit or date of creation - if there were no edits""" - return self.last_edited_at or self.added_at + def get_previous_answer(self, user=None): + """returns a previous answer to a given answer; + only works on the "answer" post types""" + assert(self.post_type == 'answer') + all_answers = self.thread.get_answers(user=user) + + matching_answers = all_answers.filter( + added_at__lt=self.added_at, + ).order_by('-added_at') + + if len(matching_answers) == 0: + return None + + answer = matching_answers[0] + + if answer.id == self.id: + return None + if answer.added_at > self.added_at: + return None + + return answer def has_group(self, group): """true if post belongs to the group""" diff --git a/askbot/models/question.py b/askbot/models/question.py index 2d282fbc..d1fa7cae 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -600,6 +600,13 @@ class Thread(models.Model): else: return self.get_answers(user).count() + def get_oldest_answer_id(self, user=None): + """give oldest visible answer id for the user""" + answers = self.get_answers(user=user).order_by('added_at') + if len(answers) > 0: + return answers[0].id + return None + def get_sharing_info(self, visitor=None): """returns a dictionary with abbreviated thread sharing info: * users - up to a certain number of users, excluding the visitor diff --git a/askbot/templates/question.html b/askbot/templates/question.html index b3610bd0..b7410a17 100644 --- a/askbot/templates/question.html +++ b/askbot/templates/question.html @@ -15,7 +15,43 @@ /*<![CDATA[*/ //below is pure cross-browser javascript, no jQuery askbot['data']['userIsThreadModerator'] = {% if user_is_thread_moderator %}true{% else %}false{% endif %}; + askbot['data']['oldestAnswerId'] = {% if oldest_answer_id %}{{ oldest_answer_id }}{% else %}-1{% endif %}; (function(){ + + var hasClass = function(node, selector) { + var classes = (" " + node.className + " ").split(' '); + for (var i = 0; i < classes.length; i++) { + if (classes[i] === selector) { + return true; + } + } + return false; + } + + var findChildrenByClassName = function(node, className) { + var nodes = []; + var walk = function(node) { + if (hasClass(node, className)) { + nodes.push(node); + } + if (node.childNodes) { + for (var i=0; i < node.childNodes.length; i++) { + walk(node.childNodes[i]); + } + } + }; + walk(node); + return nodes; + }; + + var removeNode = function(node) { + node.parentNode.removeChild(node); + }; + + var trim = function(text) { + return text.replace(/^\s+|\s+$/g, ''); + }; + var data = askbot['data']; if (data['userIsAuthenticated']){ var votes = {}; @@ -57,20 +93,32 @@ } function hide_convert_answer_links(post_id){ - var answer_convert_id = 'post-' + post_id + '-convert'; - var convert_answer = document.getElementById(answer_convert_id); + var id1 = 'post-' + post_id + '-convert';//for repost as Q comment + var repostAsQuestionComment = document.getElementById(id1); + var id2 = 'post-' + post_id + '-repost-as-comment-under-previous-answer'; + var repostAsPrevAnsComment = document.getElementById(id2); + var extraOptsList = repostAsQuestionComment.parentNode; + var extraOpts = extraOptsList.parentNode; if (data['userIsAdminOrMod']){ var answer_id = 'post-id-' + post_id; var answer_container = document.getElementById(answer_id); - var answer_element= answer_container.getElementsByClassName('answer-body')[0].children[1]; - if ( - answer_element.textContent.length > - askbot['data']['maxCommentLength'] - ){ - convert_answer.parentNode.removeChild(convert_answer); + var answerBody = findChildrenByClassName(answer_container, 'answer-body')[0]; + //todo: this is not reliable + var answerBodyNodes = answerBody.childNodes; + var answerElement = answerBodyNodes[answerBodyNodes.length - 1]; + if (trim(answerElement.textContent).length > askbot['data']['maxCommentLength']) { + repostAsQuestionComment.parentNode.removeChild(repostAsQuestionComment); + repostAsPrevAnsComment.parentNode.removeChild(repostAsPrevAnsComment); + } else if (parseInt(post_id) === data['oldestAnswerId']) { + repostAsPrevAnsComment.parentNode.removeChild(repostAsPrevAnsComment); } } else{ - convert_answer.parentNode.removeChild(convert_answer); + repostAsQuestionComment.parentNode.removeChild(repostAsQuestionComment); + repostAsPrevAnsComment.parentNode.removeChild(repostAsPrevAnsComment); + } + + if (extraOptsList.getElementsByTagName('li').length === 0) { + extraOpts.parentNode.removeChild(extraOpts); } } @@ -87,20 +135,21 @@ if (data['userIsAdminOrMod']){ return;//all remaining functions stay on } - if (data['user_posts'] !== undefined) { - if (post_id in data['user_posts']){ - //todo: remove edit button from older comments - return;//same here - } + if (data['user_posts'] && post_id in data['user_posts']){ + //todo: remove edit button from older comments + return; } + var deleteBtn = document.getElementById('post-' + post_id + '-delete'); + var controls = deleteBtn.parentNode; if (//maybe remove "delete" button data['userReputation'] < {{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}} ) { - var delete_btn = document.getElementById( - 'post-' + post_id + '-delete' - ); - delete_btn.parentNode.removeChild(delete_btn); + removeNode(deleteBtn); + } + var flags = findChildrenByClassName(controls, 'question-flag'); + if (flags.length > 0) { + removeNode(flags[0]); } if (//maybe remove "edit" button data['userReputation'] < @@ -115,9 +164,9 @@ data['userReputation'] < {{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}} ){ - var retag_btn = document.getElementById('retag'); - if (retag_btn) { - retag_btn.parentNode.removeChild(retag_btn); + var retagBtn = document.getElementById('retag'); + if (retagBtn) { + retagBtn.parentNode.removeChild(retagBtn); } } } @@ -156,7 +205,7 @@ function hide_convert_links(){ if (!askbot['data']['userIsAdminOrMod']){ - var links = document.getElementsByClassName('convert-comment'); + var links = findChildrenByClassName(document, 'convert-comment'); for (i=0; i<links.length; i++){ links[i].setAttribute('style', 'display:none;'); } diff --git a/askbot/templates/question/answer_controls.html b/askbot/templates/question/answer_controls.html index 4efc7247..c7d3c4d9 100644 --- a/askbot/templates/question/answer_controls.html +++ b/askbot/templates/question/answer_controls.html @@ -1,32 +1,8 @@ {#<span class="action-link swap-qa"> <a id="swap-question-with-answer-{{answer.id}}">{% trans %}swap with question{% endtrans %}</a> </span>uncomment if needed#} -<span class="action-link"> - <a class="permant-link" - href="{{ answer.get_absolute_url(question_post=question) }}" - title="{% trans %}permanent link{% endtrans %}"> - {% trans %}link{% endtrans %} - </a> -</span> -<span - id="post-{{answer.id}}-publish" - class="action-link" -> - {% if answer.id in published_answer_ids %} - <a - class="answer-unpublish" - data-answer-id="{{ answer.id }}" - >{% trans %}unpublish{% endtrans %}</a> - {% else %} - <a - class="answer-publish" - data-answer-id="{{ answer.id}}" - >{% trans %}publish{% endtrans %}</a> - {% endif %} -</span> -<span id='post-{{answer.id}}-delete' class="action-link delete-post"> - <a class="question-delete" - >{% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a> +<span id='post-{{answer.id}}-edit' class="action-link"> + <a class="question-edit" href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a> </span> {% if answer.offensive_flag_count > 0 %} <span @@ -52,15 +28,63 @@ <a class="question-flag">{% trans %}flag offensive{% endtrans %}</a> </span> {% endif %} -<span id='post-{{answer.id}}-edit' class="action-link"> - <a class="question-edit" href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a> +<span id='post-{{answer.id}}-delete' class="action-link delete-post"> + <a class="question-delete" + >{% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a> +</span> +<span + id="post-{{answer.id}}-publish" + class="action-link" +> + {% if answer.id in published_answer_ids %} + <a + class="answer-unpublish" + data-answer-id="{{ answer.id }}" + >{% trans %}unpublish{% endtrans %}</a> + {% else %} + <a + class="answer-publish" + data-answer-id="{{ answer.id}}" + >{% trans %}publish{% endtrans %}</a> + {% endif %} +</span> +<span class="action-link"> + <a class="permant-link" + href="{{ answer.get_absolute_url(question_post=question) }}" + title="{% trans %}permanent link{% endtrans %}"> + {% trans %}link{% endtrans %} + </a> </span> -<span id='post-{{answer.id}}-convert' class="action-link"> - <form class="answer-convert" action="{% url answer_to_comment %}" method="POST"> - {% csrf_token %} - <input type="hidden" name="answer_id" id="id_answer_id" value="{{answer.id}}"/> - <input type="submit" name="" value="{% trans %}convert to comment{% endtrans %}"/> - </form> +<span class="action-link dropdown-toggle">{% trans %}more{% endtrans %} +<ul class="dropdown-menu"> + <li id='post-{{answer.id}}-convert'> + <form + class="answer-convert" + action="{% url repost_answer_as_comment_under_question %}" + method="post" + > + {% csrf_token %} + <input type="hidden" name="answer_id" id="id_answer_id" value="{{answer.id}}"/> + <input + type="submit" + value="{% trans %}repost as a question comment{% endtrans %}" + /> + </form> + </li> + <li id='post-{{ answer.id }}-repost-as-comment-under-previous-answer'> + <form class="answer-convert repost-as-comment-under-previous-answer" + action="{% url repost_answer_as_comment_under_previous_answer %}" + method="post" + > + {% csrf_token %} + <input type="hidden" name="answer_id" value="{{ answer.id }}"/> + <input + type="submit" + value="{% trans %}repost as a comment under the older answer{% endtrans %}" + /> + </form> + </li> +</ul> </span> <script type="text/javascript"> askbot['functions']['hideConvertAnswerLinks']('{{ answer.id }}'); diff --git a/askbot/templates/question/javascript.html b/askbot/templates/question/javascript.html index dc0c68f0..665bdbac 100644 --- a/askbot/templates/question/javascript.html +++ b/askbot/templates/question/javascript.html @@ -10,7 +10,6 @@ askbot['urls']['editComment'] = '{% url edit_comment %}'; askbot['urls']['deleteComment'] = '{% url delete_comment %}'; askbot['urls']['convertComment'] = '{% url comment_to_answer %}'; - askbot['urls']['convertAnswer'] = '{% url answer_to_comment %}'; askbot['urls']['getComment'] = '{% url get_comment %}'; askbot['urls']['saveDraftAnswer'] = '{% url save_draft_answer %}'; askbot['urls']['vote_url'] = '{% url vote question.id %}'; diff --git a/askbot/templates/question/question_controls.html b/askbot/templates/question/question_controls.html index c782d9ad..88ef42d8 100644 --- a/askbot/templates/question/question_controls.html +++ b/askbot/templates/question/question_controls.html @@ -1,12 +1,8 @@ -<a - id="post-{{question.id}}-delete" - class="question-delete" ->{% if question.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a> -{% if thread.closed %} - <a class="question-close" href="{% url reopen question.id %}">{% trans %}reopen{% endtrans %}</a> -{% else %} - <a class="question-close" href="{% url close question.id %}">{% trans %}close{% endtrans %}</a> -{% endif %} +<a id="post-{{question.id}}-edit" class="question-edit" href="{% url edit_question question.id %}">{% trans %}edit{% endtrans %}</a> +<script type="text/javascript"> + var retagUrl = "{% url retag_question question.id %}"; +</script> +<a id="retag" class="question-retag"href="{% url retag_question question.id %}">{% trans %}retag{% endtrans %}</a> {% if question.offensive_flag_count > 0 %} <span id="question-offensive-remove-flag-{{ question.id }}" @@ -29,11 +25,15 @@ <a class="question-flag">{% trans %}flag offensive{% endtrans %}</a> </span> {% endif %} -<script type="text/javascript"> - var retagUrl = "{% url retag_question question.id %}"; -</script> -<a id="retag" class="question-retag"href="{% url retag_question question.id %}">{% trans %}retag{% endtrans %}</a> -<a id="post-{{question.id}}-edit" class="question-edit" href="{% url edit_question question.id %}">{% trans %}edit{% endtrans %}</a> +{% if thread.closed %} + <a class="question-close" href="{% url reopen question.id %}">{% trans %}reopen{% endtrans %}</a> +{% else %} + <a class="question-close" href="{% url close question.id %}">{% trans %}close{% endtrans %}</a> +{% endif %} +<a + id="post-{{question.id}}-delete" + class="question-delete" +>{% if question.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a> <script type="text/javascript"> askbot['functions']['renderPostControls']('{{question.id}}'); </script> diff --git a/askbot/urls.py b/askbot/urls.py index a82b4694..551b9ecd 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -194,15 +194,22 @@ urlpatterns = patterns('', views.readers.get_comment, name='get_comment' ), - url(#post only + url( r'^comment/convert/$', views.writers.comment_to_answer, name='comment_to_answer' ), + url( + r'^answer/repost-as-comment-under-question/$', + views.writers.repost_answer_as_comment, + kwargs={'destination': 'comment_under_question'}, + name='repost_answer_as_comment_under_question' + ), url(#post only - r'^answer/convert/$', - views.writers.answer_to_comment, - name='answer_to_comment' + '^answer/repost-as-comment-under-previous-answer/$', + views.writers.repost_answer_as_comment, + kwargs={'destination': 'comment_under_previous_answer'}, + name='repost_answer_as_comment_under_previous_answer' ), url(#post only r'^answer/publish/$', diff --git a/askbot/views/readers.py b/askbot/views/readers.py index 7fbcf6d0..51a4da8e 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -598,6 +598,7 @@ def question(request, id):#refactor - long subroutine. display question body, an 'user_post_id_list': user_post_id_list, 'user_can_post_comment': user_can_post_comment,#in general 'user_already_gave_answer': user_already_gave_answer, + 'oldest_answer_id': thread.get_oldest_answer_id(request.user), 'previous_answer': previous_answer, 'tab_id' : answer_sort_method, 'favorited' : favorited, diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 74c96235..d767fe77 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -812,22 +812,43 @@ def comment_to_answer(request): @decorators.admins_only @decorators.post_only -def answer_to_comment(request): +#todo: change the urls config for this +def repost_answer_as_comment(request, destination=None): + assert( + destination in ( + 'comment_under_question', + 'comment_under_previous_answer' + ) + ) answer_id = request.POST.get('answer_id') if answer_id: answer_id = int(answer_id) answer = get_object_or_404(models.Post, post_type = 'answer', id=answer_id) + + if destination == 'comment_under_question': + destination_post = answer.thread._question_post() + else: + #comment_under_previous_answer + destination_post = answer.get_previous_answer(user=request.user) + #todo: implement for comment under other answer + + if destination_post is None: + message = _('Error - could not find the destination post') + request.user.message_set.create(message=message) + return HttpResponseRedirect(answer.get_absolute_url()) + if len(answer.text) <= askbot_settings.MAX_COMMENT_LENGTH: answer.post_type = 'comment' - answer.parent = answer.thread._question_post() + answer.parent = destination_post #can we trust this? old_comment_count = answer.comment_count answer.comment_count = 0 answer_comments = models.Post.objects.get_comments().filter(parent=answer) - answer_comments.update(parent=answer.parent) + answer_comments.update(parent=destination_post) + #why this and not just "save"? answer.parse_and_save(author=answer.author) answer.thread.update_answer_count() |