diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-05-09 16:05:33 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-05-09 16:05:33 -0400 |
commit | 34c01db1df6297c8ef46bb0d667b219774ecd1ea (patch) | |
tree | 6dbac228a60cb605dbe272379a149ca29e31933b | |
parent | 5f26975cc42b012fba086b69f54fc81219bd3ff7 (diff) | |
download | askbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.tar.gz askbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.tar.bz2 askbot-34c01db1df6297c8ef46bb0d667b219774ecd1ea.zip |
added optional tag search box
-rw-r--r-- | askbot/conf/forum_data_rules.py | 9 | ||||
-rw-r--r-- | askbot/models/question.py | 27 | ||||
-rw-r--r-- | askbot/search/state_manager.py | 9 | ||||
-rw-r--r-- | askbot/skins/common/media/js/live_search.js | 125 | ||||
-rw-r--r-- | askbot/skins/common/media/js/utils.js | 1 | ||||
-rw-r--r-- | askbot/skins/default/media/style/style.less | 25 | ||||
-rw-r--r-- | askbot/skins/default/templates/main_page/sidebar.html | 4 | ||||
-rw-r--r-- | askbot/skins/default/templates/main_page/tag_search.html | 7 | ||||
-rw-r--r-- | askbot/views/readers.py | 9 |
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, |