mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	js: Remove inner spacing from object literals.
We’re configuring Prettier with bracketSpacing: false. Generated by ESLint. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							a20c12366f
						
					
				
				
					commit
					883e2fd325
				
			@@ -105,6 +105,7 @@
 | 
			
		||||
        "no-var": "error",
 | 
			
		||||
        "space-unary-ops": "error",
 | 
			
		||||
        "no-whitespace-before-property": "error",
 | 
			
		||||
        "object-curly-spacing": ["error", "never"],
 | 
			
		||||
        "one-var": [ "error", "never" ],
 | 
			
		||||
        "prefer-arrow-callback": "error",
 | 
			
		||||
        "prefer-const": [ "error",
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ module.exports = {
 | 
			
		||||
    ],
 | 
			
		||||
    plugins: [
 | 
			
		||||
        "@babel/proposal-class-properties",
 | 
			
		||||
        ["@babel/plugin-proposal-unicode-property-regex", { useUnicodeFlag: false }],
 | 
			
		||||
        ["@babel/plugin-proposal-unicode-property-regex", {useUnicodeFlag: false}],
 | 
			
		||||
    ],
 | 
			
		||||
    sourceType: "unambiguous",
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -147,7 +147,7 @@ exports.select_item_via_typeahead = function (field_selector, str, item) {
 | 
			
		||||
            $(field_selector)
 | 
			
		||||
                .focus()
 | 
			
		||||
                .val(str)
 | 
			
		||||
                .trigger($.Event("keyup", { which: 0 }));
 | 
			
		||||
                .trigger($.Event("keyup", {which: 0}));
 | 
			
		||||
 | 
			
		||||
            // You might think these steps should be split by casper.then,
 | 
			
		||||
            // but apparently that's enough to make the typeahead close (??),
 | 
			
		||||
@@ -228,7 +228,7 @@ exports.wait_for_message_fully_processed = function (content) {
 | 
			
		||||
                responds.
 | 
			
		||||
            */
 | 
			
		||||
            return row.find(".star").length === 1;
 | 
			
		||||
        }, { content: content});
 | 
			
		||||
        }, {content: content});
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -249,8 +249,8 @@ exports.pm_recipient = {
 | 
			
		||||
    set: function (recip) {
 | 
			
		||||
        casper.evaluate(function (recipient) {
 | 
			
		||||
            $("#private_message_recipient").text(recipient)
 | 
			
		||||
                .trigger({ type: "keydown", keyCode: 13 });
 | 
			
		||||
        }, { recipient: recip });
 | 
			
		||||
                .trigger({type: "keydown", keyCode: 13});
 | 
			
		||||
        }, {recipient: recip});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expect: function (expected_value) {
 | 
			
		||||
@@ -373,7 +373,7 @@ exports.get_stream_id = function (stream_name) {
 | 
			
		||||
// presses by code, only strings of printable characters.
 | 
			
		||||
exports.keypress = function (code) {
 | 
			
		||||
    casper.evaluate(function (code) {
 | 
			
		||||
        $("body").trigger($.Event("keydown", { which: code }));
 | 
			
		||||
        $("body").trigger($.Event("keydown", {which: code}));
 | 
			
		||||
    }, {
 | 
			
		||||
        code: code,
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -29,23 +29,23 @@ casper.then(function () {
 | 
			
		||||
// Send some messages.
 | 
			
		||||
 | 
			
		||||
common.then_send_many([
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test verona A" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test verona A"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test verona B" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test verona B"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "other subject",
 | 
			
		||||
      content: "test verona C" },
 | 
			
		||||
    {stream: "Verona", subject: "other subject",
 | 
			
		||||
     content: "test verona C"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal A" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal A"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal B" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal B"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com",
 | 
			
		||||
      content: "personal C" }]);
 | 
			
		||||
    {recipient: "cordelia@zulip.com",
 | 
			
		||||
     content: "personal C"}]);
 | 
			
		||||
 | 
			
		||||
common.wait_for_receive(function () {
 | 
			
		||||
    common.expected_messages("zhome", [
 | 
			
		||||
@@ -66,11 +66,11 @@ common.wait_for_receive(function () {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
common.then_send_many([
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test verona D" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test verona D"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal D" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal D"},
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
common.then_log_out();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,35 +16,35 @@ casper.then(function () {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
common.then_send_many([
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test message A" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test message A"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test message B" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test message B"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "other subject",
 | 
			
		||||
      content: "test message C" },
 | 
			
		||||
    {stream: "Verona", subject: "other subject",
 | 
			
		||||
     content: "test message C"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Denmark", subject: "frontend test",
 | 
			
		||||
      content: "other message" },
 | 
			
		||||
    {stream: "Denmark", subject: "frontend test",
 | 
			
		||||
     content: "other message"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal A" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal A"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal B" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal B"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com",
 | 
			
		||||
      content: "personal C" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com",
 | 
			
		||||
     content: "personal C"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "frontend test",
 | 
			
		||||
      content: "test message D" },
 | 
			
		||||
    {stream: "Verona", subject: "frontend test",
 | 
			
		||||
     content: "test message D"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
      content: "personal D" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com, hamlet@zulip.com",
 | 
			
		||||
     content: "personal D"},
 | 
			
		||||
 | 
			
		||||
    { recipient: "cordelia@zulip.com",
 | 
			
		||||
      content: "personal E" },
 | 
			
		||||
    {recipient: "cordelia@zulip.com",
 | 
			
		||||
     content: "personal E"},
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,11 @@ casper.then(function () {
 | 
			
		||||
 | 
			
		||||
// Send a message to try replying to
 | 
			
		||||
common.then_send_many([
 | 
			
		||||
    { stream: "Verona",
 | 
			
		||||
    {stream: "Verona",
 | 
			
		||||
     subject: "Reply test",
 | 
			
		||||
     content: "We reply to this message",
 | 
			
		||||
    },
 | 
			
		||||
    { recipient: "cordelia@zulip.com",
 | 
			
		||||
    {recipient: "cordelia@zulip.com",
 | 
			
		||||
     content: "And reply to this message",
 | 
			
		||||
    },
 | 
			
		||||
]);
 | 
			
		||||
 
 | 
			
		||||
@@ -287,7 +287,7 @@ function get_suggestions(str) {
 | 
			
		||||
            $(".create_default_stream")
 | 
			
		||||
                .focus()
 | 
			
		||||
                .val(str)
 | 
			
		||||
                .trigger($.Event("keyup", { which: 0 }));
 | 
			
		||||
                .trigger($.Event("keyup", {which: 0}));
 | 
			
		||||
        }, str);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,26 +8,26 @@ casper.then(function () {
 | 
			
		||||
 | 
			
		||||
// setup environment: several messages to different topics
 | 
			
		||||
common.then_send_many([
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #1",
 | 
			
		||||
      content: "copy paste test A" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #1",
 | 
			
		||||
     content: "copy paste test A"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #1",
 | 
			
		||||
      content: "copy paste test B" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #1",
 | 
			
		||||
     content: "copy paste test B"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
      content: "copy paste test C" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
     content: "copy paste test C"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
      content: "copy paste test D" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
     content: "copy paste test D"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
      content: "copy paste test E" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #2",
 | 
			
		||||
     content: "copy paste test E"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #3",
 | 
			
		||||
      content: "copy paste test F" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #3",
 | 
			
		||||
     content: "copy paste test F"},
 | 
			
		||||
 | 
			
		||||
    { stream: "Verona", subject: "copy-paste-subject #3",
 | 
			
		||||
      content: "copy paste test G" },
 | 
			
		||||
    {stream: "Verona", subject: "copy-paste-subject #3",
 | 
			
		||||
     content: "copy paste test G"},
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
common.wait_for_receive(function () {
 | 
			
		||||
@@ -69,7 +69,7 @@ function copy_messages(start_message, end_message) {
 | 
			
		||||
        $("#copytempdiv").remove();
 | 
			
		||||
 | 
			
		||||
        // emulate copy event
 | 
			
		||||
        $("body").trigger($.Event("keydown", { which: 67, ctrlKey: true }));
 | 
			
		||||
        $("body").trigger($.Event("keydown", {which: 67, ctrlKey: true}));
 | 
			
		||||
 | 
			
		||||
        // find temp div with copied text
 | 
			
		||||
        var temp_div = $("#copytempdiv");
 | 
			
		||||
 
 | 
			
		||||
@@ -133,9 +133,9 @@ people.add_active_user(me);
 | 
			
		||||
people.initialize_current_user(me.user_id);
 | 
			
		||||
 | 
			
		||||
const presence_info = new Map();
 | 
			
		||||
presence_info.set(alice.user_id, { status: "inactive" });
 | 
			
		||||
presence_info.set(fred.user_id, { status: "active" });
 | 
			
		||||
presence_info.set(jill.user_id, { status: "active" });
 | 
			
		||||
presence_info.set(alice.user_id, {status: "inactive"});
 | 
			
		||||
presence_info.set(fred.user_id, {status: "active"});
 | 
			
		||||
presence_info.set(jill.user_id, {status: "active"});
 | 
			
		||||
 | 
			
		||||
presence.presence_info = presence_info;
 | 
			
		||||
 | 
			
		||||
@@ -217,13 +217,13 @@ run_test("huddle_data.process_loaded_messages", () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
presence.presence_info = new Map();
 | 
			
		||||
presence.presence_info.set(alice.user_id, { status: activity.IDLE });
 | 
			
		||||
presence.presence_info.set(fred.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(jill.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(mark.user_id, { status: activity.IDLE });
 | 
			
		||||
presence.presence_info.set(norbert.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(zoe.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(me.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(alice.user_id, {status: activity.IDLE});
 | 
			
		||||
presence.presence_info.set(fred.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(jill.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(mark.user_id, {status: activity.IDLE});
 | 
			
		||||
presence.presence_info.set(norbert.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(zoe.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(me.user_id, {status: activity.ACTIVE});
 | 
			
		||||
 | 
			
		||||
function clear_buddy_list() {
 | 
			
		||||
    buddy_list.populate({
 | 
			
		||||
@@ -404,12 +404,12 @@ run_test("handlers", () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
presence.presence_info = new Map();
 | 
			
		||||
presence.presence_info.set(alice.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(fred.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(jill.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(mark.user_id, { status: activity.IDLE });
 | 
			
		||||
presence.presence_info.set(norbert.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(zoe.user_id, { status: activity.ACTIVE });
 | 
			
		||||
presence.presence_info.set(alice.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(fred.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(jill.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(mark.user_id, {status: activity.IDLE});
 | 
			
		||||
presence.presence_info.set(norbert.user_id, {status: activity.ACTIVE});
 | 
			
		||||
presence.presence_info.set(zoe.user_id, {status: activity.ACTIVE});
 | 
			
		||||
 | 
			
		||||
reset_setup();
 | 
			
		||||
 | 
			
		||||
@@ -475,13 +475,13 @@ run_test("filter_user_ids", () => {
 | 
			
		||||
    user_ids = get_user_ids();
 | 
			
		||||
    assert.deepEqual(user_ids, [alice.user_id, fred.user_id]);
 | 
			
		||||
 | 
			
		||||
    presence.presence_info.set(alice.user_id, { status: activity.IDLE });
 | 
			
		||||
    presence.presence_info.set(alice.user_id, {status: activity.IDLE});
 | 
			
		||||
    user_filter.val("fr,al"); // match fred and alice partials and idle user
 | 
			
		||||
    user_ids = get_user_ids();
 | 
			
		||||
    assert.deepEqual(user_ids, [fred.user_id, alice.user_id]);
 | 
			
		||||
 | 
			
		||||
    $.stub_selector(".user-list-filter", []);
 | 
			
		||||
    presence.presence_info.set(alice.user_id, { status: activity.ACTIVE });
 | 
			
		||||
    presence.presence_info.set(alice.user_id, {status: activity.ACTIVE});
 | 
			
		||||
    user_ids = get_user_ids();
 | 
			
		||||
    assert.deepEqual(user_ids, [alice.user_id, fred.user_id]);
 | 
			
		||||
});
 | 
			
		||||
@@ -666,7 +666,7 @@ run_test("update_presence_info", () => {
 | 
			
		||||
    activity.update_presence_info(alice.user_id, info, server_time);
 | 
			
		||||
    assert(inserted);
 | 
			
		||||
 | 
			
		||||
    const expected = { status: "active", last_active: 500 };
 | 
			
		||||
    const expected = {status: "active", last_active: 500};
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(alice.user_id), expected);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
const noop = () => {};
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const fs = require("fs");
 | 
			
		||||
 | 
			
		||||
const template = fs.readFileSync("templates/corporate/billing.html", "utf-8");
 | 
			
		||||
const dom = new JSDOM(template, { pretendToBeVisual: true });
 | 
			
		||||
const dom = new JSDOM(template, {pretendToBeVisual: true});
 | 
			
		||||
const document = dom.window.document;
 | 
			
		||||
 | 
			
		||||
let jquery_init;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const fs = require("fs");
 | 
			
		||||
const template = fs.readFileSync("templates/corporate/upgrade.html", "utf-8");
 | 
			
		||||
const dom = new JSDOM(template, { pretendToBeVisual: true });
 | 
			
		||||
const dom = new JSDOM(template, {pretendToBeVisual: true});
 | 
			
		||||
const jquery = require("jquery")(dom.window);
 | 
			
		||||
 | 
			
		||||
set_global("$", global.make_zjquery());
 | 
			
		||||
 
 | 
			
		||||
@@ -102,7 +102,7 @@ run_test("test_basics", () => {
 | 
			
		||||
    (function test_remove() {
 | 
			
		||||
        let bot;
 | 
			
		||||
 | 
			
		||||
        bot_data.add({ ...test_bot, is_active: true });
 | 
			
		||||
        bot_data.add({...test_bot, is_active: true});
 | 
			
		||||
 | 
			
		||||
        bot = bot_data.get(43);
 | 
			
		||||
        assert.equal("Bot 1", bot.full_name);
 | 
			
		||||
@@ -121,7 +121,7 @@ run_test("test_basics", () => {
 | 
			
		||||
    (function test_delete() {
 | 
			
		||||
        let bot;
 | 
			
		||||
 | 
			
		||||
        bot_data.add({ ...test_bot, is_active: true });
 | 
			
		||||
        bot_data.add({...test_bot, is_active: true});
 | 
			
		||||
 | 
			
		||||
        bot = bot_data.get(43);
 | 
			
		||||
        assert.equal("Bot 1", bot.full_name);
 | 
			
		||||
 
 | 
			
		||||
@@ -105,10 +105,10 @@ run_test("huddle_fraction_present", () => {
 | 
			
		||||
    huddle = people.emails_strings_to_user_ids_string(huddle);
 | 
			
		||||
 | 
			
		||||
    let presence_info = new Map();
 | 
			
		||||
    presence_info.set(alice.user_id, { status: "active" }); // counts as present
 | 
			
		||||
    presence_info.set(fred.user_id, { status: "idle" }); // does not count as present
 | 
			
		||||
    presence_info.set(alice.user_id, {status: "active"}); // counts as present
 | 
			
		||||
    presence_info.set(fred.user_id, {status: "idle"}); // does not count as present
 | 
			
		||||
    // jill not in list
 | 
			
		||||
    presence_info.set(mark.user_id, { status: "offline" }); // does not count
 | 
			
		||||
    presence_info.set(mark.user_id, {status: "offline"}); // does not count
 | 
			
		||||
    presence.presence_info = presence_info;
 | 
			
		||||
 | 
			
		||||
    assert.equal(
 | 
			
		||||
@@ -117,7 +117,7 @@ run_test("huddle_fraction_present", () => {
 | 
			
		||||
 | 
			
		||||
    presence_info = new Map();
 | 
			
		||||
    for (const user of [alice, fred, jill, mark]) {
 | 
			
		||||
        presence_info.set(user.user_id, { status: "active" }); // counts as present
 | 
			
		||||
        presence_info.set(user.user_id, {status: "active"}); // counts as present
 | 
			
		||||
    }
 | 
			
		||||
    presence.presence_info = presence_info;
 | 
			
		||||
 | 
			
		||||
@@ -128,10 +128,10 @@ run_test("huddle_fraction_present", () => {
 | 
			
		||||
    huddle = "alice@zulip.com,fred@zulip.com,jill@zulip.com,mark@zulip.com";
 | 
			
		||||
    huddle = people.emails_strings_to_user_ids_string(huddle);
 | 
			
		||||
    presence_info = new Map();
 | 
			
		||||
    presence_info.set(alice.user_id, { status: "idle" });
 | 
			
		||||
    presence_info.set(fred.user_id, { status: "idle" }); // does not count as present
 | 
			
		||||
    presence_info.set(alice.user_id, {status: "idle"});
 | 
			
		||||
    presence_info.set(fred.user_id, {status: "idle"}); // does not count as present
 | 
			
		||||
    // jill not in list
 | 
			
		||||
    presence_info.set(mark.user_id, { status: "offline" }); // does not count
 | 
			
		||||
    presence_info.set(mark.user_id, {status: "offline"}); // does not count
 | 
			
		||||
    presence.presence_info = presence_info;
 | 
			
		||||
 | 
			
		||||
    assert.equal(
 | 
			
		||||
 
 | 
			
		||||
@@ -11,10 +11,10 @@ run_test("pick_color", () => {
 | 
			
		||||
    color_data.reset();
 | 
			
		||||
 | 
			
		||||
    color_data.claim_colors([
 | 
			
		||||
        { color: "orange" },
 | 
			
		||||
        { foo: "whatever" },
 | 
			
		||||
        { color: "yellow" },
 | 
			
		||||
        { color: "bogus" },
 | 
			
		||||
        {color: "orange"},
 | 
			
		||||
        {foo: "whatever"},
 | 
			
		||||
        {color: "yellow"},
 | 
			
		||||
        {color: "bogus"},
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const expected_colors = [
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@ zrequire("components");
 | 
			
		||||
 | 
			
		||||
const noop = function () {};
 | 
			
		||||
 | 
			
		||||
const LEFT_KEY = { which: 37, preventDefault: noop, stopPropagation: noop };
 | 
			
		||||
const RIGHT_KEY = { which: 39, preventDefault: noop, stopPropagation: noop };
 | 
			
		||||
const LEFT_KEY = {which: 37, preventDefault: noop, stopPropagation: noop};
 | 
			
		||||
const RIGHT_KEY = {which: 39, preventDefault: noop, stopPropagation: noop};
 | 
			
		||||
 | 
			
		||||
run_test("basics", () => {
 | 
			
		||||
    let keydown_f;
 | 
			
		||||
@@ -136,9 +136,9 @@ run_test("basics", () => {
 | 
			
		||||
    widget = components.toggle({
 | 
			
		||||
        selected: 0,
 | 
			
		||||
        values: [
 | 
			
		||||
            { label: i18n.t("Keyboard shortcuts"), key: "keyboard-shortcuts" },
 | 
			
		||||
            { label: i18n.t("Message formatting"), key: "message-formatting" },
 | 
			
		||||
            { label: i18n.t("Search operators"), key: "search-operators" },
 | 
			
		||||
            {label: i18n.t("Keyboard shortcuts"), key: "keyboard-shortcuts"},
 | 
			
		||||
            {label: i18n.t("Message formatting"), key: "message-formatting"},
 | 
			
		||||
            {label: i18n.t("Search operators"), key: "search-operators"},
 | 
			
		||||
        ],
 | 
			
		||||
        html_class: "stream_sorter_toggle",
 | 
			
		||||
        callback: function (name, key) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
const rewiremock = require("rewiremock/node");
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
 | 
			
		||||
set_global("bridge", false);
 | 
			
		||||
 | 
			
		||||
@@ -1470,7 +1470,7 @@ run_test("on_events", () => {
 | 
			
		||||
 | 
			
		||||
        channel.post = function (payload) {
 | 
			
		||||
            assert.equal(payload.url, "/json/calls/zoom/create");
 | 
			
		||||
            payload.success({ url: "example.zoom.com" });
 | 
			
		||||
            payload.success({url: "example.zoom.com"});
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        handler(ev);
 | 
			
		||||
@@ -1482,7 +1482,7 @@ run_test("on_events", () => {
 | 
			
		||||
 | 
			
		||||
        channel.get = function (options) {
 | 
			
		||||
            assert(options.url === "/json/calls/bigbluebutton/create");
 | 
			
		||||
            options.success({ url: "/calls/bigbluebutton/join?meeting_id=%22zulip-1%22&password=%22AAAAAAAAAA%22&checksum=%2232702220bff2a22a44aee72e96cfdb4c4091752e%22" });
 | 
			
		||||
            options.success({url: "/calls/bigbluebutton/join?meeting_id=%22zulip-1%22&password=%22AAAAAAAAAA%22&checksum=%2232702220bff2a22a44aee72e96cfdb4c4091752e%22"});
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        handler(ev);
 | 
			
		||||
@@ -1692,7 +1692,7 @@ run_test("create_message_object", () => {
 | 
			
		||||
    assert.equal(message.to_user_ids, "31,32");
 | 
			
		||||
    assert.equal(message.content, "burrito");
 | 
			
		||||
 | 
			
		||||
    const { email_list_to_user_ids_string } = people;
 | 
			
		||||
    const {email_list_to_user_ids_string} = people;
 | 
			
		||||
    people.email_list_to_user_ids_string = () => undefined;
 | 
			
		||||
    message = compose.create_message_object();
 | 
			
		||||
    assert.deepEqual(message.to, [alice.email, bob.email]);
 | 
			
		||||
 
 | 
			
		||||
@@ -276,7 +276,7 @@ global.user_groups.add(backend);
 | 
			
		||||
global.user_groups.add(call_center);
 | 
			
		||||
 | 
			
		||||
const make_emoji = function (emoji_dict) {
 | 
			
		||||
    return { emoji_name: emoji_dict.name, emoji_code: emoji_dict.emoji_code };
 | 
			
		||||
    return {emoji_name: emoji_dict.name, emoji_code: emoji_dict.emoji_code};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
run_test("topics_seen_for", () => {
 | 
			
		||||
@@ -759,7 +759,7 @@ run_test("initialize", () => {
 | 
			
		||||
        actual_value = options.updater(cordelia, event);
 | 
			
		||||
        assert.equal(appended_name, "Cordelia Lear");
 | 
			
		||||
 | 
			
		||||
        const click_event = { type: "click", target: "#doesnotmatter" };
 | 
			
		||||
        const click_event = {type: "click", target: "#doesnotmatter"};
 | 
			
		||||
        options.query = "othello";
 | 
			
		||||
        // Focus lost (caused by the click event in the typeahead list)
 | 
			
		||||
        $("#private_message_recipient").blur();
 | 
			
		||||
@@ -827,12 +827,12 @@ run_test("initialize", () => {
 | 
			
		||||
        //
 | 
			
		||||
        // Again, here we only verify that the highlighter has been set to
 | 
			
		||||
        // content_highlighter.
 | 
			
		||||
        fake_this = { completing: "mention", token: "othello" };
 | 
			
		||||
        fake_this = {completing: "mention", token: "othello"};
 | 
			
		||||
        actual_value = options.highlighter.call(fake_this, othello);
 | 
			
		||||
        expected_value = `        <img class="typeahead-image" src="/avatar/${othello.user_id}&s=50" />\n<strong>Othello, the Moor of Venice</strong>`;
 | 
			
		||||
        assert.equal(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "mention", token: "hamletcharacters" };
 | 
			
		||||
        fake_this = {completing: "mention", token: "hamletcharacters"};
 | 
			
		||||
        actual_value = options.highlighter.call(fake_this, hamletcharacters);
 | 
			
		||||
        expected_value = '        <i class="typeahead-image icon fa fa-group" aria-hidden="true"></i>\n<strong>hamletcharacters</strong>  \n<small class="autocomplete_secondary">Characters of Hamlet</small>\n';
 | 
			
		||||
        assert.equal(actual_value, expected_value);
 | 
			
		||||
@@ -846,19 +846,19 @@ run_test("initialize", () => {
 | 
			
		||||
            return ct.compose_content_matcher(completing, token)(item);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "emoji", token: "ta" };
 | 
			
		||||
        fake_this = {completing: "emoji", token: "ta"};
 | 
			
		||||
        assert.equal(match(fake_this, make_emoji(emoji_tada)), true);
 | 
			
		||||
        assert.equal(match(fake_this, make_emoji(emoji_moneybag)), false);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "stream", token: "swed" };
 | 
			
		||||
        fake_this = {completing: "stream", token: "swed"};
 | 
			
		||||
        assert.equal(match(fake_this, sweden_stream), true);
 | 
			
		||||
        assert.equal(match(fake_this, denmark_stream), false);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "syntax", token: "py" };
 | 
			
		||||
        fake_this = {completing: "syntax", token: "py"};
 | 
			
		||||
        assert.equal(match(fake_this, "python"), true);
 | 
			
		||||
        assert.equal(match(fake_this, "javascript"), false);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "non-existing-completion" };
 | 
			
		||||
        fake_this = {completing: "non-existing-completion"};
 | 
			
		||||
        assert.equal(match(fake_this), undefined);
 | 
			
		||||
 | 
			
		||||
        function sort_items(fake_this, item) {
 | 
			
		||||
@@ -869,30 +869,30 @@ run_test("initialize", () => {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // options.sorter()
 | 
			
		||||
        fake_this = { completing: "emoji", token: "ta" };
 | 
			
		||||
        fake_this = {completing: "emoji", token: "ta"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [make_emoji(emoji_stadium),
 | 
			
		||||
                                              make_emoji(emoji_tada)]);
 | 
			
		||||
        expected_value = [make_emoji(emoji_tada), make_emoji(emoji_stadium)];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "emoji", token: "th" };
 | 
			
		||||
        fake_this = {completing: "emoji", token: "th"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [make_emoji(emoji_thermometer),
 | 
			
		||||
                                              make_emoji(emoji_thumbs_up)]);
 | 
			
		||||
        expected_value = [make_emoji(emoji_thumbs_up), make_emoji(emoji_thermometer)];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "emoji", token: "he" };
 | 
			
		||||
        fake_this = {completing: "emoji", token: "he"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [make_emoji(emoji_headphones),
 | 
			
		||||
                                              make_emoji(emoji_heart)]);
 | 
			
		||||
        expected_value = [make_emoji(emoji_heart), make_emoji(emoji_headphones)];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "slash", token: "m" };
 | 
			
		||||
        fake_this = {completing: "slash", token: "m"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [my_slash, me_slash]);
 | 
			
		||||
        expected_value = [me_slash, my_slash];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "stream", token: "de" };
 | 
			
		||||
        fake_this = {completing: "stream", token: "de"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [sweden_stream, denmark_stream]);
 | 
			
		||||
        expected_value = [denmark_stream, sweden_stream];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
@@ -900,12 +900,12 @@ run_test("initialize", () => {
 | 
			
		||||
        // Matches in the descriptions affect the order as well.
 | 
			
		||||
        // Testing "co" for "cold", in both streams' description. It's at the
 | 
			
		||||
        // beginning of Sweden's description, so that one should go first.
 | 
			
		||||
        fake_this = { completing: "stream", token: "co" };
 | 
			
		||||
        fake_this = {completing: "stream", token: "co"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [denmark_stream, sweden_stream]);
 | 
			
		||||
        expected_value = [sweden_stream, denmark_stream];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "syntax", token: "ap" };
 | 
			
		||||
        fake_this = {completing: "syntax", token: "ap"};
 | 
			
		||||
        actual_value = sort_items(fake_this, ["abap", "applescript"]);
 | 
			
		||||
        expected_value = ["applescript", "abap"];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
@@ -920,7 +920,7 @@ run_test("initialize", () => {
 | 
			
		||||
        stream_data.is_active = function () {
 | 
			
		||||
            return false;
 | 
			
		||||
        };
 | 
			
		||||
        fake_this = { completing: "stream", token: "s" };
 | 
			
		||||
        fake_this = {completing: "stream", token: "s"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [sweden_stream, serbia_stream]);
 | 
			
		||||
        expected_value = [sweden_stream, serbia_stream];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
@@ -932,12 +932,12 @@ run_test("initialize", () => {
 | 
			
		||||
        expected_value = [sweden_stream, serbia_stream];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "stream", token: "ser" };
 | 
			
		||||
        fake_this = {completing: "stream", token: "ser"};
 | 
			
		||||
        actual_value = sort_items(fake_this, [denmark_stream, serbia_stream]);
 | 
			
		||||
        expected_value = [serbia_stream, denmark_stream];
 | 
			
		||||
        assert.deepEqual(actual_value, expected_value);
 | 
			
		||||
 | 
			
		||||
        fake_this = { completing: "non-existing-completion" };
 | 
			
		||||
        fake_this = {completing: "non-existing-completion"};
 | 
			
		||||
        assert.equal(sort_items(fake_this), undefined);
 | 
			
		||||
 | 
			
		||||
        compose_textarea_typeahead_called = true;
 | 
			
		||||
@@ -977,12 +977,12 @@ run_test("initialize", () => {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $("#stream_message_recipient_topic").data = function () {
 | 
			
		||||
        return { typeahead: { shown: true }};
 | 
			
		||||
        return {typeahead: {shown: true}};
 | 
			
		||||
    };
 | 
			
		||||
    $("form#send_message_form").keydown(event);
 | 
			
		||||
 | 
			
		||||
    const stub_typeahead_hidden = function () {
 | 
			
		||||
        return { typeahead: { shown: false }};
 | 
			
		||||
        return {typeahead: {shown: false}};
 | 
			
		||||
    };
 | 
			
		||||
    $("#stream_message_recipient_topic").data = stub_typeahead_hidden;
 | 
			
		||||
    $("#stream_message_recipient_stream").data = stub_typeahead_hidden;
 | 
			
		||||
@@ -1057,7 +1057,7 @@ run_test("initialize", () => {
 | 
			
		||||
    };
 | 
			
		||||
    // We execute .keydown() in order to make nextFocus !== false
 | 
			
		||||
    $("#stream_message_recipient_topic").data = function () {
 | 
			
		||||
        return { typeahead: { shown: true }};
 | 
			
		||||
        return {typeahead: {shown: true}};
 | 
			
		||||
    };
 | 
			
		||||
    $("form#send_message_form").keydown(event);
 | 
			
		||||
    $("form#send_message_form").keyup(event);
 | 
			
		||||
@@ -1075,7 +1075,7 @@ run_test("initialize", () => {
 | 
			
		||||
        // This .one() function emulates the possible infinite recursion that
 | 
			
		||||
        // in_handler tries to avoid.
 | 
			
		||||
        $("#stream_message_recipient_stream").one = function (event, handler) {
 | 
			
		||||
            handler({ preventDefault: noop });
 | 
			
		||||
            handler({preventDefault: noop});
 | 
			
		||||
            f();  // This time in_handler will already be true.
 | 
			
		||||
            stream_one_called = true;
 | 
			
		||||
        };
 | 
			
		||||
@@ -1351,8 +1351,8 @@ run_test("tokenizing", () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
run_test("content_highlighter", () => {
 | 
			
		||||
    let fake_this = { completing: "emoji" };
 | 
			
		||||
    const emoji = { emoji_name: "person shrugging", emoji_url: "¯\\_(ツ)_/¯" };
 | 
			
		||||
    let fake_this = {completing: "emoji"};
 | 
			
		||||
    const emoji = {emoji_name: "person shrugging", emoji_url: "¯\\_(ツ)_/¯"};
 | 
			
		||||
    let th_render_typeahead_item_called = false;
 | 
			
		||||
    typeahead_helper.render_emoji = function (item) {
 | 
			
		||||
        assert.deepEqual(item, emoji);
 | 
			
		||||
@@ -1360,7 +1360,7 @@ run_test("content_highlighter", () => {
 | 
			
		||||
    };
 | 
			
		||||
    ct.content_highlighter.call(fake_this, emoji);
 | 
			
		||||
 | 
			
		||||
    fake_this = { completing: "mention" };
 | 
			
		||||
    fake_this = {completing: "mention"};
 | 
			
		||||
    let th_render_person_called = false;
 | 
			
		||||
    typeahead_helper.render_person = function (person) {
 | 
			
		||||
        assert.deepEqual(person, othello);
 | 
			
		||||
@@ -1376,7 +1376,7 @@ run_test("content_highlighter", () => {
 | 
			
		||||
    ct.content_highlighter.call(fake_this, backend);
 | 
			
		||||
 | 
			
		||||
    // We don't have any fancy rendering for slash commands yet.
 | 
			
		||||
    fake_this = { completing: "slash" };
 | 
			
		||||
    fake_this = {completing: "slash"};
 | 
			
		||||
    let th_render_slash_command_called = false;
 | 
			
		||||
    const me_slash = {
 | 
			
		||||
        text: "/me is excited (Display action text)",
 | 
			
		||||
@@ -1389,7 +1389,7 @@ run_test("content_highlighter", () => {
 | 
			
		||||
    };
 | 
			
		||||
    ct.content_highlighter.call(fake_this, me_slash);
 | 
			
		||||
 | 
			
		||||
    fake_this = { completing: "stream" };
 | 
			
		||||
    fake_this = {completing: "stream"};
 | 
			
		||||
    let th_render_stream_called = false;
 | 
			
		||||
    typeahead_helper.render_stream = function (stream) {
 | 
			
		||||
        assert.deepEqual(stream, denmark_stream);
 | 
			
		||||
@@ -1397,15 +1397,15 @@ run_test("content_highlighter", () => {
 | 
			
		||||
    };
 | 
			
		||||
    ct.content_highlighter.call(fake_this, denmark_stream);
 | 
			
		||||
 | 
			
		||||
    fake_this = { completing: "syntax" };
 | 
			
		||||
    fake_this = {completing: "syntax"};
 | 
			
		||||
    th_render_typeahead_item_called = false;
 | 
			
		||||
    typeahead_helper.render_typeahead_item = function (item) {
 | 
			
		||||
        assert.deepEqual(item, { primary: "py" });
 | 
			
		||||
        assert.deepEqual(item, {primary: "py"});
 | 
			
		||||
        th_render_typeahead_item_called = true;
 | 
			
		||||
    };
 | 
			
		||||
    ct.content_highlighter.call(fake_this, "py");
 | 
			
		||||
 | 
			
		||||
    fake_this = { completing: "something-else" };
 | 
			
		||||
    fake_this = {completing: "something-else"};
 | 
			
		||||
    assert(!ct.content_highlighter.call(fake_this));
 | 
			
		||||
 | 
			
		||||
    // Verify that all stub functions have been called.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,9 @@ set_global("page_params", {
 | 
			
		||||
});
 | 
			
		||||
set_global("compose_ui", {});
 | 
			
		||||
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const { window } = new JSDOM("<!DOCTYPE html><p>Hello world</p>");
 | 
			
		||||
const { DOMParser, document } = window;
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const {window} = new JSDOM("<!DOCTYPE html><p>Hello world</p>");
 | 
			
		||||
const {DOMParser, document} = window;
 | 
			
		||||
set_global("$", require("jquery")(window));
 | 
			
		||||
set_global("DOMParser", DOMParser);
 | 
			
		||||
set_global("document", document);
 | 
			
		||||
 
 | 
			
		||||
@@ -288,11 +288,11 @@ with_overrides((override) => {
 | 
			
		||||
    // realm
 | 
			
		||||
    function test_realm_boolean(event, parameter_name) {
 | 
			
		||||
        page_params[parameter_name] = true;
 | 
			
		||||
        event = { ...event };
 | 
			
		||||
        event = {...event};
 | 
			
		||||
        event.value = false;
 | 
			
		||||
        dispatch(event);
 | 
			
		||||
        assert.equal(page_params[parameter_name], false);
 | 
			
		||||
        event = { ...event };
 | 
			
		||||
        event = {...event};
 | 
			
		||||
        event.value = true;
 | 
			
		||||
        dispatch(event);
 | 
			
		||||
        assert.equal(page_params[parameter_name], true);
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@ run_test("draft_model", () => {
 | 
			
		||||
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    (function test_get() {
 | 
			
		||||
        const expected = { id1: draft_1, id2: draft_2 };
 | 
			
		||||
        const expected = {id1: draft_1, id2: draft_2};
 | 
			
		||||
        ls.set("drafts", expected);
 | 
			
		||||
 | 
			
		||||
        assert.deepEqual(draft_model.get(), expected);
 | 
			
		||||
@@ -111,7 +111,7 @@ run_test("draft_model", () => {
 | 
			
		||||
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    (function test_get() {
 | 
			
		||||
        ls.set("drafts", { id1: draft_1 });
 | 
			
		||||
        ls.set("drafts", {id1: draft_1});
 | 
			
		||||
 | 
			
		||||
        assert.deepEqual(draft_model.getDraft("id1"), draft_1);
 | 
			
		||||
        assert.equal(draft_model.getDraft("id2"), false);
 | 
			
		||||
@@ -120,9 +120,9 @@ run_test("draft_model", () => {
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    (function test_addDraft() {
 | 
			
		||||
        stub_timestamp(1, () => {
 | 
			
		||||
            const expected = { ...draft_1 };
 | 
			
		||||
            const expected = {...draft_1};
 | 
			
		||||
            expected.updatedAt = 1;
 | 
			
		||||
            const id = draft_model.addDraft({ ...draft_1 });
 | 
			
		||||
            const id = draft_model.addDraft({...draft_1});
 | 
			
		||||
 | 
			
		||||
            assert.deepEqual(ls.get("drafts")[id], expected);
 | 
			
		||||
        });
 | 
			
		||||
@@ -131,10 +131,10 @@ run_test("draft_model", () => {
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    (function test_editDraft() {
 | 
			
		||||
        stub_timestamp(2, () => {
 | 
			
		||||
            ls.set("drafts", { id1: draft_1 });
 | 
			
		||||
            const expected = { ...draft_2 };
 | 
			
		||||
            ls.set("drafts", {id1: draft_1});
 | 
			
		||||
            const expected = {...draft_2};
 | 
			
		||||
            expected.updatedAt = 2;
 | 
			
		||||
            draft_model.editDraft("id1", { ...draft_2 });
 | 
			
		||||
            draft_model.editDraft("id1", {...draft_2});
 | 
			
		||||
 | 
			
		||||
            assert.deepEqual(ls.get("drafts").id1, expected);
 | 
			
		||||
        });
 | 
			
		||||
@@ -142,7 +142,7 @@ run_test("draft_model", () => {
 | 
			
		||||
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    (function test_deleteDraft() {
 | 
			
		||||
        ls.set("drafts", { id1: draft_1 });
 | 
			
		||||
        ls.set("drafts", {id1: draft_1});
 | 
			
		||||
        draft_model.deleteDraft("id1");
 | 
			
		||||
 | 
			
		||||
        assert.deepEqual(ls.get("drafts"), {});
 | 
			
		||||
@@ -304,7 +304,7 @@ run_test("format_drafts", () => {
 | 
			
		||||
    const draft_model = drafts.draft_model;
 | 
			
		||||
    const ls = localstorage();
 | 
			
		||||
    localStorage.clear();
 | 
			
		||||
    const data = { id1: draft_1, id2: draft_2, id3: draft_3, id4: draft_4, id5: draft_5 };
 | 
			
		||||
    const data = {id1: draft_1, id2: draft_2, id3: draft_3, id4: draft_4, id5: draft_5};
 | 
			
		||||
    ls.set("drafts", data);
 | 
			
		||||
    assert.deepEqual(draft_model.get(), data);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ set_global("$", global.make_zjquery());
 | 
			
		||||
 | 
			
		||||
const noop = () => {};
 | 
			
		||||
const _list_render = {
 | 
			
		||||
    create: () => ({ init: noop }),
 | 
			
		||||
    create: () => ({init: noop}),
 | 
			
		||||
};
 | 
			
		||||
set_global("list_render", _list_render);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ set_global("sent_messages", {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
set_global("message_store", {
 | 
			
		||||
    get: () => ({ failed_request: true }),
 | 
			
		||||
    get: () => ({failed_request: true}),
 | 
			
		||||
    update_booleans: () => {},
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,8 +55,8 @@ function blocked_history() {
 | 
			
		||||
run_test("basics", () => {
 | 
			
		||||
    reset();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_newer_batch({ update_loading_indicator: false });
 | 
			
		||||
    fetch_status.start_older_batch({ update_loading_indicator: false });
 | 
			
		||||
    fetch_status.start_newer_batch({update_loading_indicator: false});
 | 
			
		||||
    fetch_status.start_older_batch({update_loading_indicator: false});
 | 
			
		||||
 | 
			
		||||
    blocked_newer();
 | 
			
		||||
    blocked_older();
 | 
			
		||||
@@ -81,8 +81,8 @@ run_test("basics", () => {
 | 
			
		||||
 | 
			
		||||
    reset();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_newer_batch({ update_loading_indicator: true });
 | 
			
		||||
    fetch_status.start_older_batch({ update_loading_indicator: true });
 | 
			
		||||
    fetch_status.start_newer_batch({update_loading_indicator: true});
 | 
			
		||||
    fetch_status.start_older_batch({update_loading_indicator: true});
 | 
			
		||||
 | 
			
		||||
    blocked_newer();
 | 
			
		||||
    blocked_older();
 | 
			
		||||
@@ -105,7 +105,7 @@ run_test("basics", () => {
 | 
			
		||||
 | 
			
		||||
    can_load_older();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_older_batch({ update_loading_indicator: false });
 | 
			
		||||
    fetch_status.start_older_batch({update_loading_indicator: false});
 | 
			
		||||
 | 
			
		||||
    blocked_older();
 | 
			
		||||
    can_load_newer();
 | 
			
		||||
@@ -121,7 +121,7 @@ run_test("basics", () => {
 | 
			
		||||
    can_load_newer();
 | 
			
		||||
    can_load_history();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_older_batch({ update_loading_indicator: true });
 | 
			
		||||
    fetch_status.start_older_batch({update_loading_indicator: true});
 | 
			
		||||
 | 
			
		||||
    blocked_older();
 | 
			
		||||
    can_load_newer();
 | 
			
		||||
@@ -142,7 +142,7 @@ run_test("basics", () => {
 | 
			
		||||
    can_load_older();
 | 
			
		||||
    can_load_newer();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_newer_batch({ update_loading_indicator: false });
 | 
			
		||||
    fetch_status.start_newer_batch({update_loading_indicator: false});
 | 
			
		||||
 | 
			
		||||
    can_load_older();
 | 
			
		||||
    blocked_newer();
 | 
			
		||||
@@ -155,7 +155,7 @@ run_test("basics", () => {
 | 
			
		||||
    can_load_older();
 | 
			
		||||
    can_load_newer();
 | 
			
		||||
 | 
			
		||||
    fetch_status.start_newer_batch({ update_loading_indicator: true });
 | 
			
		||||
    fetch_status.start_newer_batch({update_loading_indicator: true});
 | 
			
		||||
 | 
			
		||||
    can_load_older();
 | 
			
		||||
    blocked_newer();
 | 
			
		||||
 
 | 
			
		||||
@@ -203,41 +203,41 @@ run_test("basics", () => {
 | 
			
		||||
 | 
			
		||||
function assert_not_mark_read_with_has_operands(additional_operators_to_test) {
 | 
			
		||||
    additional_operators_to_test = additional_operators_to_test || [];
 | 
			
		||||
    let has_operator = [{ operator: "has", operand: "link" }];
 | 
			
		||||
    let has_operator = [{operator: "has", operand: "link"}];
 | 
			
		||||
    let filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    has_operator = [{ operator: "has", operand: "link", negated: true }];
 | 
			
		||||
    has_operator = [{operator: "has", operand: "link", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    has_operator = [{ operator: "has", operand: "image" }];
 | 
			
		||||
    has_operator = [{operator: "has", operand: "image"}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    has_operator = [{ operator: "has", operand: "image", negated: true }];
 | 
			
		||||
    has_operator = [{operator: "has", operand: "image", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    has_operator = [{ operator: "has", operand: "attachment", negated: true }];
 | 
			
		||||
    has_operator = [{operator: "has", operand: "attachment", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    has_operator = [{ operator: "has", operand: "attachment" }];
 | 
			
		||||
    has_operator = [{operator: "has", operand: "attachment"}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(has_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
}
 | 
			
		||||
function assert_not_mark_read_with_is_operands(additional_operators_to_test) {
 | 
			
		||||
    additional_operators_to_test = additional_operators_to_test || [];
 | 
			
		||||
    let is_operator = [{ operator: "is", operand: "starred" }];
 | 
			
		||||
    let is_operator = [{operator: "is", operand: "starred"}];
 | 
			
		||||
    let filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "starred", negated: true }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "starred", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "mentioned" }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "mentioned"}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    if (additional_operators_to_test.length === 0) {
 | 
			
		||||
        assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -245,34 +245,34 @@ function assert_not_mark_read_with_is_operands(additional_operators_to_test) {
 | 
			
		||||
        assert(!filter.can_mark_messages_read());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "mentioned", negated: true }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "mentioned", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "alerted" }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "alerted"}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "alerted", negated: true }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "alerted", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "unread" }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "unread"}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    is_operator = [{ operator: "is", operand: "unread", negated: true }];
 | 
			
		||||
    is_operator = [{operator: "is", operand: "unread", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(is_operator));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function assert_not_mark_read_when_searching(additional_operators_to_test) {
 | 
			
		||||
    additional_operators_to_test = additional_operators_to_test || [];
 | 
			
		||||
    let search_op = [{ operator: "search", operand: "keyword" }];
 | 
			
		||||
    let search_op = [{operator: "search", operand: "keyword"}];
 | 
			
		||||
    let filter = new Filter(additional_operators_to_test.concat(search_op));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    search_op = [{ operator: "search", operand: "keyword", negated: true }];
 | 
			
		||||
    search_op = [{operator: "search", operand: "keyword", negated: true}];
 | 
			
		||||
    filter = new Filter(additional_operators_to_test.concat(search_op));
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
}
 | 
			
		||||
@@ -283,7 +283,7 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching();
 | 
			
		||||
 | 
			
		||||
    const stream_operator = [
 | 
			
		||||
        { operator: "stream", operand: "foo" },
 | 
			
		||||
        {operator: "stream", operand: "foo"},
 | 
			
		||||
    ];
 | 
			
		||||
    let filter = new Filter(stream_operator);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -292,14 +292,14 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching(stream_operator);
 | 
			
		||||
 | 
			
		||||
    const stream_negated_operator = [
 | 
			
		||||
        { operator: "stream", operand: "foo", negated: true },
 | 
			
		||||
        {operator: "stream", operand: "foo", negated: true},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(stream_negated_operator);
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    const stream_topic_operators = [
 | 
			
		||||
        { operator: "stream", operand: "foo" },
 | 
			
		||||
        { operator: "topic", operand: "bar" },
 | 
			
		||||
        {operator: "stream", operand: "foo"},
 | 
			
		||||
        {operator: "topic", operand: "bar"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(stream_topic_operators);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -308,22 +308,22 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching(stream_topic_operators);
 | 
			
		||||
 | 
			
		||||
    const stream_negated_topic_operators = [
 | 
			
		||||
        { operator: "stream", operand: "foo" },
 | 
			
		||||
        { operator: "topic", operand: "bar", negated: true},
 | 
			
		||||
        {operator: "stream", operand: "foo"},
 | 
			
		||||
        {operator: "topic", operand: "bar", negated: true},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(stream_negated_topic_operators);
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
 | 
			
		||||
    const pm_with = [
 | 
			
		||||
        { operator: "pm-with", operand: "joe@example.com," },
 | 
			
		||||
        {operator: "pm-with", operand: "joe@example.com,"},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const pm_with_negated = [
 | 
			
		||||
        { operator: "pm-with", operand: "joe@example.com,", negated: true},
 | 
			
		||||
        {operator: "pm-with", operand: "joe@example.com,", negated: true},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const group_pm = [
 | 
			
		||||
        { operator: "pm-with", operand: "joe@example.com,STEVE@foo.com" },
 | 
			
		||||
        {operator: "pm-with", operand: "joe@example.com,STEVE@foo.com"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(pm_with);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -339,7 +339,7 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching(pm_with);
 | 
			
		||||
 | 
			
		||||
    const is_private = [
 | 
			
		||||
        { operator: "is", operand: "private" },
 | 
			
		||||
        {operator: "is", operand: "private"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(is_private);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -348,7 +348,7 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching(is_private);
 | 
			
		||||
 | 
			
		||||
    const in_all = [
 | 
			
		||||
        { operator: "in", operand: "all" },
 | 
			
		||||
        {operator: "in", operand: "all"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(in_all);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -357,10 +357,10 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
    assert_not_mark_read_when_searching(in_all);
 | 
			
		||||
 | 
			
		||||
    const in_home = [
 | 
			
		||||
        { operator: "in", operand: "home" },
 | 
			
		||||
        {operator: "in", operand: "home"},
 | 
			
		||||
    ];
 | 
			
		||||
    const in_home_negated = [
 | 
			
		||||
        { operator: "in", operand: "home", negated: true },
 | 
			
		||||
        {operator: "in", operand: "home", negated: true},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(in_home);
 | 
			
		||||
    assert(filter.can_mark_messages_read());
 | 
			
		||||
@@ -372,10 +372,10 @@ run_test("can_mark_messages_read", () => {
 | 
			
		||||
 | 
			
		||||
    // Do not mark messages as read when in an unsupported 'in:*' filter.
 | 
			
		||||
    const in_random = [
 | 
			
		||||
        { operator: "in", operand: "xxxxxxxxx" },
 | 
			
		||||
        {operator: "in", operand: "xxxxxxxxx"},
 | 
			
		||||
    ];
 | 
			
		||||
    const in_random_negated = [
 | 
			
		||||
        { operator: "in", operand: "xxxxxxxxx", negated: true },
 | 
			
		||||
        {operator: "in", operand: "xxxxxxxxx", negated: true},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(in_random);
 | 
			
		||||
    assert(!filter.can_mark_messages_read());
 | 
			
		||||
@@ -504,18 +504,18 @@ run_test("redundancies", () => {
 | 
			
		||||
    let filter;
 | 
			
		||||
 | 
			
		||||
    terms = [
 | 
			
		||||
        { operator: "pm-with", operand: "joe@example.com," },
 | 
			
		||||
        { operator: "is", operand: "private" },
 | 
			
		||||
        {operator: "pm-with", operand: "joe@example.com,"},
 | 
			
		||||
        {operator: "is", operand: "private"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(terms);
 | 
			
		||||
    assert(filter.can_bucket_by("pm-with"));
 | 
			
		||||
 | 
			
		||||
    terms = [
 | 
			
		||||
        { operator: "pm-with",
 | 
			
		||||
        {operator: "pm-with",
 | 
			
		||||
         operand: "joe@example.com,",
 | 
			
		||||
         negated: true,
 | 
			
		||||
        },
 | 
			
		||||
        { operator: "is", operand: "private" },
 | 
			
		||||
        {operator: "is", operand: "private"},
 | 
			
		||||
    ];
 | 
			
		||||
    filter = new Filter(terms);
 | 
			
		||||
    assert(filter.can_bucket_by("is-private", "not-pm-with"));
 | 
			
		||||
@@ -1338,11 +1338,11 @@ run_test("first_valid_id_from", () => {
 | 
			
		||||
    const filter = new Filter(terms);
 | 
			
		||||
 | 
			
		||||
    const messages = {
 | 
			
		||||
        5: { id: 5, alerted: true },
 | 
			
		||||
        10: { id: 10 },
 | 
			
		||||
        20: { id: 20, alerted: true },
 | 
			
		||||
        30: { id: 30, type: "stream" },
 | 
			
		||||
        40: { id: 40, alerted: false },
 | 
			
		||||
        5: {id: 5, alerted: true},
 | 
			
		||||
        10: {id: 10},
 | 
			
		||||
        20: {id: 20, alerted: true},
 | 
			
		||||
        30: {id: 30, type: "stream"},
 | 
			
		||||
        40: {id: 40, alerted: false},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const msg_ids = [10, 20, 30, 40];
 | 
			
		||||
@@ -1394,7 +1394,7 @@ run_test("navbar_helpers", () => {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function test_redirect_url_with_search(test_case) {
 | 
			
		||||
        test_case.operator.push({ operator: "search", operand: "fizzbuzz"});
 | 
			
		||||
        test_case.operator.push({operator: "search", operand: "fizzbuzz"});
 | 
			
		||||
        const filter = new Filter(test_case.operator);
 | 
			
		||||
        assert.equal(
 | 
			
		||||
            filter.generate_redirect_url(),
 | 
			
		||||
@@ -1425,30 +1425,30 @@ run_test("navbar_helpers", () => {
 | 
			
		||||
        test_redirect_url_with_search(test_case);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const in_home = [{ operator: "in", operand: "home"}];
 | 
			
		||||
    const in_all = [{ operator: "in", operand: "all"}];
 | 
			
		||||
    const is_starred = [{ operator: "is", operand: "starred"}];
 | 
			
		||||
    const is_private = [{ operator: "is", operand: "private"}];
 | 
			
		||||
    const is_mentioned = [{ operator: "is", operand: "mentioned"}];
 | 
			
		||||
    const streams_public = [{ operator: "streams", operand: "public"}];
 | 
			
		||||
    const in_home = [{operator: "in", operand: "home"}];
 | 
			
		||||
    const in_all = [{operator: "in", operand: "all"}];
 | 
			
		||||
    const is_starred = [{operator: "is", operand: "starred"}];
 | 
			
		||||
    const is_private = [{operator: "is", operand: "private"}];
 | 
			
		||||
    const is_mentioned = [{operator: "is", operand: "mentioned"}];
 | 
			
		||||
    const streams_public = [{operator: "streams", operand: "public"}];
 | 
			
		||||
    const stream_topic_operators = [
 | 
			
		||||
        { operator: "stream", operand: "foo" },
 | 
			
		||||
        { operator: "topic", operand: "bar" },
 | 
			
		||||
        {operator: "stream", operand: "foo"},
 | 
			
		||||
        {operator: "topic", operand: "bar"},
 | 
			
		||||
    ];
 | 
			
		||||
    // foo stream exists
 | 
			
		||||
    const stream_operator = [{ operator: "stream", operand: "foo"}];
 | 
			
		||||
    const stream_operator = [{operator: "stream", operand: "foo"}];
 | 
			
		||||
    make_private_sub("psub", "22");
 | 
			
		||||
    const private_stream_operator = [{ operator: "stream", operand: "psub"}];
 | 
			
		||||
    const private_stream_operator = [{operator: "stream", operand: "psub"}];
 | 
			
		||||
    make_web_public_sub("webPublicSub", "12"); // capitalized just to try be tricky and robust.
 | 
			
		||||
    const web_public_stream_operator = [{ operator: "stream", operand: "webPublicSub"}];
 | 
			
		||||
    const non_existent_stream = [{ operator: "stream", operand: "Elephant" }];
 | 
			
		||||
    const web_public_stream_operator = [{operator: "stream", operand: "webPublicSub"}];
 | 
			
		||||
    const non_existent_stream = [{operator: "stream", operand: "Elephant"}];
 | 
			
		||||
    const non_existent_stream_topic = [
 | 
			
		||||
        { operator: "stream", operand: "Elephant" },
 | 
			
		||||
        { operator: "topic", operand: "pink" },
 | 
			
		||||
        {operator: "stream", operand: "Elephant"},
 | 
			
		||||
        {operator: "topic", operand: "pink"},
 | 
			
		||||
    ];
 | 
			
		||||
    const pm_with = [{ operator: "pm-with", operand: "joe@example.com"}];
 | 
			
		||||
    const group_pm = [{ operator: "pm-with", operand: "joe@example.com,STEVE@foo.com"}];
 | 
			
		||||
    const group_pm_including_missing_person = [{ operator: "pm-with", operand: "joe@example.com,STEVE@foo.com,sally@doesnotexist.com"}];
 | 
			
		||||
    const pm_with = [{operator: "pm-with", operand: "joe@example.com"}];
 | 
			
		||||
    const group_pm = [{operator: "pm-with", operand: "joe@example.com,STEVE@foo.com"}];
 | 
			
		||||
    const group_pm_including_missing_person = [{operator: "pm-with", operand: "joe@example.com,STEVE@foo.com,sally@doesnotexist.com"}];
 | 
			
		||||
 | 
			
		||||
    const test_cases = [
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -106,7 +106,7 @@ zrequire("overlays");
 | 
			
		||||
zrequire("message_store");
 | 
			
		||||
 | 
			
		||||
run_test("message_store", () => {
 | 
			
		||||
    const in_message = { ...messages.isaac_to_denmark_stream };
 | 
			
		||||
    const in_message = {...messages.isaac_to_denmark_stream};
 | 
			
		||||
 | 
			
		||||
    assert.equal(in_message.alerted, undefined);
 | 
			
		||||
    message_store.set_message_booleans(in_message);
 | 
			
		||||
@@ -133,7 +133,7 @@ run_test("unread", () => {
 | 
			
		||||
 | 
			
		||||
    assert.equal(unread.num_unread_for_topic(stream_id, topic_name), 0);
 | 
			
		||||
 | 
			
		||||
    const in_message = { ...messages.isaac_to_denmark_stream };
 | 
			
		||||
    const in_message = {...messages.isaac_to_denmark_stream};
 | 
			
		||||
    message_store.set_message_booleans(in_message);
 | 
			
		||||
 | 
			
		||||
    unread.process_loaded_messages([in_message]);
 | 
			
		||||
@@ -554,7 +554,7 @@ run_test("unread_ops", () => {
 | 
			
		||||
    assert.deepEqual(channel_post_opts, {
 | 
			
		||||
        url: "/json/messages/flags",
 | 
			
		||||
        idempotent: true,
 | 
			
		||||
        data: { messages: "[50]", op: "add", flag: "read" },
 | 
			
		||||
        data: {messages: "[50]", op: "add", flag: "read"},
 | 
			
		||||
        success: channel_post_opts.success,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -357,11 +357,11 @@ run_test("sorting", () => {
 | 
			
		||||
        cleared = true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const alice = { name: "alice", salary: 50 };
 | 
			
		||||
    const bob = { name: "Bob", salary: 40 };
 | 
			
		||||
    const cal = { name: "cal", salary: 30 };
 | 
			
		||||
    const dave = { name: "dave", salary: 25 };
 | 
			
		||||
    const ellen = { name: "ellen", salary: 95 };
 | 
			
		||||
    const alice = {name: "alice", salary: 50};
 | 
			
		||||
    const bob = {name: "Bob", salary: 40};
 | 
			
		||||
    const cal = {name: "cal", salary: 30};
 | 
			
		||||
    const dave = {name: "dave", salary: 25};
 | 
			
		||||
    const ellen = {name: "ellen", salary: 95};
 | 
			
		||||
 | 
			
		||||
    const list = [bob, ellen, dave, alice, cal];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -335,7 +335,7 @@ run_test("marked", () => {
 | 
			
		||||
        {input: "\ud83d\udca9",
 | 
			
		||||
         expected: '<p><span aria-label="poop" class="emoji emoji-1f4a9" role="img" title="poop">:poop:</span></p>'},
 | 
			
		||||
        {input: "\u{1f6b2}",
 | 
			
		||||
         expected: "<p>\u{1f6b2}</p>" },
 | 
			
		||||
         expected: "<p>\u{1f6b2}</p>"},
 | 
			
		||||
        {input: "Silent mention: @_**Cordelia Lear**",
 | 
			
		||||
         expected: '<p>Silent mention: <span class="user-mention silent" data-user-id="101">Cordelia Lear</span></p>'},
 | 
			
		||||
        {input: "> Mention in quote: @**Cordelia Lear**\n\nMention outside quote: @**Cordelia Lear**",
 | 
			
		||||
@@ -583,7 +583,7 @@ run_test("python_to_js_filter", () => {
 | 
			
		||||
run_test("katex_throws_unexpected_exceptions", () => {
 | 
			
		||||
    katex.renderToString = function () { throw new Error("some-exception"); };
 | 
			
		||||
    blueslip.expect("error", "Error: some-exception");
 | 
			
		||||
    const message = { raw_content: "$$a$$" };
 | 
			
		||||
    const message = {raw_content: "$$a$$"};
 | 
			
		||||
    markdown.apply_markdown(message);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -284,7 +284,7 @@ function simulate_narrow() {
 | 
			
		||||
 | 
			
		||||
    narrow_state.active = function () { return true; };
 | 
			
		||||
    narrow_state.public_operators = function () {
 | 
			
		||||
        return [{ operator: "pm-with", operand: alice.email }];
 | 
			
		||||
        return [{operator: "pm-with", operand: alice.email}];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const msg_list = new message_list.MessageList({
 | 
			
		||||
 
 | 
			
		||||
@@ -72,13 +72,13 @@ run_test("read", () => {
 | 
			
		||||
    // For testing purpose limit the batch size value to 5 instead of 1000
 | 
			
		||||
    message_flags._unread_batch_size = 5;
 | 
			
		||||
    let msgs_to_flag_read = [
 | 
			
		||||
        { locally_echoed: false, id: 1 },
 | 
			
		||||
        { locally_echoed: false, id: 2 },
 | 
			
		||||
        { locally_echoed: false, id: 3 },
 | 
			
		||||
        { locally_echoed: false, id: 4 },
 | 
			
		||||
        { locally_echoed: false, id: 5 },
 | 
			
		||||
        { locally_echoed: false, id: 6 },
 | 
			
		||||
        { locally_echoed: false, id: 7 },
 | 
			
		||||
        {locally_echoed: false, id: 1},
 | 
			
		||||
        {locally_echoed: false, id: 2},
 | 
			
		||||
        {locally_echoed: false, id: 3},
 | 
			
		||||
        {locally_echoed: false, id: 4},
 | 
			
		||||
        {locally_echoed: false, id: 5},
 | 
			
		||||
        {locally_echoed: false, id: 6},
 | 
			
		||||
        {locally_echoed: false, id: 7},
 | 
			
		||||
    ];
 | 
			
		||||
    message_flags.send_read(msgs_to_flag_read);
 | 
			
		||||
    assert.deepEqual(channel_post_opts, {
 | 
			
		||||
@@ -113,16 +113,16 @@ run_test("read", () => {
 | 
			
		||||
    channel_post_opts.success(success_response_data);
 | 
			
		||||
 | 
			
		||||
    // Don't flag locally echoed messages as read
 | 
			
		||||
    const local_msg_1 = { locally_echoed: true, id: 1 };
 | 
			
		||||
    const local_msg_2 = { locally_echoed: true, id: 2 };
 | 
			
		||||
    const local_msg_1 = {locally_echoed: true, id: 1};
 | 
			
		||||
    const local_msg_2 = {locally_echoed: true, id: 2};
 | 
			
		||||
    msgs_to_flag_read = [
 | 
			
		||||
        local_msg_1,
 | 
			
		||||
        local_msg_2,
 | 
			
		||||
        { locally_echoed: false, id: 3 },
 | 
			
		||||
        { locally_echoed: false, id: 4 },
 | 
			
		||||
        { locally_echoed: false, id: 5 },
 | 
			
		||||
        { locally_echoed: false, id: 6 },
 | 
			
		||||
        { locally_echoed: false, id: 7 },
 | 
			
		||||
        {locally_echoed: false, id: 3},
 | 
			
		||||
        {locally_echoed: false, id: 4},
 | 
			
		||||
        {locally_echoed: false, id: 5},
 | 
			
		||||
        {locally_echoed: false, id: 6},
 | 
			
		||||
        {locally_echoed: false, id: 7},
 | 
			
		||||
    ];
 | 
			
		||||
    message_flags.send_read(msgs_to_flag_read);
 | 
			
		||||
    assert.deepEqual(channel_post_opts, {
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ run_test("msg_edited_vars", () => {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function build_message_group(messages) {
 | 
			
		||||
        return { message_containers: messages };
 | 
			
		||||
        return {message_containers: messages};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function build_list(message_groups) {
 | 
			
		||||
@@ -104,8 +104,8 @@ run_test("msg_edited_vars", () => {
 | 
			
		||||
    (function test_msg_edited_vars() {
 | 
			
		||||
        const messages = [
 | 
			
		||||
            build_message_context(),
 | 
			
		||||
            build_message_context({}, { include_sender: false }),
 | 
			
		||||
            build_message_context({ is_me_message: true, content: "<p>/me test</p>" }),
 | 
			
		||||
            build_message_context({}, {include_sender: false}),
 | 
			
		||||
            build_message_context({is_me_message: true, content: "<p>/me test</p>"}),
 | 
			
		||||
        ];
 | 
			
		||||
        const message_group = build_message_group(messages);
 | 
			
		||||
        const list = build_list([message_group]);
 | 
			
		||||
 
 | 
			
		||||
@@ -134,7 +134,7 @@ run_test("basics", () => {
 | 
			
		||||
 | 
			
		||||
    const helper = test_helper();
 | 
			
		||||
    const terms = [
 | 
			
		||||
        { operator: "stream", operand: "Denmark" },
 | 
			
		||||
        {operator: "stream", operand: "Denmark"},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const selected_id = 1000;
 | 
			
		||||
@@ -212,7 +212,7 @@ run_test("basics", () => {
 | 
			
		||||
    current_msg_list.get_row = () => row;
 | 
			
		||||
    util.sorted_ids = () => [];
 | 
			
		||||
 | 
			
		||||
    narrow.activate([{ operator: "is", operand: "private" }], {
 | 
			
		||||
    narrow.activate([{operator: "is", operand: "private"}], {
 | 
			
		||||
        then_select_id: selected_id,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,9 @@ run_test("stream", () => {
 | 
			
		||||
    assert(narrow_state.is_for_stream_id(test_stream.stream_id));
 | 
			
		||||
 | 
			
		||||
    const expected_operators = [
 | 
			
		||||
        { negated: false, operator: "stream", operand: "Test" },
 | 
			
		||||
        { negated: false, operator: "topic", operand: "Bar" },
 | 
			
		||||
        { negated: false, operator: "search", operand: "yo" },
 | 
			
		||||
        {negated: false, operator: "stream", operand: "Test"},
 | 
			
		||||
        {negated: false, operator: "topic", operand: "Bar"},
 | 
			
		||||
        {negated: false, operator: "search", operand: "yo"},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const public_operators = narrow_state.public_operators();
 | 
			
		||||
 
 | 
			
		||||
@@ -257,7 +257,7 @@ run_test("basic_notifications", () => {
 | 
			
		||||
 | 
			
		||||
    // Notifications API stub
 | 
			
		||||
    class StubNotification {
 | 
			
		||||
        constructor(title, { icon, body, tag }) {
 | 
			
		||||
        constructor(title, {icon, body, tag}) {
 | 
			
		||||
            this.icon = icon;
 | 
			
		||||
            this.body = body;
 | 
			
		||||
            this.tag = tag;
 | 
			
		||||
 
 | 
			
		||||
@@ -477,9 +477,9 @@ run_test("get_people_for_stream_create", () => {
 | 
			
		||||
 | 
			
		||||
    const others = people.get_people_for_stream_create();
 | 
			
		||||
    const expected = [
 | 
			
		||||
        { email: "alice1@example.com", user_id: alice1.user_id, full_name: "Alice" },
 | 
			
		||||
        { email: "alice2@example.com", user_id: alice2.user_id, full_name: "Alice" },
 | 
			
		||||
        { email: "bob@example.com", user_id: bob.user_id, full_name: "Bob van Roberts" },
 | 
			
		||||
        {email: "alice1@example.com", user_id: alice1.user_id, full_name: "Alice"},
 | 
			
		||||
        {email: "alice2@example.com", user_id: alice2.user_id, full_name: "Alice"},
 | 
			
		||||
        {email: "bob@example.com", user_id: bob.user_id, full_name: "Bob van Roberts"},
 | 
			
		||||
    ];
 | 
			
		||||
    assert.deepEqual(others, expected);
 | 
			
		||||
 | 
			
		||||
@@ -702,7 +702,7 @@ run_test("message_methods", () => {
 | 
			
		||||
    assert.equal(people.pm_with_url(message), "#narrow/pm-with/30-me");
 | 
			
		||||
    assert.equal(people.pm_perma_link(message), "#narrow/pm-with/30-pm");
 | 
			
		||||
 | 
			
		||||
    message = { type: "stream" };
 | 
			
		||||
    message = {type: "stream"};
 | 
			
		||||
    assert.equal(people.pm_with_user_ids(message), undefined);
 | 
			
		||||
    assert.equal(people.all_user_ids_in_pm(message), undefined);
 | 
			
		||||
 | 
			
		||||
@@ -715,28 +715,28 @@ run_test("message_methods", () => {
 | 
			
		||||
    const bot = bot_botson;
 | 
			
		||||
    people.add_active_user(bot);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: bot.user_id };
 | 
			
		||||
    message = {sender_id: bot.user_id};
 | 
			
		||||
    assert.equal(people.sender_is_bot(message), true);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: maria.user_id };
 | 
			
		||||
    message = {sender_id: maria.user_id};
 | 
			
		||||
    assert.equal(people.sender_is_bot(message), undefined);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: undefined };
 | 
			
		||||
    message = {sender_id: undefined};
 | 
			
		||||
    assert.equal(people.sender_is_bot(message), false);
 | 
			
		||||
 | 
			
		||||
    // Test sender_is_guest
 | 
			
		||||
    people.add_active_user(guest);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: guest.user_id };
 | 
			
		||||
    message = {sender_id: guest.user_id};
 | 
			
		||||
    assert.equal(people.sender_is_guest(message), true);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: maria.user_id };
 | 
			
		||||
    message = {sender_id: maria.user_id};
 | 
			
		||||
    assert.equal(people.sender_is_guest(message), undefined);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: charles.user_id };
 | 
			
		||||
    message = {sender_id: charles.user_id};
 | 
			
		||||
    assert.equal(people.sender_is_guest(message), false);
 | 
			
		||||
 | 
			
		||||
    message = { sender_id: undefined };
 | 
			
		||||
    message = {sender_id: undefined};
 | 
			
		||||
    assert.equal(people.sender_is_guest(message), false);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ run_test("poll_data_holder my question", () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const vote_outbound_event = data_holder.handle.vote.outbound("99,1");
 | 
			
		||||
    assert.deepEqual(vote_outbound_event, { type: "vote", key: "99,1", vote: -1 });
 | 
			
		||||
    assert.deepEqual(vote_outbound_event, {type: "vote", key: "99,1", vote: -1});
 | 
			
		||||
 | 
			
		||||
    vote_event = {
 | 
			
		||||
        type: "vote",
 | 
			
		||||
@@ -242,7 +242,7 @@ run_test("activate another person poll", () => {
 | 
			
		||||
        poll_option_input.val("cool choice");
 | 
			
		||||
        out_data = undefined;
 | 
			
		||||
        option_button_callback(e);
 | 
			
		||||
        assert.deepEqual(out_data,  { type: "new_option", idx: 1, option: "cool choice" });
 | 
			
		||||
        assert.deepEqual(out_data,  {type: "new_option", idx: 1, option: "cool choice"});
 | 
			
		||||
 | 
			
		||||
        poll_option_input.val("");
 | 
			
		||||
        out_data = undefined;
 | 
			
		||||
@@ -280,7 +280,7 @@ run_test("activate another person poll", () => {
 | 
			
		||||
        };
 | 
			
		||||
        out_data = undefined;
 | 
			
		||||
        vote_button_callback(e);
 | 
			
		||||
        assert.deepEqual(out_data, { type: "vote", key: "100,1", vote: 1 });
 | 
			
		||||
        assert.deepEqual(out_data, {type: "vote", key: "100,1", vote: 1});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const add_question_event = [
 | 
			
		||||
@@ -405,7 +405,7 @@ run_test("activate own poll", () => {
 | 
			
		||||
        out_data = undefined;
 | 
			
		||||
        show_submit = true;
 | 
			
		||||
        question_button_callback(e);
 | 
			
		||||
        assert.deepEqual(out_data,  { type: "question", question: "Is it new?" });
 | 
			
		||||
        assert.deepEqual(out_data,  {type: "question", question: "Is it new?"});
 | 
			
		||||
 | 
			
		||||
        poll_option_input.val("");
 | 
			
		||||
        out_data = undefined;
 | 
			
		||||
 
 | 
			
		||||
@@ -181,7 +181,7 @@ run_test("set_presence_info", () => {
 | 
			
		||||
    presence.initialize(params);
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(alice.user_id),
 | 
			
		||||
                     { status: "active", last_active: recent},
 | 
			
		||||
                     {status: "active", last_active: recent},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(alice.user_id), "active");
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
@@ -190,22 +190,22 @@ run_test("set_presence_info", () => {
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(fred.user_id),
 | 
			
		||||
                     { status: "idle", last_active: now},
 | 
			
		||||
                     {status: "idle", last_active: now},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(fred.user_id), "idle");
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(me.user_id),
 | 
			
		||||
                     { status: "active", last_active: now},
 | 
			
		||||
                     {status: "active", last_active: now},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(me.user_id), "active");
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(sally.user_id),
 | 
			
		||||
                     { status: "offline", last_active: a_while_ago},
 | 
			
		||||
                     {status: "offline", last_active: a_while_ago},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(sally.user_id), "offline");
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(zoe.user_id),
 | 
			
		||||
                     { status: "offline", last_active: undefined},
 | 
			
		||||
                     {status: "offline", last_active: undefined},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(zoe.user_id), "offline");
 | 
			
		||||
    assert.equal(presence.last_active_date(zoe.user_id), undefined);
 | 
			
		||||
@@ -214,12 +214,12 @@ run_test("set_presence_info", () => {
 | 
			
		||||
    assert.equal(presence.get_status(bot.user_id), "offline");
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(john.user_id),
 | 
			
		||||
                     { status: "offline", last_active: a_while_ago},
 | 
			
		||||
                     {status: "offline", last_active: a_while_ago},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(john.user_id), "offline");
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(presence.presence_info.get(jane.user_id),
 | 
			
		||||
                     { status: "idle", last_active: now},
 | 
			
		||||
                     {status: "idle", last_active: now},
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(presence.get_status(jane.user_id), "idle");
 | 
			
		||||
 | 
			
		||||
@@ -250,7 +250,7 @@ run_test("falsy values", () => {
 | 
			
		||||
 | 
			
		||||
        assert.deepEqual(
 | 
			
		||||
            presence.presence_info.get(zoe.user_id),
 | 
			
		||||
            { status: "idle", last_active: a_bit_ago },
 | 
			
		||||
            {status: "idle", last_active: a_bit_ago},
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        presences[zoe.user_id.toString()] = {
 | 
			
		||||
@@ -262,7 +262,7 @@ run_test("falsy values", () => {
 | 
			
		||||
 | 
			
		||||
        assert.deepEqual(
 | 
			
		||||
            presence.presence_info.get(zoe.user_id),
 | 
			
		||||
            { status: "offline", last_active: undefined },
 | 
			
		||||
            {status: "offline", last_active: undefined},
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -289,7 +289,7 @@ run_test("big realms", () => {
 | 
			
		||||
run_test("last_active_date", () => {
 | 
			
		||||
    const unknown_id = 42;
 | 
			
		||||
    presence.presence_info.clear();
 | 
			
		||||
    presence.presence_info.set(alice.user_id, { last_active: 500 });
 | 
			
		||||
    presence.presence_info.set(alice.user_id, {last_active: 500});
 | 
			
		||||
    presence.presence_info.set(fred.user_id, {});
 | 
			
		||||
 | 
			
		||||
    assert.equal(presence.last_active_date(unknown_id), undefined);
 | 
			
		||||
@@ -312,7 +312,7 @@ run_test("update_info_from_event", () => {
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
        presence.presence_info.get(alice.user_id),
 | 
			
		||||
        { status: "active", last_active: 500 },
 | 
			
		||||
        {status: "active", last_active: 500},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    info = {
 | 
			
		||||
@@ -325,7 +325,7 @@ run_test("update_info_from_event", () => {
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
        presence.presence_info.get(alice.user_id),
 | 
			
		||||
        { status: "active", last_active: 510 },
 | 
			
		||||
        {status: "active", last_active: 510},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    info = {
 | 
			
		||||
@@ -338,6 +338,6 @@ run_test("update_info_from_event", () => {
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
        presence.presence_info.get(alice.user_id),
 | 
			
		||||
        { status: "idle", last_active: 1000 },
 | 
			
		||||
        {status: "idle", last_active: 1000},
 | 
			
		||||
    );
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ set_global("message_store", {
 | 
			
		||||
 | 
			
		||||
set_global("current_msg_list", {
 | 
			
		||||
    selected_message: function () {
 | 
			
		||||
        return { sent_by_me: true };
 | 
			
		||||
        return {sent_by_me: true};
 | 
			
		||||
    },
 | 
			
		||||
    selected_row: function () {
 | 
			
		||||
        return $(".selected-row");
 | 
			
		||||
@@ -103,7 +103,7 @@ run_test("open_reactions_popover", () => {
 | 
			
		||||
    assert(reactions.open_reactions_popover());
 | 
			
		||||
    assert(called);
 | 
			
		||||
 | 
			
		||||
    current_msg_list.selected_message = function () { return { sent_by_me: false }; };
 | 
			
		||||
    current_msg_list.selected_message = function () { return {sent_by_me: false}; };
 | 
			
		||||
 | 
			
		||||
    called = false;
 | 
			
		||||
    emoji_picker.toggle_emoji_popover = function (target, id) {
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ const $array = (array) => {
 | 
			
		||||
    return {each};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
set_global("page_params", { emojiset: "apple" });
 | 
			
		||||
set_global("page_params", {emojiset: "apple"});
 | 
			
		||||
 | 
			
		||||
const get_content_element = () => {
 | 
			
		||||
    $.clear_all_elements();
 | 
			
		||||
@@ -188,11 +188,11 @@ run_test("timestamp-twenty-four-hour-time", () => {
 | 
			
		||||
    // We will temporarily change the 24h setting for this test.
 | 
			
		||||
    const old_page_params = global.page_params;
 | 
			
		||||
 | 
			
		||||
    set_global("page_params", { ...old_page_params, twenty_four_hour_time: true });
 | 
			
		||||
    set_global("page_params", {...old_page_params, twenty_four_hour_time: true});
 | 
			
		||||
    rm.update_elements($content);
 | 
			
		||||
    assert.equal($timestamp.text(), "Wed, Jul 15 2020, 20:40");
 | 
			
		||||
 | 
			
		||||
    set_global("page_params", { ...old_page_params, twenty_four_hour_time: false });
 | 
			
		||||
    set_global("page_params", {...old_page_params, twenty_four_hour_time: false});
 | 
			
		||||
    rm.update_elements($content);
 | 
			
		||||
    assert.equal($timestamp.text(), "Wed, Jul 15 2020, 8:40 PM");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -273,7 +273,7 @@ run_test("initialize", () => {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const search_pill_stub = $.create(".pill");
 | 
			
		||||
    search_pill_stub.closest = () => ({ data: noop });
 | 
			
		||||
    search_pill_stub.closest = () => ({data: noop});
 | 
			
		||||
    const stub_event = {
 | 
			
		||||
        relatedTarget: search_pill_stub,
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@ function set_up() {
 | 
			
		||||
 | 
			
		||||
    // bunch of stubs
 | 
			
		||||
 | 
			
		||||
    $.validator = { addMethod: () => {} };
 | 
			
		||||
    $.validator = {addMethod: () => {}};
 | 
			
		||||
 | 
			
		||||
    $("#create_bot_form").validate = () => {};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,8 @@ const _loading = {
 | 
			
		||||
const _page_params = {
 | 
			
		||||
    is_admin: false,
 | 
			
		||||
    realm_domains: [
 | 
			
		||||
        { domain: "example.com", allow_subdomains: true },
 | 
			
		||||
        { domain: "example.org", allow_subdomains: false },
 | 
			
		||||
        {domain: "example.com", allow_subdomains: true},
 | 
			
		||||
        {domain: "example.org", allow_subdomains: false},
 | 
			
		||||
    ],
 | 
			
		||||
    realm_authentication_methods: {},
 | 
			
		||||
};
 | 
			
		||||
@@ -57,7 +57,7 @@ const _realm_logo = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const _list_render = {
 | 
			
		||||
    create: () => ({ init: noop }),
 | 
			
		||||
    create: () => ({init: noop}),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
set_global("channel", _channel);
 | 
			
		||||
@@ -1012,7 +1012,7 @@ run_test("misc", () => {
 | 
			
		||||
    };
 | 
			
		||||
    stream_data.get_sub_by_id = function (stream_id) {
 | 
			
		||||
        assert.equal(stream_id, 42);
 | 
			
		||||
        return { name: "some_stream" };
 | 
			
		||||
        return {name: "some_stream"};
 | 
			
		||||
    };
 | 
			
		||||
    settings_org.notifications_stream_widget.render(42);
 | 
			
		||||
    assert.equal(elem.text(), "#some_stream");
 | 
			
		||||
@@ -1030,7 +1030,7 @@ run_test("misc", () => {
 | 
			
		||||
    };
 | 
			
		||||
    stream_data.get_sub_by_id = function (stream_id) {
 | 
			
		||||
        assert.equal(stream_id, 75);
 | 
			
		||||
        return { name: "some_stream" };
 | 
			
		||||
        return {name: "some_stream"};
 | 
			
		||||
    };
 | 
			
		||||
    settings_org.signup_notifications_stream_widget.render(75);
 | 
			
		||||
    assert.equal(elem.text(), "#some_stream");
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ stream_data.add_sub(frontend);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const frontend_filter_terms = [
 | 
			
		||||
    { operator: "stream", operand: "frontend" },
 | 
			
		||||
    {operator: "stream", operand: "frontend"},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const frontend_filter = new Filter(frontend_filter_terms);
 | 
			
		||||
@@ -214,8 +214,8 @@ run_test("marked_subscribed", () => {
 | 
			
		||||
    stream_data.get_colors = noop;
 | 
			
		||||
    stream_data.update_calculated_fields = noop;
 | 
			
		||||
 | 
			
		||||
    set_global("subs", { update_settings_for_subscribed: noop });
 | 
			
		||||
    set_global("overlays", { streams_open: return_true });
 | 
			
		||||
    set_global("subs", {update_settings_for_subscribed: noop});
 | 
			
		||||
    set_global("overlays", {streams_open: return_true});
 | 
			
		||||
 | 
			
		||||
    // Test basic dispatching and updating stream color
 | 
			
		||||
    narrow_state.set_current_filter(frontend_filter);
 | 
			
		||||
 
 | 
			
		||||
@@ -139,9 +139,9 @@ run_test("server_history", () => {
 | 
			
		||||
 | 
			
		||||
    function add_server_history() {
 | 
			
		||||
        stream_topic_history.add_history(stream_id, [
 | 
			
		||||
            { name: "local", max_id: 501 },
 | 
			
		||||
            { name: "hist2", max_id: 31 },
 | 
			
		||||
            { name: "hist1", max_id: 30 },
 | 
			
		||||
            {name: "local", max_id: 501},
 | 
			
		||||
            {name: "hist2", max_id: 31},
 | 
			
		||||
            {name: "hist1", max_id: 30},
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -196,8 +196,8 @@ run_test("server_history", () => {
 | 
			
		||||
    // topics in the future, if they dropped off due to renames,
 | 
			
		||||
    // but that is probably an edge case we can ignore for now.
 | 
			
		||||
    stream_topic_history.add_history(stream_id, [
 | 
			
		||||
        { name: "hist2", max_id: 931 },
 | 
			
		||||
        { name: "hist3", max_id: 5 },
 | 
			
		||||
        {name: "hist2", max_id: 931},
 | 
			
		||||
        {name: "hist3", max_id: 5},
 | 
			
		||||
    ]);
 | 
			
		||||
    history = stream_topic_history.get_recent_topic_names(stream_id);
 | 
			
		||||
    assert.deepEqual(history, ["hist2", "hist1", "hist3"]);
 | 
			
		||||
@@ -222,10 +222,10 @@ run_test("test_unread_logic", () => {
 | 
			
		||||
    assert.deepEqual(history, ["toPic1", "topic2"]);
 | 
			
		||||
 | 
			
		||||
    const msgs = [
 | 
			
		||||
        { id: 150, topic: "TOPIC2" }, // will be ignored
 | 
			
		||||
        { id: 61, topic: "unread1" },
 | 
			
		||||
        { id: 60, topic: "unread1" },
 | 
			
		||||
        { id: 20, topic: "UNREAD2" },
 | 
			
		||||
        {id: 150, topic: "TOPIC2"}, // will be ignored
 | 
			
		||||
        {id: 61, topic: "unread1"},
 | 
			
		||||
        {id: 60, topic: "unread1"},
 | 
			
		||||
        {id: 20, topic: "UNREAD2"},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    for (const msg of msgs) {
 | 
			
		||||
@@ -266,9 +266,9 @@ run_test("server_history_end_to_end", () => {
 | 
			
		||||
    const stream_id = 99;
 | 
			
		||||
 | 
			
		||||
    const topics = [
 | 
			
		||||
        { name: "topic3", max_id: 501 },
 | 
			
		||||
        { name: "topic2", max_id: 31 },
 | 
			
		||||
        { name: "topic1", max_id: 30 },
 | 
			
		||||
        {name: "topic3", max_id: 501},
 | 
			
		||||
        {name: "topic2", max_id: 31},
 | 
			
		||||
        {name: "topic1", max_id: 30},
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    let get_success_callback;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
const fs = require("fs");
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const template = fs.readFileSync("templates/analytics/realm_details.html", "utf-8");
 | 
			
		||||
const dom = new JSDOM(template, { pretendToBeVisual: true });
 | 
			
		||||
const dom = new JSDOM(template, {pretendToBeVisual: true});
 | 
			
		||||
const document = dom.window.document;
 | 
			
		||||
 | 
			
		||||
let jquery_init;
 | 
			
		||||
 
 | 
			
		||||
@@ -688,20 +688,20 @@ run_test("render_emoji", () => {
 | 
			
		||||
 | 
			
		||||
run_test("sort_slash_commands", () => {
 | 
			
		||||
    const slash_commands = [
 | 
			
		||||
        { name: "my" },
 | 
			
		||||
        { name: "poll" },
 | 
			
		||||
        { name: "me" },
 | 
			
		||||
        { name: "mine" },
 | 
			
		||||
        { name: "test" },
 | 
			
		||||
        { name: "ping" },
 | 
			
		||||
        {name: "my"},
 | 
			
		||||
        {name: "poll"},
 | 
			
		||||
        {name: "me"},
 | 
			
		||||
        {name: "mine"},
 | 
			
		||||
        {name: "test"},
 | 
			
		||||
        {name: "ping"},
 | 
			
		||||
    ];
 | 
			
		||||
    assert.deepEqual(th.sort_slash_commands(slash_commands, "m"), [
 | 
			
		||||
        { name: "me" },
 | 
			
		||||
        { name: "mine" },
 | 
			
		||||
        { name: "my" },
 | 
			
		||||
        { name: "ping" },
 | 
			
		||||
        { name: "poll" },
 | 
			
		||||
        { name: "test" },
 | 
			
		||||
        {name: "me"},
 | 
			
		||||
        {name: "mine"},
 | 
			
		||||
        {name: "my"},
 | 
			
		||||
        {name: "ping"},
 | 
			
		||||
        {name: "poll"},
 | 
			
		||||
        {name: "test"},
 | 
			
		||||
    ]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -293,7 +293,7 @@ run_test("num_unread_for_topic", () => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    assert.deepEqual(missing_topics, [
 | 
			
		||||
        { pretty_name: "LuncH", message_id: 500 },
 | 
			
		||||
        {pretty_name: "LuncH", message_id: 500},
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    topic_dict.set("lUNCh", "whatever");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
const noop = () => {};
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const fs = require("fs");
 | 
			
		||||
 | 
			
		||||
const template = fs.readFileSync("templates/corporate/upgrade.html", "utf-8");
 | 
			
		||||
const dom = new JSDOM(template, { pretendToBeVisual: true });
 | 
			
		||||
const dom = new JSDOM(template, {pretendToBeVisual: true});
 | 
			
		||||
const document = dom.window.document;
 | 
			
		||||
let jquery_init;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
 | 
			
		||||
set_global("$", global.make_zjquery());
 | 
			
		||||
set_global("DOMParser", new JSDOM().window.DOMParser);
 | 
			
		||||
@@ -34,7 +34,7 @@ run_test("extract_pm_recipients", () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
run_test("is_pm_recipient", () => {
 | 
			
		||||
    const message = { to_user_ids: "31,32,33" };
 | 
			
		||||
    const message = {to_user_ids: "31,32,33"};
 | 
			
		||||
    assert(util.is_pm_recipient(31, message));
 | 
			
		||||
    assert(util.is_pm_recipient(32, message));
 | 
			
		||||
    assert(!util.is_pm_recipient(34, message));
 | 
			
		||||
@@ -126,10 +126,10 @@ run_test("get_edit_event_prev_topic", () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
run_test("is_mobile", () => {
 | 
			
		||||
    global.window.navigator = { userAgent: "Android" };
 | 
			
		||||
    global.window.navigator = {userAgent: "Android"};
 | 
			
		||||
    assert(util.is_mobile());
 | 
			
		||||
 | 
			
		||||
    global.window.navigator = { userAgent: "Not mobile" };
 | 
			
		||||
    global.window.navigator = {userAgent: "Not mobile"};
 | 
			
		||||
    assert(!util.is_mobile());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -274,7 +274,7 @@ run_test("error checking", () => {
 | 
			
		||||
 | 
			
		||||
    const replace_content = "whatever";
 | 
			
		||||
    const find = "whatever";
 | 
			
		||||
    const ul = {opts: { attrs: [] }};
 | 
			
		||||
    const ul = {opts: {attrs: []}};
 | 
			
		||||
 | 
			
		||||
    vdom.update(replace_content, find, ul, ul);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ class CommonUtils {
 | 
			
		||||
                    "--window-size=1400,1024",
 | 
			
		||||
                    "--no-sandbox", "--disable-setuid-sandbox",
 | 
			
		||||
                ],
 | 
			
		||||
                defaultViewport: { width: 1280, height: 1024 },
 | 
			
		||||
                defaultViewport: {width: 1280, height: 1024},
 | 
			
		||||
                headless: true,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
@@ -104,7 +104,7 @@ class CommonUtils {
 | 
			
		||||
        // tag for script tags that load JavaScript which means that whey will be executed after DOM
 | 
			
		||||
        // is parsed but before DOMContentLoaded event is fired.
 | 
			
		||||
        await Promise.all([
 | 
			
		||||
            page.waitForNavigation({ waitUntil: "domcontentloaded" }),
 | 
			
		||||
            page.waitForNavigation({waitUntil: "domcontentloaded"}),
 | 
			
		||||
            page.$eval("#login_form", (form) => form.submit()),
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
@@ -189,7 +189,7 @@ class CommonUtils {
 | 
			
		||||
    async send_message(page, type, params) {
 | 
			
		||||
        // If a message is outside the view, we do not need
 | 
			
		||||
        // to wait for it to be processed later.
 | 
			
		||||
        const { outside_view } = params;
 | 
			
		||||
        const {outside_view} = params;
 | 
			
		||||
        delete params.outside_view;
 | 
			
		||||
 | 
			
		||||
        await page.waitForSelector("#compose-textarea");
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ async function realm_creation_tests(page) {
 | 
			
		||||
    // first input is focused when we are typing something for other fields causing
 | 
			
		||||
    // validation errors. The code for focusing the input is wrapped in jQuery
 | 
			
		||||
    // $() calls which runs when DOMContentLoaded is fired.
 | 
			
		||||
    await page.waitForNavigation({ waitUntil: "domcontentloaded" });
 | 
			
		||||
    await page.waitForNavigation({waitUntil: "domcontentloaded"});
 | 
			
		||||
 | 
			
		||||
    // Make sure the realm creation page is loaded correctly by
 | 
			
		||||
    // checking the text in <p> tag under pitch class is as expected.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,12 @@ async function message_basic_tests(page) {
 | 
			
		||||
 | 
			
		||||
    console.log("Sending messages");
 | 
			
		||||
    await common.send_multiple_messages(page, [
 | 
			
		||||
        { stream: "Verona", topic: "test", content: "verona test a" },
 | 
			
		||||
        { stream: "Verona", topic: "test", content: "verona test b" },
 | 
			
		||||
        { stream: "Verona", topic: "other topic", content: "verona other topic c" },
 | 
			
		||||
        { recipient: "cordelia@zulip.com, hamlet@zulip.com", content: "group pm a" },
 | 
			
		||||
        { recipient: "cordelia@zulip.com, hamlet@zulip.com", content: "group pm b" },
 | 
			
		||||
        { recipient: "cordelia@zulip.com", content: "pm c" },
 | 
			
		||||
        {stream: "Verona", topic: "test", content: "verona test a"},
 | 
			
		||||
        {stream: "Verona", topic: "test", content: "verona test b"},
 | 
			
		||||
        {stream: "Verona", topic: "other topic", content: "verona other topic c"},
 | 
			
		||||
        {recipient: "cordelia@zulip.com, hamlet@zulip.com", content: "group pm a"},
 | 
			
		||||
        {recipient: "cordelia@zulip.com, hamlet@zulip.com", content: "group pm b"},
 | 
			
		||||
        {recipient: "cordelia@zulip.com", content: "pm c"},
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    await common.check_messages_sent(page, "zhome", [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
const fs = require("fs");
 | 
			
		||||
const Handlebars = require("handlebars/dist/cjs/handlebars.js");
 | 
			
		||||
const path = require("path");
 | 
			
		||||
const { SourceMapConsumer, SourceNode } = require("source-map");
 | 
			
		||||
const {SourceMapConsumer, SourceNode} = require("source-map");
 | 
			
		||||
 | 
			
		||||
const templates_path = path.resolve(__dirname, "../../static/templates");
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +30,7 @@ hb.JavaScriptCompiler = ZJavaScriptCompiler;
 | 
			
		||||
require.extensions[".hbs"] = (module, filename) => {
 | 
			
		||||
    const code = fs.readFileSync(filename, "utf-8");
 | 
			
		||||
    const name = path.relative(templates_path, filename).slice(0, -".hbs".length);
 | 
			
		||||
    const pc = hb.precompile(code, { preventIndent: true, srcName: filename });
 | 
			
		||||
    const pc = hb.precompile(code, {preventIndent: true, srcName: filename});
 | 
			
		||||
    const node = new SourceNode();
 | 
			
		||||
    node.add([
 | 
			
		||||
        "let hb, template;\n",
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
 * HTML.  This makes it easier to spot relevant differences.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
const {JSDOM} = require("jsdom");
 | 
			
		||||
const _ = require("underscore");
 | 
			
		||||
 | 
			
		||||
const mdiff = require("./mdiff.js");
 | 
			
		||||
@@ -125,7 +125,7 @@ class MarkdownComparer {
 | 
			
		||||
        element_actual.remove();
 | 
			
		||||
        element_expected.remove();
 | 
			
		||||
 | 
			
		||||
        return { are_equivalent, html };
 | 
			
		||||
        return {are_equivalent, html};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assertEqual(actual, expected, message) {
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@ function diff_strings(string_0, string_1) {
 | 
			
		||||
    return output_lines.join("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { diff_strings };
 | 
			
		||||
module.exports = {diff_strings};
 | 
			
		||||
 | 
			
		||||
// Simple CLI for this module
 | 
			
		||||
// Only run this code if called as a command-line utility
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
module.exports = ({ file }) => ({
 | 
			
		||||
module.exports = ({file}) => ({
 | 
			
		||||
    parser: file.extname === ".scss" ? "postcss-scss" : false,
 | 
			
		||||
    plugins: {
 | 
			
		||||
        // Warning: despite appearances, order is significant
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ function render_attachments_ui() {
 | 
			
		||||
    list_render.create(uploaded_files_table, attachments, {
 | 
			
		||||
        name: "uploaded-files-list",
 | 
			
		||||
        modifier: function (attachment) {
 | 
			
		||||
            return render_uploaded_files_list({ attachment: attachment });
 | 
			
		||||
            return render_uploaded_files_list({attachment: attachment});
 | 
			
		||||
        },
 | 
			
		||||
        filter: {
 | 
			
		||||
            element: $search_input,
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ const reported_errors = new Set();
 | 
			
		||||
const last_report_attempt = new Map();
 | 
			
		||||
 | 
			
		||||
function report_error(msg, stack, opts) {
 | 
			
		||||
    opts = { show_ui_msg: false, ...opts };
 | 
			
		||||
    opts = {show_ui_msg: false, ...opts};
 | 
			
		||||
 | 
			
		||||
    if (stack === undefined) {
 | 
			
		||||
        stack = "No stacktrace available";
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ export function clean_function_name(
 | 
			
		||||
 | 
			
		||||
const sourceCache: { [source: string]: string | Promise<string> } = {};
 | 
			
		||||
 | 
			
		||||
const stack_trace_gps = new StackTraceGPS({ sourceCache });
 | 
			
		||||
const stack_trace_gps = new StackTraceGPS({sourceCache});
 | 
			
		||||
 | 
			
		||||
async function get_context(location: StackFrame): Promise<NumberedLine[] | undefined> {
 | 
			
		||||
    const sourceContent = await sourceCache[location.getFileName()];
 | 
			
		||||
@@ -91,7 +91,7 @@ export async function display_stacktrace(error: string, stack: string): Promise<
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const $alert = $("<div class='stacktrace'>").html(
 | 
			
		||||
        render_blueslip_stacktrace({ error, stackframes }),
 | 
			
		||||
        render_blueslip_stacktrace({error, stackframes}),
 | 
			
		||||
    );
 | 
			
		||||
    $(".alert-box").append($alert);
 | 
			
		||||
    $alert.addClass("show");
 | 
			
		||||
 
 | 
			
		||||
@@ -92,23 +92,23 @@ function call(args, idempotent) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exports.get = function (options) {
 | 
			
		||||
    const args = { type: "GET", dataType: "json", ...options };
 | 
			
		||||
    const args = {type: "GET", dataType: "json", ...options};
 | 
			
		||||
    return call(args, options.idempotent);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.post = function (options) {
 | 
			
		||||
    const args = { type: "POST", dataType: "json", ...options };
 | 
			
		||||
    const args = {type: "POST", dataType: "json", ...options};
 | 
			
		||||
    return call(args, options.idempotent);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.put = function (options) {
 | 
			
		||||
    const args = { type: "PUT", dataType: "json", ...options };
 | 
			
		||||
    const args = {type: "PUT", dataType: "json", ...options};
 | 
			
		||||
    return call(args, options.idempotent);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Not called exports.delete because delete is a reserved word in JS
 | 
			
		||||
exports.del = function (options) {
 | 
			
		||||
    const args = { type: "DELETE", dataType: "json", ...options };
 | 
			
		||||
    const args = {type: "DELETE", dataType: "json", ...options};
 | 
			
		||||
    return call(args, options.idempotent);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -120,7 +120,7 @@ exports.patch = function (options) {
 | 
			
		||||
        // method this way
 | 
			
		||||
        options.data.append("method", "PATCH");
 | 
			
		||||
    } else {
 | 
			
		||||
        options.data = { ...options.data, method: "PATCH" };
 | 
			
		||||
        options.data = {...options.data, method: "PATCH"};
 | 
			
		||||
    }
 | 
			
		||||
    return exports.post(options, options.idempotent);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -848,8 +848,8 @@ exports.initialize = function () {
 | 
			
		||||
            overlay: $("#" + overlay_name),
 | 
			
		||||
            on_close: function () {
 | 
			
		||||
                // close popover
 | 
			
		||||
                $(this).css({ display: "block" });
 | 
			
		||||
                $(this).animate({ opacity: 1 }, {
 | 
			
		||||
                $(this).css({display: "block"});
 | 
			
		||||
                $(this).animate({opacity: 1}, {
 | 
			
		||||
                    duration: 300,
 | 
			
		||||
                });
 | 
			
		||||
            }.bind(this),
 | 
			
		||||
 
 | 
			
		||||
@@ -882,7 +882,7 @@ exports.warn_if_private_stream_is_linked = function (linked_stream) {
 | 
			
		||||
    const stream_name = linked_stream.name;
 | 
			
		||||
 | 
			
		||||
    const warning_area = $("#compose_private_stream_alert");
 | 
			
		||||
    const context = { stream_name: stream_name };
 | 
			
		||||
    const context = {stream_name: stream_name};
 | 
			
		||||
    const new_row = render_compose_private_stream_alert(context);
 | 
			
		||||
 | 
			
		||||
    warning_area.append(new_row);
 | 
			
		||||
 
 | 
			
		||||
@@ -757,13 +757,13 @@ exports.content_highlighter = function (item) {
 | 
			
		||||
    } else if (this.completing === "stream") {
 | 
			
		||||
        return typeahead_helper.render_stream(item);
 | 
			
		||||
    } else if (this.completing === "syntax") {
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
    } else if (this.completing === "topic_jump") {
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
    } else if (this.completing === "topic_list") {
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
    } else if (this.completing === "time_jump") {
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
        return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -1075,7 +1075,7 @@ exports.initialize = function () {
 | 
			
		||||
        items: 3,
 | 
			
		||||
        fixed: true,
 | 
			
		||||
        highlighter: function (item) {
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
        },
 | 
			
		||||
        matcher: function (item) {
 | 
			
		||||
            // The matcher for "stream" is strictly prefix-based,
 | 
			
		||||
@@ -1093,7 +1093,7 @@ exports.initialize = function () {
 | 
			
		||||
        items: 3,
 | 
			
		||||
        fixed: true,
 | 
			
		||||
        highlighter: function (item) {
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
        },
 | 
			
		||||
        sorter: function (items) {
 | 
			
		||||
            const sorted = typeahead_helper.sorter(this.query, items, (x) => x);
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,7 @@ const DropdownListWidget = function (opts) {
 | 
			
		||||
        list_render.create(dropdown_list_body, opts.data, {
 | 
			
		||||
            name: `${opts.widget_name}_list`,
 | 
			
		||||
            modifier: function (item) {
 | 
			
		||||
                return render_dropdown_list({ item: item });
 | 
			
		||||
                return render_dropdown_list({item: item});
 | 
			
		||||
            },
 | 
			
		||||
            filter: {
 | 
			
		||||
                element: search_input,
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ exports.insert_local_message = function (message_request, local_id_float) {
 | 
			
		||||
    // Shallow clone of message request object that is turned into something suitable
 | 
			
		||||
    // for zulip.js:add_message
 | 
			
		||||
    // Keep this in sync with changes to compose.create_message_object
 | 
			
		||||
    const message = { ...message_request };
 | 
			
		||||
    const message = {...message_request};
 | 
			
		||||
 | 
			
		||||
    // Locally delivered messages cannot be unread (since we sent them), nor
 | 
			
		||||
    // can they alert the user.
 | 
			
		||||
 
 | 
			
		||||
@@ -29,17 +29,17 @@ let section_head_offsets = [];
 | 
			
		||||
let edit_message_id = null;
 | 
			
		||||
 | 
			
		||||
const EMOJI_CATEGORIES = [
 | 
			
		||||
    { name: "Popular", icon: "fa-star-o" },
 | 
			
		||||
    { name: "Smileys & Emotion", icon: "fa-smile-o" },
 | 
			
		||||
    { name: "People & Body", icon: "fa-thumbs-o-up" },
 | 
			
		||||
    { name: "Animals & Nature", icon: "fa-leaf" },
 | 
			
		||||
    { name: "Food & Drink", icon: "fa-cutlery" },
 | 
			
		||||
    { name: "Activities", icon: "fa-soccer-ball-o" },
 | 
			
		||||
    { name: "Travel & Places", icon: "fa-car" },
 | 
			
		||||
    { name: "Objects", icon: "fa-lightbulb-o" },
 | 
			
		||||
    { name: "Symbols", icon: "fa-hashtag" },
 | 
			
		||||
    { name: "Flags", icon: "fa-flag" },
 | 
			
		||||
    { name: "Custom", icon: "fa-cog" },
 | 
			
		||||
    {name: "Popular", icon: "fa-star-o"},
 | 
			
		||||
    {name: "Smileys & Emotion", icon: "fa-smile-o"},
 | 
			
		||||
    {name: "People & Body", icon: "fa-thumbs-o-up"},
 | 
			
		||||
    {name: "Animals & Nature", icon: "fa-leaf"},
 | 
			
		||||
    {name: "Food & Drink", icon: "fa-cutlery"},
 | 
			
		||||
    {name: "Activities", icon: "fa-soccer-ball-o"},
 | 
			
		||||
    {name: "Travel & Places", icon: "fa-car"},
 | 
			
		||||
    {name: "Objects", icon: "fa-lightbulb-o"},
 | 
			
		||||
    {name: "Symbols", icon: "fa-hashtag"},
 | 
			
		||||
    {name: "Flags", icon: "fa-flag"},
 | 
			
		||||
    {name: "Custom", icon: "fa-cog"},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function get_total_sections() {
 | 
			
		||||
@@ -212,7 +212,7 @@ function filter_emojis() {
 | 
			
		||||
                for (const alias of emoji_dict.aliases) {
 | 
			
		||||
                    const match = search_terms.every((search_term) => alias.includes(search_term));
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        search_results.push({ ...emoji_dict, emoji_name: alias });
 | 
			
		||||
                        search_results.push({...emoji_dict, emoji_name: alias});
 | 
			
		||||
                        break;  // We only need the first matching alias per emoji.
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,9 @@ import twitter_css from "!style-loader?injectType=lazyStyleTag!css-loader!../gen
 | 
			
		||||
import twitter_sheet from "emoji-datasource-twitter/img/twitter/sheets-256/64.png";
 | 
			
		||||
 | 
			
		||||
const emojisets = new Map([
 | 
			
		||||
    ["google", { css: google_css, sheet: google_sheet }],
 | 
			
		||||
    ["google-blob", { css: google_blob_css, sheet: google_blob_sheet }],
 | 
			
		||||
    ["twitter", { css: twitter_css, sheet: twitter_sheet }],
 | 
			
		||||
    ["google", {css: google_css, sheet: google_sheet}],
 | 
			
		||||
    ["google-blob", {css: google_blob_css, sheet: google_blob_sheet}],
 | 
			
		||||
    ["twitter", {css: twitter_css, sheet: twitter_sheet}],
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// For `text` emojiset we fallback to `google-blob` emojiset
 | 
			
		||||
 
 | 
			
		||||
@@ -680,7 +680,7 @@ Filter.prototype = {
 | 
			
		||||
 | 
			
		||||
    filter_with_new_params: function (params) {
 | 
			
		||||
        const terms = this._operators.map((term) => {
 | 
			
		||||
            const new_term = { ...term };
 | 
			
		||||
            const new_term = {...term};
 | 
			
		||||
            if (new_term.operator === params.operator && !new_term.negated) {
 | 
			
		||||
                new_term.operand = params.operand;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -571,12 +571,12 @@ exports.process_hotkey = function (e, hotkey) {
 | 
			
		||||
            compose_actions.cancel();
 | 
			
		||||
            // don't return, as we still want it to be picked up by the code below
 | 
			
		||||
        } else if (event_name === "page_up") {
 | 
			
		||||
            $(":focus").caret(0).animate({ scrollTop: 0 }, "fast");
 | 
			
		||||
            $(":focus").caret(0).animate({scrollTop: 0}, "fast");
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (event_name === "page_down") {
 | 
			
		||||
            // so that it always goes to the end of the text box.
 | 
			
		||||
            const height = $(":focus")[0].scrollHeight;
 | 
			
		||||
            $(":focus").caret(Infinity).animate({ scrollTop: height }, "fast");
 | 
			
		||||
            $(":focus").caret(Infinity).animate({scrollTop: height}, "fast");
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (event_name === "search_with_k") {
 | 
			
		||||
            // Do nothing; this allows one to use ctrl+k inside compose.
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ const WHALE = "/static/images/hotspots/whale.svg";
 | 
			
		||||
exports.post_hotspot_as_read = function (hotspot_name) {
 | 
			
		||||
    channel.post({
 | 
			
		||||
        url: "/json/users/me/hotspots",
 | 
			
		||||
        data: { hotspot: JSON.stringify(hotspot_name) },
 | 
			
		||||
        data: {hotspot: JSON.stringify(hotspot_name)},
 | 
			
		||||
        error: function (err) {
 | 
			
		||||
            blueslip.error(err.responseText);
 | 
			
		||||
        },
 | 
			
		||||
@@ -226,10 +226,10 @@ exports.is_open = function () {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.close_hotspot_icon = function (elem) {
 | 
			
		||||
    $(elem).animate({ opacity: 0 }, {
 | 
			
		||||
    $(elem).animate({opacity: 0}, {
 | 
			
		||||
        duration: 300,
 | 
			
		||||
        done: function () {
 | 
			
		||||
            $(elem).css({ display: "none" });
 | 
			
		||||
            $(elem).css({display: "none"});
 | 
			
		||||
        }.bind(elem),
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,9 @@ exports.set_up_toggler = function () {
 | 
			
		||||
        selected: 0,
 | 
			
		||||
        child_wants_focus: true,
 | 
			
		||||
        values: [
 | 
			
		||||
            { label: i18n.t("Keyboard shortcuts"), key: "keyboard-shortcuts" },
 | 
			
		||||
            { label: i18n.t("Message formatting"), key: "message-formatting" },
 | 
			
		||||
            { label: i18n.t("Search operators"), key: "search-operators" },
 | 
			
		||||
            {label: i18n.t("Keyboard shortcuts"), key: "keyboard-shortcuts"},
 | 
			
		||||
            {label: i18n.t("Message formatting"), key: "message-formatting"},
 | 
			
		||||
            {label: i18n.t("Search operators"), key: "search-operators"},
 | 
			
		||||
        ],
 | 
			
		||||
        callback: function (name, key) {
 | 
			
		||||
            $(".overlay-modal").hide();
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ function render_lightbox_list_images(preview_source) {
 | 
			
		||||
            const node = $("<div></div>", {
 | 
			
		||||
                class: className,
 | 
			
		||||
                "data-src": src,
 | 
			
		||||
            }).css({ backgroundImage: "url(" + src + ")"});
 | 
			
		||||
            }).css({backgroundImage: "url(" + src + ")"});
 | 
			
		||||
 | 
			
		||||
            $image_list.append(node);
 | 
			
		||||
 | 
			
		||||
@@ -291,7 +291,7 @@ exports.initialize = function () {
 | 
			
		||||
            }, 100);
 | 
			
		||||
        } else if (coords.left < this.parentNode.scrollLeft) {
 | 
			
		||||
            // subtract 2px margin
 | 
			
		||||
            $image_list.animate({ scrollLeft: coords.left - 2 }, 100);
 | 
			
		||||
            $image_list.animate({scrollLeft: coords.left - 2}, 100);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ exports.make_indicator = function (outer_container, opts) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const spinner_elem = $('<div class="loading_indicator_spinner"></div>');
 | 
			
		||||
    spinner_elem.html(render_loader({ container_id: outer_container.attr("id") }));
 | 
			
		||||
    spinner_elem.html(render_loader({container_id: outer_container.attr("id")}));
 | 
			
		||||
    container.append(spinner_elem);
 | 
			
		||||
    let text_width = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -791,7 +791,7 @@ function hide_delete_btn_show_spinner(deleting) {
 | 
			
		||||
        $("do_delete_message_button").attr("disabled", "disabled");
 | 
			
		||||
        $("#delete_message_modal > div.modal-footer > button").hide();
 | 
			
		||||
        const delete_spinner = $("#do_delete_message_spinner");
 | 
			
		||||
        loading.make_indicator(delete_spinner, { abs_positioned: true });
 | 
			
		||||
        loading.make_indicator(delete_spinner, {abs_positioned: true});
 | 
			
		||||
    } else {
 | 
			
		||||
        loading.destroy_indicator($("#do_delete_message_spinner"));
 | 
			
		||||
        $("#do_delete_message_button").prop("disabled", false);
 | 
			
		||||
 
 | 
			
		||||
@@ -344,7 +344,7 @@ exports.maybe_load_newer_messages = function (opts) {
 | 
			
		||||
 | 
			
		||||
    function load_more(data, args) {
 | 
			
		||||
        if (args.fetch_again && args.msg_list === current_msg_list) {
 | 
			
		||||
            exports.maybe_load_newer_messages({ msg_list: current_msg_list });
 | 
			
		||||
            exports.maybe_load_newer_messages({msg_list: current_msg_list});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ exports.MessageList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function  MessageList_clear(opts) {
 | 
			
		||||
        opts = { clear_selected_id: true, ...opts };
 | 
			
		||||
        opts = {clear_selected_id: true, ...opts};
 | 
			
		||||
 | 
			
		||||
        this.data.clear();
 | 
			
		||||
        this.view.clear_rendering_state(true);
 | 
			
		||||
@@ -290,7 +290,7 @@ exports.MessageList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    append_to_view: function (messages, opts) {
 | 
			
		||||
        opts = { messages_are_new: false, ...opts };
 | 
			
		||||
        opts = {messages_are_new: false, ...opts};
 | 
			
		||||
 | 
			
		||||
        this.num_appends += 1;
 | 
			
		||||
        const render_info = this.view.append(messages, opts.messages_are_new);
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ exports.set_up_muted_topics_ui = function () {
 | 
			
		||||
    list_render.create(muted_topics_table, muted_topics, {
 | 
			
		||||
        name: "muted-topics-list",
 | 
			
		||||
        modifier: function (muted_topics) {
 | 
			
		||||
            return render_muted_topic_ui_row({ muted_topics: muted_topics });
 | 
			
		||||
            return render_muted_topic_ui_row({muted_topics: muted_topics});
 | 
			
		||||
        },
 | 
			
		||||
        filter: {
 | 
			
		||||
            element: $search_input,
 | 
			
		||||
 
 | 
			
		||||
@@ -668,13 +668,13 @@ exports.by_topic = function (target_id, opts) {
 | 
			
		||||
        {operator: "stream", operand: original.stream},
 | 
			
		||||
        {operator: "topic", operand: original.topic},
 | 
			
		||||
    ];
 | 
			
		||||
    opts = { then_select_id: target_id, ...opts };
 | 
			
		||||
    opts = {then_select_id: target_id, ...opts};
 | 
			
		||||
    exports.activate(search_terms, opts);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Called for the 'narrow by stream' hotkey.
 | 
			
		||||
exports.by_recipient = function (target_id, opts) {
 | 
			
		||||
    opts = { then_select_id: target_id, ...opts };
 | 
			
		||||
    opts = {then_select_id: target_id, ...opts};
 | 
			
		||||
    // don't use current_msg_list as it won't work for muted messages or for out-of-narrow links
 | 
			
		||||
    const message = message_store.get(target_id);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ document.querySelector("#form").addEventListener("submit", () => {
 | 
			
		||||
document.querySelector("#token").focus();
 | 
			
		||||
 | 
			
		||||
async function decrypt_manual() {
 | 
			
		||||
    const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, [
 | 
			
		||||
    const key = await crypto.subtle.generateKey({name: "AES-GCM", length: 256}, true, [
 | 
			
		||||
        "decrypt",
 | 
			
		||||
    ]);
 | 
			
		||||
    return {
 | 
			
		||||
@@ -21,7 +21,7 @@ async function decrypt_manual() {
 | 
			
		||||
                    const iv = data.slice(0, 12);
 | 
			
		||||
                    const ciphertext = data.slice(12);
 | 
			
		||||
                    const plaintext = await crypto.subtle.decrypt(
 | 
			
		||||
                        { name: "AES-GCM", iv },
 | 
			
		||||
                        {name: "AES-GCM", iv},
 | 
			
		||||
                        key,
 | 
			
		||||
                        ciphertext,
 | 
			
		||||
                    );
 | 
			
		||||
@@ -40,7 +40,7 @@ async function decrypt_manual() {
 | 
			
		||||
    // key and a promise; as soon as something encrypted to that key is copied
 | 
			
		||||
    // to the clipboard, the app decrypts it and resolves the promise to the
 | 
			
		||||
    // plaintext.  This lets us skip the manual paste step.
 | 
			
		||||
    const { key, pasted } =
 | 
			
		||||
    const {key, pasted} =
 | 
			
		||||
        window.electron_bridge && window.electron_bridge.decrypt_clipboard
 | 
			
		||||
            ? window.electron_bridge.decrypt_clipboard(1)
 | 
			
		||||
            : await decrypt_manual();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { gtag, install } from "ga-gtag";
 | 
			
		||||
import {gtag, install} from "ga-gtag";
 | 
			
		||||
 | 
			
		||||
export let config;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import * as google_analytics from "./google-analytics.js";
 | 
			
		||||
import blueslip from "./../blueslip";
 | 
			
		||||
 | 
			
		||||
import { path_parts } from "./landing-page";
 | 
			
		||||
import {path_parts} from "./landing-page";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// these constants are populated immediately with data from the DOM on page load
 | 
			
		||||
@@ -90,8 +90,8 @@ function update_categories() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $(".integration-lozenges").animate(
 | 
			
		||||
        { opacity: 1 },
 | 
			
		||||
        { duration: 400 },
 | 
			
		||||
        {opacity: 1},
 | 
			
		||||
        {duration: 400},
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    adjust_font_sizing();
 | 
			
		||||
@@ -173,12 +173,12 @@ function hide_catalog_show_integration() {
 | 
			
		||||
        $(".integration-instructions#" + state.integration).css("display", "block");
 | 
			
		||||
 | 
			
		||||
        $("html, body").animate(
 | 
			
		||||
            { scrollTop: 0 },
 | 
			
		||||
            { duration: 200 },
 | 
			
		||||
            {scrollTop: 0},
 | 
			
		||||
            {duration: 200},
 | 
			
		||||
        );
 | 
			
		||||
        $("#integration-instructions-group").animate(
 | 
			
		||||
            { opacity: 1 },
 | 
			
		||||
            { duration: 300 },
 | 
			
		||||
            {opacity: 1},
 | 
			
		||||
            {duration: 300},
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        adjust_font_sizing();
 | 
			
		||||
@@ -206,8 +206,8 @@ function hide_catalog_show_integration() {
 | 
			
		||||
function hide_integration_show_catalog() {
 | 
			
		||||
    function show_catalog() {
 | 
			
		||||
        $("html, body").animate(
 | 
			
		||||
            { scrollTop: 0 },
 | 
			
		||||
            { duration: 200 },
 | 
			
		||||
            {scrollTop: 0},
 | 
			
		||||
            {duration: 200},
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $(".integration-categories-dropdown").css("display", "");
 | 
			
		||||
@@ -219,7 +219,7 @@ function hide_integration_show_catalog() {
 | 
			
		||||
    function hide_integration() {
 | 
			
		||||
        $("#integration-instruction-block").css("display", "none");
 | 
			
		||||
        $("#integration-instructions-group").css("display", "none");
 | 
			
		||||
        $(".inner-content").css({ padding: "" });
 | 
			
		||||
        $(".inner-content").css({padding: ""});
 | 
			
		||||
        $("#integration-instruction-block .integration-lozenge").remove();
 | 
			
		||||
        show_catalog();
 | 
			
		||||
    }
 | 
			
		||||
@@ -341,13 +341,13 @@ function integration_events() {
 | 
			
		||||
 | 
			
		||||
    $(".integration-instruction-block").on("click", "a .integration-category", (e) => {
 | 
			
		||||
        const category = $(e.target).data("category");
 | 
			
		||||
        dispatch("SHOW_CATEGORY", { category: category });
 | 
			
		||||
        dispatch("SHOW_CATEGORY", {category: category});
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $(".integrations a .integration-category").on("click", (e) => {
 | 
			
		||||
        const category = $(e.target).data("category");
 | 
			
		||||
        dispatch("CHANGE_CATEGORY", { category: category });
 | 
			
		||||
        dispatch("CHANGE_CATEGORY", {category: category});
 | 
			
		||||
        toggle_categories_dropdown();
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
@@ -355,7 +355,7 @@ function integration_events() {
 | 
			
		||||
    $(".integrations a .integration-lozenge").on("click", (e) => {
 | 
			
		||||
        if (!$(e.target).closest(".integration-lozenge").hasClass("integration-create-your-own")) {
 | 
			
		||||
            const integration = $(e.target).closest(".integration-lozenge").data("name");
 | 
			
		||||
            dispatch("SHOW_INTEGRATION", { integration: integration });
 | 
			
		||||
            dispatch("SHOW_INTEGRATION", {integration: integration});
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
@@ -370,7 +370,7 @@ function integration_events() {
 | 
			
		||||
    $(".integrations .searchbar input[type='text']")
 | 
			
		||||
        .focus()
 | 
			
		||||
        .on("input", (e) => {
 | 
			
		||||
            dispatch("UPDATE_QUERY", { query: e.target.value.toLowerCase() });
 | 
			
		||||
            dispatch("UPDATE_QUERY", {query: e.target.value.toLowerCase()});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    $(window).scroll(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as google_analytics from "./google-analytics.js";
 | 
			
		||||
import { detect_user_os } from "./tabbed-instructions.js";
 | 
			
		||||
import {detect_user_os} from "./tabbed-instructions.js";
 | 
			
		||||
import render_tabs from "./team.js";
 | 
			
		||||
 | 
			
		||||
export function path_parts() {
 | 
			
		||||
@@ -124,7 +124,7 @@ const apps_events = function () {
 | 
			
		||||
    $(window).on("popstate", () => {
 | 
			
		||||
        version = get_version_from_path();
 | 
			
		||||
        update_page();
 | 
			
		||||
        $("body").animate({ scrollTop: 0 }, 200);
 | 
			
		||||
        $("body").animate({scrollTop: 0}, 200);
 | 
			
		||||
        google_analytics.config({page_path: window.location.pathname});
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@@ -136,7 +136,7 @@ const apps_events = function () {
 | 
			
		||||
 | 
			
		||||
        update_path();
 | 
			
		||||
        update_page();
 | 
			
		||||
        $("body").animate({ scrollTop: 0 }, 200);
 | 
			
		||||
        $("body").animate({scrollTop: 0}, 200);
 | 
			
		||||
        google_analytics.config({page_path: window.location.pathname});
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -164,7 +164,7 @@ exports.update_elements = (content) => {
 | 
			
		||||
 | 
			
		||||
    content.find("span.timestamp-error").each(function () {
 | 
			
		||||
        const time_str = $(this).text().replace("Invalid time format: ", "");
 | 
			
		||||
        const text = i18n.t("Invalid time format: __timestamp__", { timestamp: time_str });
 | 
			
		||||
        const text = i18n.t("Invalid time format: __timestamp__", {timestamp: time_str});
 | 
			
		||||
        $(this).text(text);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,7 @@ function hide_ui_connection_error() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_events(options) {
 | 
			
		||||
    options = { dont_block: false, ...options };
 | 
			
		||||
    options = {dont_block: false, ...options};
 | 
			
		||||
 | 
			
		||||
    if (reload_state.is_in_progress()) {
 | 
			
		||||
        return;
 | 
			
		||||
 
 | 
			
		||||
@@ -110,7 +110,7 @@ exports.set_up = function () {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const spinner = $("#emoji-settings-status").expectOne();
 | 
			
		||||
        loading.make_indicator(spinner, {text: settings_ui.strings.saving });
 | 
			
		||||
        loading.make_indicator(spinner, {text: settings_ui.strings.saving});
 | 
			
		||||
 | 
			
		||||
        channel.patch({
 | 
			
		||||
            url: "/json/settings/display",
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ function populate_invites(invites_data) {
 | 
			
		||||
            item.disable_buttons = item.invited_as === settings_config.user_role_values.owner.code
 | 
			
		||||
                && !page_params.is_owner;
 | 
			
		||||
            item.referrer_email = people.get_by_user_id(item.invited_by_user_id).email;
 | 
			
		||||
            return render_admin_invites_list({ invite: item });
 | 
			
		||||
            return render_admin_invites_list({invite: item});
 | 
			
		||||
        },
 | 
			
		||||
        filter: {
 | 
			
		||||
            element: invites_table.closest(".settings-section").find(".search"),
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ function make_stream_default(stream_id) {
 | 
			
		||||
 | 
			
		||||
exports.delete_default_stream = function (stream_id, default_stream_row, alert_element) {
 | 
			
		||||
    channel.del({
 | 
			
		||||
        url: "/json/default_streams" + "?" + $.param({ stream_id: stream_id }),
 | 
			
		||||
        url: "/json/default_streams" + "?" + $.param({stream_id: stream_id}),
 | 
			
		||||
        error: function (xhr) {
 | 
			
		||||
            ui_report.generic_row_button_error(xhr, alert_element);
 | 
			
		||||
        },
 | 
			
		||||
@@ -116,7 +116,7 @@ exports.build_page = function () {
 | 
			
		||||
            return stream_data.get_non_default_stream_names();
 | 
			
		||||
        },
 | 
			
		||||
        highlighter: function (item) {
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({ primary: item });
 | 
			
		||||
            return typeahead_helper.render_typeahead_item({primary: item});
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ exports.initialize = function () {
 | 
			
		||||
    toggler = components.toggle({
 | 
			
		||||
        child_wants_focus: true,
 | 
			
		||||
        values: [
 | 
			
		||||
            { label: i18n.t("Settings"), key: "settings" },
 | 
			
		||||
            { label: i18n.t("Organization"), key: "organization" },
 | 
			
		||||
            {label: i18n.t("Settings"), key: "settings"},
 | 
			
		||||
            {label: i18n.t("Organization"), key: "organization"},
 | 
			
		||||
        ],
 | 
			
		||||
        callback: function (name, key) {
 | 
			
		||||
            if (key === "organization") {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ function update_last_full_update(end_times) {
 | 
			
		||||
 | 
			
		||||
    last_full_update = Math.min(last_full_update, end_times[end_times.length - 1]);
 | 
			
		||||
    const update_time = new Date(last_full_update * 1000);
 | 
			
		||||
    const locale_date = update_time.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
 | 
			
		||||
    const locale_date = update_time.toLocaleDateString("en-US", {year: "numeric", month: "long", day: "numeric"});
 | 
			
		||||
    const locale_time = update_time.toLocaleTimeString().replace(":00 ", " ");
 | 
			
		||||
 | 
			
		||||
    $("#id_last_full_update").text(locale_time + " on " + locale_date);
 | 
			
		||||
@@ -92,7 +92,7 @@ function populate_messages_sent_over_time(data) {
 | 
			
		||||
    // Helper functions
 | 
			
		||||
    function make_traces(dates, values, type, date_formatter) {
 | 
			
		||||
        const text = dates.map((date) => date_formatter(date));
 | 
			
		||||
        const common = { x: dates, type: type, hoverinfo: "none", text: text };
 | 
			
		||||
        const common = {x: dates, type: type, hoverinfo: "none", text: text};
 | 
			
		||||
        return {
 | 
			
		||||
            human: { // 5062a0
 | 
			
		||||
                name: i18n.t("Humans"), y: values.human, marker: {color: "#5f6ea0"},
 | 
			
		||||
@@ -113,13 +113,13 @@ function populate_messages_sent_over_time(data) {
 | 
			
		||||
        barmode: "group",
 | 
			
		||||
        width: 750,
 | 
			
		||||
        height: 400,
 | 
			
		||||
        margin: { l: 40, r: 0, b: 40, t: 0 },
 | 
			
		||||
        margin: {l: 40, r: 0, b: 40, t: 0},
 | 
			
		||||
        xaxis: {
 | 
			
		||||
            fixedrange: true,
 | 
			
		||||
            rangeslider: { bordercolor: "#D8D8D8", borderwidth: 1 },
 | 
			
		||||
            rangeslider: {bordercolor: "#D8D8D8", borderwidth: 1},
 | 
			
		||||
            type: "date",
 | 
			
		||||
        },
 | 
			
		||||
        yaxis: { fixedrange: true, rangemode: "tozero" },
 | 
			
		||||
        yaxis: {fixedrange: true, rangemode: "tozero"},
 | 
			
		||||
        legend: {
 | 
			
		||||
            x: 0.62, y: 1.12, orientation: "h", font: font_14pt,
 | 
			
		||||
        },
 | 
			
		||||
@@ -372,10 +372,10 @@ function populate_messages_sent_by_client(data) {
 | 
			
		||||
    const layout = {
 | 
			
		||||
        width: 750,
 | 
			
		||||
        height: null, // set in draw_plot()
 | 
			
		||||
        margin: { l: 3, r: 40, b: 40, t: 0 },
 | 
			
		||||
        margin: {l: 3, r: 40, b: 40, t: 0},
 | 
			
		||||
        font: font_14pt,
 | 
			
		||||
        xaxis: { range: null }, // set in draw_plot()
 | 
			
		||||
        yaxis: { showticklabels: false },
 | 
			
		||||
        xaxis: {range: null}, // set in draw_plot()
 | 
			
		||||
        yaxis: {showticklabels: false},
 | 
			
		||||
        showlegend: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -415,8 +415,8 @@ function populate_messages_sent_by_client(data) {
 | 
			
		||||
                sort: false,
 | 
			
		||||
                textinfo: "text",
 | 
			
		||||
                hoverinfo: "none",
 | 
			
		||||
                marker: { color: "#537c5e" },
 | 
			
		||||
                font: { family: "Source Sans Pro", size: 18, color: "#000000" },
 | 
			
		||||
                marker: {color: "#537c5e"},
 | 
			
		||||
                font: {family: "Source Sans Pro", size: 18, color: "#000000"},
 | 
			
		||||
            },
 | 
			
		||||
            trace_annotations: {
 | 
			
		||||
                x: annotations.values,
 | 
			
		||||
@@ -518,7 +518,7 @@ function populate_messages_sent_by_client(data) {
 | 
			
		||||
 | 
			
		||||
function populate_messages_sent_by_message_type(data) {
 | 
			
		||||
    const layout = {
 | 
			
		||||
        margin: { l: 90, r: 0, b: 0, t: 0 },
 | 
			
		||||
        margin: {l: 90, r: 0, b: 0, t: 0},
 | 
			
		||||
        width: 750,
 | 
			
		||||
        height: 300,
 | 
			
		||||
        font: font_14pt,
 | 
			
		||||
@@ -630,18 +630,18 @@ function populate_number_of_users(data) {
 | 
			
		||||
    const layout = {
 | 
			
		||||
        width: 750,
 | 
			
		||||
        height: 370,
 | 
			
		||||
        margin: { l: 40, r: 0, b: 65, t: 20 },
 | 
			
		||||
        margin: {l: 40, r: 0, b: 65, t: 20},
 | 
			
		||||
        xaxis: {
 | 
			
		||||
            fixedrange: true,
 | 
			
		||||
            rangeslider: { bordercolor: "#D8D8D8", borderwidth: 1 },
 | 
			
		||||
            rangeslider: {bordercolor: "#D8D8D8", borderwidth: 1},
 | 
			
		||||
            rangeselector: {
 | 
			
		||||
                x: 0.64, y: -0.79,
 | 
			
		||||
                buttons: [
 | 
			
		||||
                    { count: 2, label: i18n.t("Last 2 months"), step: "month", stepmode: "backward" },
 | 
			
		||||
                    { count: 6, label: i18n.t("Last 6 months"), step: "month", stepmode: "backward" },
 | 
			
		||||
                    { step: "all", label: i18n.t("All time") },
 | 
			
		||||
                    {count: 2, label: i18n.t("Last 2 months"), step: "month", stepmode: "backward"},
 | 
			
		||||
                    {count: 6, label: i18n.t("Last 6 months"), step: "month", stepmode: "backward"},
 | 
			
		||||
                    {step: "all", label: i18n.t("All time")},
 | 
			
		||||
                ]}},
 | 
			
		||||
        yaxis: { fixedrange: true, rangemode: "tozero" },
 | 
			
		||||
        yaxis: {fixedrange: true, rangemode: "tozero"},
 | 
			
		||||
        font: font_14pt,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -726,7 +726,7 @@ function populate_messages_read_over_time(data) {
 | 
			
		||||
    // Helper functions
 | 
			
		||||
    function make_traces(dates, values, type, date_formatter) {
 | 
			
		||||
        const text = dates.map((date) => date_formatter(date));
 | 
			
		||||
        const common = { x: dates, type: type, hoverinfo: "none", text: text };
 | 
			
		||||
        const common = {x: dates, type: type, hoverinfo: "none", text: text};
 | 
			
		||||
        return {
 | 
			
		||||
            everyone: {
 | 
			
		||||
                name: i18n.t("Everyone"), y: values.everyone, marker: {color: "#5f6ea0"},
 | 
			
		||||
@@ -743,13 +743,13 @@ function populate_messages_read_over_time(data) {
 | 
			
		||||
        barmode: "group",
 | 
			
		||||
        width: 750,
 | 
			
		||||
        height: 400,
 | 
			
		||||
        margin: { l: 40, r: 0, b: 40, t: 0 },
 | 
			
		||||
        margin: {l: 40, r: 0, b: 40, t: 0},
 | 
			
		||||
        xaxis: {
 | 
			
		||||
            fixedrange: true,
 | 
			
		||||
            rangeslider: { bordercolor: "#D8D8D8", borderwidth: 1 },
 | 
			
		||||
            rangeslider: {bordercolor: "#D8D8D8", borderwidth: 1},
 | 
			
		||||
            type: "date",
 | 
			
		||||
        },
 | 
			
		||||
        yaxis: { fixedrange: true, rangemode: "tozero" },
 | 
			
		||||
        yaxis: {fixedrange: true, rangemode: "tozero"},
 | 
			
		||||
        legend: {
 | 
			
		||||
            x: 0.62, y: 1.12, orientation: "h", font: font_14pt,
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ exports.set_colorpicker_color = function (colorpicker, color) {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.update_stream_color = function (sub, color, opts) {
 | 
			
		||||
    opts = { update_historical: false, ...opts };
 | 
			
		||||
    opts = {update_historical: false, ...opts};
 | 
			
		||||
    sub.color = color;
 | 
			
		||||
    const stream_id = sub.stream_id;
 | 
			
		||||
    // The swatch in the subscription row header.
 | 
			
		||||
 
 | 
			
		||||
@@ -540,9 +540,9 @@ exports.setup_page = function (callback) {
 | 
			
		||||
        sort_order = "by-stream-name";
 | 
			
		||||
        exports.sort_toggler = components.toggle({
 | 
			
		||||
            values: [
 | 
			
		||||
                { label: `<i class="fa fa-sort-alpha-asc" title="${i18n.t("Sort by name")}"></i>`, key: "by-stream-name" },
 | 
			
		||||
                { label: `<i class="fa fa-user-o" title="${i18n.t("Sort by number of subscribers")}"></i>`, key: "by-subscriber-count" },
 | 
			
		||||
                { label: `<i class="fa fa-bar-chart" title="${i18n.t("Sort by estimated weekly traffic")}"></i>`, key: "by-weekly-traffic" },
 | 
			
		||||
                {label: `<i class="fa fa-sort-alpha-asc" title="${i18n.t("Sort by name")}"></i>`, key: "by-stream-name"},
 | 
			
		||||
                {label: `<i class="fa fa-user-o" title="${i18n.t("Sort by number of subscribers")}"></i>`, key: "by-subscriber-count"},
 | 
			
		||||
                {label: `<i class="fa fa-bar-chart" title="${i18n.t("Sort by estimated weekly traffic")}"></i>`, key: "by-weekly-traffic"},
 | 
			
		||||
            ],
 | 
			
		||||
            html_class: "stream_sorter_toggle",
 | 
			
		||||
            callback: function (value, key) {
 | 
			
		||||
@@ -557,8 +557,8 @@ exports.setup_page = function (callback) {
 | 
			
		||||
        exports.toggler = components.toggle({
 | 
			
		||||
            child_wants_focus: true,
 | 
			
		||||
            values: [
 | 
			
		||||
                { label: i18n.t("Subscribed"), key: "subscribed" },
 | 
			
		||||
                { label: i18n.t("All streams"), key: "all-streams" },
 | 
			
		||||
                {label: i18n.t("Subscribed"), key: "subscribed"},
 | 
			
		||||
                {label: i18n.t("All streams"), key: "all-streams"},
 | 
			
		||||
            ],
 | 
			
		||||
            callback: function (value, key) {
 | 
			
		||||
                exports.switch_stream_tab(key);
 | 
			
		||||
@@ -801,7 +801,7 @@ function ajaxSubscribe(stream, color, stream_row) {
 | 
			
		||||
    }
 | 
			
		||||
    return channel.post({
 | 
			
		||||
        url: "/json/users/me/subscriptions",
 | 
			
		||||
        data: {subscriptions: JSON.stringify([{name: stream, color: color}]) },
 | 
			
		||||
        data: {subscriptions: JSON.stringify([{name: stream, color: color}])},
 | 
			
		||||
        success: function (resp, statusText, xhr) {
 | 
			
		||||
            if (overlays.streams_open()) {
 | 
			
		||||
                $("#create_stream_name").val("");
 | 
			
		||||
@@ -837,7 +837,7 @@ function ajaxUnsubscribe(sub, stream_row) {
 | 
			
		||||
    }
 | 
			
		||||
    return channel.del({
 | 
			
		||||
        url: "/json/users/me/subscriptions",
 | 
			
		||||
        data: {subscriptions: JSON.stringify([sub.name]) },
 | 
			
		||||
        data: {subscriptions: JSON.stringify([sub.name])},
 | 
			
		||||
        success: function () {
 | 
			
		||||
            $(".stream_change_property_info").hide();
 | 
			
		||||
            // The rest of the work is done via the unsubscribe event we will get
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ function make_tab_data(filter) {
 | 
			
		||||
        tab_data.formatted_sub_count = get_formatted_sub_count(current_stream);
 | 
			
		||||
        // the "title" is passed as a variable and doesn't get translated (nor should it)
 | 
			
		||||
        tab_data.sub_count_tooltip_text =
 | 
			
		||||
            i18n.t("__count__ users are subscribed to #__title__", { count: tab_data.sub_count, title: tab_data.title });
 | 
			
		||||
            i18n.t("__count__ users are subscribed to #__title__", {count: tab_data.sub_count, title: tab_data.title});
 | 
			
		||||
        tab_data.stream_settings_link = "#streams/" + current_stream.stream_id + "/" + current_stream.name;
 | 
			
		||||
    }
 | 
			
		||||
    return tab_data;
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ exports.render_typeahead_item = function (args) {
 | 
			
		||||
    return render_typeahead_list_item(args);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const rendered = { persons: new Map(), streams: new Map(), user_groups: new Map() };
 | 
			
		||||
const rendered = {persons: new Map(), streams: new Map(), user_groups: new Map()};
 | 
			
		||||
 | 
			
		||||
exports.render_person = function (person) {
 | 
			
		||||
    if (person.special_item_text) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Plugin } from "webpack";
 | 
			
		||||
import {Plugin} from "webpack";
 | 
			
		||||
 | 
			
		||||
declare namespace BundleTracker {
 | 
			
		||||
    interface Options {
 | 
			
		||||
 
 | 
			
		||||
@@ -146,7 +146,7 @@ exports.get_hotkey_deprecation_notice = function (originalHotkey, replacementHot
 | 
			
		||||
    return i18n.t(
 | 
			
		||||
        'We\'ve replaced the "__originalHotkey__" hotkey with "__replacementHotkey__" '
 | 
			
		||||
            + "to make this common shortcut easier to trigger.",
 | 
			
		||||
        { originalHotkey: originalHotkey, replacementHotkey: replacementHotkey },
 | 
			
		||||
        {originalHotkey: originalHotkey, replacementHotkey: replacementHotkey},
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// debugging.  It also exposes the list of modules it knows about as the keys
 | 
			
		||||
// of the require.ids object.
 | 
			
		||||
 | 
			
		||||
import webpack, { Template } from "webpack";
 | 
			
		||||
import webpack, {Template} from "webpack";
 | 
			
		||||
import path from "path";
 | 
			
		||||
 | 
			
		||||
export default class DebugRequirePlugin {
 | 
			
		||||
@@ -39,7 +39,7 @@ export default class DebugRequirePlugin {
 | 
			
		||||
 | 
			
		||||
        compiler.hooks.beforeCompile.tapPromise(
 | 
			
		||||
            "DebugRequirePlugin",
 | 
			
		||||
            async ({ normalModuleFactory }: any) => {
 | 
			
		||||
            async ({normalModuleFactory}: any) => {
 | 
			
		||||
                const resolver = normalModuleFactory.getResolver("normal");
 | 
			
		||||
                debugRequirePath = await new Promise((resolve, reject) =>
 | 
			
		||||
                    resolver.resolve(
 | 
			
		||||
@@ -60,7 +60,7 @@ export default class DebugRequirePlugin {
 | 
			
		||||
                    const ids: [string, string | number][] = [];
 | 
			
		||||
                    let debugRequireId;
 | 
			
		||||
                    chunk.hasModuleInGraph(
 | 
			
		||||
                        ({ resource, rawRequest, id }: any) => {
 | 
			
		||||
                        ({resource, rawRequest, id}: any) => {
 | 
			
		||||
                            if (resource === debugRequirePath) {
 | 
			
		||||
                                debugRequireId = id;
 | 
			
		||||
                            }
 | 
			
		||||
@@ -80,7 +80,7 @@ export default class DebugRequirePlugin {
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    ids.sort();
 | 
			
		||||
                    const { requireFn } = compilation.mainTemplate;
 | 
			
		||||
                    const {requireFn} = compilation.mainTemplate;
 | 
			
		||||
                    return Template.asString([
 | 
			
		||||
                        source,
 | 
			
		||||
                        `${requireFn}(${JSON.stringify(
 | 
			
		||||
 
 | 
			
		||||
@@ -34,14 +34,14 @@ async function run() {
 | 
			
		||||
    try {
 | 
			
		||||
        const page = await browser.newPage();
 | 
			
		||||
        // deviceScaleFactor:2 gives better quality screenshots (higher pixel density)
 | 
			
		||||
        await page.setViewport({ width: 1280, height: 1024, deviceScaleFactor: 2 });
 | 
			
		||||
        await page.setViewport({width: 1280, height: 1024, deviceScaleFactor: 2});
 | 
			
		||||
        await page.goto("http://" + host);
 | 
			
		||||
        // wait for Iago devlogin button and click on it.
 | 
			
		||||
        await page.waitForSelector('[value="iago@zulip.com"]');
 | 
			
		||||
 | 
			
		||||
        // By waiting till DOMContentLoaded we're confirming that Iago is logged in.
 | 
			
		||||
        await Promise.all([
 | 
			
		||||
            page.waitForNavigation({ waitUntil: "domcontentloaded" }),
 | 
			
		||||
            page.waitForNavigation({waitUntil: "domcontentloaded"}),
 | 
			
		||||
            page.click('[value="iago@zulip.com"]'),
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +64,7 @@ async function run() {
 | 
			
		||||
        const imagePath = options.imagePath;
 | 
			
		||||
        const imageDir = path.dirname(imagePath);
 | 
			
		||||
        mkdirp.sync(imageDir);
 | 
			
		||||
        await page.screenshot({ path: imagePath, clip: clip });
 | 
			
		||||
        await page.screenshot({path: imagePath, clip: clip});
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.log(e);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { RuleSetRule, RuleSetUseItem } from "webpack";
 | 
			
		||||
import { basename, resolve } from "path";
 | 
			
		||||
import {RuleSetRule, RuleSetUseItem} from "webpack";
 | 
			
		||||
import {basename, resolve} from "path";
 | 
			
		||||
 | 
			
		||||
export const cacheLoader: RuleSetUseItem = {
 | 
			
		||||
    loader: "cache-loader",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { basename, resolve } from "path";
 | 
			
		||||
import { cacheLoader, getExposeLoaders } from "./webpack-helpers";
 | 
			
		||||
import {basename, resolve} from "path";
 | 
			
		||||
import {cacheLoader, getExposeLoaders} from "./webpack-helpers";
 | 
			
		||||
import BundleTracker from "webpack4-bundle-tracker";
 | 
			
		||||
import CleanCss from "clean-css";
 | 
			
		||||
import DebugRequirePlugin from "./debug-require-webpack-plugin";
 | 
			
		||||
@@ -228,19 +228,19 @@ export default (env?: string): webpack.Configuration[] => {
 | 
			
		||||
    // Use the unminified versions of jquery and underscore so that
 | 
			
		||||
    // Good error messages show up in production and development in the source maps
 | 
			
		||||
    const exposeOptions = [
 | 
			
		||||
        { path: "./debug-require.js", name: "require" },
 | 
			
		||||
        { path: "blueimp-md5/js/md5.js" },
 | 
			
		||||
        { path: "clipboard/dist/clipboard.js", name: "ClipboardJS" },
 | 
			
		||||
        { path: "xdate/src/xdate.js", name: "XDate" },
 | 
			
		||||
        { path: "../static/third/marked/lib/marked.js" },
 | 
			
		||||
        { path: "../static/js/debug.js" },
 | 
			
		||||
        { path: "../static/js/blueslip.js" },
 | 
			
		||||
        { path: "../static/js/common.js" },
 | 
			
		||||
        { path: "jquery/dist/jquery.js", name: ["$", "jQuery"] },
 | 
			
		||||
        { path: "underscore/underscore.js", name: "_" },
 | 
			
		||||
        { path: "handlebars/dist/cjs/handlebars.runtime.js", name: "Handlebars" },
 | 
			
		||||
        { path: "sortablejs/Sortable.js"},
 | 
			
		||||
        { path: "winchan/winchan.js", name: "WinChan"},
 | 
			
		||||
        {path: "./debug-require.js", name: "require"},
 | 
			
		||||
        {path: "blueimp-md5/js/md5.js"},
 | 
			
		||||
        {path: "clipboard/dist/clipboard.js", name: "ClipboardJS"},
 | 
			
		||||
        {path: "xdate/src/xdate.js", name: "XDate"},
 | 
			
		||||
        {path: "../static/third/marked/lib/marked.js"},
 | 
			
		||||
        {path: "../static/js/debug.js"},
 | 
			
		||||
        {path: "../static/js/blueslip.js"},
 | 
			
		||||
        {path: "../static/js/common.js"},
 | 
			
		||||
        {path: "jquery/dist/jquery.js", name: ["$", "jQuery"]},
 | 
			
		||||
        {path: "underscore/underscore.js", name: "_"},
 | 
			
		||||
        {path: "handlebars/dist/cjs/handlebars.runtime.js", name: "Handlebars"},
 | 
			
		||||
        {path: "sortablejs/Sortable.js"},
 | 
			
		||||
        {path: "winchan/winchan.js", name: "WinChan"},
 | 
			
		||||
    ];
 | 
			
		||||
    config.module.rules.unshift(...getExposeLoaders(exposeOptions));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -192,7 +192,7 @@ add_example("get_stream_id", "/get_stream_id:get", 200, async (client) => {
 | 
			
		||||
add_example("get_stream_topics", "/users/me/{stream_id}/topics:get", 200, async (client) => {
 | 
			
		||||
    // {code_example|start}
 | 
			
		||||
    // Get all the topics in stream with ID 1
 | 
			
		||||
    return client.streams.topics.retrieve({ stream_id: 1 });
 | 
			
		||||
    return client.streams.topics.retrieve({stream_id: 1});
 | 
			
		||||
    // {code_example|end}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user