summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-10-25 01:10:24 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-10-25 01:10:24 -0400
commit6d64b95508ec03668d9c7cc32301ef17d9bc1832 (patch)
treea874ac7d3f3164d27d6c4942e754540e190ef17e
parent581be4c5a5af3a23e32e3145553b3ef3ed0e7711 (diff)
downloadaskbot-6d64b95508ec03668d9c7cc32301ef17d9bc1832.tar.gz
askbot-6d64b95508ec03668d9c7cc32301ef17d9bc1832.tar.bz2
askbot-6d64b95508ec03668d9c7cc32301ef17d9bc1832.zip
added support for sorting by relevance
-rw-r--r--askbot/__init__.py2
-rw-r--r--askbot/const/__init__.py33
-rw-r--r--askbot/models/question.py22
-rw-r--r--askbot/search/state_manager.py8
-rw-r--r--askbot/skins/default/media/js/live_search.js89
-rw-r--r--askbot/skins/default/templates/authopenid/complete.html8
-rw-r--r--askbot/skins/default/templates/macros.html39
-rw-r--r--askbot/skins/default/templates/questions.html155
-rw-r--r--askbot/views/readers.py2
9 files changed, 229 insertions, 129 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py
index beacbb24..62387bbd 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -92,4 +92,4 @@ def should_show_sort_by_relevance():
"""True if configuration support sorting
questions by search relevance
"""
- return (django_settings.DATABASE_ENGINE == 'posgresql_psycopg2')
+ return (django_settings.DATABASE_ENGINE == 'postgresql_psycopg2')
diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py
index dedbd115..7770f858 100644
--- a/askbot/const/__init__.py
+++ b/askbot/const/__init__.py
@@ -35,28 +35,29 @@ TYPE_REPUTATION = (
(10, 'assigned_by_moderator'),
)
-#do not translate these!!!
+#do not translate keys
POST_SORT_METHODS = (
- ('latest', _('newest')),
- ('oldest', _('oldest')),
- ('active', _('active')),
- ('inactive', _('inactive')),
- ('hottest', _('hottest')),
- ('coldest', _('coldest')),
- ('mostvoted', _('most voted')),
- ('leastvoted', _('least voted')),
- ('relevant', _('relevance')),
- )
+ ('age-desc', _('newest')),
+ ('age-asc', _('oldest')),
+ ('activity-desc', _('active')),
+ ('activity-asc', _('inactive')),
+ ('answers-desc', _('hottest')),
+ ('answers-asc', _('coldest')),
+ ('votes-desc', _('most voted')),
+ ('votes-asc', _('least voted')),
+ ('relevance-desc', _('relevance')),
+)
#todo: add assertion here that all sort methods are unique
#because they are keys to the hash used in implementations of Q.run_advanced_search
-DEFAULT_POST_SORT_METHOD = 'active'
+DEFAULT_POST_SORT_METHOD = 'activity-desc'
POST_SCOPE_LIST = (
- ('all', _('all')),
- ('unanswered', _('unanswered')),
- ('favorite', _('favorite')),
- )
+ ('all', _('all')),
+ ('unanswered', _('unanswered')),
+ ('favorite', _('favorite')),
+)
DEFAULT_POST_SCOPE = 'all'
+
PAGE_SIZE_CHOICES = (('10', '10',), ('30', '30',), ('50', '50',),)
#todo: remove this duplication
QUESTIONS_PER_PAGE_USER_CHOICES = (
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 4a9d7000..27a718ae 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -23,15 +23,15 @@ from askbot.utils.html import sanitize_html
#todo: too bad keys are duplicated see const sort methods
QUESTION_ORDER_BY_MAP = {
- 'latest': '-added_at',
- 'oldest': 'added_at',
- 'active': '-last_activity_at',
- 'inactive': 'last_activity_at',
- 'hottest': '-answer_count',
- 'coldest': 'answer_count',
- 'mostvoted': '-score',
- 'leastvoted': 'score',
- 'relevant': None#this is a special case for postges only
+ 'age-desc': '-added_at',
+ 'age-asc': 'added_at',
+ 'activity-desc': '-last_activity_at',
+ 'activity-asc': 'last_activity_at',
+ 'answers-desc': '-answer_count',
+ 'answers-asc': 'answer_count',
+ 'votes-desc': '-score',
+ 'votes-asc': 'score',
+ 'relevance-desc': None#this is a special case for postges only
}
class QuestionManager(models.Manager):
@@ -121,7 +121,7 @@ class QuestionManager(models.Manager):
'params': ["'" + search_query + "'"]
}
if askbot.should_show_sort_by_relevance():
- if sort_method == 'relevant':
+ if sort_method == 'relevance-desc':
extra_kwargs['order_by'] = ['-relevance',]
qs = qs.extra(**extra_kwargs)
@@ -220,7 +220,7 @@ class QuestionManager(models.Manager):
select_params = (uid_str, )
)
- if sort_method != 'relevant':
+ if sort_method != 'relevance-desc':
#relevance sort is set in the extra statement
#only for postgresql
orderby = QUESTION_ORDER_BY_MAP[sort_method]
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index 9f75d608..53eb22bc 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -140,20 +140,20 @@ class SearchState(object):
if 'query' in input_dict:
self.update_value('query', input_dict)
- self.sort = 'relevant'
+ self.sort = 'relevance-desc'
elif 'search' in unprocessed_input:#a case of use nulling search query by hand
self.reset_query()
return
if 'sort' in input_dict:
- if input_dict['sort'] == 'relevant' and self.query is None:
+ if input_dict['sort'] == 'relevance-desc' and self.query is None:
self.reset_sort()
else:
self.update_value('sort', input_dict)
#todo: plug - mysql has no relevance sort
if not askbot.should_show_sort_by_relevance():
- if self.sort == 'relevant':
+ if self.sort == 'relevance-desc':
self.reset_sort()
def reset_page(self):
@@ -163,7 +163,7 @@ class SearchState(object):
if self.query:
self.query = None
self.reset_page()
- if self.sort == 'relevant':
+ if self.sort == 'relevance-desc':
self.reset_sort()
def reset_sort(self):
diff --git a/askbot/skins/default/media/js/live_search.js b/askbot/skins/default/media/js/live_search.js
index 78318c75..06984350 100644
--- a/askbot/skins/default/media/js/live_search.js
+++ b/askbot/skins/default/media/js/live_search.js
@@ -1,3 +1,4 @@
+var prevSortMethod = sortMethod;
$(document).ready(function(){
var query = $('input#keywords');
var prev_text = $.trim(query.val());
@@ -14,7 +15,10 @@ $(document).ready(function(){
x_button.click(
function(){
query.val('');
- reset_query();
+ if (sortMethod == 'relevance-desc'){
+ sortMethod = prevSortMethod;
+ }
+ reset_query(sortMethod);
}
);
query.after(x_button);
@@ -30,11 +34,20 @@ $(document).ready(function(){
cur_text = $.trim(query.val());
if (cur_text != prev_text && running === false){
if (cur_text.length >= minSearchWordLength){
- send_query(cur_text);
+ if (prev_text.length === 0 && showSortByRelevance){
+ if (sortMethod == 'activity-desc'){
+ prevSortMethod = sortMethod;
+ sortMethod = 'relevance-desc';
+ }
+ }
+ send_query(cur_text, sortMethod);
running = true;
}
else if (cur_text.length === 0){
- reset_query();
+ if (sortMethod == 'relevance-desc'){
+ sortMethod = prevSortMethod;
+ }
+ reset_query(sortMethod);
running = true;
}
}
@@ -234,8 +247,68 @@ $(document).ready(function(){
var set_question_count = function(count_html){
$('#question-count').html(count_html);
+ };
+
+ var set_active_sort_tab = function(sort_method){
+ $('#sort_tabs>a').attr('class', 'off');
+ $('#' + sortMethod).attr('class', 'on');
+ };
+
+ var create_relevance_tab = function(){
+ relevance_tab = $('<a></a>');
+ relevance_tab.attr('href', '?sort=relevance-desc');
+ relevance_tab.attr('id', 'by_relevance');
+ relevance_tab.html($.i18n._('relevance'));
+ return relevance_tab;
}
+ var set_active_sort_tab = function(sort_method){
+ var tabs = $('#sort_tabs>a');
+ tabs.attr('class', 'off');
+ tabs.each(function(index, element){
+ var tab = $(element);
+ var tab_name = tab.attr('id').replace(/^by_/,'');
+ if (tab_name in sortButtonData){
+ tab.attr(
+ 'href',
+ '?sort=' + tab_name + '-desc'
+ );
+ tab.attr(
+ 'title',
+ sortButtonData[tab_name]['desc_tooltip']
+ );
+ tab.html(sortButtonData[tab_name]['desc_label']);
+ }
+ });
+ var bits = sort_method.split('-', 2);
+ var name = bits[0];
+ var sense = bits[1];//sense of sort
+ var antisense = (sense == 'asc' ? 'desc':'asc');
+ var active_tab = $('#by_' + name);
+ active_tab.attr('class', 'on');
+ active_tab.attr('title', sortButtonData[name][antisense + '_tooltip']);
+ active_tab.html(sortButtonData[name][sense + '_label']);
+ };
+
+ var render_relevance_sort_tab = function(){
+ if (showSortByRelevance === false){
+ return;
+ }
+ var relevance_tab = $('#by_relevance');
+ if (prev_text && prev_text.length > 0){
+ if (relevance_tab.length == 0){
+ relevance_tab = create_relevance_tab();
+ $('#sort_tabs>span').after(relevance_tab);
+ }
+ }
+ else {
+ if (relevance_tab.length > 0){
+ relevance_tab.remove();
+ }
+ }
+ set_active_sort_tab(sortMethod);
+ };
+
var render_result = function(data, text_status, xhr){
var old_list = $('#' + q_list_sel);
var new_list = $('<div></div>');
@@ -250,6 +323,7 @@ $(document).ready(function(){
set_question_count(data['question_counter']);
render_faces(data['faces']);
render_related_tags(data['related_tags']);
+ render_relevance_sort_tab();
query.focus();
}
//show new div
@@ -260,10 +334,11 @@ $(document).ready(function(){
eval_query();
}
- var send_query = function(query_text){
+ var send_query = function(query_text, sort_method){
+ var post_data = {query: query_text};
$.ajax({
url: scriptUrl + $.i18n._('questions/'),
- data: {query: query_text},
+ data: {query: query_text, sort: sort_method},
dataType: 'json',
success: render_result,
complete: try_again,
@@ -271,11 +346,11 @@ $(document).ready(function(){
prev_text = query_text;
}
- var reset_query = function(){
+ var reset_query = function(sort_method){
refresh_x_button();
$.ajax({
url: scriptUrl + $.i18n._('questions/'),
- data: {reset_query: true},
+ data: {reset_query: true, sort: sort_method},
dataType: 'json',
success: render_result,
complete: try_again,
diff --git a/askbot/skins/default/templates/authopenid/complete.html b/askbot/skins/default/templates/authopenid/complete.html
index ee5bf241..77142e74 100644
--- a/askbot/skins/default/templates/authopenid/complete.html
+++ b/askbot/skins/default/templates/authopenid/complete.html
@@ -43,11 +43,9 @@ parameters:
</div>
{% if openid_register_form.errors %}
<ul class="errorlist">
- {% if openid_register_form.non_field_errors %}
- {% for error in openid_register_form.non_field_errors %}
- <li>{{error}}</li>
- {% endfor %}
- {% endif %}
+ {% for error in openid_register_form.non_field_errors() %}
+ <li>{{error}}</li>
+ {% endfor %}
</ul>
{% endif %}
<div class="login">
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
index aa982f1b..98a7545f 100644
--- a/askbot/skins/default/templates/macros.html
+++ b/askbot/skins/default/templates/macros.html
@@ -295,3 +295,42 @@ poor design of the data or methods on data objects #}
{% endif %}
</div>
{%- endmacro -%}
+
+{%- macro reversible_sort_button(button_sort_criterium=None, asc_tooltip=None, asc_label=None,
+ desc_tooltip=None, desc_label=None, current_sort_method=None) -%}
+{#
+ sort button where descending sort is default
+ and the search method is togglable between ascending and descending
+ buttons are rendered as links with id constructed as
+ "by_" + button_sort_criterium
+ class "on" is added when current_sort_method is one of
+ button_sort_criterium + "asc" or "desc"
+#}
+ {% set key_name = button_sort_criterium %}
+ {% set sort = current_sort_method %}
+ {% if sort == key_name + "-asc" %}{# "worst" first #}
+ <a id="by_{{key_name}}"
+ href="?sort={{key_name}}-desc"
+ class="on"
+ title="{{desc_tooltip}}">{{asc_label}}</a>
+ {% elif sort == key_name + "-desc" %}{# "best first" #}
+ <a id="by_{{key_name}}"
+ href="?sort={{key_name}}-asc"
+ class="on"
+ title="{{asc_tooltip}}">{{desc_label}}</a>
+ {% else %}{# default, when other button is active #}
+ <a id="by_{{key_name}}"
+ href="?sort={{key_name}}-desc"
+ class="off"
+ title="{{desc_tooltip}}">{{desc_label}}</a>
+ {% endif %}
+ <script type="text/javascript">{# need to pass on text translations to js #}
+ var sortButtonData = sortButtonData || {};
+ sortButtonData["{{key_name}}"] = {
+ asc_tooltip: "{{asc_tooltip}}",
+ asc_label: "{{asc_label}}",
+ desc_tooltip: "{{desc_tooltip}}",
+ desc_label: "{{desc_label}}"
+ };
+ </script>
+{%- endmacro %}
diff --git a/askbot/skins/default/templates/questions.html b/askbot/skins/default/templates/questions.html
index 26e0e50e..22c3faba 100644
--- a/askbot/skins/default/templates/questions.html
+++ b/askbot/skins/default/templates/questions.html
@@ -5,12 +5,10 @@
{% block forejs %}
<script type="text/javascript">
var tags = {{ tags_autocomplete|safe }};
+ var sortMethod = '{{sort}}';
+ var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
$().ready(function(){
- var sort_tab_id = "{{ sort }}";
- $("#"+sort_tab_id).attr('className',"on");
- var scope_tab_id = "{{ scope }}";
- $("#"+scope_tab_id).attr('className',"on");
var on_tab = '#nav_questions';
$(on_tab).attr('className','on');
Hilite.exact = false;
@@ -26,94 +24,85 @@
<div class="tabBar">
<div class="tabsC">
<span class="label">{% trans %}In:{% endtrans %}</span>
- <a id="all" class="off" href="?scope=all" title="{% trans %}see all questions{% endtrans %}">{% trans %}all{% endtrans %}</a>
- <a id="unanswered" class="off" href="?scope=unanswered&amp;sort=coldest" title="{% trans %}see unanswered questions{% endtrans %}">{% trans %}unanswered{% endtrans %}</a>
+ <a id="all"
+ class="{% if scope == 'all' %}on{% else %}off{% endif %}"
+ href="?scope=all"
+ title="{% trans %}see all questions{% endtrans %}"
+ >{% trans %}all{% endtrans %}</a>
+ <a id="unanswered"
+ class="{% if scope == 'unanswered' %}on{% else %}off{% endif %}"
+ href="?scope=unanswered&amp;sort=answers-asc"
+ title="{% trans %}see unanswered questions{% endtrans %}"
+ >{% trans %}unanswered{% endtrans %}</a>
{% if request.user.is_authenticated() %}
- <a id="favorite" class="off" href="?scope=favorite" title="{% trans %}see your favorite questions{% endtrans %}">{% trans %}favorite{% endtrans %}</a>
+ <a id="favorite"
+ class="{% if scope == 'favorite' %}on{% else %}off{% endif %}"
+ href="?scope=favorite"
+ title="{% trans %}see your favorite questions{% endtrans %}"
+ >{% trans %}favorite{% endtrans %}</a>
{% endif %}
</div>
- <div class="tabsA">
+ <div id="sort_tabs" class="tabsA">
<span class="label">{% trans %}Sort by:{% endtrans %}</span>
{% if show_sort_by_relevance %}
- {% if sort == "relevant" %}
- <a id="oldest"
- href="?sort=relevant"
+ {% set asc_relevance_tooltip = gettext('most relevant questions') %}
+ {% set desc_relevance_tooltip = gettext('click to see most relevant questions') %}
+ {% set relevance_label = gettext('relevance') %}
+ {% if query %}
+ <a id="by_relevance"
+ {% if sort == "relevance-desc" %}
+ href="?sort=relevance-desc"
class="on"
- title="{% trans %}click to see most relevant questions{% endtrans %}">{% trans %}relevance{% endtrans %}</a>
- {% elif query %}
- <a id="oldest"
- href="?sort=relevant"
+ title="{{asc_relevance_tooltip}}">{{relevance_label}}
+ {% else %}
+ href="?sort=relevance-desc"
class="off"
- title="{% trans %}most relevant questions{% endtrans %}">{% trans %}relevance{% endtrans %}</a>
+ title="{{desc_relevance_tooltip}}">{{relevance_label}}
+ {% endif %}
+ </a>
{% endif %}
+ <script type="text/javascript">
+ var sortButtonData = sortButtonData || {};
+ sortButtonData['relevance'] = {
+ asc_tooltip: "{{asc_relevance_tooltip}}",
+ desc_tooltip: "{{desc_relevance_tooltip}}",
+ asc_label: "{{relevance_label}}",
+ desc_label: "{{relevance_label}}"
+ };
+ </script>
{% endif %}
- {% if sort == "oldest" %}
- <a id="oldest"
- href="?sort=latest"
- class="off"
- title="{% trans %}click to see the newest questions{% endtrans %}">{% trans %}oldest{% endtrans %}</a>
- {% elif sort == "latest" %}
- <a id="latest"
- href="?sort=oldest"
- class="off"
- title="{% trans %}click to see the oldest questions{% endtrans %}">{% trans %}newest{% endtrans %}</a>
- {% else %}
- <a id="latest"
- href="?sort=latest"
- class="off"
- title="{% trans %}click to see the newest questions{% endtrans %}">{% trans %}newest{% endtrans %}</a>
- {% endif %}
-
- {% if sort == "inactive" %}
- <a id="inactive"
- href="?sort=active"
- class="off"
- title="{% trans %}click to see the most recently updated questions{% endtrans %}">{% trans %}inactive{% endtrans %}</a>
- {% elif sort == "active" %}
- <a id="active"
- href="?sort=inactive"
- class="off"
- title="{% trans %}click to see the least recently updated questions{% endtrans %}">{% trans %}active{% endtrans %}</a>
- {% else %}
- <a id="active"
- href="?sort=active"
- class="off"
- title="{% trans %}click to see the most recently updated questions{% endtrans %}">{% trans %}active{% endtrans %}</a>
- {% endif %}
-
- {% if sort == "coldest" %}
- <a id="coldest"
- href="?sort=hottest"
- class="off"
- title="{% trans %}click to see hottest questions{% endtrans %}">{% trans %}less answers{% endtrans %}</a>
- {% elif sort == "hottest" %}
- <a id="hottest"
- href="?sort=coldest"
- class="off"
- title="{% trans %}click to see coldest questions{% endtrans %}">{% trans %}more answers{% endtrans %}</a>
- {% else %}
- <a id="hottest"
- href="?sort=hottest"
- class="off"
- title="{% trans %}click to see hottest questions{% endtrans %}">{% trans %}more answers{% endtrans %}</a>
- {% endif %}
-
- {% if sort == "leastvoted" %}
- <a id="leastvoted"
- href="?sort=mostvoted"
- class="off"
- title="{% trans %}click to see most voted questions{% endtrans %}">{% trans %}unpopular{% endtrans %}</a>
- {% elif sort == "mostvoted" %}
- <a id="mostvoted"
- href="?sort=leastvoted"
- class="off"
- title="{% trans %}click to see least voted questions{% endtrans %}">{% trans %}popular{% endtrans %}</a>
- {% else %}
- <a id="mostvoted"
- href="?sort=mostvoted"
- class="off"
- title="{% trans %}click to see most voted questions{% endtrans %}">{% trans %}popular{% endtrans %}</a>
- {% endif %}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'age',
+ asc_tooltip = gettext('click to see the oldest questions'),
+ asc_label = gettext('oldest'),
+ desc_tooltip = gettext('click to see the newest questions'),
+ desc_label = gettext('newest'),
+ current_sort_method = sort)
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'activity',
+ asc_tooltip = gettext('click to see the least recently updated questions'),
+ asc_label = gettext('inactive'),
+ desc_tooltip = gettext('click to see the most recently updated questions'),
+ desc_label = gettext('active'),
+ current_sort_method = sort)
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'answers',
+ asc_tooltip = gettext('click to see the least answered questions'),
+ asc_label = gettext('less answers'),
+ desc_tooltip = gettext('click to see the most answered questions'),
+ desc_label = gettext('more answers'),
+ current_sort_method = sort)
+ }}
+ {{macros.reversible_sort_button(
+ button_sort_criterium = 'votes',
+ asc_tooltip = gettext('click to see least voted questions'),
+ asc_label = gettext('unpopular'),
+ desc_tooltip = gettext('click to see most voted questions'),
+ desc_label = gettext('popular'),
+ current_sort_method = sort)
+ }}
</div>
</div>
{% endcache %}
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index e5d6e8c3..fb22240c 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -279,8 +279,6 @@ def questions(request):
if meta_data.get('author_name',None):
reset_method_count += 1
- print search_state.sort
-
template_context = RequestContext(request, {
'language_code': translation.get_language(),
'reset_method_count': reset_method_count,