diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-01 09:03:45 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-01 09:03:45 -0400 |
commit | 57b8ead6235ddf6f3f77f5850237cb6b09af6fb3 (patch) | |
tree | 1baf797b6b41c74d39c9c385695dcf7fdd3a3b50 | |
parent | 8692bb43f914447632d70b5eee1fff370d49821c (diff) | |
download | askbot-57b8ead6235ddf6f3f77f5850237cb6b09af6fb3.tar.gz askbot-57b8ead6235ddf6f3f77f5850237cb6b09af6fb3.tar.bz2 askbot-57b8ead6235ddf6f3f77f5850237cb6b09af6fb3.zip |
added inline category-based retagger to the question page
-rw-r--r-- | askbot/skins/common/media/js/post.js | 190 | ||||
-rw-r--r-- | askbot/skins/default/media/style/style.less | 9 | ||||
-rw-r--r-- | askbot/skins/default/templates/ask.html | 17 | ||||
-rw-r--r-- | askbot/skins/default/templates/meta/category_tree_js.html | 24 | ||||
-rw-r--r-- | askbot/skins/default/templates/question.html | 3 | ||||
-rw-r--r-- | askbot/skins/default/templates/question/javascript.html | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/question_edit.html | 18 | ||||
-rw-r--r-- | askbot/skins/default/templates/widgets/ask_form.html | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/widgets/tag_category_selector.html | 3 | ||||
-rw-r--r-- | askbot/urls.py | 5 | ||||
-rw-r--r-- | askbot/utils/category_tree.py | 35 | ||||
-rw-r--r-- | askbot/views/commands.py | 13 | ||||
-rw-r--r-- | askbot/views/readers.py | 2 | ||||
-rw-r--r-- | askbot/views/writers.py | 42 |
14 files changed, 291 insertions, 74 deletions
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js index 6e154465..918f9856 100644 --- a/askbot/skins/common/media/js/post.js +++ b/askbot/skins/common/media/js/post.js @@ -976,7 +976,7 @@ var questionRetagger = function(){ var doRetag = function(){ $.ajax({ type: "POST", - url: retagUrl, + url: retagUrl,//todo add this url to askbot['urls'] dataType: "json", data: { tags: getUniqueWords(tagInput.val()).join(' ') }, success: function(json) { @@ -992,7 +992,7 @@ var questionRetagger = function(){ } }, error: function(xhr, textStatus, errorThrown) { - showMessage(tagsDiv, 'sorry, somethin is not right here'); + showMessage(tagsDiv, 'sorry, something is not right here'); cancelRetag(); } }); @@ -2696,6 +2696,185 @@ CategorySelector.prototype.decorate = function(element) { this.populateCategoryLevel([0]); }; +/** + * @constructor + * loads html for the category selector from + * the server via ajax and activates the + * CategorySelector on the loaded HTML + */ +var CategorySelectorLoader = function() { + WrappedElement.call(this); + this._is_loaded = false; +}; +inherits(CategorySelectorLoader, WrappedElement); + +CategorySelectorLoader.prototype.setLoaded = function(is_loaded) { + this._is_loaded = is_loaded; +}; + +CategorySelectorLoader.prototype.isLoaded = function() { + return this._is_loaded; +}; + +CategorySelectorLoader.prototype.setEditor = function(editor) { + this._editor = editor; +}; + +CategorySelectorLoader.prototype.closeEditor = function() { + this._editor.hide(); + this._editor_buttons.hide(); + this._display_tags_container.show(); + this._question_body.show(); + this._question_controls.show(); +}; + +CategorySelectorLoader.prototype.openEditor = function() { + this._editor.show(); + this._editor_buttons.show(); + this._display_tags_container.hide(); + this._question_body.hide(); + this._question_controls.hide(); +}; + +CategorySelectorLoader.prototype.addEditorButtons = function() { + this._editor.after(this._editor_buttons); +}; + +CategorySelectorLoader.prototype.getOnLoadHandler = function() { + var me = this; + return function(html){ + me.setLoaded(true); + + //append loaded html to dom + var editor = $('<div>' + html + '</div>'); + me.setEditor(editor); + $('#question-tags').after(editor); + + askbot['functions']['initCategoryTree'](); + + me.addEditorButtons(); + me.openEditor(); + //add the save button + }; +}; + +CategorySelectorLoader.prototype.startLoadingHTML = function(on_load) { + var me = this; + $.ajax({ + type: 'GET', + dataType: 'json', + data: { template_name: 'widgets/tag_category_selector.html' }, + url: askbot['urls']['get_html_template'], + cache: true, + success: function(data) { + if (data['success']) { + on_load(data['html']); + } else { + showMessage(me.getElement(), data['message']); + } + } + }); +}; + +CategorySelectorLoader.prototype.getRetagHandler = function() { + var me = this; + return function() { + if (me.isLoaded() === false) { + me.startLoadingHTML(me.getOnLoadHandler()); + } else { + me.openEditor(); + } + return false; + } +}; + +CategorySelectorLoader.prototype.drawNewTags = function(new_tags) { + if (new_tags === ''){ + this._display_tags_container.html(''); + return; + } + new_tags = new_tags.split(/\s+/); + var tags_html = '' + $.each(new_tags, function(index, name){ + var tag = new Tag(); + tag.setName(name); + tags_html += tag.getElement().outerHTML(); + }); + this._display_tags_container.html(tags_html); +}; + +CategorySelectorLoader.prototype.getSaveHandler = function() { + var me = this; + return function() { + var tagInput = $('input[name="tags"]'); + $.ajax({ + type: "POST", + url: retagUrl,//add to askbot['urls'] + dataType: "json", + data: { tags: getUniqueWords(tagInput.val()).join(' ') }, + success: function(json) { + if (json['success'] === true){ + var new_tags = getUniqueWords(json['new_tags']); + oldTagsHtml = ''; + me.closeEditor(); + me.drawNewTags(new_tags.join(' ')); + } + else { + me.closeEditor(); + showMessage(me.getElement(), json['message']); + } + }, + error: function(xhr, textStatus, errorThrown) { + showMessage(tagsDiv, 'sorry, something is not right here'); + cancelRetag(); + } + }); + return false; + }; +}; + +CategorySelectorLoader.prototype.getCancelHandler = function() { + var me = this; + return function() { + me.closeEditor(); + }; +}; + +CategorySelectorLoader.prototype.decorate = function(element) { + this._element = element; + this._display_tags_container = $('#question-tags'); + this._question_body = $('.question-body'); + this._question_controls = $('#question-controls'); + + this._editor_buttons = this.makeElement('div'); + this._done_button = this.makeElement('button'); + this._done_button.html(gettext('save tags')); + this._editor_buttons.append(this._done_button); + + this._cancel_button = this.makeElement('button'); + this._cancel_button.html(gettext('cancel')); + this._editor_buttons.append(this._cancel_button); + this._editor_buttons.find('button').addClass('submit'); + this._editor_buttons.addClass('retagger-buttons'); + + //done button + setupButtonEventHandlers( + this._done_button, + this.getSaveHandler() + ); + //cancel button + setupButtonEventHandlers( + this._cancel_button, + this.getCancelHandler() + ); + + //retag button + setupButtonEventHandlers( + element, + this.getRetagHandler() + ); +}; + $(document).ready(function() { $('[id^="comments-for-"]').each(function(index, element){ var comments = new PostCommentsWidget(); @@ -2712,7 +2891,12 @@ $(document).ready(function() { deleter.setPostId(post_id); deleter.decorate($(element).find('.question-delete')); }); - questionRetagger.init(); + if (askbot['settings']['tagSource'] == 'category-tree') { + var catSelectorLoader = new CategorySelectorLoader(); + catSelectorLoader.decorate($('#retag')); + } else { + questionRetagger.init(); + } socialSharing.init(); }); diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index b0988155..193d072c 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -1393,6 +1393,11 @@ ul#related-tags li { width: 710px; padding: 6px; } + .retagger-buttons { + button { + margin: 8px 10px 5px 0; + } + } } #editor { /* adjustment for editor preview */ @@ -3521,6 +3526,10 @@ textarea.tipped-input { } } +.question-page .category-selector ul.select-box { + width: 217px; +} + /* tag editor */ .tag-editor { height: 64px; diff --git a/askbot/skins/default/templates/ask.html b/askbot/skins/default/templates/ask.html index cc6a4e49..f5a5ccff 100644 --- a/askbot/skins/default/templates/ask.html +++ b/askbot/skins/default/templates/ask.html @@ -27,21 +27,8 @@ {% if mandatory_tags %} {% include "meta/mandatory_tags_js.html" %} {% endif %} - {% if use_category_selector %} - <script type='text/javascript'> - (function(){ - var selector = new CategorySelector(); - selector.setData(JSON.parse("{{category_tree_data|escapejs}}")); - if (askbot['data']['userIsAdminOrMod']) { - selector.setEditable(true); - } - selector.decorate($('.category-selector')); - - var tag_editor = new TagEditor(); - tag_editor.decorate($('.tag-editor')); - selector.setSelectHandler(tag_editor.getAddTagHandler()); - })(); - </script> + {% if settings.TAG_SOURCE == 'category-tree' %} + {% include "meta/category_tree_js.html" %} {% endif %} <script type='text/javascript'> askbot['urls']['api_get_questions'] = '{% url api_get_questions %}'; diff --git a/askbot/skins/default/templates/meta/category_tree_js.html b/askbot/skins/default/templates/meta/category_tree_js.html new file mode 100644 index 00000000..e480cc2c --- /dev/null +++ b/askbot/skins/default/templates/meta/category_tree_js.html @@ -0,0 +1,24 @@ +<script type='text/javascript'> + askbot['functions'] = askbot['functions'] || {}; + askbot['functions']['initCategoryTree'] = function(){ + var sel_elems = $('.category-selector'); + if (sel_elems.length > 0) { + var selector = new CategorySelector(); + selector.setData(JSON.parse("{{category_tree_data|escapejs}}")); + if (askbot['data']['userIsAdminOrMod']) { + selector.setEditable(true); + } + selector.decorate(sel_elems); + + var tag_editor = new TagEditor(); + tag_editor.decorate($('.tag-editor')); + {% if page_class == 'question-page' %} + {% for tag_name in question.get_tag_names() %} + tag_editor.addTag('{{ tag_name }}'); + {% endfor %} + {% endif %} + selector.setSelectHandler(tag_editor.getAddTagHandler()); + } + }; + askbot['functions']['initCategoryTree'](); +</script> diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index f22796db..f4f36586 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -169,6 +169,9 @@ {% endblock %} {% block endjs %} {% include "question/javascript.html" %} + {% if settings.TAG_SOURCE == 'category-tree' %} + {% include "meta/category_tree_js.html" %} + {% endif %} {# <script type="text/javascript"> var messages = askbot['messages']; diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html index 3a29579d..1a61e4bd 100644 --- a/askbot/skins/default/templates/question/javascript.html +++ b/askbot/skins/default/templates/question/javascript.html @@ -17,12 +17,14 @@ askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}'; askbot['urls']['upvote_comment'] = '{% url upvote_comment %}'; askbot['urls']['delete_post'] = '{% url delete_post %}'; + askbot['urls']['get_html_template'] = '{% url get_html_template %}'; askbot['messages']['addComment'] = '{% trans %}post a comment{% endtrans %}'; {% if settings.SAVE_COMMENT_ON_ENTER %} askbot['settings']['saveCommentOnEnter'] = true; {% else %} askbot['settings']['saveCommentOnEnter'] = false; {% endif %} + askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}'; </script> <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html index 2f252cde..2576a1f1 100644 --- a/askbot/skins/default/templates/question_edit.html +++ b/askbot/skins/default/templates/question_edit.html @@ -15,6 +15,7 @@ id="select_revision" name="select_revision" value="{% trans %}select revision{% endtrans %}"> </div> + {% set use_category_selector = (settings.TAG_SOURCE == 'category-tree') %} {{ macros.edit_post( form, @@ -96,21 +97,8 @@ }); </script> - {% if use_category_selector %} - <script type='text/javascript'> - (function(){ - var selector = new CategorySelector(); - selector.setData(JSON.parse("{{category_tree_data|escapejs}}")); - if (askbot['data']['userIsAdminOrMod']) { - selector.setEditable(true); - } - selector.decorate($('.category-selector')); - - var tag_editor = new TagEditor(); - tag_editor.decorate($('.tag-editor')); - selector.setSelectHandler(tag_editor.getAddTagHandler()); - })(); - </script> + {% if settings.TAG_SOURCE == 'category-tree' %} + {% include "meta/category_tree_js.html" %} {% endif %} {% endblock %} <!-- end question_edit.html --> diff --git a/askbot/skins/default/templates/widgets/ask_form.html b/askbot/skins/default/templates/widgets/ask_form.html index f031c2cf..94b5e309 100644 --- a/askbot/skins/default/templates/widgets/ask_form.html +++ b/askbot/skins/default/templates/widgets/ask_form.html @@ -27,7 +27,7 @@ post_type = 'question', edit_title = False, mandatory_tags = mandatory_tags, - use_category_selector = use_category_selector + use_category_selector = (settings.TAG_SOURCE == 'category-tree') ) }} <div class="question-options"> diff --git a/askbot/skins/default/templates/widgets/tag_category_selector.html b/askbot/skins/default/templates/widgets/tag_category_selector.html new file mode 100644 index 00000000..9eabb6eb --- /dev/null +++ b/askbot/skins/default/templates/widgets/tag_category_selector.html @@ -0,0 +1,3 @@ +{% include "widgets/three_column_category_selector.html" %} +<div class="tags-desc">{% trans %}Tags{% endtrans %}</div> +{% include "widgets/tag_editor.html" %} diff --git a/askbot/urls.py b/askbot/urls.py index 799cc346..39170660 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -295,6 +295,11 @@ urlpatterns = patterns('', views.meta.badge, name='badge' ), + url( + r'get-html-template/', + views.commands.get_html_template, + name='get_html_template' + ), url(#ajax only r'^%s%s$' % (_('messages/'), _('markread/')), views.commands.read_message, diff --git a/askbot/utils/category_tree.py b/askbot/utils/category_tree.py index d1f0db8f..501b74fa 100644 --- a/askbot/utils/category_tree.py +++ b/askbot/utils/category_tree.py @@ -2,7 +2,32 @@ tree, stored in the settings. The tree is plain text, with levels of branching reflected by indentation (2 spaces per level). +example of desired structure, when input is parsed + + cat_tree = [ + ['dummy', + [ + ['tires', [ + ['michelin', [ + ['trucks', []], + ['cars', []], + ['motorcycles', []] + ] + ], + ['good year', []], + ['honda', []], + ] + ], + ['abandonment', []], + ['chile', []], + ['vulcanization', []], + ] + ] + ] """ +from askbot.conf import settings as askbot_settings +from django.utils import simplejson + def get_subtree(tree, path): if len(path) == 1: assert(path[0] == 0) @@ -51,3 +76,13 @@ def parse_tree(text): subtree.append([line.strip(), []]) return tree + +def get_data(): + """returns category tree data structure encoded as json + or None, if category_tree is disabled + """ + if askbot_settings.TAG_SOURCE == 'category-tree': + cat_tree = parse_tree(askbot_settings.CATEGORY_TREE) + return simplejson.dumps(cat_tree) + else: + return None diff --git a/askbot/views/commands.py b/askbot/views/commands.py index 6c06e77c..a1dc5420 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -470,6 +470,19 @@ def get_tags_by_wildcard(request): re_data = simplejson.dumps({'tag_count': count, 'tag_names': list(names)}) return HttpResponse(re_data, mimetype = 'application/json') +@decorators.ajax_only +def get_html_template(request): + """returns rendered template""" + template_name = request.REQUEST.get('template_name', None) + allowed_templates = ( + 'widgets/tag_category_selector.html', + ) + if template_name not in allowed_templates: + raise Http404 + return { + 'html': get_template(template_name).render() + } + @decorators.get_only def get_tag_list(request): """returns tags to use in the autocomplete diff --git a/askbot/views/readers.py b/askbot/views/readers.py index 8f19a802..ea67a05d 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -32,6 +32,7 @@ from askbot import models from askbot import schedules from askbot.models.tag import Tag from askbot import const +from askbot.utils import category_tree from askbot.utils import functions from askbot.utils.decorators import anonymous_forbidden, ajax_only, get_only from askbot.search.state_manager import SearchState, DummySearchState @@ -539,6 +540,7 @@ def question(request, id):#refactor - long subroutine. display question body, an 'answer' : answer_form, 'answers' : page_objects.object_list, 'answer_count': len(answers), + 'category_tree_data': category_tree.get_data(), 'user_votes': user_votes, 'user_post_id_list': user_post_id_list, 'user_can_post_comment': user_can_post_comment,#in general diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 5741ec45..488d59d9 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -260,36 +260,6 @@ def ask(request):#view used to ask a new question 'wiki': request.REQUEST.get('wiki', False), 'is_anonymous': request.REQUEST.get('is_anonymous', False), } - - if askbot_settings.TAG_SOURCE == 'category-tree': - cat_tree = category_tree.parse_tree(askbot_settings.CATEGORY_TREE) - category_tree_data = simplejson.dumps(cat_tree) - else: - category_tree_data = None - - """ - example of desired structure - cat_tree = [ - ['dummy', - [ - ['tires', [ - ['michelin', [ - ['trucks', []], - ['cars', []], - ['motorcycles', []] - ] - ], - ['good year', []], - ['honda', []], - ] - ], - ['abandonment', []], - ['chile', []], - ['vulcanization', []], - ] - ] - ] - """ data = { 'active_tab': 'ask', @@ -297,8 +267,7 @@ def ask(request):#view used to ask a new question 'form' : form, 'mandatory_tags': models.tag.get_mandatory_tags(), 'email_validation_faq_url':reverse('faq') + '#validate', - 'use_category_selector': (askbot_settings.TAG_SOURCE == 'category-tree'), - 'category_tree_data': category_tree_data, + 'category_tree_data': category_tree.get_data(), 'tag_names': list()#need to keep context in sync with edit_question for tag editor } return render_into_skin('ask.html', data, request) @@ -429,12 +398,6 @@ def edit_question(request, id): user = request.user ) - if askbot_settings.TAG_SOURCE == 'category-tree': - cat_tree = category_tree.parse_tree(askbot_settings.CATEGORY_TREE) - category_tree_data = simplejson.dumps(cat_tree) - else: - category_tree_data = None - data = { 'page_class': 'edit-question-page', 'active_tab': 'questions', @@ -443,8 +406,7 @@ def edit_question(request, id): 'mandatory_tags': models.tag.get_mandatory_tags(), 'form' : form, 'tag_names': question.thread.get_tag_names(), - 'use_category_selector': (askbot_settings.TAG_SOURCE == 'category-tree'), - 'category_tree_data': category_tree_data + 'category_tree_data': category_tree.get_data() } return render_into_skin('question_edit.html', data, request) |