From 7955f45d3b2dfc9b4bc1b6f5db93506944680f95 Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Sun, 25 Nov 2012 05:29:06 -0300 Subject: up/down keys navigation works in the dropdown, enter key takes to question page --- askbot/media/js/live_search.js | 133 +++++++++++++++++++++++++++++++---------- askbot/media/js/utils.js | 52 +++++++++++++++- askbot/media/style/style.less | 30 +++++++++- 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 = $('
  • '); - var link = $(''); + 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 @@ -380,6 +380,30 @@ WrappedElement.prototype.dispose = function(){ this._in_document = false; }; +/** + * @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 @@ -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; -- cgit v1.2.3-1-g7c22