diff --git a/tools/jslint/check-all.js b/tools/jslint/check-all.js index 7df079c368..f6d0ca1f91 100644 --- a/tools/jslint/check-all.js +++ b/tools/jslint/check-all.js @@ -57,6 +57,7 @@ var globals = + ' selected_message selected_message_id' + ' at_top_of_viewport at_bottom_of_viewport' + ' viewport' + + ' load_more_messages' ; diff --git a/zephyr/static/js/narrow.js b/zephyr/static/js/narrow.js index 79b84b869e..1f93fa3550 100644 --- a/zephyr/static/js/narrow.js +++ b/zephyr/static/js/narrow.js @@ -32,6 +32,14 @@ exports.narrowing_type = function () { } }; +exports.allow_collapse = function () { + if (narrowdata && narrowdata.allow_collapse !== undefined) { + return narrowdata.allow_collapse; + } else { + return true; + } +}; + exports.data = function () { return narrowdata; }; @@ -52,11 +60,12 @@ function do_narrow(new_narrow, bar, new_filter) { // Empty the filtered table right before we fill it again clear_table('zfilt'); - add_to_table(message_array, 'zfilt', filter_function, 'bottom'); + add_to_table(message_array, 'zfilt', filter_function, 'bottom', exports.allow_collapse()); // Show the new set of messages. $("#zfilt").addClass("focused_table"); + $("#load_more").show(); $("#show_all_messages").removeAttr("disabled"); $(".narrowed_to_bar").show(); $("#top_narrowed_whitespace").show(); @@ -180,6 +189,17 @@ exports.by_recipient = function () { } }; +exports.by_search_term = function (term) { + var new_narrow = {type: "searchterm", searchterm: term, allow_collapse: false}; + var bar = {icon: 'search', description: 'Messages containing "' + term + '"'}; + var term_lowercase = term.toLowerCase(); + do_narrow(new_narrow, bar, function (other) { + return other.subject.toLowerCase().indexOf(term_lowercase) !== -1 || + other.content.toLowerCase().indexOf(term_lowercase) !== -1; + }); + load_more_messages(); +}; + exports.show_all_messages = function () { if (!narrowdata) { return; diff --git a/zephyr/static/js/search.js b/zephyr/static/js/search.js index 1df32ea74d..5807df58dd 100644 --- a/zephyr/static/js/search.js +++ b/zephyr/static/js/search.js @@ -13,11 +13,13 @@ var mapped = {}; function render_object(obj) { if (obj.action === 'search') { - return "Search for " + obj.query; + return "Find " + obj.query; } else if (obj.action === 'stream') { return "Narrow to stream " + obj.query; } else if (obj.action === 'private_message') { return "Narrow to person " + obj.query.full_name + " <" + obj.query.email + ">"; + } else if (obj.action === 'search_narrow') { + return "Narrow to messages containing " + obj.query; } return "Error"; } @@ -30,7 +32,8 @@ exports.update_typeahead = function() { return {action: 'private_message', query: elt}; }); var options = streams.concat(people); - // The first slot is reserved for our query. + // The first two slots are reserved for our query. + options.unshift({action: 'search_narrow', query: ''}); options.unshift({action: 'search', query: ''}); mapped = {}; @@ -55,6 +58,9 @@ function narrow_or_search_for_term(item) { } else if (obj.action === "private_message") { narrow.by_private_message_partner(obj.query.full_name, obj.query.email); return ""; + } else if (obj.action === "search_narrow") { + narrow.by_search_term(obj.query); + return ""; } return item; } @@ -62,17 +68,23 @@ function narrow_or_search_for_term(item) { exports.initialize = function () { $( "#search_query" ).typeahead({ source: function (query, process) { - // Delete our old search query - var old_label = labels.shift(); - delete mapped[old_label]; - // Add our new one - var obj = {action: 'search', query: query}; + // Delete our old search queries (one for search-in-page, one for search-history) + var old_search_label = labels.shift(); + delete mapped[old_search_label]; + var old_search_narrow_label = labels.shift(); + delete mapped[old_search_narrow_label]; + // Add our new ones + var obj = {action: 'search_narrow', query: query}; var label = render_object(obj); mapped[label] = obj; labels.unshift(label); + obj = {action: 'search', query: query}; + label = render_object(obj); + mapped[label] = obj; + labels.unshift(label); return labels; }, - items: 3, + items: 4, highlighter: function (item) { var query = this.query; var string_item = render_object(mapped[item]); diff --git a/zephyr/static/js/zephyr.js b/zephyr/static/js/zephyr.js index 774bf5a81b..992a437d70 100644 --- a/zephyr/static/js/zephyr.js +++ b/zephyr/static/js/zephyr.js @@ -259,7 +259,7 @@ function add_display_time(message, prev) { message.full_date_str = time.toDateString() + " " + time.toTimeString(); } -function add_to_table(messages, table_name, filter_function, where) { +function add_to_table(messages, table_name, filter_function, where, allow_collapse) { if (messages.length === 0) return; @@ -301,7 +301,7 @@ function add_to_table(messages, table_name, filter_function, where) { message.include_recipient = false; message.include_bookend = false; - if (same_recipient(prev, message)) { + if (same_recipient(prev, message) && allow_collapse) { current_group.push(message.id); } else { if (current_group.length > 0) @@ -466,11 +466,11 @@ function add_messages(messages, where, add_to_home) { } if (narrow.active()) - add_to_table(messages, 'zfilt', narrow.predicate(), where); + add_to_table(messages, 'zfilt', narrow.predicate(), where, narrow.allow_collapse()); // Even when narrowed, add messages to the home view so they exist when we un-narrow. if (add_to_home) - add_to_table(messages, 'zhome', function () { return true; }, where); + add_to_table(messages, 'zhome', function () { return true; }, where, true); // If we received the initially selected message, select it on the client side, // but not if the user has already selected another one during load. diff --git a/zephyr/views.py b/zephyr/views.py index 875b634336..7921eb9e61 100644 --- a/zephyr/views.py +++ b/zephyr/views.py @@ -238,6 +238,10 @@ def get_old_messages_backend(request, anchor = POST(converter=to_non_negative_in if 'subject' in narrow: query = query.filter(subject = narrow['subject']) + if 'searchterm' in narrow: + query = query.filter(Q(content__icontains=narrow['searchterm']) | + Q(subject__icontains=narrow['searchterm'])) + # We add 1 to the number of messages requested to ensure that the # resulting list always contains the anchor message if num_before != 0 and num_after == 0: