mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 21:43:21 +00:00
Search streams from left sidebar (resolves #565).
Assigns hotkey 'w' to search streams. Only show search box when active. Activate with hotkey or by clicking STREAMS. Filter matches at the beginning of words in stream name. Behaviour is otherwise almost identical to user search. Casper tests.
This commit is contained in:
committed by
Tim Abbott
parent
574a304b12
commit
a51ec44005
@@ -222,6 +222,66 @@ casper.then(check_narrow_title('private - Zulip Dev - Zulip'));
|
||||
un_narrow();
|
||||
|
||||
|
||||
// Make sure stream search filters the stream list
|
||||
casper.then(function () {
|
||||
casper.test.info('Search streams using left sidebar');
|
||||
});
|
||||
|
||||
casper.then(function () {
|
||||
casper.test.assertExists('.stream-list-filter.notdisplayed', 'Stream filter box not visible initially');
|
||||
});
|
||||
|
||||
casper.thenClick('#streams_header .sidebar-title');
|
||||
|
||||
casper.then(function () {
|
||||
casper.test.assertDoesntExist('.stream-list-filter.notdisplayed', 'Stream filter box visible after click');
|
||||
});
|
||||
|
||||
casper.then(function () {
|
||||
casper.test.assertExists('#stream_filters [data-name="Denmark"]', 'Original stream list contains Denmark');
|
||||
casper.test.assertExists('#stream_filters [data-name="Scotland"]', 'Original stream list contains Scotland');
|
||||
casper.test.assertExists('#stream_filters [data-name="Verona"]', 'Original stream list contains Verona');
|
||||
});
|
||||
|
||||
// We search for the beginning of "Verona", not case sensitive
|
||||
casper.then(function () {
|
||||
casper.evaluate(function () {
|
||||
$('.stream-list-filter').expectOne()
|
||||
.focus()
|
||||
.val('ver')
|
||||
.trigger($.Event('input'));
|
||||
});
|
||||
});
|
||||
casper.then(function () {
|
||||
casper.test.assertDoesntExist('#stream_filters [data-name="Denmark"]', 'Filtered stream list does not contain Denmark');
|
||||
casper.test.assertDoesntExist('#stream_filters [data-name="Scotland"]', 'Filtered stream list does not contain Scotland');
|
||||
casper.test.assertExists('#stream_filters [data-name="Verona"]', 'Filtered stream list does contain Verona');
|
||||
});
|
||||
|
||||
// Clearing the list should give us back all the streams in the list
|
||||
casper.then(function () {
|
||||
casper.evaluate(function () {
|
||||
$('.stream-list-filter').expectOne()
|
||||
.focus()
|
||||
.val('')
|
||||
.trigger($.Event('input'));
|
||||
});
|
||||
});
|
||||
casper.then(function () {
|
||||
casper.test.assertExists('#stream_filters [data-name="Denmark"]', 'Restored stream list contains Denmark');
|
||||
casper.test.assertExists('#stream_filters [data-name="Scotland"]', 'Restored stream list contains Scotland');
|
||||
casper.test.assertExists('#stream_filters [data-name="Verona"]', 'Restored stream list contains Verona');
|
||||
});
|
||||
|
||||
casper.thenClick('#streams_header .sidebar-title');
|
||||
|
||||
casper.then(function () {
|
||||
casper.test.assertExists('.stream-list-filter.notdisplayed', 'Stream filter box not visible after second click');
|
||||
});
|
||||
|
||||
un_narrow();
|
||||
|
||||
|
||||
common.then_log_out();
|
||||
|
||||
// Run the above queued actions.
|
||||
|
||||
@@ -10,7 +10,7 @@ casper.then(function () {
|
||||
// subscriptions need to load; if they have *any* subs,
|
||||
// the word "Unsubscribe" will appear
|
||||
});
|
||||
casper.waitForText('Subscribed', function () {
|
||||
casper.waitForSelector('.sub_unsub_button.subscribed-button', function () {
|
||||
casper.test.assertTextExists('Subscribed', 'Initial subscriptions loaded');
|
||||
casper.fill('form#add_new_subscription', {stream_name: 'Waseemio'});
|
||||
casper.click('form#add_new_subscription input.btn');
|
||||
|
||||
@@ -235,7 +235,7 @@ $(function () {
|
||||
|
||||
// MISC
|
||||
|
||||
$('#streams_header a').click(function (e) {
|
||||
$('#streams_inline_cog').click(function (e) {
|
||||
ui.change_tab_to('#subscriptions');
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
@@ -57,7 +57,8 @@ var hotkeys_shift_insensitive = {
|
||||
113: {name: 'query_users', message_view_only: false}, // 'q'
|
||||
114: {name: 'reply_message', message_view_only: true}, // 'r'
|
||||
115: {name: 'narrow_by_recipient', message_view_only: true}, // 's'
|
||||
118: {name: 'narrow_private', message_view_only: true} // 'v'
|
||||
118: {name: 'narrow_private', message_view_only: true}, // 'v'
|
||||
119: {name: 'query_streams', message_view_only: false} // 'w'
|
||||
};
|
||||
|
||||
function get_hotkey_from_event(e) {
|
||||
@@ -177,6 +178,9 @@ function process_hotkey(e) {
|
||||
} else if (activity.searching()) {
|
||||
activity.escape_search();
|
||||
return true;
|
||||
} else if (stream_list.searching()) {
|
||||
stream_list.escape_search();
|
||||
return true;
|
||||
} else if (compose.composing()) {
|
||||
// If the user hit the escape key, cancel the current compose
|
||||
compose.cancel();
|
||||
@@ -194,6 +198,9 @@ function process_hotkey(e) {
|
||||
if (activity.searching()) {
|
||||
activity.blur_search();
|
||||
return true;
|
||||
} else if (stream_list.searching()) {
|
||||
stream_list.clear_and_hide_search();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +252,9 @@ function process_hotkey(e) {
|
||||
case 'query_users':
|
||||
activity.initiate_search();
|
||||
return true;
|
||||
case 'query_streams':
|
||||
stream_list.initiate_search();
|
||||
return true;
|
||||
case 'search':
|
||||
search.initiate_search();
|
||||
return true;
|
||||
|
||||
@@ -19,12 +19,40 @@ function active_stream_name() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function filter_streams_by_search(streams) {
|
||||
var search_box = $(".stream-list-filter");
|
||||
|
||||
var search_term = search_box.expectOne().val().trim();
|
||||
|
||||
if (search_term === '') {
|
||||
return streams;
|
||||
}
|
||||
|
||||
var search_terms = search_term.toLowerCase().split(",");
|
||||
search_terms = _.map(search_terms, function (s) {
|
||||
return s.trim();
|
||||
});
|
||||
|
||||
var filtered_streams = _.filter(streams, function (stream) {
|
||||
return _.any(search_terms, function (search_term) {
|
||||
var lower_stream_name = stream.toLowerCase().split(" ");
|
||||
return _.any(lower_stream_name, function (name) {
|
||||
return name.indexOf(search_term) === 0;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return filtered_streams;
|
||||
}
|
||||
|
||||
exports.build_stream_list = function () {
|
||||
var streams = stream_data.subscribed_streams();
|
||||
if (streams.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
streams = filter_streams_by_search(streams);
|
||||
|
||||
var sort_recent = (streams.length > 40);
|
||||
|
||||
streams.sort(function (a, b) {
|
||||
@@ -643,6 +671,89 @@ $(function () {
|
||||
|
||||
});
|
||||
|
||||
function actually_update_streams_for_search() {
|
||||
exports.update_streams_sidebar();
|
||||
resize.resize_page_components();
|
||||
}
|
||||
|
||||
var update_streams_for_search = _.throttle(actually_update_streams_for_search, 50);
|
||||
|
||||
exports.searching = function () {
|
||||
return $('.stream-list-filter').expectOne().is(':focus');
|
||||
};
|
||||
|
||||
exports.escape_search = function () {
|
||||
var filter = $('.stream-list-filter').expectOne();
|
||||
if (filter.val() === '') {
|
||||
exports.clear_and_hide_search();
|
||||
return;
|
||||
}
|
||||
filter.val('');
|
||||
update_streams_for_search();
|
||||
};
|
||||
|
||||
exports.initiate_search = function () {
|
||||
var filter = $('.stream-list-filter').expectOne();
|
||||
filter.removeClass('notdisplayed');
|
||||
filter.focus();
|
||||
};
|
||||
|
||||
exports.clear_and_hide_search = function () {
|
||||
var filter = $('.stream-list-filter');
|
||||
if (filter.val() !== '') {
|
||||
filter.val('');
|
||||
update_streams_for_search();
|
||||
}
|
||||
filter.blur();
|
||||
filter.addClass('notdisplayed');
|
||||
};
|
||||
|
||||
function focus_stream_filter (e) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function maybe_select_stream (e) {
|
||||
if (e.keyCode === 13) {
|
||||
// Enter key was pressed
|
||||
|
||||
var topStream = $('#stream_filters li.narrow-filter').first().data('name');
|
||||
if (topStream !== undefined) {
|
||||
// undefined if there are no results
|
||||
if (ui.home_tab_obscured()) {
|
||||
ui.change_tab_to('#home');
|
||||
}
|
||||
exports.clear_and_hide_search();
|
||||
narrow.by('stream', topStream, {select_first_unread: true, trigger: 'sidebar enter key'});
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_filter_displayed(e) {
|
||||
if (e.target.id === 'streams_inline_cog') {
|
||||
return;
|
||||
}
|
||||
if (0 === $('.stream-list-filter.notdisplayed').length) {
|
||||
exports.clear_and_hide_search();
|
||||
} else {
|
||||
exports.initiate_search();
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$(".stream-list-filter").expectOne()
|
||||
.on('click', focus_stream_filter)
|
||||
.on('input', update_streams_for_search)
|
||||
.on('keydown', maybe_select_stream);
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$("#streams_header").expectOne()
|
||||
.on('click', toggle_filter_displayed);
|
||||
});
|
||||
|
||||
return exports;
|
||||
}());
|
||||
if (typeof module !== 'undefined') {
|
||||
|
||||
@@ -472,9 +472,13 @@ $(function () {
|
||||
timerender.set_full_datetime(message, time_elem);
|
||||
});
|
||||
|
||||
$('#streams_inline_cog').tooltip({ placement: 'left',
|
||||
$('#streams_header h4').tooltip({ placement: 'right',
|
||||
animation: false });
|
||||
|
||||
$('#streams_header i[data-toggle="tooltip"]').tooltip({ placement: 'left',
|
||||
animation: false });
|
||||
|
||||
|
||||
if (feature_flags.disable_message_editing) {
|
||||
$("#edit-message-hotkey-help").hide();
|
||||
}
|
||||
|
||||
@@ -321,17 +321,24 @@ a:hover code {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#streams_list #streams_inline_cog:hover {
|
||||
#streams_inline_cog,
|
||||
#streams_filter_icon {
|
||||
float: right;
|
||||
color: #000;
|
||||
font-size: 13px;
|
||||
margin-top: 3px;
|
||||
margin-left: 6px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#streams_inline_cog:hover,
|
||||
#streams_filter_icon:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
#streams_inline_cog {
|
||||
float: right;
|
||||
color: #000;
|
||||
#streams_header a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
margin-top: 3px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
@@ -359,6 +366,10 @@ a:hover code {
|
||||
width: 4px !important;
|
||||
}
|
||||
|
||||
.stream-list-filter {
|
||||
margin-left: 1ex;
|
||||
}
|
||||
|
||||
.narrow-filter {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
<td class="hotkey">q</td>
|
||||
<td class="definition">{% trans %}Search people{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hotkey">w</td>
|
||||
<td class="definition">{% trans %}Search streams{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hotkey">Up or k</td>
|
||||
<td class="definition">{% trans %}Previous message{% endtrans %}</td>
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
<li data-name="mentioned" class="global-filter"><span class="filter-icon"><i class="icon-vector-tag"></i></span><a href="#narrow/is/mentioned">{{ _('@-mentions') }}<span class="count"><span class="value"></span></span></a></li>
|
||||
</ul>
|
||||
<div id="streams_list" class="zoom-out">
|
||||
<div id="streams_header" class="zoom-in-hide"><h4 class="sidebar-title">{{ _('STREAMS') }}</h4>
|
||||
<div id="streams_header" class="zoom-in-hide"><h4 class="sidebar-title" data-toggle="tooltip" title="Subscribed streams"><a href="">{{ _('STREAMS') }}</a></h4>
|
||||
<a href=""><i id="streams_inline_cog" class='icon-vector-cog' data-toggle="tooltip" title="Subscribe, add, or configure streams"></i></a>
|
||||
<a href=""><i id='streams_filter_icon' class='icon-vector-search' data-toggle="tooltip" title="Filter streams list"></i></a>
|
||||
</div>
|
||||
<div id="topics_header">
|
||||
<div class="all-streams-padding">
|
||||
@@ -22,6 +23,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="stream-filters-container" class="scrolling_list">
|
||||
<input class="stream-list-filter notdisplayed" type="text" placeholder="{{ _('Search streams') }}" />
|
||||
<ul id="stream_filters" class="filters"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user