list_widget: Rename unsafe modifier parameter to modifier_html.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-09-15 15:03:52 -07:00 committed by Tim Abbott
parent a4e0abb216
commit 88e9320fa5
23 changed files with 55 additions and 55 deletions

View File

@ -24,7 +24,7 @@ export function rerender_alert_words_ui() {
ListWidget.create($word_list, words, { ListWidget.create($word_list, words, {
name: "alert-words-list", name: "alert-words-list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(alert_word) { modifier_html(alert_word) {
return render_alert_word_settings_item({alert_word}); return render_alert_word_settings_item({alert_word});
}, },
$parent_container: $("#alert-word-settings"), $parent_container: $("#alert-word-settings"),

View File

@ -134,7 +134,7 @@ function render_attachments_ui(): void {
ListWidget.create<Attachment>($uploaded_files_table, attachments, { ListWidget.create<Attachment>($uploaded_files_table, attachments, {
name: "uploaded-files-list", name: "uploaded-files-list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(attachment) { modifier_html(attachment) {
return render_uploaded_files_list({attachment}); return render_uploaded_files_list({attachment});
}, },
filter: { filter: {

View File

@ -120,7 +120,7 @@ export class DropdownWidget {
this.list_widget = ListWidget.create($dropdown_list_body, this.get_options(), { this.list_widget = ListWidget.create($dropdown_list_body, this.get_options(), {
name: `${CSS.escape(this.widget_name)}-list-widget`, name: `${CSS.escape(this.widget_name)}-list-widget`,
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
return render_dropdown_list({item}); return render_dropdown_list({item});
}, },
filter: { filter: {

View File

@ -36,7 +36,7 @@ type ListWidgetFilterOpts<Item = unknown> = {
type ListWidgetOpts<Key = unknown, Item = Key> = { type ListWidgetOpts<Key = unknown, Item = Key> = {
name?: string; name?: string;
get_item: (key: Key) => Item; get_item: (key: Key) => Item;
modifier: (item: Item, filter_value: string) => string; modifier_html: (item: Item, filter_value: string) => string;
init_sort?: string | SortingFunction<Item>; init_sort?: string | SortingFunction<Item>;
initially_descending_sort?: boolean; initially_descending_sort?: boolean;
html_selector?: (item: Item) => JQuery; html_selector?: (item: Item) => JQuery;
@ -256,16 +256,16 @@ export function create<Key = unknown, Item = Key>(
let html = ""; let html = "";
for (const item of slice) { for (const item of slice) {
const s = opts.modifier(item, meta.filter_value); const item_html = opts.modifier_html(item, meta.filter_value);
if (typeof s !== "string") { if (typeof item_html !== "string") {
blueslip.error("List item is not a string", {item: s}); blueslip.error("List item is not a string", {item_html});
continue; continue;
} }
// append the HTML or nothing if corrupt (null, undef, etc.). // append the HTML or nothing if corrupt (null, undef, etc.).
if (s) { if (item_html) {
html += s; html += item_html;
} }
} }
@ -293,7 +293,7 @@ export function create<Key = unknown, Item = Key>(
return; return;
} }
const html = opts.modifier(item, meta.filter_value); const html = opts.modifier_html(item, meta.filter_value);
if (typeof html !== "string") { if (typeof html !== "string") {
blueslip.error("List item is not a string", {item: html}); blueslip.error("List item is not a string", {item: html});
return; return;
@ -432,7 +432,7 @@ export function create<Key = unknown, Item = Key>(
"Please specify modifier and html_selector when creating the widget.", "Please specify modifier and html_selector when creating the widget.",
); );
} }
const rendered_row = opts.modifier(item, meta.filter_value); const rendered_row = opts.modifier_html(item, meta.filter_value);
if (insert_index === meta.filtered_list.length - 1) { if (insert_index === meta.filtered_list.length - 1) {
const $target_row = opts.html_selector!(meta.filtered_list[insert_index - 1]); const $target_row = opts.html_selector!(meta.filtered_list[insert_index - 1]);
$target_row.after(rendered_row); $target_row.after(rendered_row);

View File

@ -883,7 +883,7 @@ export function complete_rerender() {
name: "recent_view_table", name: "recent_view_table",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
$parent_container: $("#recent_view_table"), $parent_container: $("#recent_view_table"),
modifier(item) { modifier_html(item) {
return render_recent_view_row(format_conversation(item)); return render_recent_view_row(format_conversation(item));
}, },
filter: { filter: {

View File

@ -121,7 +121,7 @@ export function populate_emoji(): void {
ListWidget.create<ServerEmoji>($emoji_table, Object.values(emoji_data), { ListWidget.create<ServerEmoji>($emoji_table, Object.values(emoji_data), {
name: "emoji_list", name: "emoji_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
if (item.deactivated !== true) { if (item.deactivated !== true) {
return render_admin_emoji_list({ return render_admin_emoji_list({
emoji: { emoji: {

View File

@ -42,7 +42,7 @@ export function populate_exports_table(exports) {
ListWidget.create($exports_table, Object.values(exports), { ListWidget.create($exports_table, Object.values(exports), {
name: "admin_exports_list", name: "admin_exports_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(data) { modifier_html(data) {
let failed_timestamp = data.failed_timestamp; let failed_timestamp = data.failed_timestamp;
let deleted_timestamp = data.deleted_timestamp; let deleted_timestamp = data.deleted_timestamp;

View File

@ -62,7 +62,7 @@ function populate_invites(invites_data) {
ListWidget.create($invites_table, invites_data.invites, { ListWidget.create($invites_table, invites_data.invites, {
name: "admin_invites_list", name: "admin_invites_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
item.invited_absolute_time = timerender.absolute_time(item.invited * 1000); item.invited_absolute_time = timerender.absolute_time(item.invited * 1000);
if (item.expiry_date !== null) { if (item.expiry_date !== null) {
item.expiry_date_absolute_time = timerender.absolute_time(item.expiry_date * 1000); item.expiry_date_absolute_time = timerender.absolute_time(item.expiry_date * 1000);

View File

@ -133,7 +133,7 @@ export function populate_linkifiers(linkifiers_data) {
ListWidget.create($linkifiers_table, linkifiers_data, { ListWidget.create($linkifiers_table, linkifiers_data, {
name: "linkifiers_list", name: "linkifiers_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(linkifier, filter_value) { modifier_html(linkifier, filter_value) {
return render_admin_linkifier_list({ return render_admin_linkifier_list({
linkifier: { linkifier: {
pattern: linkifier.pattern, pattern: linkifier.pattern,

View File

@ -22,7 +22,7 @@ export function populate_list() {
ListWidget.create($muted_users_table, all_muted_users, { ListWidget.create($muted_users_table, all_muted_users, {
name: "muted-users-list", name: "muted-users-list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(muted_user) { modifier_html(muted_user) {
return render_muted_user_ui_row({muted_user}); return render_muted_user_ui_row({muted_user});
}, },
filter: { filter: {

View File

@ -36,7 +36,7 @@ export function populate_playgrounds(playgrounds_data) {
ListWidget.create($playgrounds_table, playgrounds_data, { ListWidget.create($playgrounds_table, playgrounds_data, {
name: "playgrounds_list", name: "playgrounds_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(playground) { modifier_html(playground) {
return render_admin_playground_list({ return render_admin_playground_list({
playground: { playground: {
playground_name: playground.name, playground_name: playground.name,

View File

@ -105,7 +105,7 @@ export function build_default_stream_table() {
ListWidget.create($table, subs, { ListWidget.create($table, subs, {
name: "default_streams_list", name: "default_streams_list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
return render_admin_default_streams_list({ return render_admin_default_streams_list({
stream: item, stream: item,
can_modify: page_params.is_admin, can_modify: page_params.is_admin,

View File

@ -27,7 +27,7 @@ export function populate_list() {
ListWidget.create($user_topics_table, all_user_topics, { ListWidget.create($user_topics_table, all_user_topics, {
name: "user-topics-list", name: "user-topics-list",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(user_topic) { modifier_html(user_topic) {
const context = { const context = {
user_topic, user_topic,
user_topic_visibility_policy_values: user_topic_visibility_policy_values:

View File

@ -308,7 +308,7 @@ section.bots.create_table = () => {
bot_list_widget = ListWidget.create($bots_table, bot_user_ids, { bot_list_widget = ListWidget.create($bots_table, bot_user_ids, {
name: "admin_bot_list", name: "admin_bot_list",
get_item: bot_info, get_item: bot_info,
modifier: render_admin_user_list, modifier_html: render_admin_user_list,
html_selector: (item) => $(`tr[data-user-id='${CSS.escape(item.user_id)}']`), html_selector: (item) => $(`tr[data-user-id='${CSS.escape(item.user_id)}']`),
filter: { filter: {
$element: $bots_table.closest(".settings-section").find(".search"), $element: $bots_table.closest(".settings-section").find(".search"),
@ -343,7 +343,7 @@ section.active.create_table = (active_users) => {
ListWidget.create($users_table, active_users, { ListWidget.create($users_table, active_users, {
name: "users_table_list", name: "users_table_list",
get_item: people.get_by_user_id, get_item: people.get_by_user_id,
modifier(item) { modifier_html(item) {
const info = human_info(item); const info = human_info(item);
return render_admin_user_list(info); return render_admin_user_list(info);
}, },
@ -373,7 +373,7 @@ section.deactivated.create_table = (deactivated_users) => {
ListWidget.create($deactivated_users_table, deactivated_users, { ListWidget.create($deactivated_users_table, deactivated_users, {
name: "deactivated_users_table_list", name: "deactivated_users_table_list",
get_item: people.get_by_user_id, get_item: people.get_by_user_id,
modifier(item) { modifier_html(item) {
const info = human_info(item); const info = human_info(item);
return render_admin_user_list(info); return render_admin_user_list(info);
}, },

View File

@ -86,7 +86,7 @@ export function build_widgets() {
name: "new_stream_add_users", name: "new_stream_add_users",
get_item: people.get_by_user_id, get_item: people.get_by_user_id,
$parent_container: $add_people_container, $parent_container: $add_people_container,
modifier(user) { modifier_html(user) {
const item = { const item = {
email: user.delivery_email, email: user.delivery_email,
user_id: user.user_id, user_id: user.user_id,

View File

@ -113,7 +113,7 @@ function make_list_widget({$parent_container, name, user_ids, user_can_remove_su
return ListWidget.create($list_container, users, { return ListWidget.create($list_container, users, {
name, name,
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
return format_member_list_elem(item, user_can_remove_subscribers); return format_member_list_elem(item, user_can_remove_subscribers);
}, },
filter: { filter: {

View File

@ -99,7 +99,7 @@ export function build_widgets() {
id: settings_users.sort_user_id, id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]), ...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
}, },
modifier(user) { modifier_html(user) {
const item = { const item = {
email: user.delivery_email, email: user.delivery_email,
user_id: user.user_id, user_id: user.user_id,

View File

@ -73,7 +73,7 @@ function make_list_widget({$parent_container, name, user_ids}) {
id: settings_users.sort_user_id, id: settings_users.sort_user_id,
...ListWidget.generic_sort_functions("alphabetic", ["full_name"]), ...ListWidget.generic_sort_functions("alphabetic", ["full_name"]),
}, },
modifier(item) { modifier_html(item) {
return format_member_list_elem(item); return format_member_list_elem(item);
}, },
filter: { filter: {

View File

@ -200,7 +200,7 @@ export function setup_page(callback) {
group_list_widget = ListWidget.create($container, user_groups_list, { group_list_widget = ListWidget.create($container, user_groups_list, {
name: "user-groups-overlay", name: "user-groups-overlay",
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
item.is_member = user_groups.is_direct_member_of( item.is_member = user_groups.is_direct_member_of(
people.my_current_user_id(), people.my_current_user_id(),
item.id, item.id,

View File

@ -133,7 +133,7 @@ export function get_user_unsub_streams() {
}); });
} }
function format_user_stream_list_item(stream, user) { function format_user_stream_list_item_html(stream, user) {
const show_unsubscribe_button = const show_unsubscribe_button =
people.can_admin_user(user) || stream_data.can_unsubscribe_others(stream); people.can_admin_user(user) || stream_data.can_unsubscribe_others(stream);
const show_private_stream_unsub_tooltip = const show_private_stream_unsub_tooltip =
@ -150,7 +150,7 @@ function format_user_stream_list_item(stream, user) {
}); });
} }
function format_user_group_list_item(group) { function format_user_group_list_item_html(group) {
return render_user_group_list_item({ return render_user_group_list_item({
group_id: group.id, group_id: group.id,
name: group.name, name: group.name,
@ -164,8 +164,8 @@ function render_user_stream_list(streams, user) {
user_streams_list_widget = ListWidget.create($container, streams, { user_streams_list_widget = ListWidget.create($container, streams, {
name: `user-${user.user_id}-stream-list`, name: `user-${user.user_id}-stream-list`,
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
return format_user_stream_list_item(item, user); return format_user_stream_list_item_html(item, user);
}, },
filter: { filter: {
$element: $("#user-profile-streams-tab .stream-search"), $element: $("#user-profile-streams-tab .stream-search"),
@ -184,8 +184,8 @@ function render_user_group_list(groups, user) {
ListWidget.create($container, groups, { ListWidget.create($container, groups, {
name: `user-${user.user_id}-group-list`, name: `user-${user.user_id}-group-list`,
get_item: ListWidget.default_get_item, get_item: ListWidget.default_get_item,
modifier(item) { modifier_html(item) {
return format_user_group_list_item(item); return format_user_group_list_item_html(item);
}, },
$simplebar_container: $("#user-profile-modal .modal__body"), $simplebar_container: $("#user-profile-modal .modal__body"),
}); });

View File

@ -21,12 +21,12 @@ run_test("rerender_alert_words_ui", ({mock_template}) => {
let list_widget_create_called = false; let list_widget_create_called = false;
alert_words_ui.reset(); alert_words_ui.reset();
const ListWidget = mock_esm("../src/list_widget", { const ListWidget = mock_esm("../src/list_widget", {
modifier: noop, modifier_html: noop,
create(_container, words, opts) { create(_container, words, opts) {
const alert_words = []; const alert_words = [];
ListWidget.modifier = opts.modifier; ListWidget.modifier_html = opts.modifier_html;
for (const word of words) { for (const word of words) {
alert_words.push(opts.modifier(word)); alert_words.push(opts.modifier_html(word));
} }
list_widget_create_called = true; list_widget_create_called = true;
return alert_words; return alert_words;

View File

@ -157,7 +157,7 @@ run_test("scrolling", () => {
} }
const opts = { const opts = {
modifier: (item) => item, modifier_html: (item) => item,
get_item: (item) => item, get_item: (item) => item,
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
}; };
@ -206,7 +206,7 @@ run_test("not_scrolling", () => {
} }
const opts = { const opts = {
modifier: (item) => item, modifier_html: (item) => item,
get_item: (item) => item, get_item: (item) => item,
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
is_scroll_position_for_render: () => false, is_scroll_position_for_render: () => false,
@ -246,7 +246,7 @@ run_test("filtering", () => {
$element: $search_input, $element: $search_input,
predicate: (item, value) => item.includes(value), predicate: (item, value) => item.includes(value),
}, },
modifier(item, filter_value) { modifier_html(item, filter_value) {
last_filter_value = filter_value; last_filter_value = filter_value;
return div(item); return div(item);
}, },
@ -292,7 +292,7 @@ run_test("no filtering", () => {
let callback_called = false; let callback_called = false;
// Opts does not require a filter key. // Opts does not require a filter key.
const opts = { const opts = {
modifier: (item) => div(item), modifier_html: (item) => div(item),
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
callback_after_render() { callback_after_render() {
callback_called = true; callback_called = true;
@ -371,7 +371,7 @@ run_test("wire up filter element", () => {
filterer: (list, value) => list.filter((item) => item.toLowerCase().includes(value)), filterer: (list, value) => list.filter((item) => item.toLowerCase().includes(value)),
$element: $filter_element, $element: $filter_element,
}, },
modifier: (s) => "(" + s + ")", modifier_html: (s) => "(" + s + ")",
get_item: (item) => item, get_item: (item) => item,
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
}; };
@ -402,7 +402,7 @@ run_test("sorting", () => {
const opts = { const opts = {
name: "sorting-list", name: "sorting-list",
$parent_container: $sort_container, $parent_container: $sort_container,
modifier: (item) => div(item.name) + div(item.salary), modifier_html: (item) => div(item.name) + div(item.salary),
get_item: (item) => item, get_item: (item) => item,
filter: { filter: {
predicate: () => true, predicate: () => true,
@ -415,7 +415,7 @@ run_test("sorting", () => {
}; };
function html_for(people) { function html_for(people) {
return people.map((item) => opts.modifier(item)).join(""); return people.map((item) => opts.modifier_html(item)).join("");
} }
ListWidget.create($container, list, opts); ListWidget.create($container, list, opts);
@ -507,7 +507,7 @@ run_test("custom sort", () => {
ListWidget.create($container, list, { ListWidget.create($container, list, {
name: "custom-sort-list", name: "custom-sort-list",
modifier: (n) => "(" + n.x + ", " + n.y + ")", modifier_html: (n) => "(" + n.x + ", " + n.y + ")",
get_item: (item) => item, get_item: (item) => item,
sort_fields: { sort_fields: {
product: sort_by_product, product: sort_by_product,
@ -545,7 +545,7 @@ run_test("clear_event_handlers", () => {
const opts = { const opts = {
name: "list-we-create-twice", name: "list-we-create-twice",
$parent_container: $sort_container, $parent_container: $sort_container,
modifier() {}, modifier_html() {},
get_item() {}, get_item() {},
filter: { filter: {
$element: $filter_element, $element: $filter_element,
@ -598,7 +598,7 @@ run_test("replace_list_data w/filter update", () => {
ListWidget.create($container, list, { ListWidget.create($container, list, {
name: "replace-list", name: "replace-list",
modifier: (n) => "(" + n.toString() + ")", modifier_html: (n) => "(" + n.toString() + ")",
get_item: (item) => item, get_item: (item) => item,
filter: { filter: {
predicate: (n) => n % 2 === 0, predicate: (n) => n % 2 === 0,
@ -704,7 +704,7 @@ run_test("render item", () => {
const widget = ListWidget.create($container, list, { const widget = ListWidget.create($container, list, {
name: "replace-list", name: "replace-list",
modifier: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`, modifier_html: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`,
get_item, get_item,
html_selector: (item) => $(`tr[data-item='${item.value}']`), html_selector: (item) => $(`tr[data-item='${item.value}']`),
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
@ -741,7 +741,7 @@ run_test("render item", () => {
let get_item_called; let get_item_called;
const widget_2 = ListWidget.create($container, list, { const widget_2 = ListWidget.create($container, list, {
name: "replace-list", name: "replace-list",
modifier: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`, modifier_html: (item) => `<tr data-item=${item.value}>${item.text}</tr>\n`,
get_item(item) { get_item(item) {
get_item_called = true; get_item_called = true;
return item; return item;
@ -757,13 +757,13 @@ run_test("render item", () => {
let rendering_item = false; let rendering_item = false;
const widget_3 = ListWidget.create($container, list, { const widget_3 = ListWidget.create($container, list, {
name: "replace-list", name: "replace-list",
modifier: (item) => (rendering_item ? undefined : `${item}\n`), modifier_html: (item) => (rendering_item ? undefined : `${item}\n`),
get_item, get_item,
html_selector: (item) => $(`tr[data-item='${item}']`), html_selector: (item) => $(`tr[data-item='${item}']`),
$simplebar_container: $scroll_container, $simplebar_container: $scroll_container,
}); });
// Once we have initially rendered the widget, change the // Once we have initially rendered the widget, change the
// behavior of the modifier function. // behavior of the modifier_html function.
rendering_item = true; rendering_item = true;
blueslip.expect("error", "List item is not a string"); blueslip.expect("error", "List item is not a string");
widget_3.render_item(item); widget_3.render_item(item);
@ -829,7 +829,7 @@ run_test("Multiselect dropdown retain_selected_items", () => {
const widget = ListWidget.create($container, list, { const widget = ListWidget.create($container, list, {
name: "replace-list", name: "replace-list",
modifier: (item) => `<li data-value="${item.value}">${item.name}</li>\n`, modifier_html: (item) => `<li data-value="${item.value}">${item.name}</li>\n`,
get_item: (item) => item, get_item: (item) => item,
multiselect: { multiselect: {
selected_items: data, selected_items: data,

View File

@ -49,13 +49,13 @@ const all_visibility_policies = {
let expected_data_to_replace_in_list_widget; let expected_data_to_replace_in_list_widget;
const ListWidget = mock_esm("../src/list_widget", { const ListWidget = mock_esm("../src/list_widget", {
modifier: noop, modifier_html: noop,
generic_sort_functions: noop, generic_sort_functions: noop,
create(_container, mapped_topic_values, opts) { create(_container, mapped_topic_values, opts) {
const formatted_topics = []; const formatted_topics = [];
ListWidget.modifier = opts.modifier; ListWidget.modifier_html = opts.modifier_html;
for (const item of mapped_topic_values) { for (const item of mapped_topic_values) {
formatted_topics.push(opts.modifier(item)); formatted_topics.push(opts.modifier_html(item));
opts.filter.predicate(item); opts.filter.predicate(item);
} }
// Just for coverage, the mechanisms // Just for coverage, the mechanisms