From 02511bff1cdf73ff041df025cf09025ce0e755de Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Wed, 5 Feb 2020 21:19:47 -0800 Subject: [PATCH] =?UTF-8?q?js:=20Automatically=20convert=20=5F.each=20to?= =?UTF-8?q?=20for=E2=80=A6of.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was automatically generated by the following script, followed by lint --fix and a few small manual lint-related cleanups. import * as babelParser from "recast/parsers/babel"; import * as recast from "recast"; import * as tsParser from "recast/parsers/typescript"; import { builders as b, namedTypes as n } from "ast-types"; import { Context } from "ast-types/lib/path-visitor"; import K from "ast-types/gen/kinds"; import { NodePath } from "ast-types/lib/node-path"; import assert from "assert"; import fs from "fs"; import path from "path"; import process from "process"; const checkExpression = (node: n.Node): node is K.ExpressionKind => n.Expression.check(node); const checkStatement = (node: n.Node): node is K.StatementKind => n.Statement.check(node); for (const file of process.argv.slice(2)) { console.log("Parsing", file); const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), { parser: path.extname(file) === ".ts" ? tsParser : babelParser, }); let changed = false; let inLoop = false; let replaceReturn = false; const visitLoop = (...args: string[]) => function(this: Context, path: NodePath) { for (const arg of args) { this.visit(path.get(arg)); } const old = { inLoop }; inLoop = true; this.visit(path.get("body")); inLoop = old.inLoop; return false; }; recast.visit(ast, { visitDoWhileStatement: visitLoop("test"), visitExpressionStatement(path) { const { expression, comments } = path.node; let valueOnly; if ( n.CallExpression.check(expression) && n.MemberExpression.check(expression.callee) && !expression.callee.computed && n.Identifier.check(expression.callee.object) && expression.callee.object.name === "_" && n.Identifier.check(expression.callee.property) && ["each", "forEach"].includes(expression.callee.property.name) && [2, 3].includes(expression.arguments.length) && checkExpression(expression.arguments[0]) && (n.FunctionExpression.check(expression.arguments[1]) || n.ArrowFunctionExpression.check(expression.arguments[1])) && [1, 2].includes(expression.arguments[1].params.length) && n.Identifier.check(expression.arguments[1].params[0]) && ((valueOnly = expression.arguments[1].params[1] === undefined) || n.Identifier.check(expression.arguments[1].params[1])) && (expression.arguments[2] === undefined || n.ThisExpression.check(expression.arguments[2])) ) { const old = { inLoop, replaceReturn }; inLoop = false; replaceReturn = true; this.visit( path .get("expression") .get("arguments") .get(1) .get("body") ); inLoop = old.inLoop; replaceReturn = old.replaceReturn; const [right, { body, params }] = expression.arguments; const loop = b.forOfStatement( b.variableDeclaration("let", [ b.variableDeclarator( valueOnly ? params[0] : b.arrayPattern([params[1], params[0]]) ), ]), valueOnly ? right : b.callExpression( b.memberExpression(right, b.identifier("entries")), [] ), checkStatement(body) ? body : b.expressionStatement(body) ); loop.comments = comments; path.replace(loop); changed = true; } this.traverse(path); }, visitForStatement: visitLoop("init", "test", "update"), visitForInStatement: visitLoop("left", "right"), visitForOfStatement: visitLoop("left", "right"), visitFunction(path) { this.visit(path.get("params")); const old = { replaceReturn }; replaceReturn = false; this.visit(path.get("body")); replaceReturn = old.replaceReturn; return false; }, visitReturnStatement(path) { if (replaceReturn) { assert(!inLoop); // could use labeled continue if this ever fires const { argument, comments } = path.node; if (argument === null) { const s = b.continueStatement(); s.comments = comments; path.replace(s); } else { const s = b.expressionStatement(argument); s.comments = comments; path.replace(s, b.continueStatement()); } return false; } this.traverse(path); }, visitWhileStatement: visitLoop("test"), }); if (changed) { console.log("Writing", file); fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" }); } } Signed-off-by: Anders Kaseorg --- frontend_tests/node_tests/buddy_data.js | 13 ++-- frontend_tests/node_tests/color_data.js | 4 +- frontend_tests/node_tests/components.js | 4 +- frontend_tests/node_tests/compose.js | 5 +- frontend_tests/node_tests/emoji.js | 4 +- frontend_tests/node_tests/emoji_picker.js | 4 +- frontend_tests/node_tests/hotkey.js | 16 ++--- frontend_tests/node_tests/message_events.js | 4 +- .../node_tests/message_list_data.js | 4 +- .../node_tests/message_list_view.js | 8 +-- frontend_tests/node_tests/narrow_local.js | 4 +- frontend_tests/node_tests/people.js | 4 +- .../node_tests/search_suggestion.js | 4 +- .../node_tests/search_suggestion_legacy.js | 4 +- frontend_tests/node_tests/settings_org.js | 4 +- .../node_tests/settings_user_groups.js | 10 +-- frontend_tests/node_tests/stream_data.js | 4 +- frontend_tests/node_tests/subs.js | 9 +-- frontend_tests/node_tests/templates.js | 70 +++++++++++-------- frontend_tests/node_tests/topic_data.js | 4 +- frontend_tests/node_tests/topic_list_data.js | 4 +- frontend_tests/node_tests/typeahead_helper.js | 4 +- frontend_tests/node_tests/ui_init.js | 4 +- frontend_tests/zjsunit/bugdown_assert.js | 13 ++-- frontend_tests/zjsunit/i18n.js | 6 +- frontend_tests/zjsunit/namespace.js | 4 +- frontend_tests/zjsunit/stub.js | 6 +- static/js/activity.js | 8 +-- static/js/alert_words.js | 4 +- static/js/alert_words_ui.js | 6 +- static/js/attachments_ui.js | 4 +- static/js/bot_data.js | 5 +- static/js/buddy_data.js | 5 +- static/js/buddy_list.js | 4 +- static/js/common.js | 6 +- static/js/compose_fade.js | 12 ++-- static/js/composebox_typeahead.js | 4 +- static/js/condense.js | 8 +-- static/js/confirm_dialog.js | 4 +- static/js/copy_and_paste.js | 6 +- static/js/echo.js | 10 +-- static/js/emoji.js | 5 +- static/js/emoji_picker.js | 23 +++--- static/js/fenced_code.js | 10 +-- static/js/filter.js | 12 ++-- static/js/floating_recipient_bar.js | 8 +-- static/js/hash_util.js | 5 +- static/js/hotspots.js | 5 +- static/js/info_overlay.js | 4 +- static/js/markdown.js | 23 +++--- static/js/message_edit.js | 5 +- static/js/message_events.js | 22 +++--- static/js/message_list_data.js | 39 ++++++----- static/js/message_list_view.js | 39 ++++++----- static/js/message_live_update.js | 18 ++--- static/js/message_store.js | 12 ++-- static/js/muting.js | 6 +- static/js/muting_ui.js | 7 +- static/js/narrow.js | 9 +-- static/js/narrow_state.js | 6 +- static/js/notifications.js | 26 +++---- static/js/people.js | 33 ++++----- static/js/pm_conversations.js | 5 +- static/js/pm_list.js | 6 +- static/js/poll_widget.js | 9 +-- static/js/portico/team.js | 4 +- static/js/presence.js | 8 +-- static/js/reactions.js | 12 ++-- static/js/reload.js | 5 +- static/js/resize.js | 11 +-- static/js/search_suggestion.js | 22 +++--- static/js/server_events.js | 18 ++--- static/js/server_events_dispatch.js | 30 ++++---- static/js/settings_account.js | 5 +- static/js/settings_bots.js | 10 +-- static/js/settings_display.js | 4 +- static/js/settings_emoji.js | 6 +- static/js/settings_linkifiers.js | 5 +- static/js/settings_notifications.js | 16 ++--- static/js/settings_org.js | 32 +++++---- static/js/settings_profile_fields.js | 10 +-- static/js/settings_toggle.js | 9 ++- static/js/settings_user_groups.js | 13 ++-- static/js/starred_messages.js | 16 +++-- static/js/stream_color.js | 4 +- static/js/stream_data.js | 16 ++--- static/js/stream_events.js | 4 +- static/js/stream_list.js | 4 +- static/js/stream_sort.js | 4 +- static/js/subs.js | 28 ++++---- static/js/tictactoe_widget.js | 5 +- static/js/timerender.js | 8 +-- static/js/todo_widget.js | 5 +- static/js/topic_data.js | 6 +- static/js/topic_list_data.js | 10 +-- static/js/typeahead_helper.js | 12 ++-- static/js/ui.js | 20 +++--- static/js/unread.js | 54 +++++++------- static/js/unread_ops.js | 8 +-- static/js/user_groups.js | 14 ++-- static/js/vdom.js | 6 +- static/js/zform.js | 4 +- tools/check-openapi | 9 ++- 103 files changed, 602 insertions(+), 502 deletions(-) diff --git a/frontend_tests/node_tests/buddy_data.js b/frontend_tests/node_tests/buddy_data.js index f2411c9934..5539a4caf3 100644 --- a/frontend_tests/node_tests/buddy_data.js +++ b/frontend_tests/node_tests/buddy_data.js @@ -53,14 +53,14 @@ const bot_with_owner = { }; function make_people() { - _.each(_.range(1002, 2000), (i) => { + for (const i of _.range(1002, 2000)) { const person = { user_id: i, full_name: `Human ${i}`, email: `person${i}@example.com`, }; people.add_in_realm(person); - }); + } people.add_in_realm(bot); people.add_in_realm(bot_with_owner); @@ -85,15 +85,14 @@ function activate_people() { presence.set_info_for_user(selma.user_id, info, server_time); presence.set_info_for_user(me.user_id, info, server_time); - _.each(_.range(1000, 1400), (user_id) => { + for (const user_id of _.range(1000, 1400)) { presence.set_info_for_user(user_id, info, server_time); - }); - + } // And then 300 not active - _.each(_.range(1400, 1700), (user_id) => { + for (const user_id of _.range(1400, 1700)) { presence.set_info_for_user(user_id, {}, server_time); - }); + } } diff --git a/frontend_tests/node_tests/color_data.js b/frontend_tests/node_tests/color_data.js index e8da9410d3..39f67aa858 100644 --- a/frontend_tests/node_tests/color_data.js +++ b/frontend_tests/node_tests/color_data.js @@ -35,9 +35,9 @@ run_test('pick_color', () => { 'yellow', ]; - _.each(expected_colors, (expected_color) => { + for (const expected_color of expected_colors) { assert.equal(color_data.pick_color(), expected_color); - }); + } color_data.claim_color('blue'); assert.equal(color_data.pick_color(), 'orange'); diff --git a/frontend_tests/node_tests/components.js b/frontend_tests/node_tests/components.js index 0b9dca94a4..d4e59dadc5 100644 --- a/frontend_tests/node_tests/components.js +++ b/frontend_tests/node_tests/components.js @@ -67,9 +67,9 @@ run_test('basics', () => { }; self.removeClass = function (c) { - _.each(tabs, function (tab) { + for (const tab of tabs) { tab.removeClass(c); - }); + } }; self.eq = function (idx) { diff --git a/frontend_tests/node_tests/compose.js b/frontend_tests/node_tests/compose.js index cb6b91de62..48d2bcd26c 100644 --- a/frontend_tests/node_tests/compose.js +++ b/frontend_tests/node_tests/compose.js @@ -929,8 +929,7 @@ run_test('warn_if_private_stream_is_linked', () => { compose.warn_if_private_stream_is_linked(denmark); assert.equal($('#compose_private_stream_alert').visible(), true); - _.each(checks, function (f) { f(); }); - + for (const f of checks) { f(); } }); @@ -1175,7 +1174,7 @@ run_test('warn_if_mentioning_unsubscribed_user', () => { compose.warn_if_mentioning_unsubscribed_user(mentioned); assert.equal($('#compose_invite_users').visible(), true); - _.each(checks, function (f) { f(); }); + for (const f of checks) { f(); } // Simulate that the row was added to the DOM. diff --git a/frontend_tests/node_tests/emoji.js b/frontend_tests/node_tests/emoji.js index c4f31d7b8c..f14ebe15f0 100644 --- a/frontend_tests/node_tests/emoji.js +++ b/frontend_tests/node_tests/emoji.js @@ -116,7 +116,7 @@ run_test('translate_emoticons_to_names', () => { {name: 'before end of sentence', original: 'Hello !', expected: 'Hello !'}, ]; for (const [shortcut, full_name] of Object.entries(emoji_codes.emoticon_conversions)) { - _.each(testcases, (t) => { + for (const t of testcases) { const converted_value = full_name; let original = t.original; let expected = t.expected; @@ -125,6 +125,6 @@ run_test('translate_emoticons_to_names', () => { .replace(/()/g, converted_value); const result = emoji.translate_emoticons_to_names(original); assert.equal(result, expected); - }); + } } }); diff --git a/frontend_tests/node_tests/emoji_picker.js b/frontend_tests/node_tests/emoji_picker.js index cb55279b7b..404689ff35 100644 --- a/frontend_tests/node_tests/emoji_picker.js +++ b/frontend_tests/node_tests/emoji_picker.js @@ -14,9 +14,9 @@ run_test('initialize', () => { assert.equal(ele.icon, icon); assert.equal(ele.emojis.length, num); function check_emojis(val) { - _.each(ele.emojis, function (emoji) { + for (const emoji of ele.emojis) { assert.equal(emoji.is_realm_emoji, val); - }); + } } if (ele.name === 'Custom') { check_emojis(true); diff --git a/frontend_tests/node_tests/hotkey.js b/frontend_tests/node_tests/hotkey.js index d12b0fbece..bc64bfe34d 100644 --- a/frontend_tests/node_tests/hotkey.js +++ b/frontend_tests/node_tests/hotkey.js @@ -170,9 +170,9 @@ run_test('basic_chars', () => { } function assert_unmapped(s) { - _.each(s, function (c) { + for (const c of s) { assert.equal(process(c), false); - }); + } } // Unmapped keys should immediately return false, without @@ -215,18 +215,18 @@ run_test('basic_chars', () => { assert_unmapped('~!@#$%^*()_+{}:"<>'); } - _.each([return_true, return_false], function (settings_open) { - _.each([return_true, return_false], function (is_active) { - _.each([return_true, return_false], function (info_overlay_open) { + for (const settings_open of [return_true, return_false]) { + for (const is_active of [return_true, return_false]) { + for (const info_overlay_open of [return_true, return_false]) { set_global('overlays', { is_active: is_active, settings_open: settings_open, info_overlay_open: info_overlay_open, }); test_normal_typing(); - }); - }); - }); + } + } + } // Ok, now test keys that work when we're viewing messages. hotkey.processing_text = return_false; diff --git a/frontend_tests/node_tests/message_events.js b/frontend_tests/node_tests/message_events.js index 3d09edd0f0..5b424ee62c 100644 --- a/frontend_tests/node_tests/message_events.js +++ b/frontend_tests/node_tests/message_events.js @@ -27,7 +27,7 @@ people.add(alice); function test_helper(side_effects) { const events = []; - _.each(side_effects, (side_effect) => { + for (const side_effect of side_effects) { const parts = side_effect.split('.'); const module = parts[0]; const field = parts[1]; @@ -35,7 +35,7 @@ function test_helper(side_effects) { global[module][field] = () => { events.push(side_effect); }; - }); + } const self = {}; diff --git a/frontend_tests/node_tests/message_list_data.js b/frontend_tests/node_tests/message_list_data.js index e2bb5c8b87..5c8663c0a8 100644 --- a/frontend_tests/node_tests/message_list_data.js +++ b/frontend_tests/node_tests/message_list_data.js @@ -93,9 +93,9 @@ run_test('basics', () => { }); assert_contents(mld, [120, 130, 140, 145]); - _.each(mld.all_messages(), (msg) => { + for (const msg of mld.all_messages()) { msg.unread = false; - }); + } assert.equal(mld.first_unread_message_id(), 145); }); diff --git a/frontend_tests/node_tests/message_list_view.js b/frontend_tests/node_tests/message_list_view.js index 4906f4dda6..77c2ea44c0 100644 --- a/frontend_tests/node_tests/message_list_view.js +++ b/frontend_tests/node_tests/message_list_view.js @@ -110,10 +110,10 @@ run_test('msg_edited_vars', () => { const message_group = build_message_group(messages); const list = build_list([message_group]); - _.each(messages, function (message_container) { + for (const message_container of messages) { list._maybe_format_me_message(message_container); list._add_msg_edited_vars(message_container); - }); + } const result = list._message_groups[0].message_containers; @@ -564,11 +564,11 @@ run_test('render_windows', () => { // the list where we can move the pointer without forcing // a re-render. The code avoids hasty re-renders for // performance reasons. - _.each(_.range(start, end), function (idx) { + for (const idx of _.range(start, end)) { list.selected_idx = function () { return idx; }; const rendered = view.maybe_rerender(); assert.equal(rendered, false); - }); + } } function verify_move(idx, range) { diff --git a/frontend_tests/node_tests/narrow_local.js b/frontend_tests/node_tests/narrow_local.js index 66dd587751..ff9c976b36 100644 --- a/frontend_tests/node_tests/narrow_local.js +++ b/frontend_tests/node_tests/narrow_local.js @@ -20,11 +20,11 @@ function test_with(fixture) { // invarariant that the first unread message we find // does indeed satisfy our filter. if (fixture.unread_info.flavor === 'found') { - _.each(fixture.all_messages, (msg) => { + for (const msg of fixture.all_messages) { if (msg.id === fixture.unread_info.msg_id) { assert(filter.predicate()(msg)); } - }); + } } const muting_enabled = narrow_state.muting_enabled(); diff --git a/frontend_tests/node_tests/people.js b/frontend_tests/node_tests/people.js index 4588eb0695..e6b67e22f4 100644 --- a/frontend_tests/node_tests/people.js +++ b/frontend_tests/node_tests/people.js @@ -690,14 +690,14 @@ run_test('get_people_for_search_bar', () => { typeahead_helper.compare_by_pms = () => 0; message_store.user_ids = () => []; - _.each(_.range(20), (i) => { + for (const i of _.range(20)) { const person = { email: 'whatever@email.com', full_name: 'James Jones', user_id: 1000 + i, }; people.add_in_realm(person); - }); + } const big_results = people.get_people_for_search_bar('James'); diff --git a/frontend_tests/node_tests/search_suggestion.js b/frontend_tests/node_tests/search_suggestion.js index cb4a0ed654..165ef02e94 100644 --- a/frontend_tests/node_tests/search_suggestion.js +++ b/frontend_tests/node_tests/search_suggestion.js @@ -846,12 +846,12 @@ run_test('topic_suggestions', () => { topic_name: 'REXX', }); - _.each(['team', 'ignore', 'test'], function (topic_name) { + for (const topic_name of ['team', 'ignore', 'test']) { topic_data.add_message({ stream_id: office_id, topic_name: topic_name, }); - }); + } suggestions = get_suggestions('', 'te'); expected = [ diff --git a/frontend_tests/node_tests/search_suggestion_legacy.js b/frontend_tests/node_tests/search_suggestion_legacy.js index d0e0b1ec9c..d4d4520c69 100644 --- a/frontend_tests/node_tests/search_suggestion_legacy.js +++ b/frontend_tests/node_tests/search_suggestion_legacy.js @@ -815,12 +815,12 @@ run_test('topic_suggestions', () => { topic_name: 'REXX', }); - _.each(['team', 'ignore', 'test'], function (topic_name) { + for (const topic_name of ['team', 'ignore', 'test']) { topic_data.add_message({ stream_id: office_id, topic_name: topic_name, }); - }); + } suggestions = search.get_suggestions_legacy('te'); expected = [ diff --git a/frontend_tests/node_tests/settings_org.js b/frontend_tests/node_tests/settings_org.js index 0b916a73e0..551692cb66 100644 --- a/frontend_tests/node_tests/settings_org.js +++ b/frontend_tests/node_tests/settings_org.js @@ -8,9 +8,9 @@ let form_data; const _jQuery = { each: function (lst, f) { - _.each(lst, function (v, k) { + for (const [k, v] of lst.entries()) { f(k, v); - }); + } }, }; diff --git a/frontend_tests/node_tests/settings_user_groups.js b/frontend_tests/node_tests/settings_user_groups.js index 7fa69113b8..d07bc4df57 100644 --- a/frontend_tests/node_tests/settings_user_groups.js +++ b/frontend_tests/node_tests/settings_user_groups.js @@ -641,11 +641,12 @@ run_test('on_events', () => { }; // Any of the blur_exceptions trigger blur event. - _.each(blur_event_classes, function (class_name) { + for (const class_name of blur_event_classes) { const handler = $(user_group_selector).get_on_handler("blur", class_name); const blur_exceptions = _.without([".pill-container", ".name", ".description", ".input", ".delete"], class_name); - _.each(blur_exceptions, function (blur_exception) { + + for (const blur_exception of blur_exceptions) { api_endpoint_called = false; fake_this.closest = function (class_name) { if (class_name === blur_exception || class_name === user_group_selector) { @@ -655,7 +656,7 @@ run_test('on_events', () => { }; handler.call(fake_this, event); assert(!api_endpoint_called); - }); + } api_endpoint_called = false; fake_this.closest = function (class_name) { @@ -682,8 +683,7 @@ run_test('on_events', () => { handler.call(fake_this, event); assert(!api_endpoint_called); assert(settings_user_groups_reload_called); - }); - + } }()); (function test_update_cancel_button() { diff --git a/frontend_tests/node_tests/stream_data.js b/frontend_tests/node_tests/stream_data.js index 0ec9c1bda9..b80d5eaad5 100644 --- a/frontend_tests/node_tests/stream_data.js +++ b/frontend_tests/node_tests/stream_data.js @@ -883,12 +883,12 @@ run_test('is_subscriber_subset', () => { [bogus, bogus, false], ]; - _.each(matrix, (row) => { + for (const row of matrix) { assert.equal( stream_data.is_subscriber_subset(row[0], row[1]), row[2] ); - }); + } }); run_test('invite_streams', () => { diff --git a/frontend_tests/node_tests/subs.js b/frontend_tests/node_tests/subs.js index c7588255a9..43ee2a5be1 100644 --- a/frontend_tests/node_tests/subs.js +++ b/frontend_tests/node_tests/subs.js @@ -65,9 +65,9 @@ run_test('filter_table', () => { }, ]; - _.each(sub_row_data, function (sub) { + for (const sub of sub_row_data) { stream_data.add_sub(sub.name, sub); - }); + } let populated_subs; @@ -79,7 +79,8 @@ run_test('filter_table', () => { subs.populate_stream_settings_left_panel(); const sub_stubs = []; - _.each(populated_subs, function (data) { + + for (const data of populated_subs) { const sub_row = ".stream-row-" + data.elem; sub_stubs.push(sub_row); @@ -88,7 +89,7 @@ run_test('filter_table', () => { $(sub_row).detach = function () { return sub_row; }; - }); + } let tooltip_called = false; $(".tooltip").tooltip = function (obj) { diff --git a/frontend_tests/node_tests/templates.js b/frontend_tests/node_tests/templates.js index 4d99cefd36..93e11bb8b8 100644 --- a/frontend_tests/node_tests/templates.js +++ b/frontend_tests/node_tests/templates.js @@ -119,26 +119,29 @@ run_test('admin_default_streams_list', () => { const streams = ['devel', 'trac', 'zulip']; // When the logged in user is admin - _.each(streams, function (stream) { + for (const stream of streams) { const args = { stream: {name: stream, invite_only: false}, can_modify: true, }; html += render('admin_default_streams_list', args); - }); + } + html += ""; let span = $(html).find(".default_stream_name").first(); assert.equal(span.text(), "devel"); // When the logged in user is not admin html = ''; - _.each(streams, function (stream) { + + for (const stream of streams) { const args = { stream: {name: stream, invite_only: false}, can_modify: false, }; html += render('admin_default_streams_list', args); - }); + } + html += "
"; span = $(html).find(".default_stream_name").first(); assert.equal(span.text(), "devel"); @@ -259,7 +262,8 @@ run_test('admin_invites_list', () => { let html = ''; const invites = ['alice', 'bob', 'carl']; let invite_id = 0; - _.each(invites, function (invite) { + + for (const invite of invites) { const args = { invite: { email: invite + '@zulip.com', @@ -271,7 +275,8 @@ run_test('admin_invites_list', () => { }; html += render('admin_invites_list', args); invite_id += 1; - }); + } + html += "
"; const buttons = $(html).find('.button'); @@ -294,9 +299,11 @@ run_test('admin_tab', () => { const html = render('admin_tab', args); const admin_features = ["admin_users_table", "admin_bots_table", "admin_deactivated_users_table", "admin_invites_table"]; - _.each(admin_features, function (admin_feature) { + + for (const admin_feature of admin_features) { assert.notEqual($(html).find("#" + admin_feature).length, 0); - }); + } + assert.equal($(html).find("input.admin-realm-name").val(), 'Zulip'); }); @@ -330,7 +337,7 @@ run_test('admin_user_list', () => { const users = ['alice', 'bob', 'carl']; // When the logged in user is admin - _.each(users, function (user) { + for (const user of users) { const args = { user: { is_active: true, @@ -341,7 +348,8 @@ run_test('admin_user_list', () => { can_modify: true, }; html += render('admin_user_list', args); - }); + } + html += ""; let buttons = $(html).find('.button'); @@ -354,7 +362,8 @@ run_test('admin_user_list', () => { // When the logged in user is not admin html = ''; - _.each(users, function (user) { + + for (const user of users) { const args = { user: { is_active: true, @@ -365,7 +374,8 @@ run_test('admin_user_list', () => { can_modify: false, }; html += render('admin_user_list', args); - }); + } + html += "
"; buttons = $(html).find('.button'); @@ -377,12 +387,14 @@ run_test('alert_word_settings_item', () => { let html = '
    '; const words = ['lunch', 'support']; let args; - _.each(words, function (word) { + + for (const word of words) { args = { word: word, }; html += render('alert_word_settings_item', args); - }); + } + args = { word: '', editing: true, @@ -410,7 +422,6 @@ run_test('alert_word_settings_item', () => { assert.equal(textbox.attr('class'), 'required'); assert.equal(button.length, 1); assert.equal(button.text().trim(), 'translated: Add alert word'); - }); run_test('all_messages_sidebar_actions', () => { @@ -1140,9 +1151,9 @@ run_test('settings_tab', () => { }); // All checkboxes should be checked. - _.each(checkbox_ids, function (checkbox) { + for (const checkbox of checkbox_ids) { assert.equal($(html).find("#" + checkbox).is(":checked"), true); - }); + } // Re-render with checkbox booleans set to false. for (const option of Object.keys(page_param_checkbox_options)) { @@ -1152,9 +1163,9 @@ run_test('settings_tab', () => { html = render('settings_tab', {page_params: page_params}); // All checkboxes should be unchecked. - _.each(checkbox_ids, function (checkbox) { + for (const checkbox of checkbox_ids) { assert.equal($(html).find("#" + checkbox).is(":checked"), false); - }); + } // Check if enable_desktop_notifications setting disables subsetting too. const parent_elem = $('#pm_content_in_desktop_notifications_label').wrap("
    "); @@ -1170,7 +1181,6 @@ run_test('settings_tab', () => { assert(!parent_elem.hasClass('control-label-disabled')); assert.equal($('#pm_content_in_desktop_notifications').attr('disabled'), undefined); }); - }); run_test('stream_member_list_entry', () => { @@ -1180,23 +1190,27 @@ run_test('stream_member_list_entry', () => { // First, as non-admin. let html = render('stream_member_list_entry', {name: "King Hamlet", email: "hamlet@zulip.com"}); - _.each(everyone_items, function (item) { + + for (const item of everyone_items) { assert.equal($(html).find("." + item).length, 1); - }); - _.each(admin_items, function (item) { + } + + for (const item of admin_items) { assert.equal($(html).find("." + item).length, 0); - }); + } // Now, as admin. html = render('stream_member_list_entry', {name: "King Hamlet", email: "hamlet@zulip.com", displaying_for_admin: true}); - _.each(everyone_items, function (item) { + + for (const item of everyone_items) { assert.equal($(html).find("." + item).length, 1); - }); - _.each(admin_items, function (item) { + } + + for (const item of admin_items) { assert.equal($(html).find("." + item).length, 1); - }); + } }); run_test('stream_sidebar_actions', () => { diff --git a/frontend_tests/node_tests/topic_data.js b/frontend_tests/node_tests/topic_data.js index cc83c70958..7ea55419d7 100644 --- a/frontend_tests/node_tests/topic_data.js +++ b/frontend_tests/node_tests/topic_data.js @@ -218,11 +218,11 @@ run_test('test_unread_logic', () => { { id: 20, topic: 'UNREAD2' }, ]; - _.each(msgs, (msg) => { + for (const msg of msgs) { msg.type = 'stream'; msg.stream_id = stream_id; msg.unread = true; - }); + } unread.process_loaded_messages(msgs); diff --git a/frontend_tests/node_tests/topic_list_data.js b/frontend_tests/node_tests/topic_list_data.js index abe26e0bac..e4e44ac4ae 100644 --- a/frontend_tests/node_tests/topic_list_data.js +++ b/frontend_tests/node_tests/topic_list_data.js @@ -41,14 +41,14 @@ run_test('get_list_info w/real topic_data', () => { num_possible_topics: 0, }); - _.each(_.range(7), (i) => { + for (const i of _.range(7)) { const topic_name = 'topic ' + i; topic_data.add_message({ stream_id: general.stream_id, topic_name: topic_name, message_id: 1000 + i, }); - }); + } narrow_state.topic = () => 'topic 6'; diff --git a/frontend_tests/node_tests/typeahead_helper.js b/frontend_tests/node_tests/typeahead_helper.js index ac4dd45271..c4b8a7f593 100644 --- a/frontend_tests/node_tests/typeahead_helper.js +++ b/frontend_tests/node_tests/typeahead_helper.js @@ -198,9 +198,9 @@ const matches = [ zman, ]; -_.each(matches, function (person) { +for (const person of matches) { global.people.add_in_realm(person); -}); +} function get_typeahead_result(query, current_stream, current_topic) { const result = th.sort_recipients( diff --git a/frontend_tests/node_tests/ui_init.js b/frontend_tests/node_tests/ui_init.js index dc3811f262..5189bfbc6c 100644 --- a/frontend_tests/node_tests/ui_init.js +++ b/frontend_tests/node_tests/ui_init.js @@ -60,11 +60,11 @@ const ignore_modules = [ 'unread_ui', ]; -_.each(ignore_modules, (mod) => { +for (const mod of ignore_modules) { set_global(mod, { initialize: () => {}, }); -}); +} emoji.emojis_by_name = new Map(); diff --git a/frontend_tests/zjsunit/bugdown_assert.js b/frontend_tests/zjsunit/bugdown_assert.js index f9342f1a51..c303049d55 100644 --- a/frontend_tests/zjsunit/bugdown_assert.js +++ b/frontend_tests/zjsunit/bugdown_assert.js @@ -69,9 +69,10 @@ class MarkdownComparer { // Sorts every attribute in every element by name. Ensures consistent diff HTML output const attributeList = []; - _.forEach(node.attributes, (attr) => { + + for (const attr of node.attributes) { attributeList.push(attr); - }); + } // If put in above forEach loop, causes issues (possible nodes.attribute invalidation?) attributeList.forEach((attr) => {node.removeAttribute(attr.name);}); @@ -93,14 +94,14 @@ class MarkdownComparer { }); if (node.hasChildNodes()) { - _.forEach(node.children, (childNode) => { + for (const childNode of node.children) { this._reorderAttributes(childNode); - }); + } } if (node.content && node.content.hasChildNodes()) { - _.forEach(node.content.children, (childNode) => { + for (const childNode of node.content.children) { this._reorderAttributes(childNode); - }); + } } return node; } diff --git a/frontend_tests/zjsunit/i18n.js b/frontend_tests/zjsunit/i18n.js index 91cb8b2488..f90879a29d 100644 --- a/frontend_tests/zjsunit/i18n.js +++ b/frontend_tests/zjsunit/i18n.js @@ -30,9 +30,11 @@ exports.t = function (str, context) { suffix: key.slice(key.length - 2, key.length), }; }); - _.each(substitutions, function (item) { + + for (const item of substitutions) { str = str.replace(item.prefix + item.keyword + item.suffix, context[item.keyword]); - }); + } + return 'translated: ' + str; }; diff --git a/frontend_tests/zjsunit/namespace.js b/frontend_tests/zjsunit/namespace.js index 530fea842c..37dc59b0c2 100644 --- a/frontend_tests/zjsunit/namespace.js +++ b/frontend_tests/zjsunit/namespace.js @@ -80,7 +80,7 @@ exports.with_overrides = function (test_function) { test_function(override); - _.each(clobber_callbacks, function (f) { + for (const f of clobber_callbacks) { f(); - }); + } }; diff --git a/frontend_tests/zjsunit/stub.js b/frontend_tests/zjsunit/stub.js index 4ed6e34cd6..8ff449c895 100644 --- a/frontend_tests/zjsunit/stub.js +++ b/frontend_tests/zjsunit/stub.js @@ -1,5 +1,3 @@ -const _ = require('underscore/underscore.js'); - // Stubs don't do any magical modifications to your namespace. They // just provide you a function that records what arguments get passed // to it. To use stubs as something more like "spies," use something @@ -18,9 +16,9 @@ exports.make_stub = function () { self.get_args = function (...param_names) { const result = {}; - _.each(param_names, function (name, i) { + for (const [i, name] of param_names.entries()) { result[name] = self.last_call_args[i]; - }); + } return result; }; diff --git a/static/js/activity.js b/static/js/activity.js index 8de1b436b7..c690fcfcd8 100644 --- a/static/js/activity.js +++ b/static/js/activity.js @@ -99,7 +99,7 @@ exports.update_dom_with_unread_counts = function (counts) { exports.process_loaded_messages = function (messages) { let need_resize = false; - _.each(messages, function (message) { + for (const message of messages) { const huddle_string = people.huddle_string(message); if (huddle_string) { @@ -110,7 +110,7 @@ exports.process_loaded_messages = function (messages) { need_resize = true; } } - }); + } exports.update_huddles(); @@ -259,10 +259,10 @@ exports.update_huddles = function () { const html = render_group_pms({group_pms: group_pms}); ui.get_content_element($('#group-pms')).html(html); - _.each(huddles, function (user_ids_string) { + for (const user_ids_string of huddles) { const count = unread.num_unread_for_person(user_ids_string); set_group_count(user_ids_string, count); - }); + } show_huddles(); }; diff --git a/static/js/alert_words.js b/static/js/alert_words.js index eb2b96ce22..a94090b5f5 100644 --- a/static/js/alert_words.js +++ b/static/js/alert_words.js @@ -19,7 +19,7 @@ exports.process_message = function (message) { return; } - _.each(exports.words, function (word) { + for (const word of exports.words) { const clean = escape_user_regex(word); const before_punctuation = '\\s|^|>|[\\(\\".,\';\\[]'; const after_punctuation = '\\s|$|<|[\\)\\"\\?!:.,\';\\]!]'; @@ -44,7 +44,7 @@ exports.process_message = function (message) { } return before + "" + word + "" + after; }); - }); + } }; exports.notifies = function (message) { diff --git a/static/js/alert_words_ui.js b/static/js/alert_words_ui.js index f9b6ae9343..c74fca822a 100644 --- a/static/js/alert_words_ui.js +++ b/static/js/alert_words_ui.js @@ -5,13 +5,15 @@ exports.render_alert_words_ui = function () { const word_list = $('#alert_words_list'); word_list.find('.alert-word-item').remove(); - _.each(words, function (alert_word) { + + for (const alert_word of words) { const rendered_alert_word = render_alert_word_settings_item({ word: alert_word, editing: false, }); word_list.append(rendered_alert_word); - }); + } + const new_alert_word_form = render_alert_word_settings_item({ word: '', editing: true, diff --git a/static/js/attachments_ui.js b/static/js/attachments_ui.js index 09c95cb9ab..a87ca4f672 100644 --- a/static/js/attachments_ui.js +++ b/static/js/attachments_ui.js @@ -100,11 +100,11 @@ function render_attachments_ui() { } function format_attachment_data(new_attachments) { - _.each(new_attachments, function (attachment) { + for (const attachment of new_attachments) { const time = new XDate(attachment.create_time); attachment.create_time_str = timerender.render_now(time).time_str; attachment.size_str = exports.bytes_to_size(attachment.size); - }); + } } exports.update_attachments = function (event) { diff --git a/static/js/bot_data.js b/static/js/bot_data.js index 58d76b00a1..71f6a84cb9 100644 --- a/static/js/bot_data.js +++ b/static/js/bot_data.js @@ -83,9 +83,10 @@ exports.get_services = function bot_data__get_services(bot_id) { }; exports.initialize = function () { - _.each(page_params.realm_bots, function (bot) { + for (const bot of page_params.realm_bots) { exports.add(bot); - }); + } + delete page_params.realm_bots; }; diff --git a/static/js/buddy_data.js b/static/js/buddy_data.js index c734fb84c1..5daf225ca0 100644 --- a/static/js/buddy_data.js +++ b/static/js/buddy_data.js @@ -339,11 +339,12 @@ exports.huddle_fraction_present = function (huddle) { const user_ids = huddle.split(',').map(s => parseInt(s, 10)); let num_present = 0; - _.each(user_ids, function (user_id) { + + for (const user_id of user_ids) { if (presence.is_active(user_id)) { num_present += 1; } - }); + } if (num_present === user_ids.length) { return 1; diff --git a/static/js/buddy_list.js b/static/js/buddy_list.js index 033955735e..a11055af1b 100644 --- a/static/js/buddy_list.js +++ b/static/js/buddy_list.js @@ -72,9 +72,9 @@ function buddy_list_create() { 'height_to_fill', ]; - _.each(func_names, function (func_name) { + for (const func_name of func_names) { self[func_name] = conf[func_name]; - }); + } self.keys = []; diff --git a/static/js/common.js b/static/js/common.js index bfec346810..b655213454 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -122,11 +122,13 @@ exports.adjust_mac_shortcuts = function (key_elem_class, require_cmd_style) { if (key_text.indexOf('Ctrl') > -1 && require_cmd_style) { $(this).addClass("mac-cmd-key"); } - _.each(keys, function (key) { + + for (const key of keys) { if (keys_map.get(key)) { key_text = key_text.replace(key, keys_map.get(key)); } - }); + } + $(this).text(key_text); }); }; diff --git a/static/js/compose_fade.js b/static/js/compose_fade.js index 86d3222a0a..e9134e3cb9 100644 --- a/static/js/compose_fade.js +++ b/static/js/compose_fade.js @@ -134,15 +134,15 @@ function update_user_row_when_fading(li, conf) { } function display_users_normally(items, conf) { - _.each(items, function (li) { + for (const li of items) { conf.unfade(li); - }); + } } function fade_users(items, conf) { - _.each(items, function (li) { + for (const li of items) { update_user_row_when_fading(li, conf); - }); + } } function want_normal_display() { @@ -232,12 +232,12 @@ exports.update_rendered_message_groups = function (message_groups, get_element) // This loop is superficially similar to some code in fade_messages, but an // important difference here is that we look at each message individually, whereas // the other code takes advantage of blocks beneath recipient bars. - _.each(message_groups, function (message_group) { + for (const message_group of message_groups) { const elt = get_element(message_group); const first_message = message_group.message_containers[0].msg; const should_fade = exports.should_fade_message(first_message); change_fade_state(elt, should_fade); - }); + } }; exports.initialize = function () { diff --git a/static/js/composebox_typeahead.js b/static/js/composebox_typeahead.js index 2ecaff1b1a..e3a6220871 100644 --- a/static/js/composebox_typeahead.js +++ b/static/js/composebox_typeahead.js @@ -28,12 +28,12 @@ exports.update_emoji_data = function () { is_realm_emoji: true, }); } else { - _.each(emoji_dict.aliases, function (alias) { + for (const alias of emoji_dict.aliases) { exports.emoji_collection.push({ emoji_name: alias, emoji_code: emoji_dict.emoji_code, }); - }); + } } } }; diff --git a/static/js/condense.js b/static/js/condense.js index ba4d106e55..cb84bdb96a 100644 --- a/static/js/condense.js +++ b/static/js/condense.js @@ -177,7 +177,7 @@ exports.show_message_expander = function (row) { exports.condense_and_collapse = function (elems) { const height_cutoff = message_viewport.height() * 0.65; - _.each(elems, function (elem) { + for (const elem of elems) { const content = $(elem).find(".message_content"); const message = current_msg_list.get(rows.id($(elem))); if (content !== undefined && message !== undefined) { @@ -194,10 +194,10 @@ exports.condense_and_collapse = function (elems) { // specified whether this message should be expanded or condensed. if (message.condensed === true) { condense_row($(elem)); - return; + continue; } else if (message.condensed === false) { uncondense_row($(elem)); - return; + continue; } else if (long_message) { // By default, condense a long message. condense_row($(elem)); @@ -213,7 +213,7 @@ exports.condense_and_collapse = function (elems) { $(elem).find(".message_expander").show(); } } - }); + } }; exports.initialize = function () { diff --git a/static/js/confirm_dialog.js b/static/js/confirm_dialog.js index d76095f2d3..ef6684d9da 100644 --- a/static/js/confirm_dialog.js +++ b/static/js/confirm_dialog.js @@ -40,11 +40,11 @@ exports.launch = function (conf) { 'parent', ]; - _.each(conf_fields, function (f) { + for (const f of conf_fields) { if (!conf[f]) { blueslip.error('programmer omitted ' + f); } - }); + } conf.parent.append(confirm_dialog); diff --git a/static/js/copy_and_paste.js b/static/js/copy_and_paste.js index ed1ea90431..c2562e0584 100644 --- a/static/js/copy_and_paste.js +++ b/static/js/copy_and_paste.js @@ -109,9 +109,11 @@ function remove_div(div, ranges, selection) { window.setTimeout(function () { selection = window.getSelection(); selection.removeAllRanges(); - _.each(ranges, function (range) { + + for (const range of ranges) { selection.addRange(range); - }); + } + $('#copytempdiv').remove(); }, 0); } diff --git a/static/js/echo.js b/static/js/echo.js index b67fd52374..f73645091f 100644 --- a/static/js/echo.js +++ b/static/js/echo.js @@ -257,7 +257,7 @@ exports.process_from_server = function process_from_server(messages) { const msgs_to_rerender = []; const non_echo_messages = []; - _.each(messages, function (message) { + for (const message of messages) { // In case we get the sent message before we get the send ACK, reify here const client_message = waiting_for_ack[message.local_id]; @@ -266,7 +266,7 @@ exports.process_from_server = function process_from_server(messages) { // the "main" codepath that doesn't have to id reconciliation. // We simply return non-echo messages to our caller. non_echo_messages.push(message); - return; + continue; } exports.reify_message_id(message.local_id, message.id); @@ -297,7 +297,7 @@ exports.process_from_server = function process_from_server(messages) { msgs_to_rerender.push(client_message); delete waiting_for_ack[client_message.id]; - }); + } if (msgs_to_rerender.length > 0) { // In theory, we could just rerender messages where there were @@ -326,9 +326,9 @@ exports.message_send_error = function message_send_error(local_id, error_respons function abort_message(message) { // Remove in all lists in which it exists - _.each([message_list.all, home_msg_list, current_msg_list], function (msg_list) { + for (const msg_list of [message_list.all, home_msg_list, current_msg_list]) { msg_list.remove_and_rerender([message]); - }); + } } exports.initialize = function () { diff --git a/static/js/emoji.js b/static/js/emoji.js index 5f0806457a..cbe0d05c5f 100644 --- a/static/js/emoji.js +++ b/static/js/emoji.js @@ -45,8 +45,7 @@ exports.update_emojis = function update_emojis(realm_emojis) { }; exports.initialize = function initialize() { - - _.each(emoji_codes.names, function (value) { + for (const value of emoji_codes.names) { const base_name = emoji_codes.name_to_codepoint[value]; if (exports.default_emoji_aliases.has(base_name)) { @@ -54,7 +53,7 @@ exports.initialize = function initialize() { } else { exports.default_emoji_aliases.set(base_name, [value]); } - }); + } exports.update_emojis(page_params.realm_emoji); diff --git a/static/js/emoji_picker.js b/static/js/emoji_picker.js index e06f0c87e3..9a11c41e66 100644 --- a/static/js/emoji_picker.js +++ b/static/js/emoji_picker.js @@ -108,7 +108,8 @@ exports.generate_emoji_picker_data = function (realm_emojis) { for (const [category, codepoints] of Object.entries(emoji_codes.emoji_catalog)) { exports.complete_emoji_catalog[category] = []; - _.each(codepoints, function (codepoint) { + + for (const codepoint of codepoints) { if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) { const emoji_dict = emoji.emojis_by_name.get( emoji_codes.codepoint_to_name[codepoint] @@ -117,18 +118,19 @@ exports.generate_emoji_picker_data = function (realm_emojis) { exports.complete_emoji_catalog[category].push(emoji_dict); } } - }); + } } exports.complete_emoji_catalog.Popular = []; - _.each(typeahead.popular_emojis, function (codepoint) { + + for (const codepoint of typeahead.popular_emojis) { if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) { const emoji_dict = emoji.emojis_by_name.get(emoji_codes.codepoint_to_name[codepoint]); if (emoji_dict !== undefined) { exports.complete_emoji_catalog.Popular.push(emoji_dict); } } - }); + } const categories = get_all_emoji_categories().filter(function (category) { return !!exports.complete_emoji_catalog[category.name]; @@ -206,12 +208,14 @@ function filter_emojis() { const categories = exports.complete_emoji_catalog; const search_terms = query.split(" "); search_results.length = 0; - _.each(categories, function (category) { + + for (const category of categories) { if (category.name === "Popular") { - return; + continue; } const emojis = category.emojis; - _.each(emojis, function (emoji_dict) { + + for (const emoji_dict of emojis) { _.any(emoji_dict.aliases, function (alias) { const match = _.every(search_terms, function (search_term) { return alias.indexOf(search_term) >= 0; @@ -221,8 +225,9 @@ function filter_emojis() { return true; } }); - }); - }); + } + } + const rendered_search_results = render_emoji_popover_search_results({ search_results: search_results, message_id: message_id, diff --git a/static/js/fenced_code.js b/static/js/fenced_code.js index 415e45f94f..959cb07205 100644 --- a/static/js/fenced_code.js +++ b/static/js/fenced_code.js @@ -37,14 +37,16 @@ function wrap_code(code) { function wrap_quote(text) { const paragraphs = text.split('\n\n'); const quoted_paragraphs = []; + // Prefix each quoted paragraph with > at the // beginning of each line - _.each(paragraphs, function (paragraph) { + for (const paragraph of paragraphs) { const lines = paragraph.split('\n'); quoted_paragraphs.push(_.map( _.reject(lines, function (line) { return line === ''; }), function (line) { return '> ' + line; }).join('\n')); - }); + } + return quoted_paragraphs.join('\n\n'); } @@ -166,10 +168,10 @@ exports.process_fenced_code = function (content) { const current_handler = default_hander(); handler_stack.push(current_handler); - _.each(input, function (line) { + for (const line of input) { const handler = handler_stack[handler_stack.length - 1]; handler.handle_line(line); - }); + } // Clean up all trailing blocks by letting them // insert closing fences diff --git a/static/js/filter.js b/static/js/filter.js index e52f52fa2b..2822c2dec7 100644 --- a/static/js/filter.js +++ b/static/js/filter.js @@ -260,7 +260,8 @@ Filter.parse = function (str) { if (matches === null) { return operators; } - _.each(matches, function (token) { + + for (const token of matches) { let operator; const parts = token.split(':'); if (token[0] === '"' || parts.length === 1) { @@ -283,12 +284,13 @@ Filter.parse = function (str) { if (Filter.operator_to_prefix(operator, negated) === '') { // Put it as a search term, to not have duplicate operators search_term.push(token); - return; + continue; } term = {negated: negated, operator: operator, operand: operand}; operators.push(term); } - }); + } + // NB: Callers of 'parse' can assume that the 'search' operator is last. if (search_term.length > 0) { operator = 'search'; @@ -543,7 +545,7 @@ Filter.prototype = { }, update_email: function (user_id, new_email) { - _.each(this._operators, function (term) { + for (const term of this._operators) { switch (term.operator) { case 'group-pm-with': case 'pm-with': @@ -555,7 +557,7 @@ Filter.prototype = { new_email ); } - }); + } }, // Build a filter function from a list of operators. diff --git a/static/js/floating_recipient_bar.js b/static/js/floating_recipient_bar.js index 5ded60910b..593b5fb139 100644 --- a/static/js/floating_recipient_bar.js +++ b/static/js/floating_recipient_bar.js @@ -209,11 +209,11 @@ exports.relevant_recipient_bars = function () { items[i].show_date = items[i].date_text !== items[i - 1].date_text; } - _.each(items, function (item) { + for (const item of items) { if (!item.need_frb) { delete item.date_html; } - }); + } return items; }; @@ -303,9 +303,9 @@ exports.hide = function () { }; exports.de_clutter_dates = function (items) { - _.each(items, function (item) { + for (const item of items) { item.elem.find('.recipient_row_date').toggle(item.show_date); - }); + } }; exports.update = function () { diff --git a/static/js/hash_util.js b/static/js/hash_util.js index 32e24d7993..3a82400170 100644 --- a/static/js/hash_util.js +++ b/static/js/hash_util.js @@ -93,7 +93,8 @@ exports.operators_to_hash = function (operators) { if (operators !== undefined) { hash = '#narrow'; - _.each(operators, function (elem) { + + for (const elem of operators) { // Support legacy tuples. const operator = elem.operator; const operand = elem.operand; @@ -101,7 +102,7 @@ exports.operators_to_hash = function (operators) { const sign = elem.negated ? '-' : ''; hash += '/' + sign + exports.encodeHashComponent(operator) + '/' + exports.encode_operand(operator, operand); - }); + } } return hash; diff --git a/static/js/hotspots.js b/static/js/hotspots.js index 6e3f27a53b..3af202a8d6 100644 --- a/static/js/hotspots.js +++ b/static/js/hotspots.js @@ -236,9 +236,10 @@ exports.close_hotspot_icon = function (elem) { function close_read_hotspots(new_hotspots) { const unwanted_hotspots = _.difference(_.keys(HOTSPOT_LOCATIONS), _.pluck(new_hotspots, 'name')); - _.each(unwanted_hotspots, function (hotspot_name) { + + for (const hotspot_name of unwanted_hotspots) { exports.close_hotspot_icon($('#hotspot_' + hotspot_name + '_icon')); - }); + } } exports.load_new = function (new_hotspots) { diff --git a/static/js/info_overlay.js b/static/js/info_overlay.js index 515cd441b2..c14ae469ac 100644 --- a/static/js/info_overlay.js +++ b/static/js/info_overlay.js @@ -28,7 +28,7 @@ exports.set_up_toggler = function () { return modal; }); - _.each(modals, function (modal) { + for (const modal of modals) { keydown_util.handle({ elem: modal, handlers: { @@ -36,7 +36,7 @@ exports.set_up_toggler = function () { right_arrow: exports.toggler.maybe_go_right, }, }); - }); + } $(".informational-overlays .overlay-tabs").append(elem); diff --git a/static/js/markdown.js b/static/js/markdown.js index 02232cb09e..d2052ba560 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -135,7 +135,8 @@ exports.add_topic_links = function (message) { } const topic = util.get_message_topic(message); let links = []; - _.each(realm_filter_list, function (realm_filter) { + + for (const realm_filter of realm_filter_list) { const pattern = realm_filter[0]; const url = realm_filter[1]; let match; @@ -152,7 +153,7 @@ exports.add_topic_links = function (message) { } links.push(link_url); } - }); + } // Also make raw urls navigable const url_re = /\b(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/g; // Slightly modified from third/marked.js @@ -233,11 +234,12 @@ function handleRealmFilter(pattern, matches) { let url = realm_filter_map[pattern]; let current_group = 1; - _.each(matches, function (match) { + + for (const match of matches) { const back_ref = "\\" + current_group; url = url.replace(back_ref, match); current_group += 1; - }); + } return url; } @@ -281,11 +283,13 @@ function python_to_js_filter(pattern, url) { // flags, so keep those and ignore the rest if (match) { const py_flags = match[1].split(""); - _.each(py_flags, function (flag) { + + for (const flag of py_flags) { if ("im".indexOf(flag) !== -1) { js_flags += flag; } - }); + } + pattern = pattern.replace(inline_flag_re, ""); } // Ideally we should have been checking that realm filters @@ -315,19 +319,20 @@ exports.set_realm_filters = function (realm_filters) { realm_filter_list = []; const marked_rules = []; - _.each(realm_filters, function (realm_filter) { + + for (const realm_filter of realm_filters) { const pattern = realm_filter[0]; const url = realm_filter[1]; const js_filters = python_to_js_filter(pattern, url); if (!js_filters[0]) { // Skip any realm filters that could not be converted - return; + continue; } realm_filter_map[js_filters[0]] = js_filters[1]; realm_filter_list.push([js_filters[0], js_filters[1]]); marked_rules.push(js_filters[0]); - }); + } marked.InlineLexer.rules.zulip.realm_filters = marked_rules; }; diff --git a/static/js/message_edit.js b/static/js/message_edit.js index d34454441c..6dc62af32d 100644 --- a/static/js/message_edit.js +++ b/static/js/message_edit.js @@ -648,7 +648,8 @@ exports.show_history = function (message) { success: function (data) { const content_edit_history = []; let prev_timestamp; - _.each(data.message_history, function (msg, index) { + + for (const [index, msg] of data.message_history.entries()) { // Format timestamp nicely for display const timestamp = timerender.get_full_time(msg.timestamp); const item = { @@ -685,7 +686,7 @@ exports.show_history = function (message) { } content_edit_history.push(item); - }); + } $('#message-history').html(render_message_edit_history({ edited_messages: content_edit_history, diff --git a/static/js/message_events.js b/static/js/message_events.js index 53f6cca0b6..68c94bc272 100644 --- a/static/js/message_events.js +++ b/static/js/message_events.js @@ -1,8 +1,9 @@ function maybe_add_narrowed_messages(messages, msg_list) { const ids = []; - _.each(messages, function (elem) { + + for (const elem of messages) { ids.push(elem.id); - }); + } channel.get({ url: '/json/messages/matches_narrow', @@ -17,14 +18,15 @@ function maybe_add_narrowed_messages(messages, msg_list) { let new_messages = []; const elsewhere_messages = []; - _.each(messages, function (elem) { + + for (const elem of messages) { if (data.messages.hasOwnProperty(elem.id)) { util.set_match_data(elem, data.messages[elem.id]); new_messages.push(elem); } else { elsewhere_messages.push(elem); } - }); + } // This second call to add_message_metadata in the // insert_new_messages code path helps in very rare race @@ -105,10 +107,10 @@ exports.update_messages = function update_messages(events) { let changed_compose = false; let message_content_edited = false; - _.each(events, function (event) { + for (const event of events) { const msg = message_store.get(event.message_id); if (msg === undefined) { - return; + continue; } delete msg.local_edit_timestamp; @@ -176,10 +178,10 @@ exports.update_messages = function update_messages(events) { } } - _.each(event.message_ids, function (id) { + for (const id of event.message_ids) { const msg = message_store.get(id); if (msg === undefined) { - return; + continue; } // Remove the recent topics entry for the old topics; @@ -215,7 +217,7 @@ exports.update_messages = function update_messages(events) { current_msg_list.remove_and_rerender([{id: id}]); } } - }); + } } if (event.orig_content !== undefined) { @@ -249,7 +251,7 @@ exports.update_messages = function update_messages(events) { notifications.received_messages([msg]); alert_words.process_message(msg); - }); + } // If a topic was edited, we re-render the whole view to get any // propagated edits to be updated (since the topic edits can have diff --git a/static/js/message_list_data.js b/static/js/message_list_data.js index db0624b990..dc6d0c89bd 100644 --- a/static/js/message_list_data.js +++ b/static/js/message_list_data.js @@ -194,11 +194,11 @@ MessageListData.prototype = { }, update_user_full_name: function (user_id, full_name) { - _.each(this._items, function (item) { + for (const item of this._items) { if (item.sender_id && item.sender_id === user_id) { item.sender_full_name = full_name; } - }); + } }, update_user_avatar: function (user_id, avatar_url) { @@ -206,20 +206,20 @@ MessageListData.prototype = { // We may want to de-dup some logic with update_user_full_name, // especially if we want to optimize this with some kind of // hash that maps sender_id -> messages. - _.each(this._items, function (item) { + for (const item of this._items) { if (item.sender_id && item.sender_id === user_id) { item.small_avatar_url = avatar_url; } - }); + } }, update_stream_name: function (stream_id, new_stream_name) { - _.each(this._items, function (item) { + for (const item of this._items) { if (item.stream_id && item.stream_id === stream_id) { item.display_recipient = new_stream_name; item.stream = new_stream_name; } - }); + } }, add_messages: function (messages) { @@ -240,7 +240,7 @@ MessageListData.prototype = { // that fail our filter predicate messages = self.valid_non_duplicated_messages(messages); - _.each(messages, function (msg) { + for (const msg of messages) { // Put messages in correct order on either side of the // message list. This code path assumes that messages // is a (1) sorted, and (2) consecutive block of @@ -253,7 +253,7 @@ MessageListData.prototype = { } else { interior_messages.push(msg); } - }); + } } if (interior_messages.length > 0) { @@ -330,18 +330,21 @@ MessageListData.prototype = { remove: function (messages) { const self = this; - _.each(messages, function (message) { + + for (const message of messages) { const stored_message = self._hash[message.id]; if (stored_message !== undefined) { delete self._hash[stored_message]; } delete self._local_only[message.id]; - }); + } const msg_ids_to_remove = {}; - _.each(messages, function (message) { + + for (const message of messages) { msg_ids_to_remove[message.id] = true; - }); + } + this._items = _.filter(this._items, function (message) { return !msg_ids_to_remove.hasOwnProperty(message.id); }); @@ -426,15 +429,15 @@ MessageListData.prototype = { potential_closest_matches.unshift(_.last(potential_closest_matches) - 1); let best_match = items[closest].id; - _.each(potential_closest_matches, function (potential_idx) { + for (const potential_idx of potential_closest_matches) { if (potential_idx < 0) { - return; + continue; } const item = items[potential_idx]; if (item === undefined) { blueslip.warn('Invalid potential_idx: ' + potential_idx); - return; + continue; } const potential_match = item.id; @@ -443,7 +446,7 @@ MessageListData.prototype = { best_match = potential_match; closest = potential_idx; } - }); + } } return items[closest].id; }, @@ -457,9 +460,9 @@ MessageListData.prototype = { const id_set = {}; - _.each(msg_ids, function (msg_id) { + for (const msg_id of msg_ids) { id_set[msg_id] = true; - }); + } let idx = this.selected_idx() + 1; while (idx < this._items.length) { diff --git a/static/js/message_list_view.js b/static/js/message_list_view.js index 80fdab2f58..23679dcdea 100644 --- a/static/js/message_list_view.js +++ b/static/js/message_list_view.js @@ -288,7 +288,7 @@ MessageListView.prototype = { } } - _.each(message_containers, function (message_container) { + for (const message_container of message_containers) { const message_reactions = reactions.get_message_reactions(message_container.msg); message_container.msg.message_reactions = message_reactions; message_container.include_recipient = false; @@ -359,7 +359,7 @@ MessageListView.prototype = { self._add_msg_edited_vars(message_container); prev = message_container; - }); + } finish_group(); @@ -513,11 +513,12 @@ MessageListView.prototype = { } const self = this; - _.each($message_rows, function (dom_row) { + + for (const dom_row of $message_rows) { const row = $(dom_row); self._put_row(row); self._post_process_single_row(row); - }); + } }, _post_process_single_row: function (row) { @@ -721,9 +722,9 @@ MessageListView.prototype = { let last_message_row; let last_group_row; - _.each(message_containers, function (message_container) { + for (const message_container of message_containers) { self.message_containers[message_container.msg.id] = message_container; - }); + } // Render new message groups on the top if (message_actions.prepend_groups.length > 0) { @@ -751,7 +752,7 @@ MessageListView.prototype = { if (message_actions.rerender_groups.length > 0) { save_scroll_position(); - _.each(message_actions.rerender_groups, function (message_group) { + for (const message_group of message_actions.rerender_groups) { const old_message_group = $('#' + message_group.message_group_id); // Remove the top date_row, we'll re-add it after rendering old_message_group.prev('.date_row').remove(); @@ -768,7 +769,7 @@ MessageListView.prototype = { self._post_process(dom_messages); old_message_group.replaceWith(rendered_groups); condense.condense_and_collapse(dom_messages); - }); + } } // Update the rendering for message rows which used to be last @@ -780,11 +781,12 @@ MessageListView.prototype = { // class doesn't do anything. if (message_actions.rerender_messages_next_same_sender.length > 0) { const targets = message_actions.rerender_messages_next_same_sender; - _.each(targets, function (message_container) { + + for (const message_container of targets) { const row = self.get_row(message_container.msg.id); $(row).find("div.messagebox").toggleClass("next_is_same_sender", message_container.next_is_same_sender); - }); + } } // Insert new messages in to the last message group @@ -917,14 +919,14 @@ MessageListView.prototype = { let id_of_last_message_sent_by_us = -1; // C++ iterators would have made this less painful - _.each(rendered_elems.reverse(), function (elem) { + for (const elem of rendered_elems.reverse()) { // Sometimes there are non-DOM elements in rendered_elems; only // try to get the heights of actual trs. if (elem.is("div")) { new_messages_height += elem.height(); // starting from the last message, ignore message heights that weren't sent by me. if (id_of_last_message_sent_by_us > -1) { - return; + continue; } const row_id = rows.id(elem); // check for `row_id` NaN in case we're looking at a date row or bookend row @@ -933,7 +935,7 @@ MessageListView.prototype = { id_of_last_message_sent_by_us = rows.id(elem); } } - }, this); + } return new_messages_height; }, @@ -1241,7 +1243,8 @@ MessageListView.prototype = { const message_groups = []; let current_group = []; - _.each(message_containers, function (message_container) { + + for (const message_container of message_containers) { if (current_group.length === 0 || same_recipient(current_group[current_group.length - 1], message_container)) { current_group.push(message_container); @@ -1250,13 +1253,15 @@ MessageListView.prototype = { current_group = []; } self._rerender_message(message_container, message_content_edited); - }); + } + if (current_group.length !== 0) { message_groups.push(current_group); } - _.each(message_groups, function (messages_in_group) { + + for (const messages_in_group of message_groups) { self._rerender_header(messages_in_group, message_content_edited); - }); + } }, append: function (messages, messages_are_new) { diff --git a/static/js/message_live_update.js b/static/js/message_live_update.js index be257ec7f8..1df6932f78 100644 --- a/static/js/message_live_update.js +++ b/static/js/message_live_update.js @@ -1,31 +1,31 @@ exports.update_stream_name = function (stream_id, new_name) { - _.each([home_msg_list, message_list.narrowed, message_list.all], function (list) { + for (const list of [home_msg_list, message_list.narrowed, message_list.all]) { if (list === undefined) { - return; + continue; } list.update_stream_name(stream_id, new_name); - }); + } }; exports.update_user_full_name = function (user_id, full_name) { - _.each([home_msg_list, message_list.narrowed, message_list.all], function (list) { + for (const list of [home_msg_list, message_list.narrowed, message_list.all]) { if (list === undefined) { - return; + continue; } list.update_user_full_name(user_id, full_name); - }); + } }; exports.update_avatar = function (user_id, avatar_url) { let url = avatar_url; url = people.format_small_avatar_url(url); - _.each([home_msg_list, message_list.narrowed, message_list.all], function (list) { + for (const list of [home_msg_list, message_list.narrowed, message_list.all]) { if (list === undefined) { - return; + continue; } list.update_user_avatar(user_id, url); - }); + } }; window.message_live_update = exports; diff --git a/static/js/message_store.js b/static/js/message_store.js index fe3174a2f0..7417fc650e 100644 --- a/static/js/message_store.js +++ b/static/js/message_store.js @@ -67,9 +67,9 @@ exports.process_message_for_recent_private_messages = function (message) { return; } - _.each(user_ids, function (user_id) { + for (const user_id of user_ids) { pm_conversations.set_partner(user_id); - }); + } pm_conversations.recent.insert(user_ids, message.id); }; @@ -176,9 +176,9 @@ exports.add_message_metadata = function (message) { exports.process_message_for_recent_private_messages(message); if (people.is_my_user_id(message.sender_id)) { - _.each(message.display_recipient, (recip) => { + for (const recip of message.display_recipient) { message_user_ids.add(recip.id); - }); + } } break; } @@ -202,7 +202,7 @@ exports.reify_message_id = function (opts) { stored_messages.delete(old_id); } - _.each([message_list.all, home_msg_list, message_list.narrowed], function (msg_list) { + for (const msg_list of [message_list.all, home_msg_list, message_list.narrowed]) { if (msg_list !== undefined) { msg_list.change_message_id(old_id, new_id); @@ -210,7 +210,7 @@ exports.reify_message_id = function (opts) { msg_list.view.change_message_id(old_id, new_id); } } - }); + } }; window.message_store = exports; diff --git a/static/js/muting.js b/static/js/muting.js index 19e3d9e1b5..5181c64550 100644 --- a/static/js/muting.js +++ b/static/js/muting.js @@ -40,7 +40,7 @@ exports.get_muted_topics = function () { exports.set_muted_topics = function (tuples) { muted_topics.clear(); - _.each(tuples, function (tuple) { + for (const tuple of tuples) { const stream_name = tuple[0]; const topic = tuple[1]; @@ -48,11 +48,11 @@ exports.set_muted_topics = function (tuples) { if (!stream_id) { blueslip.warn('Unknown stream in set_muted_topics: ' + stream_name); - return; + continue; } exports.add_muted_topic(stream_id, topic); - }); + } }; exports.initialize = function () { diff --git a/static/js/muting_ui.js b/static/js/muting_ui.js index 1089f6a0fe..e6198ccbd7 100644 --- a/static/js/muting_ui.js +++ b/static/js/muting_ui.js @@ -70,7 +70,8 @@ exports.update_muted_topics = function (muted_topics) { exports.set_up_muted_topics_ui = function (muted_topics) { const muted_topics_table = $("#muted_topics_table tbody"); muted_topics_table.empty(); - _.each(muted_topics, function (tup) { + + for (const tup of muted_topics) { const stream_id = tup[0]; const topic = tup[1]; @@ -78,7 +79,7 @@ exports.set_up_muted_topics_ui = function (muted_topics) { if (!stream) { blueslip.warn('Unknown stream_id in set_up_muted_topics_ui: ' + stream_id); - return; + continue; } const template_data = { @@ -89,7 +90,7 @@ exports.set_up_muted_topics_ui = function (muted_topics) { const row = render_muted_topic_ui_row(template_data); muted_topics_table.append(row); - }); + } }; exports.mute = function (stream_id, topic) { diff --git a/static/js/narrow.js b/static/js/narrow.js index e99ada7cba..ed2110c4d5 100644 --- a/static/js/narrow.js +++ b/static/js/narrow.js @@ -296,10 +296,11 @@ exports.activate = function (raw_operators, opts) { if (page_params.search_pills_enabled && opts.trigger !== 'search') { search_pill_widget.widget.clear(true); - _.each(operators, function (operator) { + + for (const operator of operators) { const search_string = Filter.unparse([operator]); search_pill.append_search_string(search_string, search_pill_widget.widget); - }); + } } if (filter.contains_only_private_messages()) { @@ -887,7 +888,7 @@ function show_search_query() { search_string_display.append($('').text(stream_topic_string)); } - _.each(query_words, function (query_word) { + for (const query_word of query_words) { search_string_display.append(' '); // if query contains stop words, it is enclosed by a tag @@ -899,7 +900,7 @@ function show_search_query() { // We use .text("...") to sanitize the user-given query_string. search_string_display.append($('').text(query_word)); } - }); + } if (query_contains_stop_words) { search_string_display.html(i18n.t( diff --git a/static/js/narrow_state.js b/static/js/narrow_state.js index 927ef68392..ff029f3b81 100644 --- a/static/js/narrow_state.js +++ b/static/js/narrow_state.js @@ -49,7 +49,8 @@ exports.search_string = function () { function collect_single(operators) { const seen = new Dict(); const result = new Dict(); - _.each(operators, function (elem) { + + for (const elem of operators) { const key = elem.operator; if (seen.has(key)) { result.delete(key); @@ -57,7 +58,8 @@ function collect_single(operators) { result.set(key, elem.operand); seen.set(key, true); } - }); + } + return result; } diff --git a/static/js/notifications.js b/static/js/notifications.js index fa92530e0a..c4187dc13e 100644 --- a/static/js/notifications.js +++ b/static/js/notifications.js @@ -578,13 +578,13 @@ exports.request_desktop_notifications_permission = function () { }; exports.received_messages = function (messages) { - _.each(messages, function (message) { + for (const message of messages) { if (!exports.message_is_notifiable(message)) { - return; + continue; } if (!unread.message_unread(message)) { // The message is already read; Zulip is currently in focus. - return; + continue; } message.notification_sent = true; @@ -598,7 +598,7 @@ exports.received_messages = function (messages) { if (exports.should_send_audible_notification(message) && supports_sound) { $("#notifications-area").find("audio")[0].play(); } - }); + } }; function get_message_header(message) { @@ -656,13 +656,13 @@ exports.notify_local_mixes = function (messages, need_user_to_scroll) { sent_messages.messages here. */ - _.each(messages, function (message) { + for (const message of messages) { if (!people.is_my_user_id(message.sender_id)) { // This can happen if the client is offline for a while // around the time this client sends a message; see the // caller of message_events.insert_new_messages. blueslip.info('Slightly unexpected: A message not sent by us batches with those that were.'); - return; + continue; } let reason = exports.get_local_notify_mix_reason(message); @@ -678,7 +678,7 @@ exports.notify_local_mixes = function (messages, need_user_to_scroll) { // This is the HAPPY PATH--for most messages we do nothing // other than maybe sending the above message. - return; + continue; } const link_msg_id = message.id; @@ -687,15 +687,15 @@ exports.notify_local_mixes = function (messages, need_user_to_scroll) { {message_recipient: get_message_header(message)}); exports.notify_above_composebox(reason, link_class, link_msg_id, link_text); - }); + } }; // for callback when we have to check with the server if a message should be in // the current_msg_list (!can_apply_locally; a.k.a. "a search"). exports.notify_messages_outside_current_search = function (messages) { - _.each(messages, function (message) { + for (const message of messages) { if (!people.is_current_user(message.sender_email)) { - return; + continue; } const link_text = i18n.t("Narrow to __- message_recipient__", {message_recipient: get_message_header(message)}); @@ -703,7 +703,7 @@ exports.notify_messages_outside_current_search = function (messages) { "compose_notification_narrow_by_topic", message.id, link_text); - }); + } }; exports.clear_compose_notifications = function () { @@ -718,14 +718,14 @@ exports.reify_message_id = function (opts) { // If a message ID that we're currently storing (as a link) has changed, // update that link as well - _.each($('#out-of-view-notification a'), function (e) { + for (const e of $('#out-of-view-notification a')) { const elem = $(e); const message_id = elem.data('message-id'); if (message_id === old_id) { elem.data('message-id', new_id); } - }); + } }; exports.register_click_handlers = function () { diff --git a/static/js/people.js b/static/js/people.js index 2a9d4e565d..d545bf1004 100644 --- a/static/js/people.js +++ b/static/js/people.js @@ -861,11 +861,11 @@ exports.filter_people_by_search_terms = function (users, search_terms) { // Loop through users and populate filtered_users only // if they include search_terms - _.each(users, function (user) { + for (const user of users) { const person = exports.get_by_email(user.email); // Get person object (and ignore errors) if (!person || !person.full_name) { - return; + continue; } // Return user emails that include search terms @@ -876,7 +876,8 @@ exports.filter_people_by_search_terms = function (users, search_terms) { if (match) { filtered_users.set(person.user_id, true); } - }); + } + return filtered_users; }; @@ -1019,15 +1020,15 @@ exports.extract_people_from_message = function (message) { } // Add new people involved in this message to the people list - _.each(involved_people, function (person) { + for (const person of involved_people) { if (person.unknown_local_echo_user) { - return; + continue; } const user_id = person.user_id || person.id; if (people_by_user_id_dict.has(user_id)) { - return; + continue; } exports.report_late_add(user_id, person.email); @@ -1039,7 +1040,7 @@ exports.extract_people_from_message = function (message) { is_admin: person.is_realm_admin || false, is_bot: person.is_bot || false, }); - }); + } }; function safe_lower(s) { @@ -1094,15 +1095,15 @@ exports.maybe_incr_recipient_count = function (message) { } // Track the number of PMs we've sent to this person to improve autocomplete - _.each(message.display_recipient, function (recip) { + for (const recip of message.display_recipient) { if (recip.unknown_local_echo_user) { - return; + continue; } const user_id = recip.id; exports.incr_recipient_count(user_id); - }); + } }; exports.set_full_name = function (person_obj, new_full_name) { @@ -1181,20 +1182,20 @@ exports.is_my_user_id = function (user_id) { }; exports.initialize = function () { - _.each(page_params.realm_users, function (person) { + for (const person of page_params.realm_users) { exports.add_in_realm(person); - }); + } - _.each(page_params.realm_non_active_users, function (person) { + for (const person of page_params.realm_non_active_users) { exports.add(person); - }); + } - _.each(page_params.cross_realm_bots, function (person) { + for (const person of page_params.cross_realm_bots) { if (!people_dict.has(person.email)) { exports.add(person); } cross_realm_dict.set(person.user_id, person); - }); + } exports.initialize_current_user(page_params.user_id); diff --git a/static/js/pm_conversations.js b/static/js/pm_conversations.js index 69e92723e9..ddbc5e8ef7 100644 --- a/static/js/pm_conversations.js +++ b/static/js/pm_conversations.js @@ -71,9 +71,10 @@ exports.recent = (function () { }; self.initialize = function () { - _.each(page_params.recent_private_conversations, function (conversation) { + for (const conversation of page_params.recent_private_conversations) { self.insert(conversation.user_ids, conversation.max_message_id); - }); + } + delete page_params.recent_private_messages; }; diff --git a/static/js/pm_list.js b/static/js/pm_list.js index 855a705982..1c96076e09 100644 --- a/static/js/pm_list.js +++ b/static/js/pm_list.js @@ -53,12 +53,11 @@ exports.get_active_user_ids_string = function () { }; exports._get_convos = function () { - const private_messages = pm_conversations.recent.get(); const display_messages = []; const active_user_ids_string = exports.get_active_user_ids_string(); - _.each(private_messages, function (private_message_obj) { + for (const private_message_obj of private_messages) { const user_ids_string = private_message_obj.user_ids_string; const reply_to = people.user_ids_string_to_emails_string(user_ids_string); const recipients_string = people.get_recipients(user_ids_string); @@ -97,7 +96,8 @@ exports._get_convos = function () { is_group: is_group, }; display_messages.push(display_message); - }); + } + return display_messages; }; diff --git a/static/js/poll_widget.js b/static/js/poll_widget.js index 592bd46d92..31680b550a 100644 --- a/static/js/poll_widget.js +++ b/static/js/poll_widget.js @@ -168,12 +168,12 @@ exports.poll_data_holder = function (is_my_poll, question, options) { }; // function to add all options added along with the /poll command - _.each(options, function (option, i) { + for (const [i, option] of options.entries()) { self.handle.new_option.inbound('canned', { idx: i, option: option, }); - }); + } return self; }; @@ -355,9 +355,10 @@ exports.activate = function (opts) { } elem.handle_events = function (events) { - _.each(events, function (event) { + for (const event of events) { poll_data.handle_event(event.sender_id, event.data); - }); + } + render_question(); render_results(); }; diff --git a/static/js/portico/team.js b/static/js/portico/team.js index 9c0bc3a233..b46447085e 100644 --- a/static/js/portico/team.js +++ b/static/js/portico/team.js @@ -48,7 +48,7 @@ export default function render_tabs() { $('#tab-total').html(total_tab_html); - _.each(repos, function (repo) { + for (const repo of repos) { // Set as the loading template for now, and load when clicked. $('#tab-' + repo).html($('#loading-template').html()); @@ -73,5 +73,5 @@ export default function render_tabs() { loaded_repos.push(repo); } }); - }); + } } diff --git a/static/js/presence.js b/static/js/presence.js index 1a848d520a..923dfebe07 100644 --- a/static/js/presence.js +++ b/static/js/presence.js @@ -114,19 +114,19 @@ exports.update_info_for_small_realm = function () { // that the server didn't include in its presence update. const persons = people.get_realm_persons(); - _.each(persons, function (person) { + for (const person of persons) { const user_id = person.user_id; let status = "offline"; if (exports.presence_info.has(user_id)) { // this is normal, we have data for active // users that we don't want to clobber. - return; + continue; } if (person.is_bot) { // we don't show presence for bots - return; + continue; } if (people.is_my_user_id(user_id)) { @@ -137,7 +137,7 @@ exports.update_info_for_small_realm = function () { status: status, last_active: undefined, }); - }); + } }; exports.last_active_date = function (user_id) { diff --git a/static/js/reactions.js b/static/js/reactions.js index b56181bc04..82e8ad2863 100644 --- a/static/js/reactions.js +++ b/static/js/reactions.js @@ -333,11 +333,11 @@ exports.remove_reaction = function (event) { // Do the data part first: // Remove reactions from our message object. - _.each(message.reactions, function (reaction, index) { + for (const [index, reaction] of message.reactions.entries()) { if (reaction.local_id === local_id && reaction.user.id === user_id) { i = index; } - }); + } if (i !== -1) { message.reactions.splice(i, 1); @@ -401,13 +401,14 @@ exports.get_emojis_used_by_user_for_message_id = function (message_id) { exports.get_message_reactions = function (message) { const message_reactions = new Dict(); - _.each(message.reactions, function (reaction) { + + for (const reaction of message.reactions) { const user_id = reaction.user.id; reaction.local_id = exports.get_local_reaction_id(reaction); if (!people.is_known_user_id(user_id)) { blueslip.warn('Unknown user_id ' + user_id + ' in reaction for message ' + message.id); - return; + continue; } reaction.user_ids = []; let collapsed_reaction = message_reactions.get(reaction.local_id); @@ -416,7 +417,8 @@ exports.get_message_reactions = function (message) { message_reactions.set(reaction.local_id, collapsed_reaction); } collapsed_reaction.user_ids.push(user_id); - }); + } + const reactions = Array.from(message_reactions.values(), reaction => { reaction.local_id = reaction.local_id; reaction.reaction_type = reaction.reaction_type; diff --git a/static/js/reload.js b/static/js/reload.js index 5e44aa9ffc..49d1733aac 100644 --- a/static/js/reload.js +++ b/static/js/reload.js @@ -117,10 +117,11 @@ exports.initialize = function () { fragment = fragment.replace(/^reload:/, ""); const keyvals = fragment.split("+"); const vars = {}; - _.each(keyvals, function (str) { + + for (const str of keyvals) { const pair = str.split("="); vars[pair[0]] = decodeURIComponent(pair[1]); - }); + } if (vars.msg !== undefined) { const send_now = parseInt(vars.send_after_reload, 10); diff --git a/static/js/resize.js b/static/js/resize.js index 98cf9dd66e..d8eadb1068 100644 --- a/static/js/resize.js +++ b/static/js/resize.js @@ -14,15 +14,16 @@ function confine_to_range(lo, val, hi) { function size_blocks(blocks, usable_height) { let sum_height = 0; - _.each(blocks, function (block) { - sum_height += block.real_height; - }); - _.each(blocks, function (block) { + for (const block of blocks) { + sum_height += block.real_height; + } + + for (const block of blocks) { let ratio = block.real_height / sum_height; ratio = confine_to_range(0.05, ratio, 0.85); block.max_height = confine_to_range(80, usable_height * ratio, 1.2 * block.real_height); - }); + } } function set_user_list_heights(res, usable_height, buddy_list_wrapper, group_pms) { diff --git a/static/js/search_suggestion.js b/static/js/search_suggestion.js index c93a4dd6a0..3829c5d786 100644 --- a/static/js/search_suggestion.js +++ b/static/js/search_suggestion.js @@ -613,10 +613,10 @@ function make_attacher(base) { }; self.attach_many = function (suggestions) { - _.each(suggestions, function (suggestion) { + for (const suggestion of suggestions) { prepend_base(suggestion); self.push(suggestion); - }); + } }; return self; @@ -718,12 +718,12 @@ exports.get_search_result = function (base_query, query) { const max_items = exports.max_num_of_search_results; - _.each(filterers, function (filterer) { + for (const filterer of filterers) { if (attacher.result.length < max_items) { const suggestions = filterer(last, base_operators); attacher.attach_many(suggestions); } - }); + } return attacher.result.slice(0, max_items); }; @@ -804,12 +804,12 @@ exports.get_search_result_legacy = function (query) { const max_items = exports.max_num_of_search_results; - _.each(filterers, function (filterer) { + for (const filterer of filterers) { if (attacher.result.length < max_items) { const suggestions = filterer(last, base_operators); attacher.attach_many(suggestions); } - }); + } // This is unique to the legacy search system. With pills // it is difficult to "suggest" a subset of operators, @@ -835,17 +835,19 @@ exports.get_suggestions = function (base_query, query) { }; exports.finalize_search_result = function (result) { - _.each(result, function (sug) { + for (const sug of result) { const first = sug.description.charAt(0).toUpperCase(); sug.description = first + sug.description.slice(1); - }); + } // Typeahead expects us to give it strings, not objects, // so we maintain our own hash back to our objects const lookup_table = {}; - _.each(result, function (obj) { + + for (const obj of result) { lookup_table[obj.search_string] = obj; - }); + } + const strings = _.map(result, function (obj) { return obj.search_string; }); diff --git a/static/js/server_events.js b/static/js/server_events.js index 24d3a2b7d1..22805e30e7 100644 --- a/static/js/server_events.js +++ b/static/js/server_events.js @@ -20,7 +20,7 @@ function get_events_success(events) { return _.pick(event, 'id', 'type', 'op'); }; - _.each(events, function (event) { + for (const event of events) { try { get_events_params.last_event_id = Math.max(get_events_params.last_event_id, event.id); @@ -29,7 +29,7 @@ function get_events_success(events) { {event: clean_event(event)}, ex.stack); } - }); + } if (waiting_on_homeview_load) { events_stored_while_loading = events_stored_while_loading.concat(events); @@ -77,7 +77,7 @@ function get_events_success(events) { } }; - _.each(events, function (event) { + for (const event of events) { try { dispatch_event(event); } catch (ex1) { @@ -86,7 +86,7 @@ function get_events_success(events) { {event: clean_event(event)}, ex1.stack); } - }); + } if (messages.length !== 0) { // Sort by ID, so that if we get multiple messages back from @@ -98,7 +98,8 @@ function get_events_success(events) { if (messages.length > 0) { _.each(messages, message_store.set_message_booleans); let sent_by_this_client = false; - _.each(messages, function (msg) { + + for (const msg of messages) { const msg_state = sent_messages.messages[msg.local_id]; if (msg_state) { // Almost every time, this message will be the @@ -112,7 +113,8 @@ function get_events_success(events) { // correctly. sent_by_this_client = true; } - }); + } + message_events.insert_new_messages(messages, sent_by_this_client); } } catch (ex2) { @@ -148,9 +150,9 @@ function get_events_success(events) { // We do things like updating message flags and deleting messages last, // to avoid ordering issues that are caused by batch handling of // messages above. - _.each(post_message_events, function (event) { + for (const event of post_message_events) { server_events_dispatch.dispatch_normal_event(event); - }); + } } function show_ui_connection_error() { diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js index 6dc1cf2e96..0cc40017e1 100644 --- a/static/js/server_events_dispatch.js +++ b/static/js/server_events_dispatch.js @@ -273,13 +273,14 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { settings_streams.update_default_streams_table(); } else if (event.op === 'create') { stream_data.create_streams(event.streams); - _.each(event.streams, function (stream) { + + for (const stream of event.streams) { const sub = stream_data.get_sub_by_id(stream.stream_id); stream_data.update_calculated_fields(sub); subs.add_sub_to_table(sub); - }); + } } else if (event.op === 'delete') { - _.each(event.streams, function (stream) { + for (const stream of event.streams) { const was_subscribed = stream_data.get_sub_by_id(stream.stream_id).subscribed; subs.remove_stream(stream.stream_id); stream_data.delete_sub(stream.stream_id); @@ -298,7 +299,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { settings_org.render_notifications_stream_ui( page_params.realm_signup_notifications_stream_id, 'signup_notifications'); } - }); + } } break; @@ -319,7 +320,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { case 'subscription': if (event.op === 'add') { - _.each(event.subscriptions, function (rec) { + for (const rec of event.subscriptions) { const sub = stream_data.get_sub_by_id(rec.stream_id); if (sub) { stream_data.update_stream_email_address(sub, rec.email_address); @@ -327,28 +328,28 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { } else { blueslip.error('Subscribing to unknown stream with ID ' + rec.stream_id); } - }); + } } else if (event.op === 'peer_add') { - _.each(event.subscriptions, function (sub) { + for (const sub of event.subscriptions) { if (stream_data.add_subscriber(sub, event.user_id)) { $(document).trigger('peer_subscribe.zulip', {stream_name: sub}); } else { blueslip.warn('Cannot process peer_add event'); } - }); + } } else if (event.op === 'peer_remove') { - _.each(event.subscriptions, function (sub) { + for (const sub of event.subscriptions) { if (stream_data.remove_subscriber(sub, event.user_id)) { $(document).trigger('peer_unsubscribe.zulip', {stream_name: sub}); } else { blueslip.warn('Cannot process peer_remove event.'); } - }); + } } else if (event.op === 'remove') { - _.each(event.subscriptions, function (rec) { + for (const rec of event.subscriptions) { const sub = stream_data.get_sub_by_id(rec.stream_id); stream_events.mark_unsubscribed(sub); - }); + } } else if (event.op === 'update') { stream_events.update_property( event.stream_id, @@ -469,9 +470,10 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { const new_value = event.operation === "add"; switch (event.flag) { case 'starred': - _.each(event.messages, function (message_id) { + for (const message_id of event.messages) { message_flags.update_starred_flag(message_id, new_value); - }); + } + if (event.operation === "add") { starred_messages.add(event.messages); } else { diff --git a/static/js/settings_account.js b/static/js/settings_account.js index ad7f55030e..e335eef73f 100644 --- a/static/js/settings_account.js +++ b/static/js/settings_account.js @@ -100,9 +100,10 @@ function update_user_custom_profile_fields(fields, method) { if (method === undefined) { blueslip.error("Undefined method in update_user_custom_profile_fields"); } - _.each(fields, function (field) { + + for (const field of fields) { update_custom_profile_field(field, method); - }); + } } exports.append_custom_profile_fields = function (element_id, user_id) { diff --git a/static/js/settings_bots.js b/static/js/settings_bots.js index 5bd8e9edcd..94ed088d89 100644 --- a/static/js/settings_bots.js +++ b/static/js/settings_bots.js @@ -77,7 +77,7 @@ exports.render_bots = function () { const all_bots_for_current_user = bot_data.get_all_bots_for_current_user(); let user_owns_an_active_bot = false; - _.each(all_bots_for_current_user, function (elem) { + for (const elem of all_bots_for_current_user) { add_bot_row({ name: elem.full_name, email: elem.email, @@ -89,7 +89,7 @@ exports.render_bots = function () { zuliprc: 'zuliprc', // Most browsers do not allow filename starting with `.` }); user_owns_an_active_bot = user_owns_an_active_bot || elem.is_active; - }); + } if (exports.can_create_new_bots()) { if (!user_owns_an_active_bot) { @@ -217,12 +217,14 @@ exports.set_up = function () { $('#download_botserverrc').click(function () { const OUTGOING_WEBHOOK_BOT_TYPE_INT = 3; let content = ""; - _.each(bot_data.get_all_bots_for_current_user(), function (bot) { + + for (const bot of bot_data.get_all_bots_for_current_user()) { if (bot.is_active && bot.bot_type === OUTGOING_WEBHOOK_BOT_TYPE_INT) { const bot_token = bot_data.get_services(bot.user_id)[0].token; content += exports.generate_botserverrc_content(bot.email, bot.api_key, bot_token); } - }); + } + $(this).attr("href", "data:application/octet-stream;charset=utf-8," + encodeURIComponent(content)); }); diff --git a/static/js/settings_display.js b/static/js/settings_display.js index 5c9f69820d..3e6b4f2f44 100644 --- a/static/js/settings_display.js +++ b/static/js/settings_display.js @@ -77,7 +77,7 @@ exports.set_up = function () { overlays.close_modal('default_language_modal'); }); - _.each(exports.all_display_settings.settings.user_display_settings, function (setting) { + for (const setting of exports.all_display_settings.settings.user_display_settings) { $("#" + setting).change(function () { const data = {}; data[setting] = JSON.stringify($(this).prop('checked')); @@ -91,7 +91,7 @@ exports.set_up = function () { change_display_setting(data, "#display-settings-status"); } }); - }); + } $("#default_language_modal .language").click(function (e) { e.preventDefault(); diff --git a/static/js/settings_emoji.js b/static/js/settings_emoji.js index bccc50aa94..86d5572790 100644 --- a/static/js/settings_emoji.js +++ b/static/js/settings_emoji.js @@ -134,9 +134,11 @@ exports.set_up = function () { $('#admin_emoji_submit').attr('disabled', true); const emoji = {}; const formData = new FormData(); - _.each($(this).serializeArray(), function (obj) { + + for (const obj of $(this).serializeArray()) { emoji[obj.name] = obj.value; - }); + } + $.each($('#emoji_file_input')[0].files, function (i, file) { formData.append('file-' + i, file); }); diff --git a/static/js/settings_linkifiers.js b/static/js/settings_linkifiers.js index 717b402bbc..9506615a83 100644 --- a/static/js/settings_linkifiers.js +++ b/static/js/settings_linkifiers.js @@ -121,9 +121,10 @@ exports.build_page = function () { pattern_status.hide(); format_status.hide(); const filter = {}; - _.each($(this).serializeArray(), function (obj) { + + for (const obj of $(this).serializeArray()) { filter[obj.name] = obj.value; - }); + } channel.post({ url: "/json/realm/filters", diff --git a/static/js/settings_notifications.js b/static/js/settings_notifications.js index e3341c69a8..c3c025adf3 100644 --- a/static/js/settings_notifications.js +++ b/static/js/settings_notifications.js @@ -97,8 +97,8 @@ exports.set_enable_digest_emails_visibility = function () { }; exports.set_up = function () { - _.each(notification_settings_status, function (setting) { - _.each(setting.settings, function (sub_setting) { + for (const setting of notification_settings_status) { + for (const sub_setting of setting.settings) { $("#" + sub_setting).change(function () { let value; @@ -113,8 +113,8 @@ exports.set_up = function () { change_notification_setting(sub_setting, value, "#" + setting.status_label); }); - }); - }); + } + } update_desktop_icon_count_display(); @@ -138,19 +138,19 @@ exports.set_up = function () { }; exports.update_page = function () { - _.each(exports.all_notification_settings_labels, function (setting) { + for (const setting of exports.all_notification_settings_labels) { if (setting === 'enable_offline_push_notifications' && !page_params.realm_push_notifications_enabled) { // If push notifications are disabled at the realm level, // we should just leave the checkbox always off. - return; + continue; } else if (setting === 'desktop_icon_count_display') { update_desktop_icon_count_display(); - return; + continue; } $("#" + setting).prop('checked', page_params[setting]); - }); + } }; window.settings_notifications = exports; diff --git a/static/js/settings_org.js b/static/js/settings_org.js index 6a09c5ea7d..84062ced09 100644 --- a/static/js/settings_org.js +++ b/static/js/settings_org.js @@ -384,20 +384,23 @@ exports.populate_realm_domains = function (realm_domains) { const realm_domains_table_body = $("#realm_domains_table tbody").expectOne(); realm_domains_table_body.find("tr").remove(); - _.each(realm_domains, function (realm_domain) { + + for (const realm_domain of realm_domains) { realm_domains_table_body.append( render_settings_admin_realm_domains_list({ realm_domain: realm_domain, }) ); - }); + } }; function sort_object_by_key(obj) { const keys = _.keys(obj).sort(); const new_obj = {}; - _.each(keys, function (key) { + + for (const key of keys) { new_obj[key] = obj[key]; - }); + } + return new_obj; } exports.populate_auth_methods = function (auth_methods) { @@ -672,9 +675,11 @@ exports.build_page = function () { function get_auth_method_table_data() { const new_auth_methods = {}; const auth_method_rows = $("#id_realm_authentication_methods").find('tr.method_row'); - _.each(auth_method_rows, function (method_row) { + + for (const method_row of auth_method_rows) { new_auth_methods[$(method_row).data('method')] = $(method_row).find('input').prop('checked'); - }); + } + return new_auth_methods; } @@ -711,11 +716,12 @@ exports.build_page = function () { subsection.find('.save-button').show(); const properties_elements = get_subsection_property_elements(subsection); let show_change_process_button = false; - _.each(properties_elements, function (elem) { + + for (const elem of properties_elements) { if (check_property_changed(elem)) { show_change_process_button = true; } - }); + } const save_btn_controls = subsection.find('.subsection-header .save-button-controls'); const button_state = show_change_process_button ? "unsaved" : "discarded"; @@ -872,7 +878,8 @@ exports.build_page = function () { function populate_data_for_request(subsection) { const data = {}; const properties_elements = get_subsection_property_elements(subsection); - _.each(properties_elements, function (input_elem) { + + for (let input_elem of properties_elements) { input_elem = $(input_elem); if (check_property_changed(input_elem)) { const input_type = input_elem.data("setting-widget-type"); @@ -880,18 +887,19 @@ exports.build_page = function () { const property_name = input_elem.attr('id').replace("id_realm_", ""); if (input_type === 'bool') { data[property_name] = JSON.stringify(input_elem.prop('checked')); - return; + continue; } if (input_type === 'text') { data[property_name] = JSON.stringify(input_elem.val().trim()); - return; + continue; } if (input_type === 'integer') { data[property_name] = JSON.stringify(parseInt(input_elem.val().trim(), 10)); } } } - }); + } + return data; } diff --git a/static/js/settings_profile_fields.js b/static/js/settings_profile_fields.js index 72bbcd72e9..f76daa609f 100644 --- a/static/js/settings_profile_fields.js +++ b/static/js/settings_profile_fields.js @@ -247,13 +247,13 @@ function set_up_choices_field_edit_form(profile_field, field_data) { const choices_data = exports.parse_field_choices_from_field_data(field_data); - _.each(choices_data, function (choice) { + for (const choice of choices_data) { choice_list.append( render_settings_profile_field_choice({ text: choice.text, }) ); - }); + } // Add blank choice at last create_choice_row(choice_list); @@ -350,7 +350,8 @@ exports.do_populate_profile_fields = function (profile_fields_data) { profile_fields_table.find("tr.profile-field-row").remove(); // Clear all rows. profile_fields_table.find("tr.profile-field-form").remove(); // Clear all rows. order = []; - _.each(profile_fields_data, function (profile_field) { + + for (const profile_field of profile_fields_data) { order.push(profile_field.id); let field_data = {}; if (profile_field.field_data) { @@ -377,7 +378,8 @@ exports.do_populate_profile_fields = function (profile_fields_data) { realm_default_external_accounts: page_params.realm_default_external_accounts, }) ); - }); + } + if (page_params.is_admin) { const field_list = $("#admin_profile_fields_table")[0]; Sortable.create(field_list, { diff --git a/static/js/settings_toggle.js b/static/js/settings_toggle.js index 1c002a58eb..22fb94fe76 100644 --- a/static/js/settings_toggle.js +++ b/static/js/settings_toggle.js @@ -34,19 +34,18 @@ exports.toggle_org_setting_collapse = function () { const show_more_settings_text = i18n.t("Show more"); if (is_collapsed) { - _.each($(".collapse-org-settings"), function (elem) { + for (const elem of $(".collapse-org-settings")) { $(elem).removeClass("hide-org-settings"); - }); + } $("#toggle_collapse_chevron").removeClass("fa-angle-double-down"); $("#toggle_collapse_chevron").addClass("fa-angle-double-up"); $("#toggle_collapse").text(show_fewer_settings_text); - } else { - _.each($(".collapse-org-settings"), function (elem) { + for (const elem of $(".collapse-org-settings")) { $(elem).addClass("hide-org-settings"); - }); + } $("#toggle_collapse_chevron").removeClass("fa-angle-double-up"); $("#toggle_collapse_chevron").addClass("fa-angle-double-down"); diff --git a/static/js/settings_user_groups.js b/static/js/settings_user_groups.js index f6bc3296d4..39a9f87a8e 100644 --- a/static/js/settings_user_groups.js +++ b/static/js/settings_user_groups.js @@ -38,10 +38,10 @@ exports.can_edit = function (group_id) { }; exports.populate_user_groups = function () { - const user_groups_section = $('#user-groups').expectOne(); const user_groups_array = user_groups.get_realm_user_groups(); - _.each(user_groups_array, function (data) { + + for (const data of user_groups_array) { user_groups_section.append(render_admin_user_group_list({ user_group: { name: data.name, @@ -257,7 +257,7 @@ exports.populate_user_groups = function () { }, 100); }); }()); - }); + } }; exports.set_up = function () { @@ -273,12 +273,13 @@ exports.set_up = function () { const group = { members: JSON.stringify([people.my_current_user_id()]), }; - _.each($(this).serializeArray(), function (obj) { + + for (const obj of $(this).serializeArray()) { if (obj.value.trim() === "") { - return; + continue; } group[obj.name] = obj.value; - }); + } channel.post({ url: "/json/user_groups/create", diff --git a/static/js/starred_messages.js b/static/js/starred_messages.js index 99ced1e877..ad8ace1f1a 100644 --- a/static/js/starred_messages.js +++ b/static/js/starred_messages.js @@ -2,23 +2,27 @@ exports.ids = new Set(); exports.initialize = function () { exports.ids.clear(); - _.each(page_params.starred_messages, function (id) { + + for (const id of page_params.starred_messages) { exports.ids.add(id); - }); + } + exports.rerender_ui(); }; exports.add = function (ids) { - _.each(ids, function (id) { + for (const id of ids) { exports.ids.add(id); - }); + } + exports.rerender_ui(); }; exports.remove = function (ids) { - _.each(ids, function (id) { + for (const id of ids) { exports.ids.delete(id); - }); + } + exports.rerender_ui(); }; diff --git a/static/js/stream_color.js b/static/js/stream_color.js index 540645744f..33d272d021 100644 --- a/static/js/stream_color.js +++ b/static/js/stream_color.js @@ -11,7 +11,7 @@ function update_table_stream_color(table, stream_name, color) { const stream_labels = $("#floating_recipient_bar").add(table).find(".stream_label"); - _.each(stream_labels, function (label) { + for (const label of stream_labels) { const $label = $(label); if ($.trim($label.text()) === stream_name) { const messages = $label.closest(".recipient_row").children(".message_row"); @@ -21,7 +21,7 @@ function update_table_stream_color(table, stream_name, color) { $label.removeClass(exports.color_classes); $label.addClass(color_class); } - }); + } } function update_stream_sidebar_swatch_color(id, color) { diff --git a/static/js/stream_data.js b/static/js/stream_data.js index 9b799056fc..2915423e09 100644 --- a/static/js/stream_data.js +++ b/static/js/stream_data.js @@ -305,9 +305,9 @@ exports.get_updated_unsorted_subs = function () { let all_subs = Array.from(stream_info.values()); // Add in admin options and stream counts. - _.each(all_subs, function (sub) { + for (const sub of all_subs) { exports.update_calculated_fields(sub); - }); + } // We don't display unsubscribed streams to guest users. if (page_params.is_guest) { @@ -447,9 +447,9 @@ exports.update_calculated_fields = function (sub) { exports.update_subscribers_count(sub); // Apply the defaults for our notification settings for rendering. - _.each(stream_notification_settings, function (setting) { + for (const setting of stream_notification_settings) { sub[setting + "_display"] = exports.receives_notifications(sub.name, setting); - }); + } }; exports.all_subscribed_streams_are_in_home_view = function () { @@ -672,14 +672,14 @@ exports.is_user_subscribed = function (stream_name, user_id) { }; exports.create_streams = function (streams) { - _.each(streams, function (stream) { + for (const stream of streams) { // We handle subscriber stuff in other events. const attrs = _.defaults(stream, { subscribers: [], subscribed: false, }); exports.create_sub_from_server_data(stream.name, attrs); - }); + } }; exports.create_sub_from_server_data = function (stream_name, attrs) { @@ -754,9 +754,9 @@ exports.get_streams_for_settings_page = function () { const all_subs = unsubscribed_rows.concat(subscribed_rows); // Add in admin options and stream counts. - _.each(all_subs, function (sub) { + for (const sub of all_subs) { exports.update_calculated_fields(sub); - }); + } return all_subs; }; diff --git a/static/js/stream_events.js b/static/js/stream_events.js index d2817c2251..cca170fb52 100644 --- a/static/js/stream_events.js +++ b/static/js/stream_events.js @@ -133,12 +133,12 @@ exports.mark_unsubscribed = function (sub) { exports.remove_deactivated_user_from_all_streams = function (user_id) { const all_subs = stream_data.get_unsorted_subs(); - _.each(all_subs, function (sub) { + for (const sub of all_subs) { if (stream_data.is_user_subscribed(sub.name, user_id)) { stream_data.remove_subscriber(sub.name, user_id); subs.rerender_subscriptions_settings(sub); } - }); + } }; diff --git a/static/js/stream_list.js b/static/js/stream_list.js index b79724475c..e6244e6d18 100644 --- a/static/js/stream_list.js +++ b/static/js/stream_list.js @@ -74,9 +74,9 @@ exports.create_initial_sidebar_rows = function () { // structures that are kept in stream_data.js. const subs = stream_data.subscribed_subs(); - _.each(subs, function (sub) { + for (const sub of subs) { exports.create_sidebar_row(sub); - }); + } }; exports.build_stream_list = function () { diff --git a/static/js/stream_sort.js b/static/js/stream_sort.js index 61f9b44117..3d1861653a 100644 --- a/static/js/stream_sort.js +++ b/static/js/stream_sort.js @@ -48,7 +48,7 @@ exports.sort_groups = function (streams, search_term) { const normal_streams = []; const dormant_streams = []; - _.each(streams, function (stream) { + for (const stream of streams) { const sub = stream_data.get_sub(stream); const pinned = sub.pin_to_top; if (pinned) { @@ -58,7 +58,7 @@ exports.sort_groups = function (streams, search_term) { } else { dormant_streams.push(stream); } - }); + } pinned_streams.sort(util.strcmp); normal_streams.sort(util.strcmp); diff --git a/static/js/subs.js b/static/js/subs.js index cb7d5de78d..78d6447499 100644 --- a/static/js/subs.js +++ b/static/js/subs.js @@ -290,11 +290,11 @@ exports.show_active_stream_in_left_panel = function () { }; exports.add_tooltips_to_left_panel = function () { - _.each($("#subscriptions_table .stream-row"), function (row) { + for (const row of $("#subscriptions_table .stream-row")) { $(row).find('.sub-info-box [class$="-bar"] [class$="-count"]').tooltip({ placement: 'left', animation: false, }); - }); + } }; exports.update_settings_for_unsubscribed = function (sub) { @@ -358,7 +358,7 @@ function get_stream_id_buckets(stream_ids, query) { other: [], }; - _.each(stream_ids, function (stream_id) { + for (const stream_id of stream_ids) { const sub = stream_data.get_sub_by_id(stream_id); const match_status = triage_stream(query, sub); @@ -369,7 +369,7 @@ function get_stream_id_buckets(stream_ids, query) { } else { buckets.other.push(stream_id); } - }); + } stream_data.sort_for_stream_settings(buckets.name); stream_data.sort_for_stream_settings(buckets.desc); @@ -404,21 +404,23 @@ exports.filter_table = function (query) { const streams_list_scrolltop = ui.get_scroll_element($(".streams-list")).scrollTop(); const stream_ids = []; - _.each($("#subscriptions_table .stream-row"), function (row) { + + for (const row of $("#subscriptions_table .stream-row")) { const stream_id = stream_id_for_row(row); stream_ids.push(stream_id); - }); + } const buckets = get_stream_id_buckets(stream_ids, query); // If we just re-built the DOM from scratch we wouldn't need // all this hidden/notdisplayed logic. const hidden_ids = {}; - _.each(buckets.other, function (stream_id) { - hidden_ids[stream_id] = true; - }); - _.each($("#subscriptions_table .stream-row"), function (row) { + for (const stream_id of buckets.other) { + hidden_ids[stream_id] = true; + } + + for (const row of $("#subscriptions_table .stream-row")) { const stream_id = stream_id_for_row(row); // Below code goes away if we don't do sort-DOM-in-place. @@ -429,7 +431,7 @@ exports.filter_table = function (query) { } widgets[stream_id] = $(row).detach(); - }); + } exports.add_tooltips_to_left_panel(); @@ -441,9 +443,9 @@ exports.filter_table = function (query) { buckets.other ); - _.each(all_stream_ids, function (stream_id) { + for (const stream_id of all_stream_ids) { ui.get_content_element($('#subscriptions_table .streams-list')).append(widgets[stream_id]); - }); + } exports.maybe_reset_right_panel(); diff --git a/static/js/tictactoe_widget.js b/static/js/tictactoe_widget.js index b96925fb12..57f79f1e93 100644 --- a/static/js/tictactoe_widget.js +++ b/static/js/tictactoe_widget.js @@ -138,9 +138,10 @@ exports.activate = function (opts) { } elem.handle_events = function (events) { - _.each(events, function (event) { + for (const event of events) { tictactoe_data.handle_event(event.sender_id, event.data); - }); + } + render(); }; diff --git a/static/js/timerender.js b/static/js/timerender.js index ce03995166..282dbf0cff 100644 --- a/static/js/timerender.js +++ b/static/js/timerender.js @@ -172,14 +172,14 @@ exports.update_timestamps = function () { const to_process = update_list; update_list = []; - _.each(to_process, function (entry) { + for (const entry of to_process) { const className = entry.className; const elements = $('.' + className); // The element might not exist any more (because it // was in the zfilt table, or because we added // messages above it and re-collapsed). if (elements !== null) { - _.each(elements, function (element) { + for (const element of elements) { const time = entry.time; const time_above = entry.time_above; const rendered_time = exports.render_now(time); @@ -195,9 +195,9 @@ exports.update_timestamps = function () { time: time, time_above: time_above, }); - }); + } } - }); + } next_update = set_to_start_of_day(now.clone().addDays(1)); } diff --git a/static/js/todo_widget.js b/static/js/todo_widget.js index 14f5b1236f..bb6e333f89 100644 --- a/static/js/todo_widget.js +++ b/static/js/todo_widget.js @@ -162,9 +162,10 @@ exports.activate = function (opts) { } elem.handle_events = function (events) { - _.each(events, function (event) { + for (const event of events) { task_data.handle_event(event.sender_id, event.data); - }); + } + render_results(); }; diff --git a/static/js/topic_data.js b/static/js/topic_data.js index b9b42ae280..6a93b5e4e7 100644 --- a/static/js/topic_data.js +++ b/static/js/topic_data.js @@ -114,7 +114,7 @@ exports.topic_history = function (stream_id) { // server. We have less data about these than the // client can maintain for newer topics. - _.each(server_history, function (obj) { + for (const obj of server_history) { const name = obj.name; const message_id = obj.max_id; @@ -124,7 +124,7 @@ exports.topic_history = function (stream_id) { if (!existing.historical) { // Trust out local data more, since it // maintains counts. - return; + continue; } } @@ -137,7 +137,7 @@ exports.topic_history = function (stream_id) { pretty_name: name, historical: true, }); - }); + } }; self.get_recent_names = function () { diff --git a/static/js/topic_list_data.js b/static/js/topic_list_data.js index d34817bc3d..e87ece1332 100644 --- a/static/js/topic_list_data.js +++ b/static/js/topic_list_data.js @@ -15,13 +15,13 @@ exports.get_list_info = function (stream_id, zoomed) { const items = []; - _.each(topic_names, function (topic_name, idx) { + for (const [idx, topic_name] of topic_names.entries()) { const num_unread = unread.num_unread_for_topic(stream_id, topic_name); const is_active_topic = active_topic === topic_name.toLowerCase(); const is_topic_muted = muting.is_topic_muted(stream_id, topic_name); if (!zoomed) { - function should_show_topic() { + function should_show_topic(topics_selected) { // This function exists just for readability, to // avoid long chained conditionals to determine // which topics to include. @@ -62,7 +62,7 @@ exports.get_list_info = function (stream_id, zoomed) { return false; } - const show_topic = should_show_topic(); + const show_topic = should_show_topic(topics_selected); if (!show_topic) { if (!is_topic_muted) { // The "more topics" unread count, like @@ -70,7 +70,7 @@ exports.get_list_info = function (stream_id, zoomed) { // on unmuted topics. more_topics_unreads += num_unread; } - return; + continue; } topics_selected += 1; // We fall through to rendering the topic, using the @@ -87,7 +87,7 @@ exports.get_list_info = function (stream_id, zoomed) { }; items.push(topic_info); - }); + } return { items: items, diff --git a/static/js/typeahead_helper.js b/static/js/typeahead_helper.js index 62c1bd8b32..da10ac566d 100644 --- a/static/js/typeahead_helper.js +++ b/static/js/typeahead_helper.js @@ -27,13 +27,15 @@ exports.highlight_with_escaping_and_regex = function (regex, item) { const pieces = item.split(regex); let result = ""; - _.each(pieces, function (piece) { + + for (const piece of pieces) { if (piece.match(regex)) { result += "" + Handlebars.Utils.escapeExpression(piece) + ""; } else { result += Handlebars.Utils.escapeExpression(piece); } - }); + } + return result; }; @@ -304,7 +306,6 @@ exports.sort_recipients = function ( groups, max_num_items ) { - if (!groups) { groups = []; } @@ -356,11 +357,12 @@ exports.sort_recipients = function ( */ let items = []; - _.each(getters, (getter) => { + + for (const getter of getters) { if (items.length < max_num_items) { items = items.concat(getter()); } - }); + } return items.slice(0, max_num_items); }; diff --git a/static/js/ui.js b/static/js/ui.js index 6efbf0bef2..0f28ad953e 100644 --- a/static/js/ui.js +++ b/static/js/ui.js @@ -44,18 +44,18 @@ exports.reset_scrollbar = function (element_selector) { }; function update_message_in_all_views(message_id, callback) { - _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) { + for (const list of [message_list.all, home_msg_list, message_list.narrowed]) { if (list === undefined) { - return; + continue; } const row = list.get_row(message_id); if (row === undefined) { // The row may not exist, e.g. if you do an action on a message in // a narrowed view - return; + continue; } callback(row); - }); + } } exports.show_error_for_unsupported_platform = function () { @@ -78,11 +78,13 @@ exports.find_message = function (message_id) { // (if it was loaded when narrowed), or only in the message_list.all // (if received from the server while in a different narrow) let message; - _.each([message_list.all, home_msg_list, message_list.narrowed], function (msg_list) { + + for (const msg_list of [message_list.all, home_msg_list, message_list.narrowed]) { if (msg_list !== undefined && message === undefined) { message = msg_list.get(message_id); } - }); + } + return message; }; @@ -113,15 +115,15 @@ exports.show_message_failed = function (message_id, failed_msg) { }; exports.remove_message = function (message_id) { - _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) { + for (const list of [message_list.all, home_msg_list, message_list.narrowed]) { if (list === undefined) { - return; + continue; } const row = list.get_row(message_id); if (row !== undefined) { list.remove_and_rerender([{id: message_id}]); } - }); + } }; exports.show_failed_message_success = function (message_id) { diff --git a/static/js/unread.js b/static/js/unread.js index 7b6e777599..7edb614e73 100644 --- a/static/js/unread.js +++ b/static/js/unread.js @@ -93,26 +93,26 @@ exports.unread_pm_counter = (function () { }; self.set_pms = function (pms) { - _.each(pms, function (obj) { + for (const obj of pms) { const user_ids_string = obj.sender_id.toString(); self.set_message_ids(user_ids_string, obj.unread_message_ids); - }); + } }; self.set_huddles = function (huddles) { - _.each(huddles, function (obj) { + for (const obj of huddles) { const user_ids_string = people.pm_lookup_key(obj.user_ids_string); self.set_message_ids(user_ids_string, obj.unread_message_ids); - }); + } }; self.set_message_ids = function (user_ids_string, unread_message_ids) { - _.each(unread_message_ids, function (msg_id) { + for (const msg_id of unread_message_ids) { bucketer.add({ bucket_key: user_ids_string, item_id: msg_id, }); - }); + } }; self.add = function (message) { @@ -208,15 +208,15 @@ exports.unread_topic_counter = (function () { self.set_streams = function (objs) { - _.each(objs, function (obj) { + for (const obj of objs) { const stream_id = obj.stream_id; const topic = obj.topic; const unread_message_ids = obj.unread_message_ids; - _.each(unread_message_ids, function (msg_id) { + for (const msg_id of unread_message_ids) { self.add(stream_id, topic, msg_id); - }); - }); + } + } }; self.add = function (stream_id, topic, msg_id) { @@ -424,9 +424,9 @@ exports.update_unread_topics = function (msg, event) { }; exports.process_loaded_messages = function (messages) { - _.each(messages, function (message) { + for (const message of messages) { if (!message.unread) { - return; + continue; } unread_messages.add(message.id); @@ -449,7 +449,7 @@ exports.process_loaded_messages = function (messages) { if (message.mentioned_me_directly || is_unmuted_mention) { exports.unread_mentions_counter.add(message.id); } - }); + } }; exports.mark_as_read = function (message_id) { @@ -584,18 +584,24 @@ exports.initialize = function () { exports.unread_pm_counter.set_huddles(unread_msgs.huddles); exports.unread_pm_counter.set_pms(unread_msgs.pms); exports.unread_topic_counter.set_streams(unread_msgs.streams); - _.each(unread_msgs.mentions, message_id => exports.unread_mentions_counter.add(message_id)); - _.each(unread_msgs.huddles, function (obj) { - _.each(obj.unread_message_ids, message_id => unread_messages.add(message_id)); - }); - _.each(unread_msgs.pms, function (obj) { - _.each(obj.unread_message_ids, message_id => unread_messages.add(message_id)); - }); - _.each(unread_msgs.streams, function (obj) { - _.each(obj.unread_message_ids, message_id => unread_messages.add(message_id)); - }); - _.each(unread_msgs.mentions, message_id => unread_messages.add(message_id)); + for (const message_id of unread_msgs.mentions) { + exports.unread_mentions_counter.add(message_id); + } + + for (const obj of unread_msgs.huddles) { + for (const message_id of obj.unread_message_ids) {unread_messages.add(message_id);} + } + + for (const obj of unread_msgs.pms) { + for (const message_id of obj.unread_message_ids) {unread_messages.add(message_id);} + } + + for (const obj of unread_msgs.streams) { + for (const message_id of obj.unread_message_ids) {unread_messages.add(message_id);} + } + + for (const message_id of unread_msgs.mentions) {unread_messages.add(message_id);} }; window.unread = exports; diff --git a/static/js/unread_ops.js b/static/js/unread_ops.js index 408e7ec9f6..c2aaf54191 100644 --- a/static/js/unread_ops.js +++ b/static/js/unread_ops.js @@ -32,7 +32,7 @@ exports.process_read_messages_event = function (message_ids) { return; } - _.each(message_ids, function (message_id) { + for (const message_id of message_ids) { if (current_msg_list === message_list.narrowed) { // I'm not sure this entirely makes sense for all server // notifications. @@ -46,7 +46,7 @@ exports.process_read_messages_event = function (message_ids) { if (message) { process_newly_read_message(message, options); } - }); + } unread_ui.update_unread_counts(); }; @@ -63,14 +63,14 @@ exports.notify_server_messages_read = function (messages, options) { message_flags.send_read(messages); - _.each(messages, function (message) { + for (const message of messages) { if (current_msg_list === message_list.narrowed) { unread.set_messages_read_in_narrow(true); } unread.mark_as_read(message.id); process_newly_read_message(message, options); - }); + } unread_ui.update_unread_counts(); }; diff --git a/static/js/user_groups.js b/static/js/user_groups.js index 0ccacdbfdc..46793609d4 100644 --- a/static/js/user_groups.js +++ b/static/js/user_groups.js @@ -71,22 +71,24 @@ exports.is_member_of = function (user_group_id, user_id) { exports.add_members = function (user_group_id, user_ids) { const user_group = user_group_by_id_dict.get(user_group_id); - _.each(user_ids, function (user_id) { + + for (const user_id of user_ids) { user_group.members.add(user_id); - }); + } }; exports.remove_members = function (user_group_id, user_ids) { const user_group = user_group_by_id_dict.get(user_group_id); - _.each(user_ids, function (user_id) { + + for (const user_id of user_ids) { user_group.members.delete(user_id); - }); + } }; exports.initialize = function () { - _.each(page_params.realm_user_groups, function (user_group) { + for (const user_group of page_params.realm_user_groups) { exports.add(user_group); - }); + } delete page_params.realm_user_groups; // We are the only consumer of this. }; diff --git a/static/js/vdom.js b/static/js/vdom.js index 2b37dc5858..b211372747 100644 --- a/static/js/vdom.js +++ b/static/js/vdom.js @@ -157,14 +157,14 @@ exports.update = (replace_content, find, new_dom, old_dom) => { const child_elems = find().children(); - _.each(new_opts.keyed_nodes, (new_node, i) => { + for (const [i, new_node] of new_opts.keyed_nodes.entries()) { const old_node = old_opts.keyed_nodes[i]; if (new_node.eq(old_node)) { - return; + continue; } const rendered_dom = new_node.render(); child_elems.eq(i).replaceWith(rendered_dom); - }); + } exports.update_attrs( find(), diff --git a/static/js/zform.js b/static/js/zform.js index a8b98e11bf..f6150672b9 100644 --- a/static/js/zform.js +++ b/static/js/zform.js @@ -58,9 +58,9 @@ exports.activate = function (opts) { // Assign idx values to each of our choices so that // our template can create data-idx values for our // JS code to use later. - _.each(data.choices, function (choice, idx) { + for (const [idx, choice] of data.choices.entries()) { choice.idx = idx; - }); + } const html = render_widgets_zform_choices(data); const elem = $(html); diff --git a/tools/check-openapi b/tools/check-openapi index ac48bc1a38..b2ae6d77c5 100755 --- a/tools/check-openapi +++ b/tools/check-openapi @@ -1,13 +1,12 @@ #!/usr/bin/env node const SwaggerParser = require('swagger-parser'); -const _ = require('underscore'); function check_duplicate_operationids(file, api) { const operation_ids = []; - _.each(api.paths, function (endpoint) { - _.each(endpoint, function (value) { + for (const endpoint of api.paths) { + for (const value of endpoint) { const operation_id = value.operationId; if (operation_id !== undefined) { if (operation_ids.indexOf(operation_id) >= 0) { @@ -18,8 +17,8 @@ function check_duplicate_operationids(file, api) { operation_ids.push(operation_id); } } - }); - }); + } + } } function validate_swagger(file) {