var narrow = (function () { var exports = {}; // For tracking where you were before you narrowed. var persistent_message_id = 0; // For narrowing based on a particular message var target_id = 0; var filter_function = false; var current_operators = false; exports.active = function () { // Cast to bool return !!filter_function; }; exports.predicate = function () { if (filter_function) { return filter_function; } else { return function () { return true; }; } }; exports.operators = function () { return current_operators; }; var show_floating_recipient; var allow_collapse; exports.show_floating_recipient = function () { return (!filter_function) || show_floating_recipient; }; exports.allow_collapse = function () { return (!filter_function) || allow_collapse; }; /* 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. */ function unparse(operators) { var parts = []; $.each(operators, function (index, 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. parts.push(elem[1]); } else { // FIXME: URI encoding will look really ugly parts.push(elem[0] + ':' + encodeURIComponent(elem[1]).toLowerCase()); } }); return parts.join(' '); } // Convert a list of operators to a human-readable description. exports.describe = function (operators) { return $.map(operators, function (elem) { var operand = elem[1]; switch (elem[0]) { case 'is': if (operand === 'private-message') return 'private messages'; break; case 'stream': return 'stream ' + operand; case 'subject': return 'subject ' + operand; case 'pm-with': return 'private messages with ' + operand; case 'search': return 'messages containing ' + operand; } return '(unknown operator)'; }).join(', '); }; // Parse a string into a list of operators (see below). exports.parse = function (str) { var operators = []; var search_term = []; $.each(str.split(/ +/), function (idx, token) { var parts, operator; if (token.length === 0) return; parts = token.split(':'); if (parts.length > 1) { // Looks like an operator. // FIXME: Should we skip unknown operator names here? operator = parts.shift(); operators.push([operator, decodeURIComponent(parts.join(':'))]); } else { // Looks like a normal search term. search_term.push(token); } }); // 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; }; // Build a filter function from a list of operators. function build_filter(operators_mixed_case) { var operators = []; // We don't use $.map because it flattens returned arrays. $.each(operators_mixed_case, function (idx, operator) { operators.push([operator[0], operator[1].toLowerCase()]); }); // FIXME: This is probably pretty slow. // We could turn it into something more like a compiler: // build JavaScript code in a string and then eval() it. return function (message) { var operand, i; for (i=0; i