summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-11 21:29:01 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-11 21:29:01 -0400
commit5c915affaef87bdef508c0f3ff2b3a128d138844 (patch)
treea976eeb5a3836863a0567b90accefe61c9b7514c
parente50335853baf3238d600b0a04a5261510231474c (diff)
downloadaskbot-5c915affaef87bdef508c0f3ff2b3a128d138844.tar.gz
askbot-5c915affaef87bdef508c0f3ff2b3a128d138844.tar.bz2
askbot-5c915affaef87bdef508c0f3ff2b3a128d138844.zip
three-column tag category editor works
-rw-r--r--askbot/skins/common/media/js/post.js134
-rw-r--r--askbot/skins/common/media/js/utils.js8
-rw-r--r--askbot/skins/default/templates/meta/category_tree_js.html3
-rw-r--r--askbot/urls.py10
-rw-r--r--askbot/utils/category_tree.py26
-rw-r--r--askbot/views/commands.py33
6 files changed, 200 insertions, 14 deletions
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
index aa9795e6..fd2f5388 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -2732,6 +2732,7 @@ TagEditor.prototype.decorate = function(element) {
var Category = function() {
SelectBoxItem.call(this);
this._state = 'display';
+ this._settings = JSON.parse(askbot['settings']['tag_editor']);
};
inherits(Category, SelectBoxItem);
@@ -2739,6 +2740,14 @@ Category.prototype.getName = function() {
return this.getContent().getContent();
};
+Category.prototype.setCategoryTreeObject = function(tree) {
+ this._tree = tree;
+};
+
+Category.prototype.getCategoryTreeObject = function() {
+ return this._tree;
+};
+
Category.prototype.setState = function(state) {
this._state = state;
if ( !this._element ) {
@@ -2750,10 +2759,13 @@ Category.prototype.setState = function(state) {
this.hideEditor();
this.hideEditControls();
} else if (state === 'editable') {
+ this._tree._state = 'editable';//a hack
this.showContent();
this.hideEditor();
this.showEditControls();
} else if (state === 'edit') {
+ this._prev_tree_state = this._tree.getState();
+ this._tree._state = 'editing';//a hack
this._input_box.val(this.getName());
this.hideContent();
this.showEditor();
@@ -2802,14 +2814,68 @@ Category.prototype.hideEditor = function() {
this._cancel_button.hide();
};
+Category.prototype.getInput = function() {
+ return this._input_box.val();
+};
+
Category.prototype.getDeleteHandler = function() {
- return function(){ return false; }
+ var me = this;
+ return function() {
+ if (confirm(gettext('Delete category?'))) {
+ var tree = me.getCategoryTreeObject();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: {tag_name: me.getName()},
+ cache: false,
+ url: askbot['urls']['delete_tag'],
+ success: function(data) {
+ if (data['success']) {
+ //rebuild category tree based on data
+ tree.setData(data['tree_data']);
+ //re-open current branch
+ tree.selectPath(tree.getCurrentPath());
+ tree.setState('edit');
+ } else {
+ alert(data['message']);
+ }
+ }
+ });
+ }
+ return false;
+ };
};
Category.prototype.getSaveHandler = function() {
var me = this;
+ var settings = this._settings;
//here we need old value and new value
return function(){
+ var new_name = me.getInput();
+ try {
+ new_name = cleanTag(new_name, settings);
+ var data = {
+ old_name: me.getOriginalName(),
+ new_name: new_name
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: data,
+ cache: false,
+ url: askbot['urls']['rename_tag'],
+ success: function(data) {
+ if (data['success']) {
+ me.setName(new_name);
+ me.setState('editable');
+ } else {
+ alert(data['message']);
+ }
+ }
+ });
+ } catch (error) {
+ alert(error);
+ }
return false;
};
};
@@ -2854,16 +2920,22 @@ Category.prototype.addControls = function() {
this._element.append(delete_button);
};
+Category.prototype.getOriginalName = function() {
+ return this._original_name;
+};
+
Category.prototype.createDom = function() {
Category.superClass_.createDom.call(this);
this.addControls();
this.setState('display');
+ this._original_name = this.getName();
};
Category.prototype.decorate = function(element) {
Category.superClass_.decorate.call(this, element);
this.addControls();
this.setState('display');
+ this._original_name = this.getName();
};
var CategoryAdder = function() {
@@ -2959,7 +3031,8 @@ CategoryAdder.prototype.startAdding = function() {
//rebuild category tree based on data
tree.setData(data['tree_data']);
//re-open current branch
- tree.openPath(current_path);
+ tree.selectCategory(name);
+ tree.setState('edit');
me.setState('wait');
} else {
alert(data['message']);
@@ -3029,6 +3102,14 @@ var CategorySelectBox = function() {
};
inherits(CategorySelectBox, SelectBox);
+CategorySelectBox.prototype.addItem = function(id, name, description) {
+ var item = CategorySelectBox.superClass_.addItem.call(
+ this, id, name, description
+ );
+ item.setCategoryTreeObject(this._tree);
+ return item;
+};
+
CategorySelectBox.prototype.setState = function(state) {
this._state = state;
if (state === 'select') {
@@ -3123,6 +3204,9 @@ inherits(CategorySelector, Widget);
*/
CategorySelector.prototype.setState = function(state) {
this._state = state;
+ if (state === 'editing') {
+ return;//do not propagate this state
+ }
$.each(this._selectors, function(idx, selector){
selector.setState(state);
});
@@ -3142,21 +3226,34 @@ CategorySelector.prototype.clearCategoryLevels = function(level) {
}
};
-CategorySelector.prototype.hasCategory = function(category) {
- function inData(category, data) {
+CategorySelector.prototype.getPathToCategory = function(name) {
+ function getPath(name, data, path) {
for (var i = 0; i < data.length; i++) {
+ //calc path for new item
+ var item_path = path.slice();
+ item_path.push(i);
//check name of the current node
- if (data[i][0] === category) {
- return true;
+ if (data[i][0] === name) {
+ return item_path
}
//check in the subtree
- if (inData(category, data[i][1])) {
- return true;
+ var deep_path = getPath(name, data[i][1], item_path);
+ if (deep_path.length > item_path.length) {
+ return deep_path;
}
}
- return false;
+ return path;
+ }
+ var path = getPath(name, this._data[0][1], [0]);
+ if (path.length === 1) {
+ return undefined;
+ } else {
+ return path;
}
- return inData(category, this._data[0][1]);
+};
+
+CategorySelector.prototype.hasCategory = function(category) {
+ return this.getPathToCategory(category) !== undefined;
};
CategorySelector.prototype.getLeafItems = function(selection_path) {
@@ -3173,7 +3270,7 @@ CategorySelector.prototype.getLeafItems = function(selection_path) {
*/
CategorySelector.prototype.populateCategoryLevel = function(source_path) {
var level = source_path.length - 1;
- if (level > 3) {
+ if (level >= 3) {
return;
}
//clear all items downstream
@@ -3196,10 +3293,20 @@ CategorySelector.prototype.populateCategoryLevel = function(source_path) {
selector.clearSelection();
};
-CategorySelector.prototype.openPath = function(path) {
+CategorySelector.prototype.selectPath = function(path) {
for (var i = 1; i <= path.length; i++) {
this.populateCategoryLevel(path.slice(0, i));
}
+ for (var i = 1; i < path.length; i++) {
+ var sel_box = this._selectors[i-1];
+ var category = sel_box.getItemByIndex(path[i]);
+ sel_box.selectItem(category);
+ }
+};
+
+CategorySelector.prototype.selectCategory = function(name) {
+ var path = this.getPathToCategory(name);
+ this.selectPath(path);
};
CategorySelector.prototype.getSelectedPath = function(selected_level) {
@@ -3243,6 +3350,9 @@ CategorySelector.prototype.getEditorToggle = function() {
CategorySelector.prototype.getSelectHandler = function(level) {
var me = this;
return function(item_data) {
+ if (me.getState() === 'editing') {
+ return;//don't navigate when editing
+ }
//1) run the assigned select handler
var tag_name = item_data['title']
if (me.getState() === 'select') {
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
index 63f0027f..5d89f6ac 100644
--- a/askbot/skins/common/media/js/utils.js
+++ b/askbot/skins/common/media/js/utils.js
@@ -449,10 +449,9 @@ var SimpleContent = function(){
inherits(SimpleContent, WrappedElement);
SimpleContent.prototype.setContent = function(text) {
- //todo: for text we should use .html() for text nodes .append()
this._content = text;
if (this._element) {
- this._element.append(text);
+ this._element.html(text);
}
};
@@ -1024,6 +1023,10 @@ SelectBox.prototype.getItem = function(id){
}
return undefined;
};
+
+SelectBox.prototype.getItemByIndex = function(idx) {
+ return this._items[idx];
+};
/**
* this method sets css class to the item's DOM element
*/
@@ -1080,6 +1083,7 @@ SelectBox.prototype.addItem = function(id, name, description){
item.getElement(),
me.getSelectHandler(item)
);
+ return item;
};
SelectBox.prototype.getSelectedItem = function() {
diff --git a/askbot/skins/default/templates/meta/category_tree_js.html b/askbot/skins/default/templates/meta/category_tree_js.html
index 1a0af93a..2d176d0e 100644
--- a/askbot/skins/default/templates/meta/category_tree_js.html
+++ b/askbot/skins/default/templates/meta/category_tree_js.html
@@ -6,6 +6,7 @@
var selector = new CategorySelector();
selector.setData(JSON.parse("{{category_tree_data|escapejs}}"));
selector.decorate(sel_elems);
+ selector.setState('select');
var tag_editor = new TagEditor();
tag_editor.decorate($('.tag-editor'));
@@ -20,4 +21,6 @@
};
askbot['functions']['initCategoryTree']();
askbot['urls']['add_tag_category'] = '{% url add_tag_category %}';
+ askbot['urls']['rename_tag'] = '{% url rename_tag %}';
+ askbot['urls']['delete_tag'] = '{% url delete_tag %}';
</script>
diff --git a/askbot/urls.py b/askbot/urls.py
index 1250a685..524845a2 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -215,6 +215,16 @@ urlpatterns = patterns('',
name = 'add_tag_category'
),
url(#ajax only
+ r'^rename-tag/',
+ views.commands.rename_tag,
+ name = 'rename_tag'
+ ),
+ url(#
+ r'^delete-tag/',
+ views.commands.delete_tag,
+ name = 'delete_tag'
+ ),
+ url(#ajax only
r'^save-group-logo-url/',
views.commands.save_group_logo_url,
name = 'save_group_logo_url'
diff --git a/askbot/utils/category_tree.py b/askbot/utils/category_tree.py
index fb5e622f..fc8138e2 100644
--- a/askbot/utils/category_tree.py
+++ b/askbot/utils/category_tree.py
@@ -85,6 +85,32 @@ def has_category(tree, category_name):
#skip the dummy
return _has_category(tree[0][1], category_name)
+def _rename_category(tree, from_name, to_name):
+ for item in tree:
+ if item[0] == from_name:
+ item[0] = to_name
+ return True
+ if _rename_category(item[1], from_name, to_name):
+ return True
+ return False
+
+def rename_category(tree, from_name, to_name):
+ _rename_category(tree[0][1], from_name, to_name)
+ return sort_tree(tree)
+
+def _delete_category(tree, name):
+ for item in tree:
+ if item[0] == name:
+ tree.remove(item)
+ return True
+ if _delete_category(item[1], name):
+ return True
+ return False
+
+def delete_category(tree, name):
+ _delete_category(tree[0][1], name)
+ return sort_tree(tree)
+
def save_data(tree):
assert(askbot_settings.TAG_SOURCE == 'category-tree')
tree = sort_tree(tree)
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index a0af45de..e2a94b73 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -7,6 +7,7 @@ is not always very clean.
"""
from django.conf import settings as django_settings
from django.core import exceptions
+#from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseBadRequest
@@ -532,6 +533,38 @@ def save_tag_wiki_text(request):
@csrf.csrf_exempt
@decorators.ajax_only
@decorators.post_only
+def rename_tag(request):
+ if request.user.is_anonymous() \
+ or not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied()
+ new_name = forms.clean_tag(request.POST['new_name'])
+ old_name = forms.clean_tag(request.POST['old_name'])
+
+ #kwargs = {'from': old_name, 'to': new_name}
+ #call_command('rename_tags', **kwargs)
+
+ tree = category_tree.get_data()
+ category_tree.rename_category(tree, old_name, new_name)
+ category_tree.save_data(tree)
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def delete_tag(request):
+ """todo: actually delete tags
+ now it is only deletion of category from the tree"""
+ if request.user.is_anonymous() \
+ or not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied()
+ tag_name = forms.clean_tag(request.POST['tag_name'])
+ tree = category_tree.get_data()
+ category_tree.delete_category(tree, tag_name)
+ category_tree.save_data(tree)
+ return {'tree_data': tree}
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
def add_tag_category(request):
"""adds a category at the tip of a given path expects
the following keys in the ``request.POST``