diff --git a/frontend_tests/node_tests/filter.js b/frontend_tests/node_tests/filter.js index 49473db7c3..820e7af13b 100644 --- a/frontend_tests/node_tests/filter.js +++ b/frontend_tests/node_tests/filter.js @@ -665,6 +665,20 @@ run_test('describe', () => { string = 'stream devel, exclude messages with one or more image'; assert.equal(Filter.describe(narrow), string); + narrow = [ + {operator: 'has', operand: 'abc', negated: true}, + {operator: 'stream', operand: 'devel'}, + ]; + string = 'invalid abc operand for has operator, stream devel'; + assert.equal(Filter.describe(narrow), string); + + narrow = [ + {operator: 'has', operand: 'image', negated: true}, + {operator: 'stream', operand: 'devel'}, + ]; + string = 'exclude messages with one or more image, stream devel'; + assert.equal(Filter.describe(narrow), string); + narrow = []; string = 'all messages'; assert.equal(Filter.describe(narrow), string); diff --git a/static/js/filter.js b/static/js/filter.js index e608e03e5a..953fd6bf9f 100644 --- a/static/js/filter.js +++ b/static/js/filter.js @@ -553,6 +553,7 @@ Filter.operator_to_prefix = function (operator, negated) { case 'near': return verb + 'messages around'; + // Note: We hack around using this in "describe" below. case 'has': return verb + 'messages with one or more'; @@ -623,6 +624,14 @@ function describe_unescaped(operators) { } return operand + ' messages'; } + if (canonicalized_operator ==='has') { + // search_suggestion.get_suggestions takes care that this message will + // only be shown if the `has` operator is not at the last. + var valid_has_operands = ['image', 'images', 'link', 'links', 'attachment', 'attachments']; + if (valid_has_operands.indexOf(operand) === -1) { + return 'invalid ' + operand + ' operand for has operator'; + } + } var prefix_for_operator = Filter.operator_to_prefix(canonicalized_operator, elem.negated); if (prefix_for_operator !== '') {