summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-09 16:05:33 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-09 16:05:33 -0400
commit34c01db1df6297c8ef46bb0d667b219774ecd1ea (patch)
tree6dbac228a60cb605dbe272379a149ca29e31933b
parent5f26975cc42b012fba086b69f54fc81219bd3ff7 (diff)
downloadaskbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.tar.gz
askbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.tar.bz2
askbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.zip
added optional tag search box
-rw-r--r--askbot/conf/forum_data_rules.py9
-rw-r--r--askbot/models/question.py27
-rw-r--r--askbot/search/state_manager.py9
-rw-r--r--askbot/skins/common/media/js/live_search.js125
-rw-r--r--askbot/skins/common/media/js/utils.js1
-rw-r--r--askbot/skins/default/media/style/style.less25
-rw-r--r--askbot/skins/default/templates/main_page/sidebar.html4
-rw-r--r--askbot/skins/default/templates/main_page/tag_search.html7
-rw-r--r--askbot/views/readers.py9
9 files changed, 200 insertions, 16 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index 491ebfa8..7d98c9e8 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -201,6 +201,15 @@ settings.register(
)
settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'TAG_SEARCH_INPUT_ENABLED',
+ default = False,
+ description = _('Enable separate tag search box on main page')
+ )
+)
+
+settings.register(
livesettings.IntegerValue(
FORUM_DATA_RULES,
'MAX_COMMENTS_TO_SHOW',
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 597a95ae..7d1c3758 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -190,8 +190,31 @@ class ThreadManager(models.Manager):
qs = qs.filter(posts__post_type='question', posts__author__in=query_users) # TODO: unify with search_state.author ?
tags = search_state.unified_tags()
- for tag in tags:
- qs = qs.filter(tags__name=tag) # Tags or AND-ed here, not OR-ed (i.e. we fetch only threads with all tags)
+ if len(tags) > 0:
+
+ if askbot_settings.TAG_SEARCH_INPUT_ENABLED:
+ #todo: this may be gone or disabled per option
+ #"tag_search_box_enabled"
+ existing_tags = set(
+ Tag.objects.filter(
+ name__in = tags
+ ).values_list(
+ 'name',
+ flat = True
+ )
+ )
+
+ non_existing_tags = set(tags) - existing_tags
+ meta_data['non_existing_tags'] = list(non_existing_tags)
+ tags = existing_tags
+ else:
+ meta_data['non_existing_tags'] = list()
+
+ #construct filter for the tag search
+ for tag in tags:
+ qs = qs.filter(tags__name=tag) # Tags or AND-ed here, not OR-ed (i.e. we fetch only threads with all tags)
+ else:
+ meta_data['non_existing_tags'] = list()
if search_state.scope == 'unanswered':
qs = qs.filter(closed = False) # Do not show closed questions in unanswered section
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index 8096cbdd..f8154865 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -216,9 +216,14 @@ class SearchState(object):
ss.page = 1
return ss
- def remove_tags(self):
+ def remove_tags(self, tags = None):
ss = self.deepcopy()
- ss.tags = []
+ if tags:
+ ss.tags = list(
+ set(ss.tags) - set(tags)
+ )
+ else:
+ ss.tags = []
ss.page = 1
return ss
diff --git a/askbot/skins/common/media/js/live_search.js b/askbot/skins/common/media/js/live_search.js
index 100c3f67..f33862a1 100644
--- a/askbot/skins/common/media/js/live_search.js
+++ b/askbot/skins/common/media/js/live_search.js
@@ -1,3 +1,55 @@
+var TagWarningBox = function(){
+ WrappedElement.call(this);
+ this._tags = [];
+};
+inherits(TagWarningBox, WrappedElement);
+
+TagWarningBox.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ this._element
+ .css('display', 'block')
+ .css('margin', '0 0 13px 2px');
+ this._element.addClass('non-existing-tags');
+ this._warning = this.makeElement('p');
+ this._element.append(this._warning);
+ this._tag_container = this.makeElement('ul');
+ this._tag_container.addClass('tags');
+ this._element.append(this._tag_container);
+ this._element.append($('<div class="clearfix"></div>'));
+ this._element.hide();
+};
+
+TagWarningBox.prototype.clear = function(){
+ this._tags = [];
+ if (this._tag_container){
+ this._tag_container.empty();
+ }
+ this._warning.hide();
+ this._element.hide();
+};
+
+TagWarningBox.prototype.addTag = function(tag_name){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setLinkable(false);
+ tag.setDeletable(false);
+ var elem = this.getElement();
+ this._tag_container.append(tag.getElement());
+ this._tag_container.css('display', 'block');
+ this._tags.push(tag);
+ elem.show();
+};
+
+TagWarningBox.prototype.showWarning = function(){
+ this._warning.html(
+ ngettext(
+ 'Sorry, this tag does not exist',
+ 'Sorry, these tags do not exist',
+ this._tags.length
+ )
+ );
+ this._warning.show();
+};
var liveSearch = function(query_string) {
var query = $('input#keywords');
@@ -7,6 +59,70 @@ var liveSearch = function(query_string) {
var q_list_sel = 'question-list';//id of question listing div
var search_url = askbot['urls']['questions'];
var x_button = $('input[name=reset_query]');
+ var tag_warning_box = new TagWarningBox();
+
+ //the tag search input is optional in askbot
+ $('#ab-tag-search').parent().before(
+ tag_warning_box.getElement()
+ );
+
+ var run_tag_search = function(){
+ var search_tags = $('#ab-tag-search').val().split(/\s+/);
+ if (search_tags.length === 0) {
+ return;
+ }
+ /** @todo: the questions/ might need translation... */
+ query_string = '/questions/scope:all/sort:activity-desc/page:1/'
+ $.each(search_tags, function(idx, tag) {
+ query_string = QSutils.add_search_tag(query_string, search_tags);
+ });
+ var url = search_url + query_string;
+ $.ajax({
+ url: url,
+ dataType: 'json',
+ success: function(data, text_status, xhr){
+ render_result(data, text_status, xhr);
+ $('#ab-tag-search').val('');
+ },
+ });
+ updateHistory(url);
+ };
+
+ var activate_tag_search_input = function(){
+ //the autocomplete is set up in tag_selector.js
+ var button = $('#ab-tag-search-add');
+ if (button.length === 0){//may be absent
+ return;
+ }
+ var ac = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ maxItemsToShow: 20,
+ onItemSelect: run_tag_search,
+ delay: 10
+ });
+ ac.decorate($('#ab-tag-search'));
+ setupButtonEventHandlers(button, run_tag_search);
+ //var tag_search_input = $('#ab-tag-search');
+ //tag_search_input.keydown(
+ // makeKeyHandler(13, run_tag_search)
+ //);
+ };
+
+ var render_tag_warning = function(tag_list){
+ if ( !tag_list ) {
+ return;
+ }
+ tag_warning_box.clear();
+ $.each(tag_list, function(idx, tag_name){
+ tag_warning_box.addTag(tag_name);
+ });
+ tag_warning_box.showWarning();
+ };
var refresh_x_button = function(){
if(query_val().length > 0){
@@ -69,6 +185,10 @@ var liveSearch = function(query_string) {
},
cache: false
});
+ updateHistory(url);
+ };
+
+ var updateHistory = function(url) {
var context = { state:1, rand:Math.random() };
History.pushState( context, "Questions", url );
setTimeout(function (){
@@ -195,6 +315,7 @@ var liveSearch = function(query_string) {
}
render_related_tags(data['related_tags'], data['query_string']);
render_relevance_sort_tab(data['query_string']);
+ render_tag_warning(data['non_existing_tags']);
set_active_sort_tab(data['query_data']['sort_order'], data['query_string']);
if(data['feed_url']){
// Change RSS URL
@@ -214,11 +335,11 @@ var liveSearch = function(query_string) {
var askHrefBase = askButton.attr('href').split('?')[0];
askButton.attr('href', askHrefBase + data['query_data']['ask_query_string']); /* INFO: ask_query_string should already be URL-encoded! */
-
query.focus();
var old_list = $('#' + q_list_sel);
var new_list = $('<div></div>').hide().html(data['questions']);
+ new_list.find('.timeago').timeago();
old_list.stop(true).after(new_list).fadeOut(200, function() {
//show new div with a fadeIn effect
old_list.remove();
@@ -260,6 +381,8 @@ var liveSearch = function(query_string) {
}
});
+ activate_tag_search_input();
+
$("form#searchForm").submit(function(event) {
// if user clicks the button the s(h)e probably wants page reload,
// so provide that experience but first update the query string
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
index c82913a8..47d0f880 100644
--- a/askbot/skins/common/media/js/utils.js
+++ b/askbot/skins/common/media/js/utils.js
@@ -216,7 +216,6 @@ QSutils.add_search_tag = function(query_string, tag){
return this.patch_query_string(query_string, 'tags:' + tag_string);
};
-
/* **************************************************** */
/* some google closure-like code for the ui elements */
diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less
index 0c540698..ba50e42e 100644
--- a/askbot/skins/default/media/style/style.less
+++ b/askbot/skins/default/media/style/style.less
@@ -516,6 +516,8 @@ body.anon {
p {
margin-bottom: 4px;
+ color: @info-text;
+ font-family:@main-font;
}
p.info-box-follow-up-links {
@@ -588,13 +590,22 @@ body.anon {
}
.inputs{
- #interestingTagInput, #ignoredTagInput, #subscribedTagInput{
+ #interestingTagInput,
+ #ignoredTagInput,
+ #subscribedTagInput,
+ #ab-tag-search {
width:153px;
padding-left:5px;
border:#c9c9b5 1px solid;
height:25px;
}
- #interestingTagAdd, #ignoredTagAdd, #subscribedTagAdd {
+ #ab-tag-search {
+ width: 135px;
+ }
+ #interestingTagAdd,
+ #ignoredTagAdd,
+ #subscribedTagAdd,
+ #ab-tag-search-add {
background:url(../images/small-button-blue.png) repeat-x top;
border:0;
color:@button-label;
@@ -605,10 +616,12 @@ body.anon {
margin-top:-2px;
cursor:pointer;
.rounded-corners(4px);
- .text-shadow(0px,1px,0px,#E6F6FA);
- .box-shadow(1px, 1px, 2px, #808080);
-
-
+ .text-shadow(0px,1px,0px,#E6F6FA);
+ .box-shadow(1px, 1px, 2px, #808080);
+ }
+ #ab-tag-search-add {
+ width: 47px;
+ margin-left: 3px;
}
#interestingTagAdd:hover, #ignoredTagAdd:hover, #subscribedTag:hover {
background:url(../images/small-button-blue.png) repeat-x bottom;
diff --git a/askbot/skins/default/templates/main_page/sidebar.html b/askbot/skins/default/templates/main_page/sidebar.html
index fbfbdeb8..7acbe091 100644
--- a/askbot/skins/default/templates/main_page/sidebar.html
+++ b/askbot/skins/default/templates/main_page/sidebar.html
@@ -10,6 +10,10 @@
{% include "widgets/contributors.html" %}
{% endif %}
+{% if settings.TAG_SEARCH_INPUT_ENABLED %}
+ {% include "main_page/tag_search.html" %}
+{% endif %}
+
{% if request.user.is_authenticated() and settings.SIDEBAR_MAIN_SHOW_TAG_SELECTOR %}
{% include "widgets/tag_selector.html" %}
{% endif %}
diff --git a/askbot/skins/default/templates/main_page/tag_search.html b/askbot/skins/default/templates/main_page/tag_search.html
new file mode 100644
index 00000000..45f12b2f
--- /dev/null
+++ b/askbot/skins/default/templates/main_page/tag_search.html
@@ -0,0 +1,7 @@
+<div id="tagSearch" class="box">
+ <h2>{% trans %}Tag search{% endtrans %}</h2>
+ <div class="inputs">
+ <input id="ab-tag-search" autocomplete="off" type="text"/>
+ <input id="ab-tag-search-add" type="submit" value="{% trans %}search{% endtrans %}"/>
+ </div>
+</div>
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 613cb3c9..a75a8967 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -76,6 +76,9 @@ def questions(request, **kwargs):
qs, meta_data = models.Thread.objects.run_advanced_search(request_user=request.user, search_state=search_state)
+ if meta_data['non_existing_tags']:
+ search_state = search_state.remove_tags(meta_data['non_existing_tags'])
+
paginator = Paginator(qs, page_size)
if paginator.num_pages < search_state.page:
search_state.page = 1
@@ -129,10 +132,7 @@ def questions(request, **kwargs):
if request.is_ajax():
q_count = paginator.count
- if search_state.tags:
- question_counter = ungettext('%(q_num)s question, tagged', '%(q_num)s questions, tagged', q_count)
- else:
- question_counter = ungettext('%(q_num)s question', '%(q_num)s questions', q_count)
+ question_counter = ungettext('%(q_num)s question', '%(q_num)s questions', q_count)
question_counter = question_counter % {'q_num': humanize.intcomma(q_count),}
if q_count > page_size:
@@ -166,6 +166,7 @@ def questions(request, **kwargs):
'query_string': search_state.query_string(),
'page_size' : page_size,
'questions': questions_html.replace('\n',''),
+ 'non_existing_tags': meta_data['non_existing_tags']
}
ajax_data['related_tags'] = [{
'name': tag.name,