summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-11-25 05:29:06 -0300
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-11-25 05:29:06 -0300
commit7955f45d3b2dfc9b4bc1b6f5db93506944680f95 (patch)
tree3663a25ae90a17ac46c28e7abb4509ee1f8828a5
parent0ae05c2c4d767a9301195f05a058ef6839bb3bbe (diff)
downloadaskbot-7955f45d3b2dfc9b4bc1b6f5db93506944680f95.tar.gz
askbot-7955f45d3b2dfc9b4bc1b6f5db93506944680f95.tar.bz2
askbot-7955f45d3b2dfc9b4bc1b6f5db93506944680f95.zip
up/down keys navigation works in the dropdown, enter key takes to question page
-rw-r--r--askbot/media/js/live_search.js133
-rw-r--r--askbot/media/js/utils.js52
-rw-r--r--askbot/media/style/style.less30
3 files changed, 179 insertions, 36 deletions
diff --git a/askbot/media/js/live_search.js b/askbot/media/js/live_search.js
index d4e86eac..f099e334 100644
--- a/askbot/media/js/live_search.js
+++ b/askbot/media/js/live_search.js
@@ -1,6 +1,7 @@
var SearchDropMenu = function() {
WrappedElement.call(this);
this._data = undefined;
+ this._selectedItemIndex = 0;
}
inherits(SearchDropMenu, WrappedElement);
@@ -18,14 +19,78 @@ SearchDropMenu.prototype.setAskHandler = function(handler) {
SearchDropMenu.prototype.render = function() {
var list = this._resultsList;
list.empty();
+ var me = this;
$.each(this._data, function(idx, item) {
- var listItem = $('<li></li>');
- var link = $('<a></a>');
+ 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');
+ }
+};
+
+SearchDropMenu.prototype.selectItem = function(idx) {
+ //idx is 1-based index
+ this._selectedItemIndex = idx;
+ this._resultsList.find('li').removeClass('selected');
+ var item = this.getItem(idx);
+ if (item) {
+ item.addClass('selected');
+ }
+
+};
+
+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 !== 38 && keyCode !== 40 && keyCode != 13) {
+ return;
+ }
+ var itemCount = me.getItemCount();
+ if (itemCount > 0) {
+ var curItem = me.getSelectedItemIndex();
+ if (keyCode === 38) {
+ if (curItem > 0) {
+ curItem = curItem - 1;
+ }
+ } else if (keyCode === 40) {
+ if (curItem < itemCount) {
+ curItem = curItem + 1;
+ }
+ } else if (keyCode === 13) {
+ me.navigateToItem(curItem);
+ return false;
+ }
+ me.selectItem(curItem);
+ return false
+ }
+ };
};
SearchDropMenu.prototype.createDom = function() {
@@ -35,6 +100,7 @@ SearchDropMenu.prototype.createDom = function() {
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');
@@ -48,6 +114,7 @@ SearchDropMenu.prototype.createDom = function() {
footer.append(button);
var handler = this._askHandler;
setupButtonEventHandlers(button, handler);
+ $(document).keydown(this.makeKeyHandler());
};
SearchDropMenu.prototype.show = function() {
@@ -69,7 +136,7 @@ SearchDropMenu.prototype.hide = function() {
SearchDropMenu.prototype.reset = function() {
this._data = undefined;
- this._element.empty();
+ this._resultsList.empty();
this._element.hide();
};
@@ -81,9 +148,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);
@@ -130,41 +196,48 @@ TagWarningBox.prototype.showWarning = function(){
* @constructor
* tool tip to be shown on top of the search input
*/
-var SearchToolTip = function() {
+var InputToolTip = function() {
WrappedElement.call(this);
};
-inherits(SearchToolTip, WrappedElement);
+inherits(InputToolTip, WrappedElement);
-SearchToolTip.prototype.show = function() {
+InputToolTip.prototype.show = function() {
+ this._element.removeClass('dimmed');
this._element.show();
};
-SearchToolTip.prototype.hide = function() {
+InputToolTip.prototype.hide = function() {
+ this._element.removeClass('dimmed');
this._element.hide();
};
-SearchToolTip.prototype.setClickHandler = function(handler) {
+InputToolTip.prototype.dim = function() {
+ this._element.addClass('dimmed');
+};
+
+InputToolTip.prototype.setClickHandler = function(handler) {
this._clickHandler = handler;
};
-SearchToolTip.prototype.createDom = function() {
+InputToolTip.prototype.createDom = function() {
var element = this.makeElement('div');
this._element = element;
element.html(gettext('search or ask your question'));
- element.addClass('tool-tip');
- element.css({
- 'margin-top': '-40px',
- 'padding-top': '10px',
- 'color': '#999',
- 'height': '30px',
- 'line-height': '20px',
- 'font-size': '20px',
- 'font-style': 'italic'
- });
+ element.addClass('input-tool-tip');
var handler = this._clickHandler;
- element.click(function() { handler() });
+ var me = this;
+ element.click(function() {
+ handler();
+ me.dim();
+ return false;
+ });
+ $(document).click(function() {
+ if (element.css('display') === 'block') {
+ element.removeClass('dimmed');
+ }
+ });
};
@@ -433,6 +506,7 @@ FullTextSearch.prototype.reset = function() {
this._dropMenu.reset();
this._element.val('');
this._element.focus();
+ this._xButton.hide();
this._toolTip.show();
};
@@ -587,6 +661,7 @@ FullTextSearch.prototype.makeAskHandler = function() {
return function() {
var query = me.getSearchQuery();
window.location.href = askbot['urls']['ask'] + '?title=' + query;
+ return false;
};
};
@@ -611,17 +686,12 @@ FullTextSearch.prototype.makeKeyDownHandler = function() {
return function(e) {//don't like the keyup delay to
var keyCode = getKeyCode(e);
var query = me.getSearchQuery();
- if (query.length === 1) {
- if (keyCode !== 8 && keyCode !== 46) {
- toolTip.hide();
- xButton.show();
- }
- } else if (query.length === 0) {
+ if (query.length === 0) {
if (keyCode !== 8 && keyCode !== 48) {
toolTip.hide();
//xButton.show();//causes a jump of search input...
} else {
- toolTip.show();
+ //toolTip.show();
//xButton.hide();
}
} else {
@@ -638,9 +708,8 @@ FullTextSearch.prototype.decorate = function(element) {
this._prevText = this.getSearchQuery();
this._tag_warning_box = new TagWarningBox();
- var toolTip = new SearchToolTip();
+ var toolTip = new InputToolTip();
toolTip.setClickHandler(function() {
- toolTip.hide();
element.focus();
});
this._element.after(toolTip.getElement());
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js
index 679fd530..6ea23566 100644
--- a/askbot/media/js/utils.js
+++ b/askbot/media/js/utils.js
@@ -382,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() {
@@ -1509,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;
};
@@ -1543,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();
@@ -1668,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 6f28d1e9..3b9bcfda 100644
--- a/askbot/media/style/style.less
+++ b/askbot/media/style/style.less
@@ -471,6 +471,15 @@ body.user-messages {
-moz-box-shadow: none;
box-shadow: none;
}
+
+ div.input-tool-tip {
+ margin-top: -40px;
+ padding-top: 10px;
+ height: 30px;
+ line-height: 20px;
+ font-size: 20px;
+ font-style: italic;
+ }
}
.search-drop-menu {
@@ -490,6 +499,13 @@ body.user-messages {
li {
padding: 5px 0;
}
+ li.selected {
+ background: #aaa;
+ }
+ }
+
+ ul.empty {
+ padding: 1px;
}
.footer {
@@ -498,6 +514,13 @@ body.user-messages {
}
}
+.input-tool-tip {
+ color: #999;
+}
+.input-tool-tip.dimmed {
+ color: #ccc;
+}
+
input[type="submit"].searchBtn {
font-size: 10px;
color: #666;
@@ -572,8 +595,11 @@ input[type="submit"].searchBtn {
margin: 0 228px 0 327px;
width: auto;
}
-body.anon #searchBar {
- margin-left: 227px;/* we don't have the "followed" scope */
+body.anon {
+ #searchBar,
+ .search-drop-menu {
+ margin-left: 227px;/* we don't have the "followed" scope */
+ }
}
#searchBar.cancelable {
padding-right: 82px;