diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-11 21:29:01 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-11 21:29:01 -0400 |
commit | 5c915affaef87bdef508c0f3ff2b3a128d138844 (patch) | |
tree | a976eeb5a3836863a0567b90accefe61c9b7514c | |
parent | e50335853baf3238d600b0a04a5261510231474c (diff) | |
download | askbot-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.js | 134 | ||||
-rw-r--r-- | askbot/skins/common/media/js/utils.js | 8 | ||||
-rw-r--r-- | askbot/skins/default/templates/meta/category_tree_js.html | 3 | ||||
-rw-r--r-- | askbot/urls.py | 10 | ||||
-rw-r--r-- | askbot/utils/category_tree.py | 26 | ||||
-rw-r--r-- | askbot/views/commands.py | 33 |
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`` |