summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askbot/forms.py6
-rw-r--r--askbot/media/js/live_search.js1016
-rw-r--r--askbot/media/js/live_search_new_thread.js4
-rw-r--r--askbot/media/js/utils.js64
-rw-r--r--askbot/media/style/style.less471
-rw-r--r--askbot/models/question.py9
-rw-r--r--askbot/search/state_manager.py6
-rw-r--r--askbot/templates/answer_edit.html2
-rw-r--r--askbot/templates/ask.html7
-rw-r--r--askbot/templates/base.html1
-rw-r--r--askbot/templates/embed/ask_by_widget.html12
-rw-r--r--askbot/templates/macros.html10
-rw-r--r--askbot/templates/main_page/javascript.html6
-rw-r--r--askbot/templates/main_page/tab_bar.html4
-rw-r--r--askbot/templates/meta/bottom_scripts.html33
-rw-r--r--askbot/templates/widgets/edit_post.html2
-rw-r--r--askbot/templates/widgets/scope_nav.html2
-rw-r--r--askbot/templates/widgets/search_bar.html25
-rw-r--r--askbot/templates/widgets/secondary_header.html45
-rw-r--r--askbot/templates/widgets/user_navigation.html6
-rw-r--r--askbot/tests/page_load_tests.py14
-rw-r--r--askbot/urls.py6
-rw-r--r--askbot/views/commands.py21
23 files changed, 1247 insertions, 525 deletions
diff --git a/askbot/forms.py b/askbot/forms.py
index ed47e20e..55d864c3 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -1156,11 +1156,7 @@ class RevisionForm(forms.Form):
"""
Lists revisions of a Question or Answer
"""
- revision = forms.ChoiceField(
- widget=forms.Select(
- attrs={'style': 'width:520px'}
- )
- )
+ revision = forms.ChoiceField(widget=forms.Select())
def __init__(self, post, latest_revision, *args, **kwargs):
super(RevisionForm, self).__init__(*args, **kwargs)
diff --git a/askbot/media/js/live_search.js b/askbot/media/js/live_search.js
index f7d89c2a..5dffb677 100644
--- a/askbot/media/js/live_search.js
+++ b/askbot/media/js/live_search.js
@@ -1,3 +1,185 @@
+var SearchDropMenu = function() {
+ WrappedElement.call(this);
+ this._data = undefined;
+ this._selectedItemIndex = 0;
+ this._askButtonEnabled = true;
+}
+inherits(SearchDropMenu, WrappedElement);
+
+SearchDropMenu.prototype.setData = function(data) {
+ this._data = data;
+};
+
+SearchDropMenu.prototype.setAskHandler = function(handler) {
+ this._askHandler = handler;
+};
+
+SearchDropMenu.prototype.setAskButtonEnabled = function(isEnabled) {
+ this._askButtonEnabled = isEnabled;
+};
+
+/**
+ * assumes that data is already set
+ */
+SearchDropMenu.prototype.render = function() {
+ var list = this._resultsList;
+ list.empty();
+ var me = this;
+ $.each(this._data, function(idx, item) {
+ var listItem = me.makeElement('li');
+ var link = me.makeElement('a');
+ link.attr('href', item['url']);
+ link.html(item['title']);
+ listItem.append(link);
+ list.append(listItem);
+ });
+ if (this._data.length === 0) {
+ list.addClass('empty');
+ } else {
+ list.removeClass('empty');
+ }
+};
+
+/**
+ * @param {number} idx position of item starting from 1 for the topmost
+ * Selects item inentified by position.
+ * Scrolls the list to make top of the item visible.
+ */
+SearchDropMenu.prototype.selectItem = function(idx) {
+ //idx is 1-based index
+ this._selectedItemIndex = idx;
+ var list = this._resultsList;
+ list.find('li').removeClass('selected');
+ var item = this.getItem(idx);
+ if (item && idx > 0) {
+ item.addClass('selected');
+ var itemTopY = item.position().top;//relative to visible area
+ var curScrollTop = list.scrollTop();
+
+ /* if item is clipped on top, scroll down */
+ if (itemTopY < 0) {
+ list.scrollTop(curScrollTop + itemTopY);
+ return;
+ }
+
+ var listHeight = list.outerHeight();
+ /* pixels above the lower border of the list */
+ var itemPeepHeight = listHeight - itemTopY;
+ /* pixels below the lower border */
+ var itemSinkHeight = item.outerHeight() - itemPeepHeight;
+ if (itemSinkHeight > 0) {
+ list.scrollTop(curScrollTop + itemSinkHeight);
+ }
+ }
+
+};
+
+SearchDropMenu.prototype.getItem = function(idx) {
+ return $(this._resultsList.find('li')[idx - 1]);
+};
+
+SearchDropMenu.prototype.getItemCount = function() {
+ return this._resultsList.find('li').length;
+};
+
+SearchDropMenu.prototype.getSelectedItemIndex = function() {
+ return this._selectedItemIndex;
+};
+
+SearchDropMenu.prototype.navigateToItem = function(idx) {
+ var item = this.getItem(idx);
+ if (item) {
+ window.location.href = item.find('a').attr('href');
+ }
+};
+
+SearchDropMenu.prototype.makeKeyHandler = function() {
+ var me = this;
+ return function(e) {
+ var keyCode = getKeyCode(e);
+ if (keyCode === 27) {//escape
+ me.hide();
+ return false;
+ }
+ if (keyCode !== 38 && keyCode !== 40 && keyCode !== 13) {
+ return;
+ }
+ var itemCount = me.getItemCount();
+ if (itemCount > 0) {
+ var curItem = me.getSelectedItemIndex();
+ if (keyCode === 38) {//upArrow
+ if (curItem > 0) {
+ curItem = curItem - 1;
+ }
+ } else if (keyCode === 40) {//downArrow
+ if (curItem < itemCount) {
+ curItem = curItem + 1;
+ }
+ } else if (keyCode === 13) {//enter
+ me.navigateToItem(curItem);
+ return false;
+ }
+ me.selectItem(curItem);
+ return false
+ }
+ };
+};
+
+SearchDropMenu.prototype.createDom = function() {
+ this._element = this.makeElement('div');
+ this._element.addClass('search-drop-menu');
+ this._element.hide();
+
+ this._resultsList = this.makeElement('ul');
+ this._element.append(this._resultsList);
+ this._element.addClass('empty');
+
+ //add ask button, @todo: make into separate class?
+ var footer = this.makeElement('div');
+ this._element.append(footer);
+ this._footer = footer;
+
+ if (this._askButtonEnabled) {
+ footer.addClass('footer');
+ var button = this.makeElement('button');
+ button.addClass('submit');
+ button.html(gettext('Ask Your Question'))
+ footer.append(button);
+ var handler = this._askHandler;
+ setupButtonEventHandlers(button, handler);
+ }
+
+ $(document).keydown(this.makeKeyHandler());
+};
+
+SearchDropMenu.prototype.isOpen = function() {
+ return this._element.is(':visible');
+};
+
+SearchDropMenu.prototype.show = function() {
+ var searchBar = this._element.prev();
+ var searchBarHeight = searchBar.outerHeight();
+ var topOffset = searchBar.offset().top + searchBarHeight;
+ this._element.show();//show so that size calcs work
+ var footerHeight = this._footer.outerHeight();
+ var windowHeight = $(window).height();
+ this._resultsList.css(
+ 'max-height',
+ windowHeight - topOffset - footerHeight - 40 //what is this number?
+ );
+};
+
+SearchDropMenu.prototype.hide = function() {
+ this._element.hide();
+};
+
+SearchDropMenu.prototype.reset = function() {
+ this._data = undefined;
+ this._resultsList.empty();
+ this._selectedItemIndex = 0;
+ this._element.hide();
+};
+
var TagWarningBox = function(){
WrappedElement.call(this);
this._tags = [];
@@ -6,9 +188,8 @@ 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.css('display', 'block');
+ this._element.css('margin', '0 0 13px 2px');
this._element.addClass('non-existing-tags');
this._warning = this.makeElement('p');
this._element.append(this._warning);
@@ -51,355 +232,596 @@ TagWarningBox.prototype.showWarning = function(){
this._warning.show();
};
-var liveSearch = function(query_string) {
- var query = $('input#keywords');
- 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 x_button = $('input[name=reset_query]');
- var tag_warning_box = new TagWarningBox();
+/**
+ * @constructor
+ * tool tip to be shown on top of the search input
+ */
+var InputToolTip = function() {
+ WrappedElement.call(this);
+};
+inherits(InputToolTip, WrappedElement);
- //the tag search input is optional in askbot
- $('#ab-tag-search').parent().before(
- tag_warning_box.getElement()
- );
+InputToolTip.prototype.show = function() {
+ this._element.removeClass('dimmed');
+ this._element.show();
+};
- 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);
- };
+InputToolTip.prototype.hide = function() {
+ this._element.removeClass('dimmed');
+ this._element.hide();
+};
- 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)
- //);
- };
+InputToolTip.prototype.dim = function() {
+ this._element.addClass('dimmed');
+};
- 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();
- };
+InputToolTip.prototype.setClickHandler = function(handler) {
+ this._clickHandler = handler;
+};
- var refresh_x_button = function(){
- if(query_val().length > 0){
- if (query.hasClass('searchInput')){
- query.attr('class', 'searchInputCancelable');
- x_button.show();
- }
- } else {
- x_button.hide();
- query.attr('class', 'searchInput');
- }
- };
+InputToolTip.prototype.createDom = function() {
+ var element = this.makeElement('div');
+ this._element = element;
- var restart_query = function() {
- sortMethod = 'activity-desc';
- query.val('');
- refresh_x_button();
- send_query();
- };
+ element.html(gettext('search or ask your question'));
+ element.addClass('input-tool-tip');
- var eval_query = function(){
- 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 handler = this._clickHandler;
+ var me = this;
+ element.click(function() {
+ handler();
+ me.dim();
+ return false;
+ });
+ $(document).click(function() {
+ if (element.css('display') === 'block') {
+ element.removeClass('dimmed');
}
- };
+ });
+};
+
+
+/**
+ * @constructor
+ * provides full text search functionality
+ * which re-draws contents of the main page
+ * in response to the search query
+ */
+var FullTextSearch = function() {
+ WrappedElement.call(this);
+ this._running = false;
+ this._baseUrl = askbot['urls']['questions'];
+ this._q_list_sel = 'question-list';//id of question listing div
+ /** @todo: the questions/ needs translation... */
+ this._searchUrl = '/scope:all/sort:activity-desc/page:1/'
+ this._askButtonEnabled = true;
+};
+inherits(FullTextSearch, WrappedElement);
+
+/**
+ * @param {{boolean=}} optional, if given then function is setter
+ * otherwise it is a getter
+ * isRunning returns `true` when search is running
+ */
+FullTextSearch.prototype.isRunning = function(val) {
+ if (val === undefined) {
+ return this._running;
+ } else {
+ this._running = val;
+ }
+};
- var update_query_string = function(query_text){
- if(query_text === undefined) { // handle missing parameter
- query_text = query_val();
- }
- query_string = QSutils.patch_query_string(
- query_string,
- 'query:' + encodeURIComponent(query_text),
- query_text === '' // remove if empty
- );
- return query_text;
- };
+FullTextSearch.prototype.setAskButtonEnabled = function(isEnabled) {
+ this._askButtonEnabled = isEnabled;
+}
- var send_query = function(query_text){
- running = true;
- if(!prev_text && query_text && showSortByRelevance) {
- // If there was no query but there is some query now - and we support relevance search - then switch to it */
- query_string = QSutils.patch_query_string(query_string, 'sort:relevance-desc');
- }
- prev_text = update_query_string(query_text);
- query_string = QSutils.patch_query_string(query_string, 'page:1'); /* if something has changed, then reset the page no. */
- var url = search_url + query_string;
- $.ajax({
- url: url,
- dataType: 'json',
- success: render_result,
- complete: function(){
- running = false;
- eval_query();
- },
- cache: false
- });
- updateHistory(url);
- };
+/**
+ * @param {{string}} url for the page displaying search results
+ */
+FullTextSearch.prototype.setSearchUrl = function(url) {
+ this._searchUrl = url;
+};
- var updateHistory = function(url) {
- var context = { state:1, rand:Math.random() };
- History.pushState( context, "Questions", url );
- setTimeout(function (){
- /* HACK: For some weird reson, sometimes something overrides the above pushState so we re-aplly it
- This might be caused by some other JS plugin.
- The delay of 10msec allows the other plugin to override the URL.
- */
- History.replaceState( context, "Questions", url );
- }, 10);
- };
+FullTextSearch.prototype.getSearchUrl = function() {
+ return this._searchUrl;
+};
+
+FullTextSearch.prototype.renderTagWarning = function(tag_list){
+ if ( !tag_list ) {
+ return;
+ }
+ var tagWarningBox = this._tag_warning_box;
+ tagWarningBox.clear();
+ $.each(tag_list, function(idx, tag_name){
+ tagWarningBox.addTag(tag_name);
+ });
+ tagWarningBox.showWarning();
+};
- /* *********************************** */
+FullTextSearch.prototype.runTagSearch = function() {
+ var search_tags = $('#ab-tag-search').val().split(/\s+/);
+ if (search_tags.length === 0) {
+ return;
+ }
+ var searchUrl = this.getSearchUrl();
+ //add all tags to the url
+ searchUrl = QSutils.add_search_tag(searchUrl, search_tags);
+ var url = this._baseUrl + searchUrl;
+ var me = this;
+ $.ajax({
+ url: url,
+ dataType: 'json',
+ success: function(data, text_status, xhr){
+ me.renderFullTextResult(data, text_status, xhr);
+ $('#ab-tag-search').val('');
+ },
+ });
+ this.updateHistory(url);
+};
- var render_related_tags = function(tags, query_string){
- if (tags.length === 0) return;
+FullTextSearch.prototype.updateHistory = function(url) {
+ var context = { state:1, rand:Math.random() };
+ History.pushState( context, "Questions", url );
+ setTimeout(function(){
+ /* HACK: For some weird reson, sometimes
+ * overrides the above pushState so we re-aplly it
+ * This might be caused by some other JS plugin.
+ * The delay of 10msec allows the other plugin to override the URL.
+ */
+ History.replaceState(context, "Questions", url);
+ },
+ 10
+ );
+};
- var html_list = [];
- for (var i=0; i<tags.length; i++){
- var tag = new Tag();
- tag.setName(tags[i]['name']);
- tag.setDeletable(false);
- tag.setLinkable(true);
- tag.setUrlParams(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('</span>');
- html_list.push('<br />');
+FullTextSearch.prototype.activateTagSearchInput = 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 me = this;
+ var ac = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ maxItemsToShow: 20,
+ onItemSelect: function(){ this.runTagSearch(); },
+ delay: 10
+ });
+ ac.decorate($('#ab-tag-search'));
+ setupButtonEventHandlers(
+ button,
+ function() { me.runTagSearch() }
+ );
+};
+
+FullTextSearch.prototype.sendTitleSearchQuery = function(query_text) {
+ this.isRunning(true);
+ this._prevText = query_text;
+ var data = {query_text: query_text};
+ var me = this;
+ $.ajax({
+ url: askbot['urls']['titleSearch'],
+ data: data,
+ dataType: 'json',
+ success: function(data, text_status, xhr){
+ me.renderTitleSearchResult(data, text_status, xhr);
+ },
+ complete: function(){
+ me.isRunning(false);
+ me.evalTitleSearchQuery();
+ },
+ cache: false
+ });
+};
+
+
+FullTextSearch.prototype.sendFullTextSearchQuery = function(query_text) {
+ this.isRunning(true);
+ var searchUrl = this.getSearchUrl();
+ var prevText = this._prevText;
+ if(!prevText && query_text && askbot['settings']['showSortByRelevance']) {
+ /* If there was no query but there is some
+ * query now - and we support relevance search
+ * - then switch to it
+ */
+ searchUrl = QSutils.patch_query_string(
+ searchUrl, 'sort:relevance-desc'
+ );
+ }
+ this._prevText = this.updateQueryString(query_text);
+
+ /* if something has changed, then reset the page no. */
+ searchUrl = QSutils.patch_query_string(searchUrl, 'page:1');
+ var url = this._baseUrl + searchUrl;
+ var me = this;
+ $.ajax({
+ url: url,
+ dataType: 'json',
+ success: function(data, text_status, xhr){
+ me.renderFullTextSearchResult(data, text_status, xhr);
+ },
+ complete: function(){
+ me.isRunning(false);
+ },
+ cache: false
+ });
+ this.updateHistory(url);
+};
+
+FullTextSearch.prototype.refresh = function() {
+ this.sendFullTextSearchQuery();/* used for tag search, maybe not necessary */
+};
+
+FullTextSearch.prototype.getSearchQuery = function() {
+ return $.trim(this._query.val());
+};
+
+/**
+ * renders title search result in the dropdown under the search input
+ */
+FullTextSearch.prototype.renderTitleSearchResult = function(data) {
+ var menu = this._dropMenu;
+ menu.setData(data);
+ menu.render();
+ menu.show();
+};
+
+FullTextSearch.prototype.renderFullTextSearchResult = function(data) {
+ if (data['questions'].length === 0) {
+ return;
+ }
+
+ $('#pager').toggle(data['paginator'] !== '').html(data['paginator']);
+ $('#questionCount').html(data['question_counter']);
+ this.renderSearchTags(data['query_data']['tags'], data['query_string']);
+ if(data['faces'].length > 0) {
+ $('#contrib-users > a').remove();
+ $('#contrib-users').append(data['faces'].join(''));
+ }
+ this.renderRelatedTags(data['related_tags'], data['query_string']);
+ this.renderRelevanceSortTab(data['query_string']);
+ this.renderTagWarning(data['non_existing_tags']);
+ this.setActiveSortTab(
+ data['query_data']['sort_order'],
+ data['query_string']
+ );
+ if(data['feed_url']){
+ // Change RSS URL
+ $("#ContentLeft a.rss:first").attr("href", data['feed_url']);
+ }
+
+ // Patch scope selectors
+ var baseUrl = this._baseUrl;
+ $('#scopeWrapper > a.scope-selector').each(function(index) {
+ var old_qs = $(this).attr('href').replace(baseUrl, '');
+ var scope = QSutils.get_query_string_selector_value(old_qs, 'scope');
+ qs = QSutils.patch_query_string(data['query_string'], 'scope:' + scope);
+ $(this).attr('href', baseUrl + qs);
+ });
+
+ // Patch "Ask your question"
+ var askButton = $('#askButton');
+ 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! */
+
+ this._query.focus();
+
+ var old_list = $('#' + this._q_list_sel);
+ var new_list = $('<div></div>').hide().html(data['questions']);
+ new_list.find('.timeago').timeago();
+
+ var q_list_sel = this._q_list_sel;
+ old_list.stop(true).after(new_list).fadeOut(200, function() {
+ //show new div with a fadeIn effect
+ old_list.remove();
+ new_list.attr('id', q_list_sel);
+ new_list.fadeIn(400);
+ });
+};
+
+FullTextSearch.prototype.evalTitleSearchQuery = function() {
+ var cur_query = this.getSearchQuery();
+ var prevText = this._prevText;
+ if (cur_query !== prevText && this.isRunning() === false){
+ if (cur_query.length >= askbot['settings']['minSearchWordLength']){
+ this.sendTitleSearchQuery(cur_query);
+ } else if (cur_query.length === 0){
+ this.reset();
}
- $('#related-tags').html(html_list.join(''));
- };
+ }
+};
- var render_search_tags = function(tags, query_string){
- var search_tags = $('#searchTags');
- search_tags.empty();
- if (tags.length === 0){
- $('#listSearchTags').hide();
- $('#search-tips').hide();//wrong - if there are search users
- } else {
- $('#listSearchTags').show();
- $('#search-tips').show();
- $.each(tags, function(idx, tag_name){
- var tag = new Tag();
- tag.setName(tag_name);
- tag.setLinkable(false);
- tag.setDeletable(true);
- tag.setDeleteHandler(
- function(){
- remove_search_tag(tag_name, query_string);
- }
- );
- search_tags.append(tag.getElement());
- });
+FullTextSearch.prototype.reset = function() {
+ this._prevText = '';
+ this._dropMenu.reset();
+ this._element.val('');
+ this._element.focus();
+ this._xButton.hide();
+ this._toolTip.show();
+};
+
+FullTextSearch.prototype.refreshXButton = function() {
+ if(this.getSearchQuery().length > 0){
+ if (this._query.hasClass('searchInput')){
+ $('#searchBar').attr('class', 'cancelable');
+ this._xButton.show();
}
- };
+ } else {
+ this._xButton.hide();
+ $('#searchBar').removeClass('cancelable');
+ }
+};
- var create_relevance_tab = function(query_string){
- relevance_tab = $('<a></a>');
- href = search_url + QSutils.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;
- };
+FullTextSearch.prototype.updateQueryString = function(query_text) {
+ if (query_text === undefined) { // handle missing parameter
+ query_text = this.getSearchQuery();
+ }
+ var newUrl = QSutils.patch_query_string(
+ this._searchUrl,
+ 'query:' + encodeURIComponent(query_text),
+ query_text === '' // remove if empty
+ );
+ this.setSearchUrl(newUrl);
+ return query_text;
+};
- /* *************************************** */
+FullTextSearch.prototype.renderRelatedTags = function(tags, query_string){
+ if (tags.length === 0) return;
- var remove_search_tag = function(tag){
- query_string = QSutils.remove_search_tag(query_string, tag);
- send_query();
- };
+ var html_list = [];
+ for (var i=0; i<tags.length; i++){
+ var tag = new Tag();
+ tag.setName(tags[i]['name']);
+ tag.setDeletable(false);
+ tag.setLinkable(true);
+ tag.setUrlParams(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('</span>');
+ html_list.push('<br />');
+ }
+ $('#related-tags').html(html_list.join(''));
+};
- var set_active_sort_tab = function(sort_method, query_string){
- var tabs = $('#sort_tabs > a');
- tabs.attr('class', 'off');
- tabs.each(function(index, element){
- var tab = $(element);
- if ( tab.attr('id') ) {
- var tab_name = tab.attr('id').replace(/^by_/,'');
- if (tab_name in sortButtonData){
- href = search_url + QSutils.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']);
+FullTextSearch.prototype.renderSearchTags = function(tags, query_string){
+ var search_tags = $('#searchTags');
+ search_tags.empty();
+ var me = this;
+ if (tags.length === 0){
+ $('#listSearchTags').hide();
+ $('#search-tips').hide();//wrong - if there are search users
+ } else {
+ $('#listSearchTags').show();
+ $('#search-tips').show();
+ $.each(tags, function(idx, tag_name){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setLinkable(false);
+ tag.setDeletable(true);
+ tag.setDeleteHandler(
+ function(){
+ this.removeSearchTag(tag_name, query_string);
}
- }
+ );
+ search_tags.append(tag.getElement());
});
- var bits = sort_method.split('-', 2);
- var name = bits[0];
- var sense = bits[1];//sense of sort
- var antisense = (sense == 'asc' ? 'desc':'asc');
- var arrow = (sense == 'asc' ? ' &#9650;':' &#9660;');
- var active_tab = $('#by_' + name);
- active_tab.attr('class', 'on');
- active_tab.attr('title', sortButtonData[name][antisense + '_tooltip']);
- active_tab.html(sortButtonData[name]['label'] + arrow);
- };
+ }
+};
- var render_relevance_sort_tab = function(query_string){
- 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(query_string);
- $('#sort_tabs>span').after(relevance_tab);
+FullTextSearch.prototype.createRelevanceTab = function(query_string){
+ var relevance_tab = $('<a></a>');
+ href = this._baseUrl + QSutils.patch_query_string(query_string, 'sort:relevance-desc');
+ relevance_tab.attr('href', href);
+ relevance_tab.attr('id', 'by_relevance');
+ relevance_tab.html(
+ '<span>' + askbot['data']['sortButtonData']['relevance']['label'] + '</span>'
+ );
+ return relevance_tab;
+};
+
+FullTextSearch.prototype.removeSearchTag = function(tag) {
+ var searchUrl = this.getSearchUrl()
+ searchUrl = QSutils.remove_search_tag(searchUrl, tag);
+ this.setSearchUrl(searchUrl);
+ this.sendFullTextSearchQuery();
+};
+
+FullTextSearch.prototype.setActiveSortTab = function(sort_method, query_string){
+ var tabs = $('#sort_tabs > a');
+ tabs.attr('class', 'off');
+ var baseUrl = this._baseUrl;
+ tabs.each(function(index, element){
+ var tab = $(element);
+ if ( tab.attr('id') ) {
+ var tab_name = tab.attr('id').replace(/^by_/,'');
+ if (tab_name in askbot['data']['sortButtonData']){
+ href = baseUrl + QSutils.patch_query_string(
+ query_string,
+ 'sort:' + tab_name + '-desc'
+ );
+ tab.attr('href', href);
+ tab.attr(
+ 'title',
+ askbot['data']['sortButtonData'][tab_name]['desc_tooltip']
+ );
+ tab.html(
+ askbot['data']['sortButtonData'][tab_name]['label']
+ );
}
}
- else {
- if (relevance_tab.length > 0){
- relevance_tab.remove();
- }
+ });
+ var bits = sort_method.split('-', 2);
+ var name = bits[0];
+ var sense = bits[1];//sense of sort
+ var antisense = (sense == 'asc' ? 'desc':'asc');
+ var arrow = (sense == 'asc' ? ' &#9650;':' &#9660;');
+ var active_tab = $('#by_' + name);
+ active_tab.attr('class', 'on');
+ active_tab.attr(
+ 'title',
+ askbot['data']['sortButtonData'][name][antisense + '_tooltip']
+ );
+ active_tab.html(
+ askbot['data']['sortButtonData'][name]['label'] + arrow
+ );
+};
+
+FullTextSearch.prototype.renderRelevanceSortTab = function(query_string) {
+ if (askbot['settings']['showSortByRelevance'] === false){
+ return;
+ }
+ var relevance_tab = $('#by_relevance');
+ var prevText = this._prevText;
+ if (prevText && prevText.length > 0){
+ if (relevance_tab.length == 0){
+ relevance_tab = this.createRelevanceTab(query_string);
+ $('#sort_tabs>span').after(relevance_tab);
}
+ } else {
+ if (relevance_tab.length > 0){
+ relevance_tab.remove();
+ }
+ }
+};
+
+FullTextSearch.prototype.makeAskHandler = function() {
+ var me = this;
+ return function() {
+ var query = me.getSearchQuery();
+ window.location.href = askbot['urls']['ask'] + '?title=' + query;
+ return false;
};
+};
- var render_result = function(data, text_status, xhr){
- if (data['questions'].length > 0){
- $('#pager').toggle(data['paginator'] !== '').html(data['paginator']);
- $('#questionCount').html(data['question_counter']);
- render_search_tags(data['query_data']['tags'], data['query_string']);
- if(data['faces'].length > 0) {
- $('#contrib-users > a').remove();
- $('#contrib-users').append(data['faces'].join(''));
- }
- 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
- $("#ContentLeft a.rss:first").attr("href", data['feed_url']);
+FullTextSearch.prototype.updateToolTip = function() {
+ var query = this.getSearchQuery();
+ if (query === '') {
+ this._toolTip.show();
+ } else {
+ this._toolTip.hide();
+ }
+};
+
+/**
+ * keydown handler operates on the tooltip and the X button
+ * keyup is not good enough, because in that case
+ * tooltip will be displayed with the input box simultaneously
+ */
+FullTextSearch.prototype.makeKeyDownHandler = function() {
+ var me = this;
+ var toolTip = this._toolTip;
+ var xButton = this._xButton;
+ var dropMenu = this._dropMenu;
+ return function(e) {//don't like the keyup delay to
+ var keyCode = getKeyCode(e);
+
+ if (keyCode === 27) {//escape key
+ if (dropMenu.isOpen() === false) {
+ me.reset();
+ return false;
}
+ }
- // Patch scope selectors
- $('#scopeWrapper > a.scope-selector').each(function(index) {
- var old_qs = $(this).attr('href').replace(search_url, '');
- var scope = QSutils.get_query_string_selector_value(old_qs, 'scope');
- qs = QSutils.patch_query_string(data['query_string'], 'scope:' + scope);
- $(this).attr('href', search_url + qs);
- });
-
- // Patch "Ask your question"
- var askButton = $('#askButton');
- 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();
- new_list.attr('id', q_list_sel);
- new_list.fadeIn(400);
- });
+ var query = me.getSearchQuery();
+ if (query.length === 0) {
+ if (keyCode !== 8 && keyCode !== 48) {//del and backspace
+ toolTip.hide();
+ //xButton.show();//causes a jump of search input...
+ }
+ } else {
+ me.updateToolTip();
+ me.refreshXButton();
}
};
+};
+
+FullTextSearch.prototype.decorate = function(element) {
+ this._element = element;/* this is a bit artificial we don't use _element */
+ this._query = element;
+ this._xButton = $('input[name=reset_query]');
+ this._prevText = this.getSearchQuery();
+ this._tag_warning_box = new TagWarningBox();
+
+ var toolTip = new InputToolTip();
+ toolTip.setClickHandler(function() {
+ element.focus();
+ });
+ this._element.after(toolTip.getElement());
+ this._toolTip = toolTip;
+
+ var dropMenu = new SearchDropMenu();
+ dropMenu.setAskHandler(this.makeAskHandler());
+ dropMenu.setAskButtonEnabled(this._askButtonEnabled);
+ this._dropMenu = dropMenu;
+ element.parent().after(this._dropMenu.getElement());
+
+ var menuCloser = function(){
+ dropMenu.reset();
+ };
+ $(element).click(function(e){ return false });
+ $(document).click(menuCloser);
- /* *********************************** */
+ //the tag search input is optional in askbot
+ $('#ab-tag-search').parent().before(
+ this._tag_warning_box.getElement()
+ );
- // Wire search tags
+ // make search tags functional
var search_tags = $('#searchTags .tag-left');
+ var searchUrl = this.getSearchUrl();
+ var me = this;
$.each(search_tags, function(idx, element){
var tag = new Tag();
tag.decorate($(element));
//todo: setDeleteHandler and setHandler
//must work after decorate & must have getName
tag.setDeleteHandler(
- function(){
- remove_search_tag(tag.getName(), query_string);
- }
+ function(){
+ me.removeSearchTag(tag.getName(), searchUrl);
+ }
);
});
-
- // Wire X button
- x_button.click(function () {
- restart_query(); /* wrapped in closure because it's not yet defined at this point */
+ // enable x button (search reset)
+ this._xButton.click(function () {
+ /* wrapped in closure because it's not yet defined at this point */
+ me.reset();
});
- refresh_x_button();
+ this.refreshXButton();
- // Wire query box
+ // enable query box
var main_page_eval_handle;
- query.keyup(function(e){
- refresh_x_button();
- if (running === false){
+ this._query.keydown(this.makeKeyDownHandler());
+ this._query.keyup(function(e){
+ me.updateToolTip();
+ me.refreshXButton();
+ if (me.isRunning() === false){
clearTimeout(main_page_eval_handle);
- main_page_eval_handle = setTimeout(eval_query, 400);
+ main_page_eval_handle = setTimeout(
+ function() { me.evalTitleSearchQuery() },
+ 400
+ );
}
});
- activate_tag_search_input();
+ this.activateTagSearchInput();
+ var baseUrl = this._baseUrl;
+ var searchUrl = this.getSearchUrl();
$("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
event.preventDefault();
- update_query_string();
- window.location.href = search_url + query_string;
+ me.updateQueryString();
+ window.location.href = baseUrl + searchUrl;
});
-
- /* *********************************** */
-
- // Hook for tag_selector.js
- liveSearch.refresh = function () {
- send_query();
- };
};
diff --git a/askbot/media/js/live_search_new_thread.js b/askbot/media/js/live_search_new_thread.js
index eedd5fe8..d17951eb 100644
--- a/askbot/media/js/live_search_new_thread.js
+++ b/askbot/media/js/live_search_new_thread.js
@@ -2,7 +2,7 @@
var liveSearchNewThreadInit = function(auto_focus_out) {
var query = $('input#id_title.questionTitleInput');
var prev_text = $.trim(query.val());
- var search_url = askbot['urls']['api_get_questions'];
+ var search_url = askbot['urls']['titleSearch'];
var running = false;
var q_list_sel = 'question-list'; //id of question listing div
@@ -32,7 +32,7 @@ var liveSearchNewThreadInit = function(auto_focus_out) {
var eval_query = function(){
cur_text = $.trim(query.val());
if (cur_text !== prev_text && running === false){
- if (cur_text.length >= minSearchWordLength){
+ if (cur_text.length >= askbot['settings']['minSearchWordLength']){
send_query(cur_text);
} else if (cur_text.length === 0){
restart_query();
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js
index 2534fb21..6ea23566 100644
--- a/askbot/media/js/utils.js
+++ b/askbot/media/js/utils.js
@@ -97,6 +97,18 @@ var showMessage = function(element, msg, where) {
};
})(jQuery);
+/**
+ * @return {number} key code of the event or `undefined`
+ */
+var getKeyCode = function(e) {
+ if (e.which) {
+ return e.which;
+ } else if (e.keyCode) {
+ return e.keyCode;
+ }
+ return undefined;
+};
+
var makeKeyHandler = function(key, callback){
return function(e){
if ((e.which && e.which == key) || (e.keyCode && e.keyCode == key)){
@@ -370,6 +382,30 @@ WrappedElement.prototype.dispose = function(){
/**
* @constructor
+ * a simple link
+ */
+var Link = function() {
+ WrappedElement.call(this);
+};
+inherits(Link, WrappedElement);
+
+Link.prototype.setUrl = function(url) {
+ this._url = url;
+};
+
+Link.prototype.setText = function(text) {
+ this._text = text;
+};
+
+Link.prototype.createDom = function() {
+ var link = this.makeElement('a');
+ this._element = link;
+ link.attr('href', this._url);
+ link.html(this._text);
+};
+
+/**
+ * @constructor
* Widget is a Wrapped element with state
*/
var Widget = function() {
@@ -1497,10 +1533,14 @@ var SelectBox = function(){
this._items = [];
this._select_handler = function(){};//empty default
this._is_editable = false;
- this._item_class = SelectBoxItem;
+ this._item_class = this.setItemClass(SelectBoxItem);
};
inherits(SelectBox, Widget);
+SelectBox.prototype.setItemClass = function(itemClass) {
+ this._item_class = itemClass;
+};
+
SelectBox.prototype.setEditable = function(is_editable) {
this._is_editable = is_editable;
};
@@ -1531,7 +1571,21 @@ SelectBox.prototype.getItemByIndex = function(idx) {
return this._items[idx];
};
-//why do we have these two almost identical methods?
+/**
+ * removes all items
+ */
+SelectBox.prototype.empty = function() {
+ var items = this._items;
+ $.each(items, function(idx, item){
+ item.dispose();
+ });
+ this._items = [];
+};
+
+/*
+ * why do we have these two almost identical methods?
+ * the difference seems to be remove/vs fade out
+ */
SelectBox.prototype.removeItem = function(id){
var item = this.getItem(id);
item.getElement().fadeOut();
@@ -1656,6 +1710,12 @@ SelectBox.prototype.decorate = function(element){
});
};
+SelectBox.prototype.createDom = function() {
+ var element = this.makeElement('ul');
+ this._element = element;
+ element.addClass('select-box');
+};
+
/**
* This is a dropdown list elment
*/
diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less
index 69f4daf7..2f6d601e 100644
--- a/askbot/media/style/style.less
+++ b/askbot/media/style/style.less
@@ -395,45 +395,37 @@ body.user-messages {
border-top:#fcfcfc 1px solid;
margin-bottom:10px;
font-family:@main-font;
+}
- #homeButton{
- border-right:#afaf9e 1px solid;
- .sprites(-6px,-36px);
- height:55px;
- width:43px;
- display:block;
- float:left;
- }
+#homeButton{
+ border-right: #afaf9e 1px solid;
+ .sprites(-6px,-36px);
+ height:55px;
+ width:43px;
+ display:block;
+ float:left;
+}
- #homeButton:hover{
- .sprites(-6px-45,-36px);
- }
-
- #scopeWrapper{
- width:688px;
- float:left;
-
- a{
- display:block;
- float:left;
- }
+#homeButton:hover{
+ .sprites(-51px,-36px);
+}
- .scope-selector{
- font-size:20px;
- color:#7a7a6b;
- height:55px;
- line-height:55px;
- margin-left:16px
- }
+.scope-selector {
+ display:block;
+ float:left;
+ font-size:20px;
+ color:#7a7a6b;
+ height:55px;
+ line-height:55px;
+ margin-left:16px
+}
- .on{
- background:url(../images/scopearrow.png) no-repeat center bottom;
- }
+.scope-selector.on {
+ background:url(../images/scopearrow.png) no-repeat center bottom;
+}
- .ask-message{
- font-size:24px;
- }
- }
+.scope-selector.ask-message {
+ font-size:24px;
}
.validate-email-page {
@@ -456,90 +448,133 @@ body.user-messages {
}
#searchBar { /* Main search form , check widgets/search_bar.html */
- display: inline-block;
+ display: block;
background-color: #fff;
- width: 400px;
border: 1px solid #c9c9b5;
- float:right;
- height:42px;
- margin:6px 0px 0px 15px;
+ height: 41px;
+ z-index: 10000;
+ position: relative;
- .searchInput, .searchInputCancelable{
- font-size: 26px;
- height: 39px;
- line-height: 39px;
+ input.searchInput {
+ font-size: 22px;
+ height: 26px;
+ line-height: 26px;
font-weight:300;
background:#FFF;
border:0px;
color:#484848;
- padding-left:10px;
- padding-top: 1px;
font-family:@body-font;
- vertical-align: top;
- }
-
- .searchInput,{
- width: 340px;
+ width: 100%;
+ margin: 8px 0 6px 0;
+ padding: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
}
- .searchInputCancelable {
- width: 305px;
+ div.input-tool-tip {
+ margin-top: -40px;
+ padding-top: 10px;
+ height: 30px;
+ line-height: 20px;
+ font-size: 20px;
+ font-style: italic;
}
+}
- .logoutsearch {
- width: 337px;
- }
+.search-drop-menu {
+ box-sizing: border-box;
+ background: whitesmoke;
+ border: 1px solid #c9c9b5;
+ border-top: none;
+ margin: 0;
+ position: relative;
+ top: 0;
+ z-index: 10000;
- .searchBtn {
- font-size: 10px;
- color: #666;
- background-color: #eee;
- height: 42px;
- border:#FFF 1px solid;
- line-height: 22px;
- text-align: center;
- float:right;
- margin: 0px;
- width:48px;
- .sprites(-98px,-36px);
- cursor:pointer;
+ ul {
+ list-style: none;
+ overflow: auto;
+ padding: 0 0 10px 0;
+ margin: 0 0 20px 0;
+ position: relative;
+ li {
+ padding: 5px 10px;
+ position: relative;
+ a {
+ text-decoration: none;
+ }
+ }
+ li.selected {
+ background: #08c;
+ a {
+ color: whitesmoke;
+ }
+ }
}
- .searchBtn:hover {
- .sprites(-98px-48,-36px);
+ ul.empty {
+ padding: 5px;
+ margin: 0;
}
- .cancelSearchBtn {
- font-size: 30px;
- color: #ce8888;
- background:#fff;
- height: 42px;
- line-height: 42px;
- border:0px;
- border-left:#deded0 1px solid;
+ .footer {
text-align: center;
- width: 35px;
- cursor:pointer;
+ padding-bottom: 10px;
}
+}
- .cancelSearchBtn:hover {
- color: #d84040;
- }
+.input-tool-tip {
+ color: #999;
+}
+.input-tool-tip.dimmed {
+ color: #ccc;
}
-body.anon {
- #searchBar {
- width: 500px;
- .searchInput {
- width: 435px;
- }
+input[type="submit"].searchBtn {
+ font-size: 10px;
+ color: #666;
+ background-color: #eee;
+ height: 41px;
+ border:#FFF 1px solid;
+ line-height: 22px;
+ text-align: center;
+ float:right;
+ margin: 7px 28px 0 0;
+ width: 48px;
+ .sprites(-98px,-36px);
+ cursor:pointer;
+ position: relative;
+ z-index: 10001;
+}
+.ask-page input[type="submit"].searchBtn {
+ display: none;
+}
- .searchInputCancelable {
- width: 405px;
- }
- }
+.searchBtn:hover {
+ .sprites(-98px-48,-36px);
}
+.cancelSearchBtn {
+ font-size: 30px;
+ color: #ce8888;
+ background:#fff;
+ height: 41px;
+ line-height: 42px;
+ border:0px;
+ border-left:#deded0 1px solid;
+ text-align: center;
+ width: 35px;
+ cursor:pointer;
+ float: right;
+ margin-top: 7px;
+ position: relative;
+ z-index: 10001;
+}
+
+.cancelSearchBtn:hover {
+ color: #d84040;
+}
#askButton{ /* check blocks/secondary_header.html and widgets/ask_button.html*/
line-height:44px;
@@ -554,6 +589,37 @@ body.anon {
.button-style-hover;
}
+/*
+ Put the secondary navigation together:
+ 1) raise the search bar by 55px
+ 2) add padding to fit the buttons
+*/
+#searchBar {
+ margin: 0 228px 0 327px;
+ width: auto;
+ margin-top: -49px;
+ padding: 0 49px 0 8px;
+}
+/* line up drop menu the same way as the search bar */
+.search-drop-menu {
+ margin: 0 228px 0 327px;
+ width: auto;
+}
+.ask-page .search-drop-menu,
+body.anon.ask-page .search-drop-menu {
+ margin: 0;
+}
+body.anon {
+ #searchBar,
+ .search-drop-menu {
+ margin-left: 227px;/* we don't have the "followed" scope */
+ }
+}
+#searchBar.cancelable {
+ padding-right: 82px;
+}
+
+
/* ----- Content layout, check two_column_body.html or one_column_body.html ----- */
#ContentLeft {
@@ -1423,10 +1489,11 @@ ul#related-tags li {
#askFormBar {
display:inline-block;
- padding: 4px 7px 0px 0px;
+ padding: 4px 0 0 0;
margin-top:0px;
+ width: 100%;
- p{
+ p {
margin:0 0 5px 0;
font-size:14px;
color:@info-text-dark;
@@ -1436,10 +1503,10 @@ ul#related-tags li {
font-size: 24px;
height: 36px;
line-height: 36px;
- margin: 0px;
- padding: 0px 0 0 5px;
+ margin: 0;
+ padding: 0;/*-left: 5px;*/
border:#cce6ec 3px solid;
- width:719px;
+ width: 100%;/*719px;*/
}
}
@@ -1483,11 +1550,13 @@ ul#related-tags li {
}
#id_tags {
- border:#cce6ec 3px solid;
- height:25px;
- padding-left:5px;
- font-size:14px;
- width:395px;
+ box-sizing: border-box;
+ border: #cce6ec 3px solid;
+ height: 31px;
+ padding-left: 5px;
+ font-size: 14px;
+ width: 100%;
+ max-width: 395px;
}
}
@@ -1646,9 +1715,14 @@ ul#related-tags li {
.edit-answer-page {
.wmd-container {
width: 723px;
+ width: 100%;
}
#editor {
- width: 710px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
padding: 6px;
}
.retagger-buttons {
@@ -1784,6 +1858,7 @@ ul#related-tags li {
font-size:14px;
margin-top:5px;
margin-bottom:5px;
+ width: 100%;
}
#id_title{
font-size: 24px;
@@ -1792,7 +1867,7 @@ ul#related-tags li {
margin: 0px;
padding: 0px 0 0 5px;
border:#cce6ec 3px solid;
- width: 719px;
+ width: 100%;
margin-bottom:10px;
}
#id_summary{
@@ -1838,7 +1913,7 @@ ul#related-tags li {
vertical-align: top;
}
- .question-content{
+ .question-content {
float:right;
width:682px;
margin-bottom:10px;
@@ -2511,7 +2586,10 @@ ul#related-tags li {
form{
margin-bottom:15px;
}
- input[type="text"],input[type="password"],select{
+
+ input[type="text"],
+ input[type="password"],
+ select{
border:#cce6ec 3px solid;
height:25px;
line-height: 25px;
@@ -3756,24 +3834,12 @@ pre.prettyprint { clear:both;padding: 3px; border: 0px solid #888; }
/* language-specific fixes */
body.lang-es {
#searchBar {
- width: 398px;
- .searchInput {
- width: 337px;
- }
- .searchInputCancelable {
- width: 302px;
- }
+ /* need special left padding */
}
}
body.anon.lang-es {
#searchBar {
- width: 485px;
- .searchInput {
- width: 425px;
- }
- .searchInputCancelable {
- width: 390px;
- }
+ /* need special left padding */
}
}
@@ -4007,6 +4073,12 @@ textarea.tipped-input {
/* modifications for small screens */
@media screen and (max-width: 960px) {/* content margins touch viewport */
+ #homeButton {
+ .sprites(1px,-36px);
+ }
+ #homeButton:hover {
+ .sprites(-44px,-36px);
+ }
}
@media screen and (max-width: 480px) {
.content-wrapper {
@@ -4018,27 +4090,154 @@ textarea.tipped-input {
#ContentLeft {
width: 100%;
}
- #secondaryHeader #scopeWrapper {
+ .main-page h1,
+ #askButton,
+ #metaNav #navBadges,
+ .user-info,
+ .copyright,
+ .counts .views,
+ .counts .votes,
+ .help,
+ .rss,
+ .scope-selector,
+ .settings,
+ .tabBar,
+ .tags,
+ .userinfo,
+ .widgets {
display: none;
}
- #askButton {
- display: block;
- float: none;
- margin: auto;
- margin-top: 5px;
+
+ .ask-page,
+ .edit-question-page {
+ input[type="submit"].searchBtn {
+ display: none;
+ }
}
- #homeButton {
+
+ .ask-page,
+ .edit-answer-page,
+ .edit-question-page {
+ .preview-toggle,
+ .proxy-user-info,
+ .answer-options,
+ .question-options,
+ .revision-comment,
+ .wmd-preview,
+ #wmd-hr-button,
+ #wmd-heading-button {
+ display: none;
+ }
+ }
+
+ .edit-answer-page,
+ .edit-question-page {
+ label[for="id_title"],
+ label[for="id_revision"],
+ #id_revision {
+ display: none;
+ }
+ #fmedit #id_title {
+ margin: 15px 0 0 0;
+ }
}
- .main-page {
- h1,
- .counts .views,
- .counts .votes,
- .rss,
- .tabBar,
- .tags,
- .userinfo {
+
+ .question-page {
+ .comment-votes {
display: none;
}
+ .comments {
+ form.post-comments {
+ margin: 0 10px 0 0;
+ }
+ .comment .comment-body {
+ margin-left: 5px;
+ }
+ }
+ .post-update-info-container {
+ float: none;
+ width: 100%;
+ }
+ .post-update-info {
+ float: none;
+ margin-left: 0;
+ width: 100%-5;
+
+ br,
+ .badge1,
+ .badge2,
+ .badge3,
+ .gravatar,
+ .reputation-score,
+ .badge-count {
+ display: none;
+ }
+ }
+ .question-content,
+ ul.post-retag input {
+ width: 100%-12;
+ }
+ .answer-table,
+ #question-table {
+ width: 100%-15;
+ }
+ }
+
+ .users-page {
+ .userList td {
+ display: block;
+ width: 100%;
+ .user {
+ width: 100%;
+ }
+ }
+ }
+
+ .user-profile-page {
+ td {
+ display: block;
+ }
+ }
+
+ .footer-links,
+ .powered-link {
+ text-align: center;
+ width: 100%;
+ }
+
+ #userToolsNav {
+ margin-left: 10px;
+ }
+
+ #metaNav {
+ float: left;
+ a#navUsers,
+ a#navTags,
+ a#navGroups {
+ background: none;
+ color: #d0e296;
+ font-size: 16px;
+ text-decoration: underline;
+ margin-left: 20px;
+ padding-left: 0;
+ }
+ }
+ .powered-link {
+ margin-bottom: 15px;
+ }
+ .short-summary:first-child {
+ padding-top: 0;
+ }
+ #searchBar,
+ body.anon #searchBar {
+ margin: -49px 8px 0 52px;
+ }
+ .search-drop-menu,
+ body.anon .search-drop-menu {
+ margin: 0 8px 0 52px;
+ }
+ input[type="submit"].searchBtn {
+ margin-right: 8px;
}
.short-summary {
width: 100%;
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 5c0d5732..3e908167 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -42,6 +42,14 @@ class ThreadQuerySet(models.query.QuerySet):
groups = [Group.objects.get_global_group()]
return self.filter(groups__in=groups).distinct()
+ def get_for_title_query(self, search_query):
+ """returns threads matching title query
+ todo: possibly add tags
+ todo: implement full text search on relevant fields
+ """
+ return self.filter(title__icontains=search_query)
+
+
class ThreadManager(BaseQuerySetManager):
def get_query_set(self):
@@ -174,6 +182,7 @@ class ThreadManager(BaseQuerySetManager):
def get_for_query(self, search_query, qs=None):
"""returns a query set of questions,
matching the full text query
+ todo: move to query set
"""
if getattr(django_settings, 'ENABLE_HAYSTACK_SEARCH', False):
from askbot.search.haystack import AskbotSearchQuerySet
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index a02f1577..7b6b746c 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -170,10 +170,16 @@ class SearchState(object):
SAFE_CHARS = const.TAG_SEP + '_+.-'
def query_string(self):
+ """returns part of the url to the main page,
+ responsible to display the full text search results,
+ taking into account sort method, selected scope
+ and search tags"""
+
lst = [
'scope:' + self.scope,
'sort:' + self.sort
]
+
if self.query:
lst.append('query:' + urllib.quote(smart_str(self.query), safe=self.SAFE_CHARS))
if self.tags:
diff --git a/askbot/templates/answer_edit.html b/askbot/templates/answer_edit.html
index 20c0684d..887714cb 100644
--- a/askbot/templates/answer_edit.html
+++ b/askbot/templates/answer_edit.html
@@ -25,6 +25,7 @@
editor_type = settings.EDITOR_TYPE
)
}}
+ <div class="answer-options">
{% if settings.WIKI_ON and answer.wiki == False %}
{{ macros.checkbox_in_div(form.wiki) }}
{% endif %}
@@ -34,6 +35,7 @@
%}
{{ macros.checkbox_in_div(form.post_privately) }}
{% endif %}
+ </div>
<div class="after-editor">
<input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
<input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
diff --git a/askbot/templates/ask.html b/askbot/templates/ask.html
index 27434f83..5e54ad6f 100644
--- a/askbot/templates/ask.html
+++ b/askbot/templates/ask.html
@@ -20,11 +20,6 @@
<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
{% endif %}
- <script type='text/javascript'>
- var sortMethod = undefined;//need for live_search
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
- </script>
- <script type='text/javascript' src='{{"/js/live_search_new_thread.js"|media}}'></script>
{% include "meta/editor_data.html" %}
{% if mandatory_tags %}
{% include "meta/mandatory_tags_js.html" %}
@@ -33,7 +28,6 @@
{% include "meta/category_tree_js.html" %}
{% endif %}
<script type='text/javascript'>
- askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
askbot['urls']['saveDraftQuestion'] = '{% url save_draft_question %}';
{% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
var codeFriendlyMarkdown = true;
@@ -41,7 +35,6 @@
var codeFriendlyMarkdown = false;
{% endif %}
$().ready(function(){
- liveSearchNewThreadInit();
//set current module button style
$('#editor').TextAreaResizer();
//highlight code synctax when editor has new text
diff --git a/askbot/templates/base.html b/askbot/templates/base.html
index 63d7115f..ffe3bf84 100644
--- a/askbot/templates/base.html
+++ b/askbot/templates/base.html
@@ -9,6 +9,7 @@
<meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS|escape}}" />
{% if settings.GOOGLE_SITEMAP_CODE %}
<meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
{% endif %}
<link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" />
{% block before_css %}{% endblock %}
diff --git a/askbot/templates/embed/ask_by_widget.html b/askbot/templates/embed/ask_by_widget.html
index 4cec5f6d..ef139d1c 100644
--- a/askbot/templates/embed/ask_by_widget.html
+++ b/askbot/templates/embed/ask_by_widget.html
@@ -213,13 +213,15 @@
<script type="text/javascript" src='{{"/js/live_search_new_thread.js"|media}}'></script>
<script type="text/javascript" charset="utf-8">
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
- askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
+ askbot['settings']['minSearchWordLength'] = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ askbot['urls']['titleSearch'] = '{% url title_search %}';
askbot['urls']['upload'] = '{% url upload %}';
$(document).ready(function(){
- $("#id_title").focus();
- $("#id_title").addClass('questionTitleInput');
- liveSearchNewThreadInit(true);
+ var searchInput = $('#id_title');
+ searchInput.addClass('questionTitleInput');
+ var search = new FullTextSearch();
+ search.decorate(searchInput);
+ searchInput.focus();
});
</script>
{% endblock %}
diff --git a/askbot/templates/macros.html b/askbot/templates/macros.html
index 8e578dec..f2194a9d 100644
--- a/askbot/templates/macros.html
+++ b/askbot/templates/macros.html
@@ -498,11 +498,11 @@ for the purposes of the AJAX comment editor #}
title="{{desc_tooltip}}"><span>{{label}}</span></a>
{% endif %}
<script type="text/javascript">{# need to pass on text translations to js #}
- var sortButtonData = sortButtonData || {};
- sortButtonData["{{key_name}}"] = {
- label: "{{label}}",
- asc_tooltip: "{{asc_tooltip}}",
- desc_tooltip: "{{desc_tooltip}}"
+ askbot['data']['sortButtonData'] = askbot['data']['sortButtonData'] || {};
+ askbot['data']['sortButtonData']['{{key_name}}'] = {
+ label: '{{label}}',
+ asc_tooltip: '{{asc_tooltip}}',
+ desc_tooltip: '{{desc_tooltip}}'
};
</script>
{%- endmacro %}
diff --git a/askbot/templates/main_page/javascript.html b/askbot/templates/main_page/javascript.html
index f1e0fb44..bb7190ce 100644
--- a/askbot/templates/main_page/javascript.html
+++ b/askbot/templates/main_page/javascript.html
@@ -1,12 +1,9 @@
<script type="text/javascript">
/*<![CDATA[*/
- var sortMethod = '{{sort}}';
- var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ askbot['settings']['showSortByRelevance'] = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
$(document).ready(function(){
/*var on_tab = '#nav_questions';
$(on_tab).attr('className','on');*/
- liveSearch('{{ search_state.query_string()|escapejs }}');
Hilite.exact = false;
Hilite.elementid = "question-list";
Hilite.debug_referrer = location.href;
@@ -48,4 +45,3 @@
{% if request.user.is_authenticated() %}
<script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
{% endif %}
-<script type="text/javascript" src='{{"/js/live_search.js"|media}}'></script>
diff --git a/askbot/templates/main_page/tab_bar.html b/askbot/templates/main_page/tab_bar.html
index 37f63012..c86abd89 100644
--- a/askbot/templates/main_page/tab_bar.html
+++ b/askbot/templates/main_page/tab_bar.html
@@ -33,8 +33,8 @@
</a>
{% endif %}
<script type="text/javascript">
- var sortButtonData = sortButtonData || {};
- sortButtonData['relevance'] = {
+ var askbot['data']['sortButtonData'] = askbot['data']['sortButtonData'] || {};
+ askbot['data']['sortButtonData']['relevance'] = {
asc_tooltip: "{{asc_relevance_tooltip}}",
desc_tooltip: "{{desc_relevance_tooltip}}",
label: "{{relevance_label}}"
diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html
index b3fcd815..24c2ba10 100644
--- a/askbot/templates/meta/bottom_scripts.html
+++ b/askbot/templates/meta/bottom_scripts.html
@@ -24,8 +24,11 @@
askbot['urls']['follow_user'] = '/followit/follow/user/{{'{{'}}userId{{'}}'}}/';
askbot['urls']['unfollow_user'] = '/followit/unfollow/user/{{'{{'}}userId{{'}}'}}/';
askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
- askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}';
askbot['urls']['getEditor'] = '{% url "get_editor" %}';
+ askbot['urls']['titleSearch'] = '{% url "title_search" %}';
+ askbot['urls']['ask'] = '{% url "ask" %}';
+ askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}';
+ askbot['settings']['minSearchWordLength'] = {{settings.MIN_SEARCH_WORD_LENGTH}};
</script>
<script
type="text/javascript"
@@ -39,6 +42,7 @@
<!-- History.js -->
<script type='text/javascript' src="{{"/js/jquery.history.js"|media }}"></script>
<script type='text/javascript' src="{{"/js/utils.js"|media }}"></script>
+<script type="text/javascript" src="{{'/js/live_search.js'|media}}"></script>
{% if settings.ENABLE_MATHJAX %}
<script type='text/javascript' src="{{settings.MATHJAX_BASE_URL}}/MathJax.js">
MathJax.Hub.Config({
@@ -52,13 +56,34 @@
/*<![CDATA[*/
$(document).ready(function(){
// focus input on the search bar endcomment
- {% if active_tab in ('users', 'questions', 'tags') %}
- $('#keywords').focus();
+ {% if active_tab in ('users', 'questions', 'tags', 'badges') %}
+ var searchInput = $('#keywords');
{% elif active_tab == 'ask' %}
- $('#id_title').focus();
+ var searchInput = $('#id_title');
{% else %}
+ var searchInput = undefined;
animateHashes();
{% endif %}
+
+ if (searchInput) {
+ searchInput.focus();
+ }
+
+ {% if active_tab in ('questions', 'badges', 'ask') %}
+ if (searchInput) {
+ var search = new FullTextSearch();
+ {% if search_state %}
+ search.setSearchUrl('{{ search_state.query_string()|escapejs }}');
+ {% else %}
+ search.setSearchUrl('');
+ {% endif %}
+ {% if active_tab == 'ask' %}
+ search.setAskButtonEnabled(false);
+ {% endif %}
+ search.decorate(searchInput);
+ }
+ {% endif %}
+
if (askbot['data']['userIsAdminOrMod']) {
$('body').addClass('admin');
}
diff --git a/askbot/templates/widgets/edit_post.html b/askbot/templates/widgets/edit_post.html
index b9bfa1e3..57770570 100644
--- a/askbot/templates/widgets/edit_post.html
+++ b/askbot/templates/widgets/edit_post.html
@@ -64,7 +64,7 @@
</div>
{% endif %}
{% if 'summary' in post_form['fields'] %}
- <div class="form-item">
+ <div class="form-item revision-comment">
<strong>{{ post_form.summary.label_tag() }}</strong> <br/>
{{ post_form.summary }}
<div class="title-desc">
diff --git a/askbot/templates/widgets/scope_nav.html b/askbot/templates/widgets/scope_nav.html
index a6bda630..b68d899c 100644
--- a/askbot/templates/widgets/scope_nav.html
+++ b/askbot/templates/widgets/scope_nav.html
@@ -1,3 +1,4 @@
+<div id="scopeNav">
{% if active_tab != "ask" %}
{% if not search_state %} {# get empty SearchState() if there's none #}
{% set search_state=search_state|get_empty_search_state %}
@@ -13,3 +14,4 @@
{% else %}
<div class="scope-selector ask-message">{% trans %}Please ask your question here{% endtrans %}</div>
{% endif %}
+</div>
diff --git a/askbot/templates/widgets/search_bar.html b/askbot/templates/widgets/search_bar.html
index 59c4fd58..8c485c73 100644
--- a/askbot/templates/widgets/search_bar.html
+++ b/askbot/templates/widgets/search_bar.html
@@ -1,17 +1,7 @@
{% if active_tab != "ask" %}
{% spaceless %}
-<div id="searchBar">
+<div id="searchBar" {% if query %}class="cancelable"{% endif %}>
{# url action depends on which tab is active #}
- <form
- {% if active_tab == "tags" %}
- action="{% url tags %}"
- {% elif active_tab == "users" %}
- action="{% url users %}"
- {% else %}
- action="{% url questions %}" id="searchForm"
- {% endif %}
- method="get">
- <input type="submit" value="" name="search" class="searchBtn" />
{% if active_tab == "tags" %}
<input type="hidden" name="t" value="tag"/>
{% else %}
@@ -21,26 +11,13 @@
{% endif %}
{# class was searchInput #}
<input
- {% if query %}
- class="searchInputCancelable"
- {% else %}
class="searchInput"
- {% endif %}
type="text"
autocomplete="off"
value="{{ query|default_if_none('') }}"
name="query"
id="keywords"
/>
- <input type="button"
- value="X"
- name="reset_query"
- class="cancelSearchBtn"
- {% if not query %}{# query is only defined by questions view (active_tab) #}
- style="display: none;"
- {% endif %}
- />
- </form>
</div>
{% endspaceless %}
{% endif %}
diff --git a/askbot/templates/widgets/secondary_header.html b/askbot/templates/widgets/secondary_header.html
index caf190bc..f0aca706 100644
--- a/askbot/templates/widgets/secondary_header.html
+++ b/askbot/templates/widgets/secondary_header.html
@@ -1,12 +1,45 @@
<!-- template secondary_header.html -->
<div id="secondaryHeader">
<div class="content-wrapper">
- <a id="homeButton" href="{% url questions %}"></a>
- <div id="scopeWrapper">
- {% include "widgets/scope_nav.html" %}
+ {# form is wrapping search buttons and the search bar inputs #}
+ <form
+ {% if active_tab == "tags" %}
+ action="{% url tags %}"
+ {% elif active_tab == "users" %}
+ action="{% url users %}"
+ {% else %}
+ action="{% url questions %}" id="searchForm"
+ {% endif %}
+ method="get">
+ <div>
+ {#
+ Some or all contents of this div may be dropped
+ over the search bar via negative margins,
+ to make sure that the search bar can occupy 100%
+ of the content width.
+ Search bar may have padding on the left and right
+ to accomodate the buttons.
+ #}
+ <a id="homeButton" href="{% url questions %}"></a>
+ {% include "widgets/scope_nav.html" %}
+ {#
+ three buttons below are in the opposite order because
+ they are floated at the right
+ #}
+ {% include "widgets/ask_button.html" %}
+ <input type="submit" value="" name="search" class="searchBtn" />
+ <input type="button"
+ value="X"
+ name="reset_query"
+ class="cancelSearchBtn"
+ {% if not query %}{# query is only defined by questions view (active_tab) #}
+ style="display: none;"
+ {% endif %}
+ />
+ {# clears button floats #}
+ <div class="clearfix"></div>
+ </div>
{% include "widgets/search_bar.html" %} {# include search form widget #}
- </div>
- {% include "widgets/ask_button.html" %}
- <div class="clean"></div>
+ </form>
</div>
</div>
diff --git a/askbot/templates/widgets/user_navigation.html b/askbot/templates/widgets/user_navigation.html
index 06b0cdb9..4cb6314a 100644
--- a/askbot/templates/widgets/user_navigation.html
+++ b/askbot/templates/widgets/user_navigation.html
@@ -20,7 +20,7 @@
<a href="{{ settings.LOGIN_URL }}?next={{request.path|clean_login_url}}">{% trans %}Hi there! Please sign in{% endtrans %}</a>
{% endif %}
{% if request.user.is_authenticated() and request.user.is_administrator() %}
- <a href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
- <a href="{% url widgets %}">{% trans %}widgets{% endtrans %}</a>
+ <a class="settings" href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
+ <a class="widgets" href="{% url widgets %}">{% trans %}widgets{% endtrans %}</a>
{% endif %}
- <a href="{% url "help" %}" title="{% trans %}help{% endtrans %}">{% trans %}help{% endtrans %}</a>
+ <a class="help" href="{% url "help" %}" title="{% trans %}help{% endtrans %}">{% trans %}help{% endtrans %}</a>
diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py
index 6c820fef..73a646d6 100644
--- a/askbot/tests/page_load_tests.py
+++ b/askbot/tests/page_load_tests.py
@@ -153,14 +153,14 @@ class PageLoadTestCase(AskbotTestCase):
self.proto_test_ask_page(True, 200)
@with_settings(GROUPS_ENABLED=False)
- def test_api_get_questions_groups_disabled(self):
- data = {'query': 'Question'}
- response = self.client.get(reverse('api_get_questions'), data)
+ def test_title_search_groups_disabled(self):
+ data = {'query_text': 'Question'}
+ response = self.client.get(reverse('title_search'), data)
data = simplejson.loads(response.content)
self.assertTrue(len(data) > 1)
@with_settings(GROUPS_ENABLED=True)
- def test_api_get_questions_groups_enabled(self):
+ def test_title_search_groups_enabled(self):
group = models.Group(name='secret group', openness=models.Group.OPEN)
group.save()
@@ -169,14 +169,14 @@ class PageLoadTestCase(AskbotTestCase):
question = self.post_question(user=user, title='alibaba', group_id=group.id)
#ask for data anonymously - should get nothing
- query_data = {'query': 'alibaba'}
- response = self.client.get(reverse('api_get_questions'), query_data)
+ query_data = {'query_text': 'alibaba'}
+ response = self.client.get(reverse('title_search'), query_data)
response_data = simplejson.loads(response.content)
self.assertEqual(len(response_data), 0)
#log in - should get the question
self.client.login(method='force', user_id=user.id)
- response = self.client.get(reverse('api_get_questions'), query_data)
+ response = self.client.get(reverse('title_search'), query_data)
response_data = simplejson.loads(response.content)
self.assertEqual(len(response_data), 1)
diff --git a/askbot/urls.py b/askbot/urls.py
index 4694b38c..4fd63658 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -74,9 +74,9 @@ urlpatterns = patterns('',
# END main page urls
url(
- r'^api/get_questions/',
- views.commands.api_get_questions,
- name='api_get_questions'
+ r'^api/title_search/',
+ views.commands.title_search,
+ name='title_search'
),
url(
r'^get-thread-shared-users/',
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index de5bb12b..c901b6c6 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -696,31 +696,30 @@ def subscribe_for_tags(request):
@decorators.get_only
-def api_get_questions(request):
- """json api for retrieving questions"""
- query = request.GET.get('query', '').strip()
- if not query:
+def title_search(request):
+ """json api for retrieving questions by title match"""
+ query = request.GET.get('query_text')
+
+ if query is None:
return HttpResponseBadRequest('Invalid query')
+ query = query.strip()
+
if askbot_settings.GROUPS_ENABLED:
threads = models.Thread.objects.get_visible(user=request.user)
else:
threads = models.Thread.objects.all()
- threads = models.Thread.objects.get_for_query(
- search_query=query,
- qs=threads
- )
-
- if should_show_sort_by_relevance():
- threads = threads.extra(order_by = ['-relevance'])
+ threads = threads.get_for_title_query(query)
#todo: filter out deleted threads, for now there is no way
threads = threads.distinct()[:30]
+
thread_list = [{
'title': escape(thread.title),
'url': thread.get_absolute_url(),
'answer_count': thread.get_answer_count(request.user)
} for thread in threads]
+
json_data = simplejson.dumps(thread_list)
return HttpResponse(json_data, mimetype = "application/json")