list_render: Dedent 200+ lines of code.

This is all cosmetic.

Instead of:

    const.widget = {
        foo: function () = {
        },

        bar: function () {
        },
    };

We have:

    const widget = {};

    widget.foo = function () = {
    };

    widget.bar = function () {
    };
This commit is contained in:
Steve Howell 2020-04-11 11:52:38 +00:00 committed by Tim Abbott
parent 29b22da1ff
commit 42c2e9c429
1 changed files with 193 additions and 193 deletions

View File

@ -81,238 +81,238 @@ exports.create = function ($container, list, opts) {
}
exports.validate_filter(opts);
const widget = {
// Reads the provided list (in the scope directly above)
// and renders the next block of messages automatically
// into the specified container.
render: function (load_count) {
load_count = load_count || opts.load_count || DEFAULTS.LOAD_COUNT;
const widget = {};
// Stop once the offset reaches the length of the original list.
if (meta.offset >= meta.filtered_list.length) {
return;
// Reads the provided list (in the scope directly above)
// and renders the next block of messages automatically
// into the specified container.
widget.render = function (load_count) {
load_count = load_count || opts.load_count || DEFAULTS.LOAD_COUNT;
// Stop once the offset reaches the length of the original list.
if (meta.offset >= meta.filtered_list.length) {
return;
}
const slice = meta.filtered_list.slice(meta.offset, meta.offset + load_count);
const finish = blueslip.start_timing('list_render ' + opts.name);
let html = "";
for (const item of slice) {
let _item = opts.modifier(item);
// if valid jQuery selection, attempt to grab all elements within
// and string them together into a giant outerHTML fragment.
if (_item.constructor === jQuery) {
_item = (function ($nodes) {
let html = "";
$nodes.each(function () {
if (this.nodeType === 1) {
html += this.outerHTML;
}
});
return html;
}(_item));
}
const slice = meta.filtered_list.slice(meta.offset, meta.offset + load_count);
const finish = blueslip.start_timing('list_render ' + opts.name);
let html = "";
for (const item of slice) {
let _item = opts.modifier(item);
// if valid jQuery selection, attempt to grab all elements within
// and string them together into a giant outerHTML fragment.
if (_item.constructor === jQuery) {
_item = (function ($nodes) {
let html = "";
$nodes.each(function () {
if (this.nodeType === 1) {
html += this.outerHTML;
}
});
return html;
}(_item));
}
// if is a valid element, get the outerHTML.
if (_item instanceof Element) {
_item = _item.outerHTML;
}
// append the HTML or nothing if corrupt (null, undef, etc.).
html += _item || "";
// if is a valid element, get the outerHTML.
if (_item instanceof Element) {
_item = _item.outerHTML;
}
finish();
// append the HTML or nothing if corrupt (null, undef, etc.).
html += _item || "";
}
$container.append($(html));
meta.offset += load_count;
finish();
return this;
},
$container.append($(html));
meta.offset += load_count;
// Fills the container with an initial batch of items.
// Needs to be enough to exceed the max height, so that a
// scrollable area is created.
init: function () {
this.clear();
this.render(DEFAULTS.INITIAL_RENDER_COUNT);
return this;
},
return this;
};
filter: function (map_function) {
meta.filtered_list = meta.list(map_function);
},
// Fills the container with an initial batch of items.
// Needs to be enough to exceed the max height, so that a
// scrollable area is created.
widget.init = function () {
this.clear();
this.render(DEFAULTS.INITIAL_RENDER_COUNT);
return this;
};
// reset the data associated with a list. This is so that instead of
// initializing a new progressive list render instance, you can just
// update the data of an existing one.
data: function (...args) {
// if no args are provided then just return the existing data.
// this interface is similar to how many jQuery functions operate,
// where a call to the method without data returns the existing data.
if (args.length === 0) {
return meta.list;
}
const [data] = args;
widget.filter = function (map_function) {
meta.filtered_list = meta.list(map_function);
};
if (Array.isArray(data)) {
meta.list = data;
meta.filtered_list = data;
// reset the data associated with a list. This is so that instead of
// initializing a new progressive list render instance, you can just
// update the data of an existing one.
widget.data = function (...args) {
// if no args are provided then just return the existing data.
// this interface is similar to how many jQuery functions operate,
// where a call to the method without data returns the existing data.
if (args.length === 0) {
return meta.list;
}
const [data] = args;
if (opts.filter && opts.filter.element) {
const value = $(opts.filter.element).val().toLocaleLowerCase();
filter_list(value);
}
if (Array.isArray(data)) {
meta.list = data;
meta.filtered_list = data;
widget.clear();
return this;
if (opts.filter && opts.filter.element) {
const value = $(opts.filter.element).val().toLocaleLowerCase();
filter_list(value);
}
blueslip.warn("The data object provided to the progressive" +
" list render is invalid");
return this;
},
clear: function () {
$container.html("");
meta.offset = 0;
return this;
},
set_container: function ($new_container) {
if ($new_container) {
$container = $new_container;
}
widget.clear();
return this;
}
set_opts: function (new_opts) {
if (opts) {
opts = new_opts;
blueslip.warn("The data object provided to the progressive" +
" list render is invalid");
return this;
};
widget.clear = function () {
$container.html("");
meta.offset = 0;
return this;
};
widget.set_container = function ($new_container) {
if ($new_container) {
$container = $new_container;
}
return this;
};
widget.set_opts = function (new_opts) {
if (opts) {
opts = new_opts;
}
return this;
};
widget.reverse = function () {
meta.filtered_list.reverse();
widget.init();
return this;
};
// the sorting function is either the function or string that calls the
// function to sort the list by. The prop is used for generic functions
// that can be called to sort with a particular prop.
// the `map` will normalize the values with a function you provide to make
// it easier to sort with.
// `do_not_display` will signal to not update the DOM, likely because in
// the next function it will be updated in the DOM.
widget.sort = function (sorting_function, prop, do_not_display) {
meta.prop = prop;
if (typeof sorting_function === "function") {
meta.sorting_function = sorting_function;
} else if (typeof sorting_function === "string") {
if (typeof prop === "string") {
/* eslint-disable max-len */
meta.sorting_function = meta.generic_sorting_functions.get(sorting_function)(prop);
} else {
meta.sorting_function = meta.sorting_functions.get(sorting_function);
}
}
return this;
},
// we do not want to sort if we are just looking to reverse
// by calling with no sorting_function
if (meta.sorting_function) {
meta.filtered_list = meta.filtered_list.sort(meta.sorting_function);
}
reverse: function () {
meta.filtered_list.reverse();
if (!do_not_display) {
// clear and re-initialize the list with the newly filtered subset
// of items.
widget.init();
return this;
},
// the sorting function is either the function or string that calls the
// function to sort the list by. The prop is used for generic functions
// that can be called to sort with a particular prop.
if (opts.filter && opts.filter.onupdate) {
opts.filter.onupdate();
}
}
};
// the `map` will normalize the values with a function you provide to make
// it easier to sort with.
widget.add_sort_function = function (name, sorting_function) {
meta.sorting_functions.set(name, sorting_function);
};
// `do_not_display` will signal to not update the DOM, likely because in
// the next function it will be updated in the DOM.
sort: function (sorting_function, prop, do_not_display) {
meta.prop = prop;
// generic sorting functions are ones that will use a specified prop
// and perform a sort on it with the given sorting function.
widget.add_generic_sort_function = function (name, sorting_function) {
meta.generic_sorting_functions.set(name, sorting_function);
};
if (typeof sorting_function === "function") {
meta.sorting_function = sorting_function;
} else if (typeof sorting_function === "string") {
if (typeof prop === "string") {
/* eslint-disable max-len */
meta.sorting_function = meta.generic_sorting_functions.get(sorting_function)(prop);
} else {
meta.sorting_function = meta.sorting_functions.get(sorting_function);
}
widget.remove_sort = function () {
meta.sorting_function = false;
};
// this sets the events given the particular arguments assigned in
// the container and opts.
widget.__set_events = function () {
let $nearestScrollingContainer = $container;
while ($nearestScrollingContainer.length) {
if ($nearestScrollingContainer.is("body, html")) {
blueslip.warn("Please wrap progressive scrolling lists in an element with 'max-height' attribute. Error found in:\n" + blueslip.preview_node($container));
break;
}
// we do not want to sort if we are just looking to reverse
// by calling with no sorting_function
if (meta.sorting_function) {
meta.filtered_list = meta.filtered_list.sort(meta.sorting_function);
if ($nearestScrollingContainer.css("max-height") !== "none") {
break;
}
if (!do_not_display) {
$nearestScrollingContainer = $nearestScrollingContainer.parent();
}
// 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.
$nearestScrollingContainer.scroll(function () {
if (this.scrollHeight - (this.scrollTop + this.clientHeight) < 10) {
widget.render();
}
});
if (opts.parent_container) {
opts.parent_container.on("click", "[data-sort]", exports.handle_sort);
}
if (opts.filter && opts.filter.element) {
opts.filter.element.on(opts.filter.event || "input", function () {
const self = this;
const value = self.value.toLocaleLowerCase();
// run the sort algorithm that was used last, which is done
// by passing `undefined` -- which will make it use the params
// from the last sort.
// it will then also not run an update in the DOM (because we
// pass `true`), because it will update regardless below at
// `widget.init()`.
widget.sort(undefined, meta.prop, true);
filter_list(value);
// clear and re-initialize the list with the newly filtered subset
// of items.
widget.init();
if (opts.filter && opts.filter.onupdate) {
if (opts.filter.onupdate) {
opts.filter.onupdate();
}
}
},
add_sort_function: function (name, sorting_function) {
meta.sorting_functions.set(name, sorting_function);
},
// generic sorting functions are ones that will use a specified prop
// and perform a sort on it with the given sorting function.
add_generic_sort_function: function (name, sorting_function) {
meta.generic_sorting_functions.set(name, sorting_function);
},
remove_sort: function () {
meta.sorting_function = false;
},
// this sets the events given the particular arguments assigned in
// the container and opts.
__set_events: function () {
let $nearestScrollingContainer = $container;
while ($nearestScrollingContainer.length) {
if ($nearestScrollingContainer.is("body, html")) {
blueslip.warn("Please wrap progressive scrolling lists in an element with 'max-height' attribute. Error found in:\n" + blueslip.preview_node($container));
break;
}
if ($nearestScrollingContainer.css("max-height") !== "none") {
break;
}
$nearestScrollingContainer = $nearestScrollingContainer.parent();
}
// 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.
$nearestScrollingContainer.scroll(function () {
if (this.scrollHeight - (this.scrollTop + this.clientHeight) < 10) {
widget.render();
}
});
}
if (opts.parent_container) {
opts.parent_container.on("click", "[data-sort]", exports.handle_sort);
}
if (opts.filter && opts.filter.element) {
opts.filter.element.on(opts.filter.event || "input", function () {
const self = this;
const value = self.value.toLocaleLowerCase();
// run the sort algorithm that was used last, which is done
// by passing `undefined` -- which will make it use the params
// from the last sort.
// it will then also not run an update in the DOM (because we
// pass `true`), because it will update regardless below at
// `widget.init()`.
widget.sort(undefined, meta.prop, true);
filter_list(value);
// clear and re-initialize the list with the newly filtered subset
// of items.
widget.init();
if (opts.filter.onupdate) {
opts.filter.onupdate();
}
});
}
return this;
},
return this;
};
widget.__set_events();