mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
Move parse/unparse from narrow to Filter.
I'm trying to move well-isolated methods out of narrow.js, so that narrow.js is more strongly focused on UI/ajax interactions and big, heavy lifting stuff. The logical home for parse/unparse seemed to be Filter, and they brought along two private methods with them. The big code moves involved trivial follow ups like s/exports/Filter/. (imported from commit ace0fe5aa1c7abce0334d079ba9eb8d9a57bd10f)
This commit is contained in:
@@ -47,6 +47,81 @@ Filter.canonicalize_tuple = function (tuple) {
|
||||
return [operator, operand];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* We use a variant of URI encoding which looks reasonably
|
||||
nice and still handles unambiguously cases such as
|
||||
spaces in operands.
|
||||
|
||||
This is just for the search bar, not for saving the
|
||||
narrow in the URL fragment. There we do use full
|
||||
URI encoding to avoid problematic characters. */
|
||||
function encodeOperand(operand) {
|
||||
return operand.replace(/%/g, '%25')
|
||||
.replace(/\+/g, '%2B')
|
||||
.replace(/ /g, '+');
|
||||
}
|
||||
|
||||
function decodeOperand(encoded) {
|
||||
return util.robust_uri_decode(encoded.replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
// Parse a string into a list of operators (see below).
|
||||
Filter.parse = function (str) {
|
||||
var operators = [];
|
||||
var search_term = [];
|
||||
var matches = str.match(/"[^"]+"|\S+/g);
|
||||
if (matches === null) {
|
||||
return operators;
|
||||
}
|
||||
_.each(matches, function (token) {
|
||||
var parts, operator;
|
||||
if (token.length === 0) {
|
||||
return;
|
||||
}
|
||||
parts = token.split(':');
|
||||
if (token[0] === '"' || parts.length === 1) {
|
||||
// Looks like a normal search term.
|
||||
search_term.push(token);
|
||||
} else {
|
||||
// Looks like an operator.
|
||||
// FIXME: Should we skip unknown operator names here?
|
||||
operator = parts.shift();
|
||||
operators.push([operator, decodeOperand(parts.join(':'))]);
|
||||
}
|
||||
});
|
||||
// NB: Callers of 'parse' can assume that the 'search' operator is last.
|
||||
if (search_term.length > 0) {
|
||||
operators.push(['search', search_term.join(' ')]);
|
||||
}
|
||||
return operators;
|
||||
};
|
||||
|
||||
/* Convert a list of operators to a string.
|
||||
Each operator is a key-value pair like
|
||||
|
||||
['subject', 'my amazing subject']
|
||||
|
||||
These are not keys in a JavaScript object, because we
|
||||
might need to support multiple operators of the same type.
|
||||
*/
|
||||
Filter.unparse = function (operators) {
|
||||
var parts = _.map(operators, function (elem) {
|
||||
var operator = elem[0];
|
||||
if (operator === 'search') {
|
||||
// Search terms are the catch-all case.
|
||||
// All tokens that don't start with a known operator and
|
||||
// a colon are glued together to form a search term.
|
||||
return elem[1];
|
||||
} else {
|
||||
return elem[0] + ':' + encodeOperand(elem[1]);
|
||||
}
|
||||
});
|
||||
return parts.join(' ');
|
||||
};
|
||||
|
||||
|
||||
|
||||
Filter.prototype = {
|
||||
predicate: function Filter_predicate() {
|
||||
if (this._predicate === undefined) {
|
||||
|
||||
@@ -39,48 +39,8 @@ exports.public_operators = function () {
|
||||
return current_filter.public_operators();
|
||||
};
|
||||
|
||||
/* We use a variant of URI encoding which looks reasonably
|
||||
nice and still handles unambiguously cases such as
|
||||
spaces in operands.
|
||||
|
||||
This is just for the search bar, not for saving the
|
||||
narrow in the URL fragment. There we do use full
|
||||
URI encoding to avoid problematic characters. */
|
||||
function encodeOperand(operand) {
|
||||
return operand.replace(/%/g, '%25')
|
||||
.replace(/\+/g, '%2B')
|
||||
.replace(/ /g, '+');
|
||||
}
|
||||
|
||||
function decodeOperand(encoded) {
|
||||
return util.robust_uri_decode(encoded.replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
/* Convert a list of operators to a string.
|
||||
Each operator is a key-value pair like
|
||||
|
||||
['subject', 'my amazing subject']
|
||||
|
||||
These are not keys in a JavaScript object, because we
|
||||
might need to support multiple operators of the same type.
|
||||
*/
|
||||
exports.unparse = function (operators) {
|
||||
var parts = _.map(operators, function (elem) {
|
||||
var operator = elem[0];
|
||||
if (operator === 'search') {
|
||||
// Search terms are the catch-all case.
|
||||
// All tokens that don't start with a known operator and
|
||||
// a colon are glued together to form a search term.
|
||||
return elem[1];
|
||||
} else {
|
||||
return elem[0] + ':' + encodeOperand(elem[1]);
|
||||
}
|
||||
});
|
||||
return parts.join(' ');
|
||||
};
|
||||
|
||||
exports.search_string = function () {
|
||||
return exports.unparse(exports.operators());
|
||||
return Filter.unparse(exports.operators());
|
||||
};
|
||||
|
||||
// Collect operators which appear only once into an object,
|
||||
@@ -125,37 +85,6 @@ exports.set_compose_defaults = function (opts) {
|
||||
}
|
||||
};
|
||||
|
||||
// Parse a string into a list of operators (see below).
|
||||
exports.parse = function (str) {
|
||||
var operators = [];
|
||||
var search_term = [];
|
||||
var matches = str.match(/"[^"]+"|\S+/g);
|
||||
if (matches === null) {
|
||||
return operators;
|
||||
}
|
||||
_.each(matches, function (token) {
|
||||
var parts, operator;
|
||||
if (token.length === 0) {
|
||||
return;
|
||||
}
|
||||
parts = token.split(':');
|
||||
if (token[0] === '"' || parts.length === 1) {
|
||||
// Looks like a normal search term.
|
||||
search_term.push(token);
|
||||
} else {
|
||||
// Looks like an operator.
|
||||
// FIXME: Should we skip unknown operator names here?
|
||||
operator = parts.shift();
|
||||
operators.push([operator, decodeOperand(parts.join(':'))]);
|
||||
}
|
||||
});
|
||||
// NB: Callers of 'parse' can assume that the 'search' operator is last.
|
||||
if (search_term.length > 0) {
|
||||
operators.push(['search', search_term.join(' ')]);
|
||||
}
|
||||
return operators;
|
||||
};
|
||||
|
||||
exports.stream = function () {
|
||||
if (current_filter === undefined) {
|
||||
return undefined;
|
||||
@@ -305,7 +234,7 @@ exports.activate = function (operators, opts) {
|
||||
}
|
||||
|
||||
// Put the narrow operators in the search bar.
|
||||
$('#search_query').val(exports.unparse(operators));
|
||||
$('#search_query').val(Filter.unparse(operators));
|
||||
search.update_button_visibility();
|
||||
compose.update_recipient_on_narrow();
|
||||
compose_fade.update_message_list();
|
||||
|
||||
@@ -5,7 +5,7 @@ var exports = {};
|
||||
function narrow_or_search_for_term(search_string) {
|
||||
var search_query_box = $("#search_query");
|
||||
ui.change_tab_to('#home');
|
||||
var operators = narrow.parse(search_string);
|
||||
var operators = Filter.parse(search_string);
|
||||
narrow.activate(operators, {trigger: 'search'});
|
||||
|
||||
// It's sort of annoying that this is not in a position to
|
||||
@@ -90,7 +90,7 @@ exports.initialize = function () {
|
||||
// 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)
|
||||
narrow.activate(narrow.parse(search_query_box.val()));
|
||||
narrow.activate(Filter.parse(search_query_box.val()));
|
||||
search_query_box.blur();
|
||||
update_buttons_with_focus(false);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ function get_stream_suggestions(operators) {
|
||||
var prefix = 'Narrow to stream';
|
||||
var highlighted_stream = typeahead_helper.highlight_query_in_phrase(query, stream);
|
||||
var description = prefix + ' ' + highlighted_stream;
|
||||
var search_string = narrow.unparse([['stream', stream]]);
|
||||
var search_string = Filter.unparse([['stream', stream]]);
|
||||
return {description: description, search_string: search_string};
|
||||
});
|
||||
|
||||
@@ -178,7 +178,7 @@ function get_private_suggestions(all_people, operators) {
|
||||
var suggestions = _.map(people, function (person) {
|
||||
var name = highlight_person(query, person);
|
||||
var description = 'Narrow to private messages with ' + name;
|
||||
var search_string = narrow.unparse([['pm-with', person.email]]);
|
||||
var search_string = Filter.unparse([['pm-with', person.email]]);
|
||||
return {description: description, search_string: search_string};
|
||||
});
|
||||
|
||||
@@ -214,7 +214,7 @@ function get_person_suggestions(all_people, query, prefix, operator) {
|
||||
function get_default_suggestion(operators) {
|
||||
// Here we return the canonical suggestion for the full query that the
|
||||
// user typed. (The caller passes us the parsed query as "operators".)
|
||||
var search_string = narrow.unparse(operators);
|
||||
var search_string = Filter.unparse(operators);
|
||||
var description = describe(operators);
|
||||
description = Handlebars.Utils.escapeExpression(description);
|
||||
return {description: description, search_string: search_string};
|
||||
@@ -244,7 +244,7 @@ function get_topic_suggestions(query_operators) {
|
||||
|
||||
// If somebody explicitly types search:, then we might
|
||||
// not want to suggest topics, but I feel this is a very
|
||||
// minor issue, and narrow.parse() is currently lossy
|
||||
// minor issue, and Filter.parse() is currently lossy
|
||||
// in terms of telling us whether they provided the operator,
|
||||
// i.e. "foo" and "search:foo" both become [['search', 'foo']].
|
||||
switch (operator) {
|
||||
@@ -312,7 +312,7 @@ function get_topic_suggestions(query_operators) {
|
||||
return _.map(topics, function (topic) {
|
||||
var topic_operator = ['topic', topic];
|
||||
var operators = query_operators.concat([topic_operator]);
|
||||
var search_string = narrow.unparse(operators);
|
||||
var search_string = Filter.unparse(operators);
|
||||
var description = describe(operators);
|
||||
return {description: description, search_string: search_string};
|
||||
});
|
||||
@@ -331,7 +331,7 @@ function get_operator_subset_suggestions(query, operators) {
|
||||
|
||||
for (i = operators.length - 1; i >= 1; --i) {
|
||||
var subset = operators.slice(0, i);
|
||||
var search_string = narrow.unparse(subset);
|
||||
var search_string = Filter.unparse(subset);
|
||||
var description = describe(subset);
|
||||
var suggestion = {description: description, search_string: search_string};
|
||||
suggestions.push(suggestion);
|
||||
@@ -400,7 +400,7 @@ exports.get_suggestions = function (query) {
|
||||
var suggestions;
|
||||
|
||||
// Add an entry for narrow by operators.
|
||||
var operators = narrow.parse(query);
|
||||
var operators = Filter.parse(query);
|
||||
suggestion = get_default_suggestion(operators);
|
||||
result = [suggestion];
|
||||
|
||||
|
||||
@@ -53,5 +53,15 @@ var Filter = require('js/filter.js');
|
||||
assert(!predicate({type: 'stream', stream: 'foo', subject: 'whatever'}));
|
||||
}());
|
||||
|
||||
(function test_parse_and_unparse() {
|
||||
var string ='stream:Foo topic:Bar yo';
|
||||
var operators = [['stream', 'Foo'], ['topic', 'Bar'], ['search', 'yo']];
|
||||
|
||||
assert.deepEqual(Filter.parse(string), operators);
|
||||
|
||||
string = 'stream:Foo topic:Bar yo';
|
||||
assert.deepEqual(Filter.unparse(operators), string);
|
||||
}());
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,16 +12,6 @@ var narrow = require('js/narrow.js');
|
||||
var Filter = global.Filter;
|
||||
var stream_data = global.stream_data;
|
||||
|
||||
(function test_parse_and_unparse() {
|
||||
var string ='stream:Foo topic:Bar yo';
|
||||
var operators = [['stream', 'Foo'], ['topic', 'Bar'], ['search', 'yo']];
|
||||
|
||||
assert.deepEqual(narrow.parse(string), operators);
|
||||
|
||||
string = 'stream:Foo topic:Bar yo';
|
||||
assert.deepEqual(narrow.unparse(operators), string);
|
||||
}());
|
||||
|
||||
(function test_stream() {
|
||||
var operators = [['stream', 'Foo'], ['topic', 'Bar'], ['search', 'yo']];
|
||||
narrow._set_current_filter(new Filter(operators));
|
||||
|
||||
@@ -30,11 +30,7 @@ set_global('stream_data', {
|
||||
get_name: stream_data.get_name
|
||||
});
|
||||
|
||||
var narrow = require('js/narrow.js');
|
||||
set_global('narrow', {
|
||||
parse: narrow.parse,
|
||||
unparse: narrow.unparse
|
||||
});
|
||||
set_global('narrow', {});
|
||||
|
||||
(function test_basic_get_suggestions() {
|
||||
var query = 'fred';
|
||||
|
||||
Reference in New Issue
Block a user