summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-01 09:03:45 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-01 09:03:45 -0400
commit57b8ead6235ddf6f3f77f5850237cb6b09af6fb3 (patch)
tree1baf797b6b41c74d39c9c385695dcf7fdd3a3b50
parent8692bb43f914447632d70b5eee1fff370d49821c (diff)
downloadaskbot-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.js190
-rw-r--r--askbot/skins/default/media/style/style.less9
-rw-r--r--askbot/skins/default/templates/ask.html17
-rw-r--r--askbot/skins/default/templates/meta/category_tree_js.html24
-rw-r--r--askbot/skins/default/templates/question.html3
-rw-r--r--askbot/skins/default/templates/question/javascript.html2
-rw-r--r--askbot/skins/default/templates/question_edit.html18
-rw-r--r--askbot/skins/default/templates/widgets/ask_form.html2
-rw-r--r--askbot/skins/default/templates/widgets/tag_category_selector.html3
-rw-r--r--askbot/urls.py5
-rw-r--r--askbot/utils/category_tree.py35
-rw-r--r--askbot/views/commands.py13
-rw-r--r--askbot/views/readers.py2
-rw-r--r--askbot/views/writers.py42
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)