diff --git a/frontend_tests/node_tests/list_render.js b/frontend_tests/node_tests/list_render.js
index 145e86ea58..93c30890a5 100644
--- a/frontend_tests/node_tests/list_render.js
+++ b/frontend_tests/node_tests/list_render.js
@@ -1,4 +1,3 @@
-zrequire('scroll_util');
zrequire('list_render');
// We need these stubs to get by instanceof checks.
@@ -10,6 +9,7 @@ function Element() {
return { };
}
set_global('Element', Element);
+set_global('ui', {});
// We only need very simple jQuery wrappers for when the
// "real" code wraps html or sets up click handlers.
@@ -54,14 +54,8 @@ function make_container() {
return container;
}
-function make_scroll_container(container) {
+function make_scroll_container() {
const scroll_container = {};
- scroll_container.is = () => false;
- scroll_container.length = () => 1;
- scroll_container.css = (prop) => {
- assert.equal(prop, 'max-height');
- return 100;
- };
scroll_container.cleared = false;
@@ -79,8 +73,6 @@ function make_scroll_container(container) {
scroll_container.cleared = true;
};
- container.parent = () => scroll_container;
-
return scroll_container;
}
@@ -147,16 +139,23 @@ function div(item) {
run_test('scrolling', () => {
const container = make_container();
- const scroll_container = make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const items = [];
+ let get_scroll_element_called = false;
+ ui.get_scroll_element = (element) => {
+ get_scroll_element_called = true;
+ return element;
+ };
+
for (let i = 0; i < 200; i += 1) {
items.push('item ' + i);
}
const opts = {
modifier: (item) => item,
+ simplebar_container: scroll_container,
};
container.html = (html) => { assert.equal(html, ''); };
@@ -166,6 +165,7 @@ run_test('scrolling', () => {
container.appended_data.html(),
items.slice(0, 80).join(''),
);
+ assert.equal(get_scroll_element_called, true);
// Set up our fake geometry so it forces a scroll action.
scroll_container.scrollTop = 180;
@@ -183,7 +183,7 @@ run_test('scrolling', () => {
run_test('filtering', () => {
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const search_input = make_search_input();
@@ -202,6 +202,7 @@ run_test('filtering', () => {
predicate: (item, value) => item.includes(value),
},
modifier: (item) => div(item),
+ simplebar_container: scroll_container,
};
container.html = (html) => { assert.equal(html, ''); };
@@ -246,12 +247,13 @@ run_test('filtering', () => {
run_test('no filtering', () => {
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
container.html = () => {};
// Opts does not require a filter key.
const opts = {
modifier: (item) => div(item),
+ simplebar_container: scroll_container,
};
const widget = list_render.create(container, ['apple', 'banana'], opts);
widget.render();
@@ -321,7 +323,7 @@ run_test('wire up filter element', () => {
];
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const filter_element = make_filter_element();
// We don't care about what gets drawn initially.
@@ -333,6 +335,7 @@ run_test('wire up filter element', () => {
element: filter_element,
},
modifier: (s) => '(' + s + ')',
+ simplebar_container: scroll_container,
};
list_render.create(container, lst, opts);
@@ -345,7 +348,7 @@ run_test('wire up filter element', () => {
run_test('sorting', () => {
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const sort_container = make_sort_container();
let cleared;
@@ -369,6 +372,7 @@ run_test('sorting', () => {
filter: {
predicate: () => true,
},
+ simplebar_container: scroll_container,
};
function html_for(people) {
@@ -476,7 +480,7 @@ run_test('sorting', () => {
run_test('custom sort', () => {
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
container.html = () => {};
const n42 = {x: 6, y: 7};
@@ -501,6 +505,7 @@ run_test('custom sort', () => {
x_value: sort_by_x,
},
init_sort: sort_by_product,
+ simplebar_container: scroll_container,
});
assert.deepEqual(
@@ -530,7 +535,7 @@ run_test('custom sort', () => {
run_test('clear_event_handlers', () => {
const container = make_container();
- const scroll_container = make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const sort_container = make_sort_container();
const filter_element = make_filter_element();
@@ -546,6 +551,7 @@ run_test('clear_event_handlers', () => {
element: filter_element,
predicate: () => true,
},
+ simplebar_container: scroll_container,
};
// Create it the first time.
@@ -565,15 +571,22 @@ run_test('errors', () => {
// We don't care about actual data for this test.
const list = 'stub';
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
blueslip.expect('error', 'Need opts to create widget.');
list_render.create(container, list);
blueslip.reset();
+ blueslip.expect('error', 'simplebar_container is missing.');
+ list_render.create(container, list, {
+ modifier: 'hello world',
+ });
+ blueslip.reset();
+
blueslip.expect('error', 'get_item should be a function');
list_render.create(container, list, {
get_item: 'not a function',
+ simplebar_container: scroll_container,
});
blueslip.reset();
@@ -582,6 +595,7 @@ run_test('errors', () => {
filter: {
predicate: 'wrong type',
},
+ simplebar_container: scroll_container,
});
blueslip.reset();
@@ -591,6 +605,7 @@ run_test('errors', () => {
filterer: () => true,
predicate: () => true,
},
+ simplebar_container: scroll_container,
});
blueslip.reset();
@@ -598,6 +613,7 @@ run_test('errors', () => {
list_render.create(container, list, {
filter: {
},
+ simplebar_container: scroll_container,
});
blueslip.reset();
@@ -605,6 +621,7 @@ run_test('errors', () => {
blueslip.expect('error', 'List item is not a string: 999');
list_render.create(container, list, {
modifier: () => 999,
+ simplebar_container: scroll_container,
});
blueslip.reset();
});
@@ -633,7 +650,7 @@ run_test('sort helpers', () => {
run_test('replace_list_data w/filter update', () => {
const container = make_container();
- make_scroll_container(container);
+ const scroll_container = make_scroll_container();
container.html = () => {};
const list = [1, 2, 3, 4];
@@ -648,6 +665,7 @@ run_test('replace_list_data w/filter update', () => {
num_updates += 1;
},
},
+ simplebar_container: scroll_container,
});
assert.equal(num_updates, 0);
@@ -722,7 +740,7 @@ run_test('opts.get_item', () => {
run_test('render item', () => {
const container = make_container();
- const scroll_container = make_scroll_container(container);
+ const scroll_container = make_scroll_container();
const INITIAL_RENDER_COUNT = 80; // Keep this in sync with the actual code.
container.html = () => {};
let called = false;
@@ -758,6 +776,7 @@ run_test('render item', () => {
modifier: (item) => `
${item.text}
\n`,
get_item: get_item,
html_selector: (item) => `tr[data-item='${item}']`,
+ simplebar_container: scroll_container,
});
const item = INITIAL_RENDER_COUNT - 1;
@@ -786,6 +805,7 @@ run_test('render item', () => {
modifier: (item) => `${item.text}
\n`,
get_item: get_item,
html_selector: 'hello world',
+ simplebar_container: scroll_container,
});
blueslip.reset();
@@ -797,6 +817,7 @@ run_test('render item', () => {
get_item_called = true;
return item;
},
+ simplebar_container: scroll_container,
});
get_item_called = false;
widget_2.render_item(item);
@@ -809,6 +830,7 @@ run_test('render item', () => {
modifier: (item) => rendering_item ? undefined : `${item}\n`,
get_item: get_item,
html_selector: (item) => `tr[data-item='${item}']`,
+ simplebar_container: scroll_container,
});
// Once we have initially rendered the widget, change the
// behavior of the modifier function.
diff --git a/frontend_tests/node_tests/scroll_util.js b/frontend_tests/node_tests/scroll_util.js
index 782025203a..591ef8af2d 100644
--- a/frontend_tests/node_tests/scroll_util.js
+++ b/frontend_tests/node_tests/scroll_util.js
@@ -89,21 +89,3 @@ run_test('scroll_element_into_container', () => {
scroll_util.scroll_element_into_container(elem2, container);
assert.equal(container.scrollTop(), 250 - 100 + 3 + 15);
});
-
-run_test('get_list_scrolling_container error', () => {
- const body = {
- length: 1,
- is: (sel) => {
- assert.equal(sel, 'body, html');
- return true;
- },
- };
-
- blueslip.expect(
- 'error',
- "Please wrap lists in an element with " +
- "'max-height' attribute.",
- );
-
- scroll_util.get_list_scrolling_container(body);
-});
diff --git a/static/js/attachments_ui.js b/static/js/attachments_ui.js
index 6f00820685..75483e22b8 100644
--- a/static/js/attachments_ui.js
+++ b/static/js/attachments_ui.js
@@ -96,6 +96,7 @@ function render_attachments_ui() {
sort_fields: {
mentioned_in: sort_mentioned_in,
},
+ simplebar_container: $('#attachments-settings .progressive-table-wrapper'),
});
ui.reset_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
diff --git a/static/js/dropdown_list_widget.js b/static/js/dropdown_list_widget.js
index bf7862f6f0..aa7e2d0159 100644
--- a/static/js/dropdown_list_widget.js
+++ b/static/js/dropdown_list_widget.js
@@ -78,6 +78,7 @@ const DropdownListWidget = function (opts) {
return item.name.toLowerCase().includes(value);
},
},
+ simplebar_container: $(`#${opts.container_id} .dropdown-list-wrapper`),
});
$(`#${opts.container_id} .dropdown-search`).click((e) => {
e.stopPropagation();
diff --git a/static/js/list_render.js b/static/js/list_render.js
index 1246ea7477..014b9323e1 100644
--- a/static/js/list_render.js
+++ b/static/js/list_render.js
@@ -17,6 +17,10 @@ exports.validate_opts = (opts) => {
blueslip.error('html_selector should be a function.');
return false;
}
+ if (!opts.simplebar_container) {
+ blueslip.error('simplebar_container is missing.');
+ return false;
+ }
return true;
};
@@ -264,7 +268,7 @@ exports.create = function ($container, list, opts) {
};
widget.set_up_event_handlers = function () {
- meta.scroll_container = scroll_util.get_list_scrolling_container($container);
+ meta.scroll_container = ui.get_scroll_element(opts.simplebar_container);
// on scroll of the nearest scrolling container, if it hits the bottom
// of the container then fetch a new block of items and render them.
diff --git a/static/js/muting_ui.js b/static/js/muting_ui.js
index 6eabf500ea..9bfac827d3 100644
--- a/static/js/muting_ui.js
+++ b/static/js/muting_ui.js
@@ -90,6 +90,7 @@ exports.set_up_muted_topics_ui = function () {
},
},
parent_container: $('#muted-topic-settings'),
+ simplebar_container: $('#muted-topic-settings .progressive-table-wrapper'),
});
};
diff --git a/static/js/recent_topics.js b/static/js/recent_topics.js
index 4c722fd446..9f1820467e 100644
--- a/static/js/recent_topics.js
+++ b/static/js/recent_topics.js
@@ -419,6 +419,7 @@ exports.complete_rerender = function () {
topic_sort: topic_sort,
},
html_selector: get_topic_row,
+ simplebar_container: $('#recent_topics_table .table_fix_head'),
});
revive_current_focus();
};
diff --git a/static/js/scroll_util.js b/static/js/scroll_util.js
index 341c57c9b8..37cdd9f236 100644
--- a/static/js/scroll_util.js
+++ b/static/js/scroll_util.js
@@ -1,30 +1,3 @@
-exports.get_list_scrolling_container = function (container) {
- /*
- This is used for list widgets that don't
- have SimpleBar (in contrast to, say,
- ui.get_scroll_element().
- */
-
- let nearestScrollingContainer = container;
-
- while (nearestScrollingContainer.length) {
- if (nearestScrollingContainer.is("body, html")) {
- blueslip.error(
- "Please wrap lists in an element with " +
- "'max-height' attribute.");
- break;
- }
-
- if (nearestScrollingContainer.css("max-height") !== "none") {
- break;
- }
-
- nearestScrollingContainer = nearestScrollingContainer.parent();
- }
-
- return nearestScrollingContainer;
-};
-
exports.scroll_delta = function (opts) {
const elem_top = opts.elem_top;
const container_height = opts.container_height;
diff --git a/static/js/settings_emoji.js b/static/js/settings_emoji.js
index cbdeb28a0a..1bfd930000 100644
--- a/static/js/settings_emoji.js
+++ b/static/js/settings_emoji.js
@@ -106,6 +106,7 @@ exports.populate_emoji = function (emoji_data) {
author_full_name: sort_author_full_name,
},
init_sort: ['alphabetic', 'name'],
+ simplebar_container: $('#emoji-settings .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_emoji_loading_indicator'));
diff --git a/static/js/settings_exports.js b/static/js/settings_exports.js
index 1113771f85..7f90a2f798 100644
--- a/static/js/settings_exports.js
+++ b/static/js/settings_exports.js
@@ -72,6 +72,7 @@ exports.populate_exports_table = function (exports) {
sort_fields: {
user: sort_user,
},
+ simplebar_container: $('#data-exports .progressive-table-wrapper'),
});
const spinner = $('.export_row .export_url_spinner');
diff --git a/static/js/settings_invites.js b/static/js/settings_invites.js
index 13762e9458..7690b4853a 100644
--- a/static/js/settings_invites.js
+++ b/static/js/settings_invites.js
@@ -68,6 +68,7 @@ function populate_invites(invites_data) {
sort_fields: {
invitee: sort_invitee,
},
+ simplebar_container: $('#admin-invites-list .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_invites_loading_indicator'));
diff --git a/static/js/settings_linkifiers.js b/static/js/settings_linkifiers.js
index a12325b495..48aee7a56b 100644
--- a/static/js/settings_linkifiers.js
+++ b/static/js/settings_linkifiers.js
@@ -65,6 +65,7 @@ exports.populate_filters = function (filters_data) {
pattern: sort_pattern,
url: sort_url,
},
+ simplebar_container: $('#filter-settings .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_filters_loading_indicator'));
diff --git a/static/js/settings_streams.js b/static/js/settings_streams.js
index 77521a676c..fc771b892b 100644
--- a/static/js/settings_streams.js
+++ b/static/js/settings_streams.js
@@ -42,6 +42,7 @@ exports.build_default_stream_table = function () {
},
parent_container: $("#admin-default-streams-list").expectOne(),
init_sort: ['alphabetic', 'name'],
+ simplebar_container: $('#admin-default-streams-list .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_default_streams_loading_indicator'));
diff --git a/static/js/settings_users.js b/static/js/settings_users.js
index cfbb9315e5..023230729d 100644
--- a/static/js/settings_users.js
+++ b/static/js/settings_users.js
@@ -271,6 +271,7 @@ section.bots.create_table = () => {
email: sort_bot_email,
bot_owner: sort_bot_owner,
},
+ simplebar_container: $('#admin-bot-list .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_bots_loading_indicator'));
@@ -298,6 +299,7 @@ section.active.create_table = (active_users) => {
last_active: sort_last_active,
role: sort_role,
},
+ simplebar_container: $('#admin-user-list .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_users_loading_indicator'));
@@ -324,6 +326,7 @@ section.deactivated.create_table = (deactivated_users) => {
email: sort_email,
role: sort_role,
},
+ simplebar_container: $('#admin-deactivated-users-list .progressive-table-wrapper'),
});
loading.destroy_indicator($('#admin_page_deactivated_users_loading_indicator'));
diff --git a/static/js/stream_edit.js b/static/js/stream_edit.js
index f128baca4d..b7de6f84ac 100644
--- a/static/js/stream_edit.js
+++ b/static/js/stream_edit.js
@@ -320,6 +320,7 @@ function show_subscription_settings(sub_row) {
}
},
},
+ simplebar_container: $('.subscriber_list_container'),
});
user_pill.set_up_typeahead_on_pills(sub_settings.find('.input'),