summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Zielinski <tomasz.zielinski@pyconsultant.eu>2012-01-12 13:34:22 +0100
committerTomasz Zielinski <tomasz.zielinski@pyconsultant.eu>2012-01-12 23:40:21 +0100
commitde2bfcb341acab31a8922d407b1efe756d09bbee (patch)
tree25ffb0ab1d50417792fc590b603f6e98384b803d
parentc8cb1d4571a891f237d00d403de0fa8ea4a88539 (diff)
downloadaskbot-de2bfcb341acab31a8922d407b1efe756d09bbee.tar.gz
askbot-de2bfcb341acab31a8922d407b1efe756d09bbee.tar.bz2
askbot-de2bfcb341acab31a8922d407b1efe756d09bbee.zip
Further SearchState && JS cleanup - search kind of works now but still needs
a lot of attention
-rw-r--r--askbot/conf/__init__.py3
-rw-r--r--askbot/forms.py71
-rw-r--r--askbot/search/state_manager.py224
-rw-r--r--askbot/skins/common/media/js/live_search.js304
-rw-r--r--askbot/skins/default/templates/macros.html29
-rw-r--r--askbot/skins/default/templates/main_page/tab_bar.html3
-rw-r--r--askbot/tests/search_state_tests.py2
-rw-r--r--askbot/urls.py4
-rw-r--r--askbot/views/readers.py35
9 files changed, 196 insertions, 479 deletions
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
index 026a6185..9892a2a4 100644
--- a/askbot/conf/__init__.py
+++ b/askbot/conf/__init__.py
@@ -31,4 +31,5 @@ def should_show_sort_by_relevance():
"""True if configuration support sorting
questions by search relevance
"""
- return ('postgresql_psycopg2' in askbot.get_database_engine_name())
+ return True
+ #return ('postgresql_psycopg2' in askbot.get_database_engine_name())
diff --git a/askbot/forms.py b/askbot/forms.py
index 82bbcb25..08645fcd 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -496,77 +496,6 @@ class SendMessageForm(forms.Form):
)
-class AdvancedSearchForm(forms.Form):
- """nothing must be required in this form
- it is used by the main questions view for input validation only
- """
- scope = forms.ChoiceField(choices=const.POST_SCOPE_LIST, required=False)
- sort = forms.ChoiceField(choices=const.POST_SORT_METHODS, required=False)
- query = forms.CharField(max_length=256, required=False)
- #search field is actually a button, used to detect manual button click
- search = forms.CharField(max_length=16, required=False)
- reset_tags = forms.BooleanField(required=False)
- reset_author = forms.BooleanField(required=False)
- reset_query = forms.BooleanField(required=False)
- start_over = forms.BooleanField(required=False)
- tags = forms.CharField(max_length=256, required=False)
- remove_tag = forms.CharField(max_length=256, required=False)
- author = forms.IntegerField(required=False)
- page_size = forms.ChoiceField(choices=const.PAGE_SIZE_CHOICES, required=False)
- page = forms.IntegerField(required=False)
-
- def clean_tags(self):
- if 'tags' in self.cleaned_data:
- tags_input = self.cleaned_data['tags'].strip()
- split_re = re.compile(const.TAG_SPLIT_REGEX)
- tag_strings = split_re.split(tags_input)
- tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
- out = set()
- for s in tag_strings:
- if tagname_re.search(s):
- out.add(s)
- if len(out) > 0:
- self.cleaned_data['tags'] = out
- else:
- self.cleaned_data['tags'] = None
- return self.cleaned_data['tags']
-
- def clean_query(self):
- if 'query' in self.cleaned_data:
- q = self.cleaned_data['query'].strip()
- if q == '':
- q = None
- self.cleaned_data['query'] = q
- return self.cleaned_data['query']
-
- def clean_page_size(self):
- if 'page_size' in self.cleaned_data:
- if self.cleaned_data['page_size'] == '':
- self.cleaned_data['page_size'] = None
- else:
- page_size = self.cleaned_data['page_size']
- #by this time it is guaranteed to be castable as int
- self.cleaned_data['page_size'] = int(page_size)
- return self.cleaned_data['page_size']
-
- def clean(self):
- #todo rewrite
- data = self.cleaned_data
- cleanup_dict(data, 'scope', '')
- cleanup_dict(data, 'tags', None)
- cleanup_dict(data, 'sort', '')
- cleanup_dict(data, 'query', None)
- cleanup_dict(data, 'search', '')
- cleanup_dict(data, 'reset_tags', False)
- cleanup_dict(data, 'reset_author', False)
- cleanup_dict(data, 'reset_query', False)
- cleanup_dict(data, 'remove_tag', '')
- cleanup_dict(data, 'start_over', False)
- cleanup_dict(data, 'author', None)
- cleanup_dict(data, 'page', None)
- cleanup_dict(data, 'page_size', None)
- return data
-
class NotARobotForm(forms.Form):
recaptcha = RecaptchaField(
private_key = askbot_settings.RECAPTCHA_SECRET,
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index adb56138..627d91e6 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -1,27 +1,14 @@
-#search state manager object
-#that lives in the session and takes care of the state
-#persistece during the search session
+"""Search state manager object"""
import re
-import copy
+
+from django.utils.http import urlquote
+
import askbot
import askbot.conf
from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.utils.functions import strip_plus
-import logging
-
-ACTIVE_COMMANDS = (
- 'sort', 'search', 'query',
- 'reset_query', 'reset_author', 'reset_tags', 'remove_tag',
- 'tags', 'scope', 'page_size', 'start_over',
- 'page'
-)
-def some_in(what, where):
- for element in what:
- if element in where:
- return True
- return False
def extract_matching_token(text, regexes):
"""if text matches any of the regexes,
@@ -92,166 +79,79 @@ def parse_query(query):
}
class SearchState(object):
- def __init__(self):
- self.scope = const.DEFAULT_POST_SCOPE
- self.query = None
- self.stripped_query = None
- self.query_tags = []
- self.query_users = []
- self.query_title = None
- self.search = None
- self.tags = None
- self.author = None
- self.sort = const.DEFAULT_POST_SORT_METHOD
- self.page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)
- self.page = 1
- self.logged_in = False
- logging.debug('new search state initialized')
+ def __init__(self, scope, sort, query, tags, author, page, page_size, user_logged_in):
+ # INFO: zip(*[('a', 1), ('b', 2)])[0] == ('a', 'b')
+
+ if (scope not in zip(*const.POST_SCOPE_LIST)[0]) or (scope == 'favorite' and not user_logged_in):
+ self.scope = const.DEFAULT_POST_SCOPE
+ else:
+ self.scope = scope
+
+ if query:
+ self.query = ' '.join(query.split('+')).strip()
+ if self.query == '':
+ self.query = None
+ else:
+ self.query = None
+
+ if self.query:
+ #pull out values of [title:xxx], [user:some one]
+ #[tag: sometag], title:'xxx', title:"xxx", @user, @'some user',
+ #and #tag - (hash symbol to delineate the tag
+ query_bits = parse_query(self.query)
+ self.stripped_query = query_bits['stripped_query']
+ self.query_tags = query_bits['query_tags']
+ self.query_users = query_bits['query_users']
+ self.query_title = query_bits['query_title']
+ else:
+ self.stripped_query = None
+ self.query_tags = None
+ self.query_users = None
+ self.query_title = None
+
+ if (sort not in zip(*const.POST_SORT_METHODS)[0]) or (sort == 'relevance-desc' and (not self.query or not askbot.conf.should_show_sort_by_relevance())):
+ self.sort = const.DEFAULT_POST_SORT_METHOD
+ else:
+ self.sort = sort
+
+ if tags:
+ # const.TAG_SPLIT_REGEX, const.TAG_REGEX
+ #' '.join(tags.split('+'))
+ self.tags = tags.split('+')
+ else:
+ self.tags = None
+
+ if author:
+ self.author = int(author)
+ else:
+ self.author = None
+
+ if page:
+ self.page = int(page)
+ else:
+ self.page = 1
+
+ if not page_size or page_size not in zip(*const.PAGE_SIZE_CHOICES)[0]:
+ self.page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)
+ else:
+ self.page_size = int(page_size)
def __str__(self):
out = 'scope=%s\n' % self.scope
out += 'query=%s\n' % self.query
- if hasattr(self, 'search'):
- manual_search = (self.search == 'search')
- out += 'manual_search = %s\n' % str(manual_search)
if self.tags:
out += 'tags=%s\n' % ','.join(self.tags)
out += 'author=%s\n' % self.author
out += 'sort=%s\n' % self.sort
out += 'page_size=%d\n' % self.page_size
out += 'page=%d\n' % self.page
- out += 'logged_in=%s\n' % str(self.logged_in)
return out
- def reset(self):
- #re-initialize, but keep login state
- is_logged_in = self.logged_in
- self.__init__()
- self.logged_in = is_logged_in
-
- def update_value(self, key, store, reset_page=True):
- if key in store:
- old_value = getattr(self, key)
- new_value = store[key]
- if new_value != old_value:
- setattr(self, key, new_value)
- if reset_page == True:
- self.reset_page()
-
- def update_from_user_input(self, input_dict, user_logged_in):
- #todo: this function will probably not
- #fit the case of multiple parameters entered at the same tiem
- if 'start_over' in input_dict:
- self.reset()
-
- reset_page = True
- if 'page' in input_dict:
- self.page = input_dict['page']
- reset_page = False # This is done to keep page from resetting in other sorting modes
-
- if 'page_size' in input_dict:
- self.update_value('page_size', input_dict)
- self.reset_page()#todo may be smarter here - start with ~same q
-
- if 'scope' in input_dict:
- if input_dict['scope'] == 'favorite' and not user_logged_in:
- self.scope = const.DEFAULT_POST_SCOPE
- else:
- self.update_value('scope', input_dict, reset_page=reset_page)
-
- if 'tags' in input_dict:
- if self.tags:
- old_tags = self.tags.copy()
- self.tags = self.tags.union(input_dict['tags'])
- if self.tags != old_tags:
- self.reset_page()
- else:
- self.tags = input_dict['tags']
-
- if 'remove_tag' in input_dict and self.tags:
- rm_set = set([input_dict['remove_tag']])
- self.tags -= rm_set
- return
-
- #all resets just return
- if 'reset_tags' in input_dict:
- if self.tags:
- self.tags = None
- self.reset_page()
- return
-
- #todo: handle case of deleting tags one-by-one
- if 'reset_author' in input_dict:
- if self.author:
- self.author = None
- self.reset_page()
- return
-
- if 'reset_query' in input_dict:
- self.reset_query()
- if input_dict.get('sort', None) == 'relevance-desc':
- self.reset_sort()
- return
-
- self.update_value('author', input_dict, reset_page=reset_page)
-
- if 'query' in input_dict:
- query_bits = parse_query(input_dict['query'])
- tmp_input_dict = copy.deepcopy(input_dict)
- tmp_input_dict.update(query_bits)
- self.update_value('query', tmp_input_dict, reset_page=reset_page)#the original query
- #pull out values of [title:xxx], [user:some one]
- #[tag: sometag], title:'xxx', title:"xxx", @user, @'some user',
- #and #tag - (hash symbol to delineate the tag
- self.update_value('stripped_query', tmp_input_dict, reset_page=reset_page)
- self.update_value('query_tags', tmp_input_dict, reset_page=reset_page)
- self.update_value('query_users', tmp_input_dict, reset_page=reset_page)
- self.update_value('query_title', tmp_input_dict, reset_page=reset_page)
- self.sort = 'relevance-desc'
- elif 'search' in input_dict:
- #a case of use nulling search query by hand
- #this branch corresponds to hitting search button manually
- #when the search query is empty
- self.reset_query()
- return
- elif askbot_settings.DECOUPLE_TEXT_QUERY_FROM_SEARCH_STATE:
- #no query in the request and the setting instructs to
- #not have the text search query sticky
- self.reset_query()
-
- if 'sort' in input_dict:
- if input_dict['sort'] == 'relevance-desc' and self.query is None:
- self.reset_sort()
- else:
- self.update_value('sort', input_dict, reset_page=reset_page)
-
- #todo: plug - mysql has no relevance sort
- if not askbot.conf.should_show_sort_by_relevance():
- if self.sort == 'relevance-desc':
- self.reset_sort()
-
- def reset_page(self):
- self.page = 1
-
- def reset_query(self):
- """reset the search query string and
- the associated "sort by relevance command"
- """
- if self.query:
- self.query = None
- self.reset_page()
- if self.sort == 'relevance-desc':
- self.reset_sort()
-
- def reset_sort(self):
- self.sort = const.DEFAULT_POST_SORT_METHOD
-
-
def query_string(self):
- out = 'section:%s' % self.scope
+ out = 'scope:%s' % self.scope
out += '/sort:%s' % self.sort
if self.query:
- out += '/query:%s' % '+'.join(self.query.split(' '))
+ out += '/query:%s' % urlquote(self.query)
if self.tags:
out += '/tags:%s' % '+'.join(self.tags)
if self.author:
diff --git a/askbot/skins/common/media/js/live_search.js b/askbot/skins/common/media/js/live_search.js
index ded6f4cf..8dcfe85f 100644
--- a/askbot/skins/common/media/js/live_search.js
+++ b/askbot/skins/common/media/js/live_search.js
@@ -1,13 +1,11 @@
-var prevSortMethod = sortMethod;
var liveSearch = function(command, query_string) {
var query = $('input#keywords');
- var query_val = function () {return $.trim(query.val());}
+ var query_val = function () {return $.trim(query.val());};
var prev_text = query_val();
var running = false;
var q_list_sel = 'question-list';//id of question listing div
var search_url = askbot['urls']['questions'];
- var current_url = search_url + query_string;
var x_button = $('input[name=reset_query]');
var refresh_x_button = function(){
@@ -22,67 +20,65 @@ var liveSearch = function(command, query_string) {
}
};
- var process_query = function(){
- if (prev_text.length === 0 && showSortByRelevance){
- if (sortMethod === 'activity-desc'){
- prevSortMethod = sortMethod;
- sortMethod = 'relevance-desc';
- }
- }
- if (current_url !== undefined){
- search_url = '/'; //resetting search_url every times
- query_string = current_url;
- }
- else {
- search_url = askbot['urls']['questions']; //resetting search_url every times
- }
- params = query_string.split('/')
- for (var i = 0; i < params.length; i++){
- if (params[i] !== ''){
- if (params[i].substring(0, 5) == "sort:"){ //change the sort method
- search_url += 'sort:'+sortMethod+'/'
- search_url += 'query:'+ encodeURIComponent(cur_text); //cur_text.split(' ').join('+') + '/' //we add the query here
- }
- else{
- search_url += params[i] + '/';
- }
- }
- }
- send_query(cur_text);
- };
-
var restart_query = function() {
+ sortMethod = 'activity-desc';
query.val('');
- (function reset_sort_method(){
- if (sortMethod === 'relevance-desc'){
- sortMethod = prevSortMethod;
- if (sortMethod === 'relevance-desc'){
- sortMethod = 'activity-desc';
- }
- } else {
- sortMethod = 'activity-desc';
- prevSortMethod = 'activity-desc';
- }
- })();
refresh_x_button();
- new_url = remove_from_url(search_url, 'query');
- search_url = askbot['urls']['questions'] + 'reset_query:true/';
- reset_query(new_url, sortMethod);
- running = true;
+ send_query();
};
var eval_query = function(){
- cur_text = query_val();
- if (cur_text !== prev_text && running === false){
- if (cur_text.length >= minSearchWordLength){
- process_query();
- running = true;
- } else if (cur_text.length === 0){
+ cur_query = query_val();
+ if (cur_query !== prev_text && running === false){
+ if (cur_query.length >= minSearchWordLength){
+ send_query(cur_query);
+ } else if (cur_query.length === 0){
restart_query();
}
}
};
+ var send_query = function(query_text){
+ running = true;
+ if(query_text === undefined) { // handle missing parameter
+ query_text = query_val();
+ }
+ query_string = patch_query_string(
+ query_string,
+ 'query:' + encodeURIComponent(query_text),
+ query_text === '' // remove if empty
+ );
+
+ var url = search_url + query_string;
+ $.ajax({
+ url: url,
+ dataType: 'json',
+ success: render_result,
+ complete: function(){
+ running = false;
+ eval_query();
+ },
+ cache: false
+ });
+ prev_text = query_text;
+ var context = { state:1, rand:Math.random() };
+ History.pushState( context, "Questions", url );
+ };
+
+ var refresh_main_page = function (){
+ $.ajax({
+ url: askbot['urls']['questions'],
+ data: {preserve_state: true},
+ dataType: 'json',
+ success: render_result
+ });
+
+ var context = { state:1, rand:Math.random() };
+ var title = "Questions";
+ var query = askbot['urls']['questions'];
+ History.pushState( context, title, query );
+ };
+
/* *********************************** */
var render_related_tags = function(tags, query_string){
@@ -98,7 +94,7 @@ var liveSearch = function(command, query_string) {
html_list.push(tag.getElement().outerHTML());
html_list.push('<span class="tag-number">&#215; ');
- html_list.push(tags[i]['used_count'])
+ html_list.push(tags[i]['used_count']);
html_list.push('</span>');
html_list.push('<br />');
}
@@ -114,7 +110,6 @@ var liveSearch = function(command, query_string) {
} else {
$('#listSearchTags').show();
$('#search-tips').show();
- var tags_html = '';
$.each(tags, function(idx, tag_name){
var tag = new Tag();
tag.setName(tag_name);
@@ -132,94 +127,77 @@ var liveSearch = function(command, query_string) {
var create_relevance_tab = function(query_string){
relevance_tab = $('<a></a>');
- href = '/questions/' + replace_in_url(query_string, 'sort:relevance-desc')
+ href = search_url + patch_query_string(query_string, 'sort:relevance-desc');
relevance_tab.attr('href', href);
relevance_tab.attr('id', 'by_relevance');
relevance_tab.html('<span>' + sortButtonData['relevance']['label'] + '</span>');
return relevance_tab;
- }
+ };
+
+ /* *************************************** */
- var replace_in_url = function (query_string, param){
- values = param.split(':')
- type = values[0]
- value = values[1]
- params = query_string.split('/')
- url=""
-
- for (var i = 0; i < params.length; i++){
- if (params[i] !== ''){
- if (params[i].substring(0, type.length) == type){
- url += param + '/'
- }
- else{
- url += params[i] + '/'
- }
+ var get_query_string_selector_value = function (query_string, selector) {
+ var params = query_string.split('/');
+ for(var i=0; i<params.length; i++) {
+ var param_split = params[i].split(':');
+ if(param_split[0] === selector) {
+ return param_split[1];
}
}
- return url
- }
+ return undefined;
+ };
- var remove_from_url = function (query_string, type){
- params = query_string.split('/')
- url=""
- for (var i = 0; i < params.length; i++){
- if (params[i] !== ''){
- if (params[i].substring(0, type.length) !== type){
- url += params[i] + '/'
- }
+ var patch_query_string = function (query_string, patch, remove) {
+ var patch_split = patch.split(':');
+ var mapping = {};
+ var params = query_string.split('/');
+ var new_query_string = '';
+
+ if(!remove) {
+ mapping[patch_split[0]] = patch_split[1]; // prepopulate the patched selector
+ }
+
+ for (var i = 0; i < params.length; i++) {
+ var param_split = params[i].split(':');
+ if(param_split[0] !== patch_split[0] && param_split[1]) {
+ mapping[param_split[0]] = param_split[1];
}
}
- return '/'+url
- }
- var remove_tag_from_url =function (query_string, tag){
- url = askbot['urls']['questions'];
- flag = false
- author = ''
- if (query_string !== null){
- params = query_string.split('/')
- for (var i = 0; i < params.length; i++){
- if (params[i] !== ''){
- if (params[i].substring(0, 5) == "tags:"){
- tags = params[i].substr(5).split('+');
- new_tags = ''
- for(var j = 0; j < tags.length; j++){
- if(encodeURIComponent(tags[j]) !== encodeURIComponent(tag)){
- if (new_tags !== ''){
- new_tags += '+'
- }
- new_tags += encodeURIComponent(tags[j]);
- }
- }
- if(new_tags !== ''){
- url += 'tags:'+new_tags+'/'
- }
- flag = true
- }
- else if (params[i].substring(0, 7) == "author:"){
- author = params[i];
- }
- else{
- url += params[i] + '/';
- }
- }
+ var add_selector = function(name) {
+ if(name in mapping) {
+ new_query_string += name + ':' + mapping[name] + '/';
}
- if (author !== '') {
- url += author+'/'
+ };
+
+ /* The order of selectors should match the Django URL */
+ add_selector('scope');
+ add_selector('sort');
+ add_selector('query');
+ add_selector('tags');
+ add_selector('author');
+ add_selector('page_size');
+ add_selector('page');
+
+ return new_query_string;
+ };
+
+ var remove_search_tag = function(tag){
+ var tag_string = get_query_string_selector_value(query_string, 'tags');
+ if(!tag_string) return; // early exit
+
+ var tags = tag_string.split('+');
+ var new_tags = [];
+
+ for(var j = 0; j < tags.length; j++){
+ if(tags[j] !== tag) {
+ new_tags.push(tags[j]);
}
}
- return url
- }
+ query_string = patch_query_string(query_string, 'tags:' + new_tags.join('+'));
- var set_section_tabs = function(query_string){
- var tabs = $('#section_tabs > a'); /* TODO: This doesn't point to anything now */
- tabs.each(function(index, element){
- var tab = $(element);
- var tab_name = tab.attr('id').replace(/^by_/,'');
- href = '/questions/' + replace_in_url(query_string, 'section:'+tab_name)
- tab.attr('href', href);
- });
+ send_query();
};
var set_active_sort_tab = function(sort_method, query_string){
@@ -229,7 +207,7 @@ var liveSearch = function(command, query_string) {
var tab = $(element);
var tab_name = tab.attr('id').replace(/^by_/,'');
if (tab_name in sortButtonData){
- href = '/questions/' + replace_in_url(query_string, 'sort:'+tab_name+'-desc')
+ href = search_url + patch_query_string(query_string, 'sort:'+tab_name+'-desc');
tab.attr('href', href);
tab.attr('title', sortButtonData[tab_name]['desc_tooltip']);
tab.html(sortButtonData[tab_name]['label']);
@@ -264,21 +242,6 @@ var liveSearch = function(command, query_string) {
}
};
- var remove_search_tag = function(tag_name, query_string){
- $.ajax({
- url: askbot['urls']['questions']+'remove_tag:'+encodeURIComponent(tag_name)+'/',
- dataType: 'json',
- success: render_result,
- complete: try_again
- });
- search_url = remove_tag_from_url(query_string, tag_name)
- current_url = search_url;
- var context = { state:1, rand:Math.random() };
- var title = "Questions";
- var query = search_url;
- History.pushState( context, title, query );
- };
-
var render_result = function(data, text_status, xhr){
if (data['questions'].length > 0){
$('#pager').toggle(data['paginator'] !== '').html(data['paginator']);
@@ -291,7 +254,6 @@ var liveSearch = function(command, query_string) {
render_related_tags(data['related_tags'], data['query_string']);
render_relevance_sort_tab(data['query_string']);
set_active_sort_tab(sortMethod, data['query_string']);
- set_section_tabs(data['query_string']);
if(data['feed_url']){
// Change RSS URL
$("#ContentLeft a.rss:first").attr("href", data['feed_url']);
@@ -308,61 +270,9 @@ var liveSearch = function(command, query_string) {
new_list.fadeIn(400);
});
}
- }
-
- /* *********************************** */
-
- var try_again = function(){
- running = false;
- eval_query();
- }
-
- var send_query = function(query_text){
- $.ajax({
- url: search_url,
- dataType: 'json',
- success: render_result,
- complete: try_again,
- cache: false
- });
- prev_text = query_text;
- var context = { state:1, rand:Math.random() };
- var title = "Questions";
- var query = search_url;
- History.pushState( context, title, query );
- }
-/*
- var reset_query = function(new_url, sort_method){
- $.ajax({
- url: search_url,
- //data: {reset_query: true, sort: sort_method},
- dataType: 'json',
- success: render_result,
- complete: try_again
- });
- prev_text = '';
- var context = { state:1, rand:Math.random() };
- var title = "Questions";
- var query = new_url;
- History.pushState( context, title, query );
- }
-*/
- var refresh_main_page = function (){
- $.ajax({
- url: askbot['urls']['questions'],
- data: {preserve_state: true},
- dataType: 'json',
- success: render_result
- });
-
- var context = { state:1, rand:Math.random() };
- var title = "Questions";
- var query = askbot['urls']['questions'];
- History.pushState( context, title, query );
};
- /* *************************************** */
-
+ /* *********************************** */
if(command === 'refresh') {
refresh_main_page();
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
index 2ffa5d25..55359e0f 100644
--- a/askbot/skins/default/templates/macros.html
+++ b/askbot/skins/default/templates/macros.html
@@ -361,22 +361,21 @@ for the purposes of the AJAX comment editor #}
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={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-desc") }}
- class="rev on"
- title="{{desc_tooltip}}"><span>{{label}} &#9650;</span></a>
- {% elif sort == key_name + "-desc" %}{# "best first" #}
- <a id="by_{{key_name}}"
- href={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-asc") }}
- class="rev on"
- title="{{asc_tooltip}}"><span>{{label}} &#9660;</span></a>
+ {% if current_sort_method == key_name + "-asc" %}{# "worst" first #}
+ <a id="by_{{key_name}}"
+ href={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-desc") }}
+ class="rev on"
+ title="{{desc_tooltip}}"><span>{{label}} &#9650;</span></a>
+ {% elif current_sort_method == key_name + "-desc" %}{# "best first" #}
+ <a id="by_{{key_name}}"
+ href={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-asc") }}
+ class="rev on"
+ title="{{asc_tooltip}}"><span>{{label}} &#9660;</span></a>
{% else %}{# default, when other button is active #}
- <a id="by_{{key_name}}"
- href={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-desc") }}
- class="off"
- title="{{desc_tooltip}}"><span>{{label}}</span></a>
+ <a id="by_{{key_name}}"
+ href={% url questions %}{{ query_string|replace_in_url("sort:"+key_name+"-desc") }}
+ class="off"
+ title="{{desc_tooltip}}"><span>{{label}}</span></a>
{% endif %}
<script type="text/javascript">{# need to pass on text translations to js #}
var sortButtonData = sortButtonData || {};
diff --git a/askbot/skins/default/templates/main_page/tab_bar.html b/askbot/skins/default/templates/main_page/tab_bar.html
index 1802640f..80a4b95f 100644
--- a/askbot/skins/default/templates/main_page/tab_bar.html
+++ b/askbot/skins/default/templates/main_page/tab_bar.html
@@ -19,7 +19,7 @@
{% set relevance_label = gettext('relevance') %}
{% if query %}
<a id="by_relevance"
- {% if sort == "relevance-desc" %}
+ {% if sortMethod == "relevance-desc" %}
href="{% url questions %}{{ query_string|replace_in_url("sort:relevance-desc") }}"
class="on"
title="{{asc_relevance_tooltip}}"><span>{{relevance_label}} &#9660;</span>
@@ -75,7 +75,6 @@
query_string = query_string,
)
}}
-
</div>
</div>
diff --git a/askbot/tests/search_state_tests.py b/askbot/tests/search_state_tests.py
index 6a6bf167..21c416f8 100644
--- a/askbot/tests/search_state_tests.py
+++ b/askbot/tests/search_state_tests.py
@@ -59,6 +59,8 @@ class SearchStateTests(TestCase):
self.assertEquals(self.state.sort, 'age-asc')
self.update({})
self.assertEquals(self.state.sort, DEFAULT_SORT)
+
+
class ParseQueryTests(unittest.TestCase):
def test_extract_users(self):
text = '@anna haha @"maria fernanda" @\'diego maradona\' hehe [user:karl marx] hoho user:\' george bush \''
diff --git a/askbot/urls.py b/askbot/urls.py
index 794660f2..3c080470 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -61,11 +61,11 @@ urlpatterns = patterns('',
# BEGIN Questions (main page) urls. All this urls work both normally and through ajax
url(
+ # Note that all parameters, even if optional, are provided to the view. Non-present ones have None value.
(r'^%s' % _('questions') +
- r'(%s)?' % r'/section:(?P<scope>\w+)' +
+ r'(%s)?' % r'/scope:(?P<scope>\w+)' +
r'(%s)?' % r'/sort:(?P<sort>[\w\-]+)' +
r'(%s)?' % r'/query:(?P<query>[^/]+)' + # INFO: question string cannot contain slash (/), which is a section terminator
- r'(%s)?' % r'/search:search' +
r'(%s)?' % r'/tags:(?P<tags>[\w\d\-\+\#]+)' +
r'(%s)?' % r'/author:(?P<author>\d+)' +
r'(%s)?' % r'/page_size:(?P<page_size>\d+)' +
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 72d3f06a..aad42b60 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -11,7 +11,7 @@ import logging
import urllib
import operator
from django.shortcuts import get_object_or_404
-from django.http import HttpResponseRedirect, HttpResponse, Http404
+from django.http import HttpResponseRedirect, HttpResponse, Http404, HttpResponseNotAllowed
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.template import Context
from django.utils import simplejson
@@ -27,7 +27,7 @@ from django.http import QueryDict
import askbot
from askbot import exceptions
from askbot.utils.diff import textDiff as htmldiff
-from askbot.forms import AdvancedSearchForm, AnswerForm, ShowQuestionForm
+from askbot.forms import AnswerForm, ShowQuestionForm
from askbot import models
from askbot import schedules
from askbot.models.badges import award_badges_signal
@@ -63,38 +63,15 @@ def index(request):#generates front page - shows listing of questions sorted in
"""
return HttpResponseRedirect(reverse('questions'))
-def questions(request, scope=const.DEFAULT_POST_SCOPE, sort=const.DEFAULT_POST_SORT_METHOD, query=None,
- search=None, tags=None, author=None, page=None, reset_tags=None,
- reset_author=None, reset_query=None,
- remove_tag=None, page_size=None):
+def questions(request, **kwargs):
"""
List of Questions, Tagged questions, and Unanswered questions.
matching search query or user selection
"""
- if request.method == 'POST': # TODO: This is 405 condition, not 404. Django 1.2+ has decorator for this: https://docs.djangoproject.com/en/1.2/topics/http/decorators/#django.views.decorators.http.require_GET
- raise Http404
-
- #make parameters dictionary
- params_dict = {
- 'scope': scope,
- 'sort': sort,
- }
- for arg_name in ('query', 'tags'):
- if locals().get(arg_name, None):
- params_dict[arg_name] = ' '.join(locals()[arg_name].split('+'))
- for arg_name in ('search', 'author', 'page', 'reset_tags', 'reset_author', 'reset_query', 'start_over', 'remove_tag', 'page_size'):
- if locals().get(arg_name, None):
- params_dict[arg_name] = locals()[arg_name]
-
- #update search state
- form = AdvancedSearchForm(params_dict)
- if form.is_valid():
- user_input = form.cleaned_data
- else:
- user_input = None
+ if request.method != 'GET':
+ return HttpResponseNotAllowed(['GET'])
- search_state = SearchState()
- search_state.update_from_user_input(input_dict=user_input, user_logged_in=request.user.is_authenticated())
+ search_state = SearchState(user_logged_in=request.user.is_authenticated(), **kwargs)
#######