2012-11-14 20:52:53 +01:00
|
|
|
var search = (function () {
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
2018-06-22 12:09:09 +02:00
|
|
|
// Exported for unit testing
|
|
|
|
exports.is_using_input_method = false;
|
2018-06-09 11:10:56 +02:00
|
|
|
|
2013-07-30 20:29:31 +02:00
|
|
|
function narrow_or_search_for_term(search_string) {
|
2012-12-12 19:36:18 +01:00
|
|
|
var search_query_box = $("#search_query");
|
2018-06-22 12:09:09 +02:00
|
|
|
if (exports.is_using_input_method) {
|
|
|
|
// Neither narrow nor search when using input tools as
|
|
|
|
// `updater` is also triggered when 'enter' is triggered
|
|
|
|
// while using input tool
|
2018-06-09 11:10:56 +02:00
|
|
|
return search_query_box.val();
|
|
|
|
}
|
2017-03-18 21:35:35 +01:00
|
|
|
ui_util.change_tab_to('#home');
|
2018-07-14 16:10:00 +02:00
|
|
|
|
|
|
|
var operators;
|
|
|
|
if (page_params.search_pills_enabled) {
|
|
|
|
// search_string only contains the suggestion selected
|
|
|
|
// from the typeahead. base_query stores the query
|
|
|
|
// corresponding to the existing pills.
|
|
|
|
var base_query = search_pill.get_search_string_for_current_filter(
|
|
|
|
search_pill_widget.my_pill);
|
|
|
|
var base_operators = Filter.parse(base_query);
|
|
|
|
var suggestion_operator = Filter.parse(search_string);
|
|
|
|
operators = base_operators.concat(suggestion_operator);
|
|
|
|
} else {
|
|
|
|
operators = Filter.parse(search_string);
|
|
|
|
}
|
2018-04-23 06:02:11 +02:00
|
|
|
narrow.activate(operators, {trigger: 'search'});
|
2012-12-17 19:47:09 +01:00
|
|
|
|
2013-07-16 04:55:46 +02:00
|
|
|
// It's sort of annoying that this is not in a position to
|
|
|
|
// blur the search box, because it means that Esc won't
|
|
|
|
// unnarrow, it'll leave the searchbox.
|
2013-02-28 22:10:22 +01:00
|
|
|
|
2013-07-16 04:55:46 +02:00
|
|
|
// Narrowing will have already put some operators in the search box,
|
|
|
|
// so leave the current text in.
|
|
|
|
search_query_box.blur();
|
|
|
|
return search_query_box.val();
|
2012-11-14 22:12:21 +01:00
|
|
|
}
|
|
|
|
|
2013-01-02 19:58:55 +01:00
|
|
|
function update_buttons_with_focus(focused) {
|
2018-06-22 11:55:21 +02:00
|
|
|
var search_query_box = $('#search_query');
|
2012-12-18 23:38:55 +01:00
|
|
|
|
|
|
|
// Show buttons iff the search input is focused, or has non-empty contents,
|
|
|
|
// or we are narrowed.
|
|
|
|
if (focused
|
2018-06-22 11:55:21 +02:00
|
|
|
|| search_query_box.val()
|
2017-04-25 15:25:31 +02:00
|
|
|
|| narrow_state.active()) {
|
2017-06-30 00:57:46 +02:00
|
|
|
$('.search_button').prop('disabled', false);
|
2012-12-18 23:38:55 +01:00
|
|
|
} else {
|
2018-06-22 11:55:21 +02:00
|
|
|
$('.search_button').prop('disabled', true);
|
2012-12-18 23:38:55 +01:00
|
|
|
}
|
2013-01-02 19:58:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
exports.update_button_visibility = function () {
|
|
|
|
update_buttons_with_focus($('#search_query').is(':focus'));
|
2012-12-18 23:38:55 +01:00
|
|
|
};
|
|
|
|
|
2012-11-14 22:12:21 +01:00
|
|
|
exports.initialize = function () {
|
2018-06-22 11:59:47 +02:00
|
|
|
var search_query_box = $('#search_query');
|
|
|
|
var searchbox_form = $('#searchbox_form');
|
2013-07-30 19:41:23 +02:00
|
|
|
|
|
|
|
// Data storage for the typeahead.
|
|
|
|
// This maps a search string to an object with a "description" field.
|
|
|
|
// (It's a bit of legacy that we have an object with only one important
|
|
|
|
// field. There's also a "search_string" field on each element that actually
|
|
|
|
// just represents the key of the hash, so it's redundant.)
|
|
|
|
var search_object = {};
|
|
|
|
|
2018-06-22 11:59:47 +02:00
|
|
|
search_query_box.typeahead({
|
2013-07-30 19:41:23 +02:00
|
|
|
source: function (query) {
|
2018-07-14 13:01:21 +02:00
|
|
|
var suggestions;
|
|
|
|
if (page_params.search_pills_enabled) {
|
2018-07-02 22:30:18 +02:00
|
|
|
var base_query = search_pill.get_search_string_for_current_filter(
|
|
|
|
search_pill_widget.my_pill);
|
|
|
|
suggestions = search_suggestion.get_suggestions(base_query, query);
|
2018-07-14 13:01:21 +02:00
|
|
|
} else {
|
|
|
|
suggestions = search_suggestion.get_suggestions_legacy(query);
|
|
|
|
}
|
2013-07-30 19:41:23 +02:00
|
|
|
// Update our global search_object hash
|
|
|
|
search_object = suggestions.lookup_table;
|
|
|
|
return suggestions.strings;
|
|
|
|
},
|
2013-08-21 17:37:54 +02:00
|
|
|
fixed: true,
|
2017-04-03 10:15:09 +02:00
|
|
|
items: 12,
|
2013-07-19 21:38:26 +02:00
|
|
|
helpOnEmptyStrings: true,
|
2013-07-23 03:05:06 +02:00
|
|
|
naturalSearch: true,
|
2012-11-18 19:19:52 +01:00
|
|
|
highlighter: function (item) {
|
2013-07-16 02:18:36 +02:00
|
|
|
var obj = search_object[item];
|
2013-07-16 01:03:13 +02:00
|
|
|
return obj.description;
|
2012-11-18 19:19:52 +01:00
|
|
|
},
|
2016-12-02 14:06:06 +01:00
|
|
|
matcher: function () {
|
2013-07-15 22:43:25 +02:00
|
|
|
return true;
|
2012-11-15 03:44:50 +01:00
|
|
|
},
|
2018-07-14 16:10:00 +02:00
|
|
|
updater: function (search_string) {
|
|
|
|
// Order is important here. narrow_or_search_for_term
|
|
|
|
// gets a search string from existing pills and obtains
|
|
|
|
// existing operators. Newly selected suggestion is added
|
|
|
|
// to those operators. If narrow_or_search_for_term was
|
|
|
|
// called after append_search_string, the existing search
|
|
|
|
// pills at the time for calling that function would also
|
|
|
|
// have the newly selected suggestion, and appending it again
|
|
|
|
// would cause duplication.
|
|
|
|
var result = narrow_or_search_for_term(search_string);
|
|
|
|
if (page_params.search_pills_enabled) {
|
|
|
|
search_pill.append_search_string(search_string,
|
|
|
|
search_pill_widget.my_pill);
|
|
|
|
$("#search_query").focus();
|
|
|
|
} else {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
},
|
2013-07-15 22:57:52 +02:00
|
|
|
sorter: function (items) {
|
|
|
|
return items;
|
2017-01-12 00:17:43 +01:00
|
|
|
},
|
2018-07-14 16:10:00 +02:00
|
|
|
stopAdvance: page_params.search_pills_enabled,
|
2012-11-14 22:12:21 +01:00
|
|
|
});
|
|
|
|
|
2018-06-22 11:59:47 +02:00
|
|
|
searchbox_form.on('compositionend', function () {
|
2018-06-09 11:10:56 +02:00
|
|
|
// Set `is_using_input_method` to true if enter is pressed to exit
|
|
|
|
// the input tool popover and get the text in the search bar. Then
|
|
|
|
// we suppress searching triggered by this enter key by checking
|
|
|
|
// `is_using_input_method` before searching.
|
|
|
|
// More details in the commit message that added this line.
|
2018-06-22 12:09:09 +02:00
|
|
|
exports.is_using_input_method = true;
|
2018-06-09 11:10:56 +02:00
|
|
|
});
|
|
|
|
|
2018-06-22 11:59:47 +02:00
|
|
|
searchbox_form.keydown(function (e) {
|
2012-12-18 23:38:55 +01:00
|
|
|
exports.update_button_visibility();
|
2012-11-14 22:12:21 +01:00
|
|
|
var code = e.which;
|
2012-11-15 20:22:20 +01:00
|
|
|
if (code === 13 && search_query_box.is(":focus")) {
|
|
|
|
// Don't submit the form so that the typeahead can instead
|
|
|
|
// handle our Enter keypress. Any searching that needs
|
|
|
|
// to be done will be handled in the keyup.
|
2012-11-14 22:12:21 +01:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-18 22:58:20 +01:00
|
|
|
}).keyup(function (e) {
|
2018-06-22 12:09:09 +02:00
|
|
|
if (exports.is_using_input_method) {
|
|
|
|
exports.is_using_input_method = false;
|
2018-06-09 11:10:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2012-11-15 20:22:20 +01:00
|
|
|
var code = e.which;
|
|
|
|
if (code === 13 && search_query_box.is(":focus")) {
|
2013-01-31 23:50:39 +01:00
|
|
|
// We just pressed enter and the box had focus, which
|
|
|
|
// means we didn't use the typeahead at all. In that
|
|
|
|
// case, we should act as though we're searching by
|
|
|
|
// operators. (The reason the other actions don't call
|
|
|
|
// this codepath is that they first all blur the box to
|
|
|
|
// indicate that they've done what they need to do)
|
2018-04-23 06:02:11 +02:00
|
|
|
narrow.activate(Filter.parse(search_query_box.val()), {trigger: 'search'});
|
2013-01-31 23:50:39 +01:00
|
|
|
search_query_box.blur();
|
|
|
|
update_buttons_with_focus(false);
|
2012-11-15 20:22:20 +01:00
|
|
|
}
|
|
|
|
});
|
2013-02-27 20:29:25 +01:00
|
|
|
|
|
|
|
// Some of these functions don't actually need to be exported,
|
|
|
|
// but the code was moved here from elsewhere, and it would be
|
|
|
|
// more work to re-order everything and make them private.
|
2017-02-18 17:08:28 +01:00
|
|
|
$('#search_exit').on('click', exports.clear_search);
|
2013-02-27 21:00:06 +01:00
|
|
|
|
2018-06-22 11:59:47 +02:00
|
|
|
search_query_box.on('focus', exports.focus_search);
|
|
|
|
search_query_box.on('blur' , function () {
|
2013-02-27 21:00:06 +01:00
|
|
|
// The search query box is a visual cue as to
|
|
|
|
// whether search or narrowing is active. If
|
2013-07-23 03:41:21 +02:00
|
|
|
// the user blurs the search box, then we should
|
2018-06-08 21:14:55 +02:00
|
|
|
// update the search string to reflect the current
|
2013-07-23 03:41:21 +02:00
|
|
|
// narrow (or lack of narrow).
|
2013-02-27 21:00:06 +01:00
|
|
|
//
|
|
|
|
// But we can't do this right away, because
|
|
|
|
// selecting something in the typeahead menu causes
|
2013-07-23 03:41:21 +02:00
|
|
|
// the box to lose focus a moment before.
|
2013-02-27 21:00:06 +01:00
|
|
|
//
|
|
|
|
// The workaround is to check 100ms later -- long
|
|
|
|
// enough for the search to have gone through, but
|
|
|
|
// short enough that the user won't notice (though
|
|
|
|
// really it would be OK if they did).
|
|
|
|
|
|
|
|
setTimeout(function () {
|
2017-04-25 15:25:31 +02:00
|
|
|
var search_string = narrow_state.search_string();
|
2018-06-22 11:59:47 +02:00
|
|
|
search_query_box.val(search_string);
|
2013-02-27 21:00:06 +01:00
|
|
|
exports.update_button_visibility();
|
|
|
|
}, 100);
|
|
|
|
});
|
2012-11-14 22:12:21 +01:00
|
|
|
};
|
|
|
|
|
2012-12-18 22:42:13 +01:00
|
|
|
exports.focus_search = function () {
|
2013-01-02 19:58:55 +01:00
|
|
|
// The search bar is not focused yet, but will be.
|
|
|
|
update_buttons_with_focus(true);
|
2012-11-14 20:52:53 +01:00
|
|
|
};
|
2012-11-01 19:20:51 +01:00
|
|
|
|
2012-11-14 20:52:53 +01:00
|
|
|
exports.initiate_search = function () {
|
2013-01-29 20:54:11 +01:00
|
|
|
$('#search_query').select();
|
2012-11-14 20:52:53 +01:00
|
|
|
};
|
2012-11-01 17:14:33 +01:00
|
|
|
|
2012-11-14 20:52:53 +01:00
|
|
|
exports.clear_search = function () {
|
2012-12-18 21:45:48 +01:00
|
|
|
narrow.deactivate();
|
2013-02-27 21:00:06 +01:00
|
|
|
|
|
|
|
$('#search_query').blur();
|
2012-12-18 23:38:55 +01:00
|
|
|
exports.update_button_visibility();
|
2012-12-07 20:18:01 +01:00
|
|
|
};
|
|
|
|
|
2012-11-14 20:52:53 +01:00
|
|
|
return exports;
|
|
|
|
|
|
|
|
}());
|
2013-07-28 23:03:43 +02:00
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = search;
|
|
|
|
}
|
2018-05-28 08:04:36 +02:00
|
|
|
window.search = search;
|