From a8dd0f645539759187ba3e271078da4b6dcd3ba3 Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Sat, 30 Oct 2010 02:42:45 -0400 Subject: improved retagging --- askbot/skins/default/media/js/com.cnprog.post.js | 238 ++++++++++++++++++++++- askbot/skins/default/media/style/style.css | 27 ++- askbot/skins/default/templates/question.html | 52 +++-- askbot/views/readers.py | 2 + askbot/views/writers.py | 27 ++- 5 files changed, 318 insertions(+), 28 deletions(-) diff --git a/askbot/skins/default/media/js/com.cnprog.post.js b/askbot/skins/default/media/js/com.cnprog.post.js index 477d4357..8273d6da 100644 --- a/askbot/skins/default/media/js/com.cnprog.post.js +++ b/askbot/skins/default/media/js/com.cnprog.post.js @@ -491,6 +491,240 @@ var Vote = function(){ }; } (); +var questionRetagger = function(){ + + var oldTagsHTML = ''; + var tagInput = null; + var tagsDiv = null; + var retagLink = null; + + var restoreEventHandlers = function(){ + $(document).unbind('click'); + }; + + var cancelRetag = function(){ + tagInput.unautocomplete();//removes dropdown if open + tagsDiv.html(oldTagsHTML); + tagsDiv.removeClass('post-retag'); + tagsDiv.addClass('post-tags'); + restoreEventHandlers(); + initRetagger(); + }; + + var render_tag = function(tag_name){ + //copy-paste from live search!!! + var url = scriptUrl + + $.i18n._('questions/') + + '?tags=' + encodeURI(tag_name); + var tag_title = $.i18n._( + "see questions tagged '{tag}'" + ).replace( + '{tag}', + tag_name + ); + return ''; + }; + + var drawNewTags = function(new_tags){ + new_tags = new_tags.split(/\s+/); + var tags_html = '' + $.each(new_tags, function(index, name){ + if (index === 0){ + tags_html = render_tag(name); + } + else { + tags_html += ' ' + render_tag(name); + } + }); + tagsDiv.html(tags_html); + }; + + var doRetag = function(){ + $.ajax({ + type: "POST", + url: retagUrl, + dataType: "json", + data: { tags: getUniqueTags().join(' ') }, + success: function(json) { + if (json['success'] === true){ + new_tags = getUniqueTags(); + oldTagsHtml = ''; + cancelRetag(); + drawNewTags(new_tags.join(' ')); + } + else { + cancelRetag(); + showMessage(tagsDiv, json['message']); + } + }, + error: function(xhr, textStatus, errorThrown) { + showMessage(tagsDiv, 'sorry, somethin is not right here'); + cancelRetag(); + } + }); + return false; + } + + var setupInputEventHandlers = function(input){ + input.keydown(function(e){ + if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)){ + cancelRetag(); + } + }); + $(document).unbind('click').click(cancelRetag, false); + input.click(function(){return false}); + }; + + var setupButtonEventHandlers = function(button){ + button.keydown(function(e){ + if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ + doRetag(); + return false; + } + }); + button.click(doRetag); + }; + + var getUniqueTags = function(){ + return $.unique($.trim(tagInput.val()).split(/\s+/)); + }; + + //todo pull from django + var validateTagLength = function(){ + var tags = getUniqueTags(); + var are_tags_ok = true; + $.each(tags, function(index, value){ + if (value.length > askbot['settings']['maxTagLength']){ + are_tags_ok = false; + } + }); + return are_tags_ok; + }; + + var validateTagCount = function(){ + var tags = getUniqueTags(); + return (tags.length <= askbot['settings']['maxTagsPerPost']); + }; + + var createRetagForm = function(old_tags_string){ + var div = $('
'); + tagInput = $(''); + //var tagLabel = $(''); + tagInput.val(old_tags_string); + //populate input + //todo: make autocomplete work + tagInput.autocomplete(tags_autocomplete, { + minChars: 1, + matchContains: true, + selectFirst: false, + max: 20, + multiple: true, + multipleSeparator: " ", + formatItem: function(row, i, max) { + return row.n + " ("+ row.c +")"; + }, + formatResult: function(row, i, max){ + return row.n; + } + }); + + div.append(tagInput); + //div.append(tagLabel); + setupInputEventHandlers(tagInput); + + //button = $(''); + //button.val($.i18n._('save tags')); + //div.append(button); + //setupButtonEventHandlers(button); + + $.validator.addMethod('limit_tag_count', validateTagCount); + $.validator.addMethod('limit_tag_length', validateTagLength); + div.validate({//copy-paste from utils.js + rules: { + tags: { + required: true, + maxlength: askbot['settings']['maxTagsPerPost'] * askbot['settings']['maxTagLength'], + limit_tag_count: true, + limit_tag_length: true, + } + }, + messages: { + tags: { + required: $.i18n._('tags cannot be empty'), + maxlength: askbot['messages']['tagLimits'], + limit_tag_count: askbot['messages']['maxTagsPerPost'], + limit_tag_length: askbot['messages']['maxTagLength'] + } + }, + submitHandler: doRetag, + errorClass: "retag-error", + }); + + return div; + }; + + var getTagsAsString = function(tags_div){ + var links = tags_div.find('a'); + var tags_str = ''; + links.each(function(index, element){ + if (index === 0){ + tags_str = $(element).html(); + } + else { + tags_str += ' ' + $(element).html(); + } + }); + return tags_str; + }; + + var noopHandler = function(){ + tagInput.focus(); + return false; + }; + + var deactivateRetagLink = function(){ + retagLink.unbind('click').click(noopHandler); + retagLink.unbind('keypress').keypress(noopHandler); + }; + + var startRetag = function(){ + tagsDiv = $('#question-tags'); + oldTagsHTML = tagsDiv.html();//save to restore on cancel + var old_tags_string = getTagsAsString(tagsDiv); + var retag_form = createRetagForm(old_tags_string); + tagsDiv.html(''); + tagsDiv.append(retag_form); + tagsDiv.removeClass('post-tags'); + tagsDiv.addClass('post-retag'); + tagInput.focus(); + deactivateRetagLink(); + return false; + }; + + var setupClickAndEnterHandler = function(element, callback){ + element.unbind('click').click(callback); + element.unbind('keypress').keypress(function(e){ + if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ + callback(); + } + }); + } + + var initRetagger = function(){ + setupClickAndEnterHandler(retagLink, startRetag); + }; + + return { + init: function(){ + retagLink = $('#retag'); + initRetagger(); + } + }; +}(); + var questionComments = createComments('question'); var answerComments = createComments('answer'); var commentsFactory = {'question' : questionComments, 'answer' : answerComments}; @@ -533,7 +767,8 @@ function createComments(type) { setupFormValidation("#" + formId, { comment: { required: true, minlength: 10} }, '', - function() { postComment(id, formId); }); + function() { postComment(id, formId); }) + ; } } else { @@ -741,6 +976,7 @@ function createComments(type) { $(document).ready(function() { questionComments.init(); + questionRetagger.init(); answerComments.init(); }); diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css index 19ca902a..7fc52e37 100755 --- a/askbot/skins/default/media/style/style.css +++ b/askbot/skins/default/media/style/style.css @@ -1281,19 +1281,21 @@ a:hover.medal { color: #fff; } -.action-link a { +.post-controls a { color: #777; padding: 3px; cursor: pointer; + border: none; + background: none; + text-decoration: none; } -.action-link: a hover { +.post-controls a:hover { background-color: #777; - text-decoration: none; color: #fff; } -.action-link-separator { +.post-controls .sep { color: #ccc; } @@ -1544,6 +1546,12 @@ table.ab-tag-filter-form { font-size: 10px; } +label.retag-error { + color: darkred; + padding-left: 5px; + font-size: 10px; +} + .error-list li { padding: 5px; } @@ -2516,7 +2524,8 @@ ul.form-horizontal-rows li input { font-weight: bold; } -.post-controls { +.post-controls, .post-tags { + clear: left; float: left; font-size: 11px; line-height: 12px; @@ -2524,6 +2533,14 @@ ul.form-horizontal-rows li input { margin-bottom: 5px; } +.post-tags { + margin-bottom:8px; +} + +.post-retag { + margin-bottom:0px; +} + #question-controls .tags { margin: 0 0 3px 0; } diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index f1b80812..fdb573b6 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -129,32 +129,31 @@
{{question.html}}
+
+ {% for tag in question.get_tag_names() %} + + {% endfor %} +
- {#todo: here we have important case to reset search state #} -
- {% for tag in question.get_tag_names() %} - - {% endfor %} -
- {% set pipe=joiner('|') %} + {% set pipe=joiner('|') %} {% if request.user|can_edit_post(question) %}{{ pipe() }} - - {% trans %}edit{% endtrans %} - - {% elif request.user|can_retag_question(question) %} - - {% trans %}retag{% endtrans %} - + {% trans %}edit{% endtrans %} + {% endif %} + {% if request.user|can_retag_question(question) %}{{ pipe() }} + {% trans %}retag{% endtrans %} + {% endif %} {% if question.closed %} {% if request.user|can_reopen_question(question) %}{{ pipe() }} - {% trans %}reopen{% endtrans %} + {% trans %}reopen{% endtrans %} {% endif %} {% else %} {% if request.user|can_close_question(question) %}{{ pipe() }} - {% trans %}close{% endtrans %} + {% trans %}close{% endtrans %} {% endif %} {% endif %} {% if request.user|can_flag_offensive(question) %}{{ pipe() }} @@ -167,8 +166,9 @@ {% endif %} {% if request.user|can_delete_post(question) %}{{ pipe() }} - {% trans %}delete{% endtrans %} + {% trans %}delete{% endtrans %} {% endif %} +
{{ @@ -455,5 +455,19 @@ {% endif %} {% endblock %} {% block endjs %} + {% if request.user|can_retag_question(question) %} + + {% endif %} {% endblock %} diff --git a/askbot/views/readers.py b/askbot/views/readers.py index fb22240c..25425659 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -524,6 +524,8 @@ def question(request, id):#refactor - long subroutine. display question body, an 'language_code': translation.get_language(), 'paginator_context' : paginator_context } + if request.user.is_authenticated(): + data['tags_autocomplete'] = _get_tags_cache_json() context = RequestContext(request, data) template = ENV.get_template('question.html') return HttpResponse(template.render(context)) diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 22407b67..aca11b63 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -198,9 +198,22 @@ def retag_question(request, id): question = question, tags = form.cleaned_data['tags'] ) - return HttpResponseRedirect(question.get_absolute_url()) + if request.is_ajax(): + response_data = {'success': True} + data = simplejson.dumps(response_data) + return HttpResponse(data, mimetype="application/json") + else: + return HttpResponseRedirect(question.get_absolute_url()) + elif request.is_ajax(): + response_data = { + 'message': unicode(form.errors['tags']), + 'success': False + } + data = simplejson.dumps(response_data) + return HttpResponse(data, mimetype="application/json") else: form = forms.RetagQuestionForm(question) + data = { 'active_tab': 'questions', 'question': question, @@ -211,8 +224,16 @@ def retag_question(request, id): template = ENV.get_template('question_retag.html') return HttpResponse(template.render(context)) except exceptions.PermissionDenied, e: - request.user.message_set.create(message = unicode(e)) - return HttpResponseRedirect(question.get_absolute_url()) + if request.is_ajax(): + response_data = { + 'message': unicode(e), + 'success': False + } + data = simplejson.dumps(response_data) + return HttpResponse(data, mimetype="application/json") + else: + request.user.message_set.create(message = unicode(e)) + return HttpResponseRedirect(question.get_absolute_url()) @login_required def edit_question(request, id): -- cgit v1.2.3-1-g7c22