mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 22:13:26 +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];
|
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 = {
|
Filter.prototype = {
|
||||||
predicate: function Filter_predicate() {
|
predicate: function Filter_predicate() {
|
||||||
if (this._predicate === undefined) {
|
if (this._predicate === undefined) {
|
||||||
|
|||||||
@@ -39,48 +39,8 @@ exports.public_operators = function () {
|
|||||||
return current_filter.public_operators();
|
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 () {
|
exports.search_string = function () {
|
||||||
return exports.unparse(exports.operators());
|
return Filter.unparse(exports.operators());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collect operators which appear only once into an object,
|
// 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 () {
|
exports.stream = function () {
|
||||||
if (current_filter === undefined) {
|
if (current_filter === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -305,7 +234,7 @@ exports.activate = function (operators, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put the narrow operators in the search bar.
|
// Put the narrow operators in the search bar.
|
||||||
$('#search_query').val(exports.unparse(operators));
|
$('#search_query').val(Filter.unparse(operators));
|
||||||
search.update_button_visibility();
|
search.update_button_visibility();
|
||||||
compose.update_recipient_on_narrow();
|
compose.update_recipient_on_narrow();
|
||||||
compose_fade.update_message_list();
|
compose_fade.update_message_list();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var exports = {};
|
|||||||
function narrow_or_search_for_term(search_string) {
|
function narrow_or_search_for_term(search_string) {
|
||||||
var search_query_box = $("#search_query");
|
var search_query_box = $("#search_query");
|
||||||
ui.change_tab_to('#home');
|
ui.change_tab_to('#home');
|
||||||
var operators = narrow.parse(search_string);
|
var operators = Filter.parse(search_string);
|
||||||
narrow.activate(operators, {trigger: 'search'});
|
narrow.activate(operators, {trigger: 'search'});
|
||||||
|
|
||||||
// It's sort of annoying that this is not in a position to
|
// 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
|
// operators. (The reason the other actions don't call
|
||||||
// this codepath is that they first all blur the box to
|
// this codepath is that they first all blur the box to
|
||||||
// indicate that they've done what they need to do)
|
// 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();
|
search_query_box.blur();
|
||||||
update_buttons_with_focus(false);
|
update_buttons_with_focus(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ function get_stream_suggestions(operators) {
|
|||||||
var prefix = 'Narrow to stream';
|
var prefix = 'Narrow to stream';
|
||||||
var highlighted_stream = typeahead_helper.highlight_query_in_phrase(query, stream);
|
var highlighted_stream = typeahead_helper.highlight_query_in_phrase(query, stream);
|
||||||
var description = prefix + ' ' + highlighted_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};
|
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 suggestions = _.map(people, function (person) {
|
||||||
var name = highlight_person(query, person);
|
var name = highlight_person(query, person);
|
||||||
var description = 'Narrow to private messages with ' + name;
|
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};
|
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) {
|
function get_default_suggestion(operators) {
|
||||||
// Here we return the canonical suggestion for the full query that the
|
// Here we return the canonical suggestion for the full query that the
|
||||||
// user typed. (The caller passes us the parsed query as "operators".)
|
// 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);
|
var description = describe(operators);
|
||||||
description = Handlebars.Utils.escapeExpression(description);
|
description = Handlebars.Utils.escapeExpression(description);
|
||||||
return {description: description, search_string: search_string};
|
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
|
// If somebody explicitly types search:, then we might
|
||||||
// not want to suggest topics, but I feel this is a very
|
// 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,
|
// in terms of telling us whether they provided the operator,
|
||||||
// i.e. "foo" and "search:foo" both become [['search', 'foo']].
|
// i.e. "foo" and "search:foo" both become [['search', 'foo']].
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
@@ -312,7 +312,7 @@ function get_topic_suggestions(query_operators) {
|
|||||||
return _.map(topics, function (topic) {
|
return _.map(topics, function (topic) {
|
||||||
var topic_operator = ['topic', topic];
|
var topic_operator = ['topic', topic];
|
||||||
var operators = query_operators.concat([topic_operator]);
|
var operators = query_operators.concat([topic_operator]);
|
||||||
var search_string = narrow.unparse(operators);
|
var search_string = Filter.unparse(operators);
|
||||||
var description = describe(operators);
|
var description = describe(operators);
|
||||||
return {description: description, search_string: search_string};
|
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) {
|
for (i = operators.length - 1; i >= 1; --i) {
|
||||||
var subset = operators.slice(0, i);
|
var subset = operators.slice(0, i);
|
||||||
var search_string = narrow.unparse(subset);
|
var search_string = Filter.unparse(subset);
|
||||||
var description = describe(subset);
|
var description = describe(subset);
|
||||||
var suggestion = {description: description, search_string: search_string};
|
var suggestion = {description: description, search_string: search_string};
|
||||||
suggestions.push(suggestion);
|
suggestions.push(suggestion);
|
||||||
@@ -400,7 +400,7 @@ exports.get_suggestions = function (query) {
|
|||||||
var suggestions;
|
var suggestions;
|
||||||
|
|
||||||
// Add an entry for narrow by operators.
|
// Add an entry for narrow by operators.
|
||||||
var operators = narrow.parse(query);
|
var operators = Filter.parse(query);
|
||||||
suggestion = get_default_suggestion(operators);
|
suggestion = get_default_suggestion(operators);
|
||||||
result = [suggestion];
|
result = [suggestion];
|
||||||
|
|
||||||
|
|||||||
@@ -53,5 +53,15 @@ var Filter = require('js/filter.js');
|
|||||||
assert(!predicate({type: 'stream', stream: 'foo', subject: 'whatever'}));
|
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 Filter = global.Filter;
|
||||||
var stream_data = global.stream_data;
|
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() {
|
(function test_stream() {
|
||||||
var operators = [['stream', 'Foo'], ['topic', 'Bar'], ['search', 'yo']];
|
var operators = [['stream', 'Foo'], ['topic', 'Bar'], ['search', 'yo']];
|
||||||
narrow._set_current_filter(new Filter(operators));
|
narrow._set_current_filter(new Filter(operators));
|
||||||
|
|||||||
@@ -30,11 +30,7 @@ set_global('stream_data', {
|
|||||||
get_name: stream_data.get_name
|
get_name: stream_data.get_name
|
||||||
});
|
});
|
||||||
|
|
||||||
var narrow = require('js/narrow.js');
|
set_global('narrow', {});
|
||||||
set_global('narrow', {
|
|
||||||
parse: narrow.parse,
|
|
||||||
unparse: narrow.unparse
|
|
||||||
});
|
|
||||||
|
|
||||||
(function test_basic_get_suggestions() {
|
(function test_basic_get_suggestions() {
|
||||||
var query = 'fred';
|
var query = 'fred';
|
||||||
|
|||||||
Reference in New Issue
Block a user