summaryrefslogtreecommitdiffstats
path: root/askbot/media/js/live_search.js
diff options
context:
space:
mode:
Diffstat (limited to 'askbot/media/js/live_search.js')
-rw-r--r--askbot/media/js/live_search.js1016
1 files changed, 719 insertions, 297 deletions
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();
- };
};