Skip to content
Permalink
Browse files Browse the repository at this point in the history
added instant search to the tags page
  • Loading branch information
evgenyfadeev committed Mar 31, 2013
1 parent 0459ee4 commit 876e366
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 48 deletions.
1 change: 1 addition & 0 deletions askbot/doc/source/changelog.rst
Expand Up @@ -3,6 +3,7 @@ Changes in Askbot

Development version
-------------------
* Added instant search to the tags page
* Added a placeholder template for the custom javascript on the question page
* Allowed to disable the big "ask" button.
* Some support for the media compression (Tyler Mandry)
Expand Down
143 changes: 142 additions & 1 deletion askbot/media/js/live_search.js
Expand Up @@ -267,6 +267,7 @@ TagWarningBox.prototype.showWarning = function(){
*/
var InputToolTip = function() {
WrappedElement.call(this);
this._promptText = gettext('search or ask your question');
};
inherits(InputToolTip, WrappedElement);

Expand All @@ -284,6 +285,10 @@ InputToolTip.prototype.dim = function() {
this._element.addClass('dimmed');
};

InputToolTip.prototype.setPromptText = function(text) {
this._promptText = text;
};

InputToolTip.prototype.setClickHandler = function(handler) {
this._clickHandler = handler;
};
Expand All @@ -292,7 +297,7 @@ InputToolTip.prototype.createDom = function() {
var element = this.makeElement('div');
this._element = element;
element.addClass('input-tool-tip');
element.html(gettext('search or ask your question'));
element.html(this._promptText);
this.decorate(element);
};

Expand Down Expand Up @@ -882,3 +887,139 @@ FullTextSearch.prototype.decorate = function(element) {

$("form#searchForm").submit(me.makeFormSubmitHandler());
};

/**
* @constructor
*/
var TagSearch = function() {
WrappedElement.call(this);
this._isRunning = false;
};
inherits(TagSearch, WrappedElement);

TagSearch.prototype.getQuery = function() {
return $.trim(this._element.val());
};

TagSearch.prototype.setQuery = function(val) {
this._element.val(val);
};

TagSearch.prototype.getSort = function() {
//todo: read it off the page
var link = $('.tabBar a.on');
if (link.length === 1) {
var sort = link.attr('id').replace('sort_', '');
if (sort === 'name' || sort === 'used') {
return sort;
}
}
return 'name';
};

TagSearch.prototype.getIsRunning = function() {
return this._isRunning;
};

TagSearch.prototype.setIsRunning = function(val) {
this._isRunning = val;
};

TagSearch.prototype.renderResult = function(html) {
this._contentBox.html(html);
};

TagSearch.prototype.runSearch = function() {
var data = {
'query': this.getQuery(),
'sort': this.getSort(),
'page': '1'
};
var me = this;
$.ajax({
dataType: 'json',
data: data,
cache: false,
url: askbot['urls']['tags'],
success: function(data) {
if (data['success']) {
me.renderResult(data['html']);
me.setIsRunning(false);
}
},
error: function() { me.setIsRunning(false); }
});
me.setIsRunning(true);
};

TagSearch.prototype.getToolTip = function() {
return this._toolTip;
};

TagSearch.prototype.makeKeyUpHandler = function() {
var me = this;
return function(evt) {
var keyCode = getKeyCode(evt);
if (me.getIsRunning() === false) {
me.runSearch();
}
};
};

TagSearch.prototype.makeKeyDownHandler = function() {
var me = this;
var xButton = this._xButton;
return function(evt) {
var query = me.getQuery();
var keyCode = getKeyCode(evt);
var toolTip = me.getToolTip();
if (keyCode === 27) {//escape
me.setQuery('');
toolTip.show();
xButton.hide();
return;
}
if (keyCode === 8 || keyCode === 48) {//del or backspace
if (query.length === 1) {
toolTip.show();
xButton.hide();
}
} else {
toolTip.hide();
xButton.show();
}
};
};

TagSearch.prototype.reset = function() {
if (this.getIsRunning() === false) {
this.setQuery('');
this._toolTip.show();
this._xButton.hide();
this.runSearch();
this._element.focus();
}
};

TagSearch.prototype.decorate = function(element) {
this._element = element;
this._contentBox = $('#ContentLeft');
this._xButton = $('input[name=reset_query]');
element.keyup(this.makeKeyUpHandler());
element.keydown(this.makeKeyDownHandler());

var me = this;
this._xButton.click(function(){ me.reset() });

var toolTip = new InputToolTip();
toolTip.setPromptText(askbot['data']['tagSearchPromptText']);
toolTip.setClickHandler(function() {
element.focus();
});
element.after(toolTip.getElement());
//below is called after getElement, b/c element must be defined
if (this.getQuery() !== '') {
toolTip.hide();//hide if search query is not empty
}
this._toolTip = toolTip;
};
1 change: 0 additions & 1 deletion askbot/media/style/style.css
Expand Up @@ -547,7 +547,6 @@ input[type="submit"].searchBtn {
z-index: 10001;
}
.groups-page input[type="submit"].searchBtn,
.tags-page input[type="submit"].searchBtn,
.badges-pages input[type="submit"].searchBtn,
.user-profile-page input[type="submit"].searchBtn,
.meta input[type="submit"].searchBtn,
Expand Down
1 change: 0 additions & 1 deletion askbot/media/style/style.less
Expand Up @@ -592,7 +592,6 @@ input[type="submit"].searchBtn {
}

.groups-page, /* todo: clean up - should not need this */
.tags-page,
.badges-pages,
.user-profile-page,
.meta,
Expand Down
3 changes: 3 additions & 0 deletions askbot/templates/meta/bottom_scripts.html
Expand Up @@ -84,6 +84,9 @@
search.setAskButtonEnabled(false);
}
search.decorate(searchInput);
} else if (activeTab === 'tags') {
var search = new TagSearch();
search.decorate(searchInput);
}

if (askbot['data']['userIsAdminOrMod']) {
Expand Down
39 changes: 3 additions & 36 deletions askbot/templates/tags.html
@@ -1,43 +1,8 @@
{% extends "two_column_body.html" %}
{% import "macros.html" as macros %}
<!-- tags.html -->
{% block title %}{% spaceless %}{% trans %}Tags{% endtrans %}{% endspaceless %}{% endblock %}
{% block content %}
<!-- Tabs -->
{% include "tags/header.html" %}
{% if tag_list_type == 'list' %}
{% if not tags.object_list %}
<span>{% trans %}Nothing found{% endtrans %}</span>
{% endif %}
{% if tags.object_list %}
<div class='clearfix'></div>
<ul class='tags'>
{% for tag in tags.object_list %}
<li>
{{ macros.tag_widget(
tag=tag.name,
html_tag='div',
truncate_long_tag=True,
extra_content='<span class="tag-number">&#215; ' ~
tag.used_count|intcomma ~ '</span>'
)
}}
</li>
{% endfor %}
</ul>
<div class="clean"></div>
<div class="pager">
{{macros.paginator(paginator_context)}}
</div>
{% endif %}
{% else %}
<div class="clearfix"></div>
{% if not tags %}
<span>{% trans %}Nothing found{% endtrans %}</span>
{% endif %}
{{ macros.tag_cloud(tags=tags, font_sizes=font_size, search_state=search_state) }}
{% endif %}

{% include "tags/content.html" %}
{% endblock %}
{% block endjs %}
<script type="text/javascript">
Expand All @@ -49,7 +14,9 @@
Hilite.elementid = "searchtags";
Hilite.debug_referrer = location.href;
});
askbot['data']['tagSearchPromptText'] = "{% trans %}search for tags{% endtrans %}";
/*]]>*/
</script>
{% include "tags/custom_javascript.httml" ignore missing %}
{% endblock %}
<!-- end tags.html -->
34 changes: 34 additions & 0 deletions askbot/templates/tags/content.html
@@ -0,0 +1,34 @@
{% import "macros.html" as macros %}
{% include "tags/header.html" %}
{% if tag_list_type == 'list' %}
{% if not tags.object_list %}
<span>{% trans %}Nothing found{% endtrans %}</span>
{% endif %}
{% if tags.object_list %}
<div class='clearfix'></div>
<ul class='tags'>
{% for tag in tags.object_list %}
<li>
{{ macros.tag_widget(
tag=tag.name,
html_tag='div',
truncate_long_tag=True,
extra_content='<span class="tag-number">&#215; ' ~
tag.used_count|intcomma ~ '</span>'
)
}}
</li>
{% endfor %}
</ul>
<div class="clean"></div>
<div class="pager">
{{macros.paginator(paginator_context)}}
</div>
{% endif %}
{% else %}
<div class="clearfix"></div>
{% if not tags %}
<span>{% trans %}Nothing found{% endtrans %}</span>
{% endif %}
{{ macros.tag_cloud(tags=tags, font_sizes=font_size, search_state=search_state) }}
{% endif %}
7 changes: 4 additions & 3 deletions askbot/templates/tags/header.html
@@ -1,9 +1,10 @@
<div id="content-header">
{% set tag_query = stag|escape %}
{% if page_title %}
<h1 class="section-title">{{ page_title }}</h1>
{% else %}
{% if stag %}
<h1 class="section-title">{% trans %}Tags, matching "{{ stag }}"{% endtrans %}</h1>
<h1 class="section-title">{% trans %}Tags, matching "{{ tag_query }}"{% endtrans %}</h1>
{% else %}
<h1 class="section-title">{% trans %}Tags{% endtrans %}</h1>
{% endif %}
Expand All @@ -13,13 +14,13 @@ <h1 class="section-title">{% trans %}Tags{% endtrans %}</h1>
<span class="label">{% trans %}Sort by &raquo;{% endtrans %}</span>
<a
id="sort_name"
href="{% url tags %}?sort=name"
href="{% url tags %}?sort=name{% if tag_query %}&query={{ tag_query }}{% endif %}"
{% if tab_id == 'name' %}class="on"{% endif %}
title="{% trans %}sorted alphabetically{% endtrans %}"
><span>{% trans %}by name{% endtrans %}</span></a>
<a
id="sort_used"
href="{% url tags %}?sort=used"
href="{% url tags %}?sort=used{% if tag_query %}&query={{ tag_query }}{% endif %}"
{% if tab_id == 'used' %}class="on"{% endif %}
title="{% trans %}sorted by frequency of tag use{% endtrans %}"
><span>{% trans %}by popularity{% endtrans %}</span></a>
Expand Down
3 changes: 2 additions & 1 deletion askbot/templates/widgets/search_bar.html
Expand Up @@ -7,14 +7,15 @@
{# url action depends on which tab is active #}
{% if active_tab == "tags" %}
<input type="hidden" name="t" value="tag"/>
{% set query=stag %}
{% elif active_tab == "users" %}
<input type="hidden" name="t" value="user"/>
{% endif %}
<input
class="searchInput"
type="text"
autocomplete="off"
value="{{ query|default_if_none('') }}"
value="{{ query|default_if_none('')|escape }}"
name="query"
id="keywords"
/>
Expand Down
18 changes: 13 additions & 5 deletions askbot/views/readers.py
Expand Up @@ -245,9 +245,10 @@ def questions(request, **kwargs):
def tags(request):#view showing a listing of available tags - plain list

#1) Get parameters. This normally belongs to form cleaning.
sortby = request.GET.get('sort', 'used')
post_data = request.GET
sortby = post_data.get('sort', 'used')
try:
page = int(request.GET.get('page', '1'))
page = int(post_data.get('page', '1'))
except ValueError:
page = 1

Expand All @@ -256,13 +257,13 @@ def tags(request):#view showing a listing of available tags - plain list
else:
order_by = '-used_count'

query = request.GET.get('query', '').strip()
query = post_data.get('query', '').strip()
tag_list_type = askbot_settings.TAG_LIST_FORMAT

#2) Get query set for the tags.
query_params = {'deleted': False}
if query != '':
query_params['name__icontains': query]
query_params['name__icontains'] = query

tags_qs = Tag.objects.filter(**query_params).exclude(used_count=0)

Expand Down Expand Up @@ -307,7 +308,14 @@ def tags(request):#view showing a listing of available tags - plain list

data['tags'] = tags

return render(request, 'tags.html', data)
if request.is_ajax():
template = get_template('tags/content.html')
template_context = RequestContext(request, data)
json_data = {'success': True, 'html': template.render(template_context)}
json_string = simplejson.dumps(json_data)
return HttpResponse(json_string, mimetype='application/json')
else:
return render(request, 'tags.html', data)

@csrf.csrf_protect
def question(request, id):#refactor - long subroutine. display question body, answers and comments
Expand Down

0 comments on commit 876e366

Please sign in to comment.