<commit_before>var message_list = (function () {

var exports = {};

exports.narrowed = undefined;

exports.MessageList = function (opts) {
    if (opts.data) {
        this.muting_enabled = opts.data.muting_enabled;
        this.data = opts.data;
    } else {
        var filter = opts.filter;

        this.muting_enabled = opts.muting_enabled;
        this.data = new MessageListData({
            muting_enabled: this.muting_enabled,
            filter: filter,
        });
    }

    _.extend(opts, {
        collapse_messages: true,
    });

    var collapse_messages = opts.collapse_messages;
    var table_name = opts.table_name;
    this.view = new MessageListView(this, table_name, collapse_messages);
    this.fetch_status = FetchStatus();
    this.table_name = table_name;
    this.narrowed = this.table_name === "zfilt";
    this.num_appends = 0;

    return this;
};

exports.MessageList.prototype = {
    add_messages: function MessageList_add_messages(messages, opts) {
        var self = this;

        // This adds all messages to our data, but only returns
        // the currently viewable ones.
        var info = this.data.add_messages(messages);

        var top_messages = info.top_messages;
        var bottom_messages = info.bottom_messages;
        var interior_messages = info.interior_messages;

        if (interior_messages.length > 0) {
            self.view.rerender_the_whole_thing();
            return true;
        }
        if (top_messages.length > 0) {
            self.view.prepend(top_messages);
        }

        if (bottom_messages.length > 0) {
            self.append_to_view(bottom_messages, opts);
        }

        if (self === exports.narrowed && !self.empty()) {
            // If adding some new messages to the message tables caused
            // our current narrow to no longer be empty, hide the empty
            // feed placeholder text.
            narrow.hide_empty_narrow_message();
        }

        if (self === exports.narrowed && !self.empty() &&
            self.selected_id() === -1) {
            // And also select the newly arrived message.
            self.select_id(self.selected_id(), {then_scroll: true, use_closest: true});
        }
    },

    get: function (id) {
        return this.data.get(id);
    },

    num_items: function () {
        return this.data.num_items();
    },

    empty: function () {
        return this.data.empty();
    },

    first: function () {
        return this.data.first();
    },

    last: function () {
        return this.data.last();
    },

    prev: function () {
        return this.data.prev();
    },

    next: function () {
        return this.data.next();
    },

    is_at_end: function () {
        return this.data.is_at_end();
    },

    nth_most_recent_id: function (n) {
        return this.data.nth_most_recent_id(n);
    },

    is_search: function () {
        return this.data.is_search();
    },

    clear: function  MessageList_clear(opts) {
        opts = _.extend({clear_selected_id: true}, opts);

        this.data.clear();
        this.view.clear_rendering_state(true);

        if (opts.clear_selected_id) {
            this.data.clear_selected_id();
        }
    },

    selected_id: function () {
        return this.data.selected_id();
    },

    select_id: function MessageList_select_id(id, opts) {
        opts = _.extend({
            then_scroll: false,
            target_scroll_offset: undefined,
            use_closest: false,
            empty_ok: false,
            mark_read: true,
            force_rerender: false,
        }, opts, {
            id: id,
            msg_list: this,
            previously_selected: this.data.selected_id(),
        });

        function convert_id(str_id) {
            var id = parseFloat(str_id);
            if (isNaN(id)) {
                blueslip.fatal("Bad message id " + str_id);
            }
            return id;
        }

        id = convert_id(id);

        var closest_id = this.closest_id(id);

        var error_data;

        // The name "use_closest" option is a bit legacy.  We
        // are always gonna move to the closest visible id; the flag
        // just says whether we call blueslip.error or not.  The caller
        // sets use_closest to true when it expects us to move the
        // pointer as needed, so only generate an error if the flag is
        // false.
        if (!opts.use_closest && closest_id !== id) {
            error_data = {
                table_name: this.table_name,
                id: id,
                closest_id: closest_id,
            };
            blueslip.error("Selected message id not in MessageList",
                           error_data);
        }

        if (closest_id === -1 && !opts.empty_ok) {
            error_data = {
                table_name: this.table_name,
                id: id,
                items_length: this.data.num_items(),
            };
            blueslip.fatal("Cannot select id -1", error_data);
        }

        id = closest_id;
        opts.id = id;
        this.data.set_selected_id(id);

        if (opts.force_rerender) {
            this.rerender();
        } else if (!opts.from_rendering) {
            this.view.maybe_rerender();
        }

        $(document).trigger($.Event('message_selected.zulip', opts));
    },

    reselect_selected_id: function MessageList_select_closest_id() {
        this.select_id(this.data.selected_id(), {from_rendering: true});
    },

    selected_message: function MessageList_selected_message() {
        return this.get(this.data.selected_id());
    },

    selected_row: function MessageList_selected_row() {
        return this.get_row(this.data.selected_id());
    },

    closest_id: function (id) {
        return this.data.closest_id(id);
    },

    advance_past_messages: function (msg_ids) {
        return this.data.advance_past_messages(msg_ids);
    },

    selected_idx: function () {
        return this.data.selected_idx();
    },

    subscribed_bookend_content: function (stream_name) {
        return i18n.t("You subscribed to stream __stream__",
                      {stream: stream_name});
    },

    unsubscribed_bookend_content: function (stream_name) {
        return i18n.t("You unsubscribed from stream __stream__",
                      {stream: stream_name});
    },

    not_subscribed_bookend_content: function (stream_name) {
        return i18n.t("You are not subscribed to stream __stream__",
                      {stream: stream_name});
    },

    // Maintains a trailing bookend element explaining any changes in
    // your subscribed/unsubscribed status at the bottom of the
    // message list.
    update_trailing_bookend: function MessageList_update_trailing_bookend() {
        this.view.clear_trailing_bookend();
        if (!this.narrowed) {
            return;
        }
        var stream_name = narrow_state.stream();
        if (stream_name === undefined) {
            return;
        }
        var trailing_bookend_content;
        var show_button = true;
        var subscribed = stream_data.is_subscribed(stream_name);
        if (subscribed) {
            trailing_bookend_content = this.subscribed_bookend_content(stream_name);
        } else {
            if (!this.last_message_historical) {
                trailing_bookend_content = this.unsubscribed_bookend_content(stream_name);

                // For invite only streams or streams that no longer
                // exist, hide the resubscribe button
                // Hide button for guest users
                var sub = stream_data.get_sub(stream_name);
                if (sub !== undefined) {
                    show_button = !page_params.is_guest && !sub.invite_only;
                } else {
                    show_button = false;
                }
            } else {
                trailing_bookend_content = this.not_subscribed_bookend_content(stream_name);
            }
        }
        if (trailing_bookend_content !== undefined) {
            this.view.render_trailing_bookend(trailing_bookend_content, subscribed, show_button);
        }
    },

    unmuted_messages: function (messages) {
        return this.data.unmuted_messages(messages);
    },

    append: function MessageList_append(messages, opts) {
        var viewable_messages = this.data.append(messages);
        this.append_to_view(viewable_messages, opts);
    },

    append_to_view: function (messages, opts) {
        opts = _.extend({messages_are_new: false}, opts);

        this.num_appends += 1;
        this.view.append(messages, opts.messages_are_new);
    },

    remove_and_rerender: function MessageList_remove_and_rerender(messages) {
        this.data.remove(messages);
        this.rerender();
    },

    show_edit_message: function MessageList_show_edit_message(row, edit_obj) {
        row.find(".message_edit_form").empty().append(edit_obj.form);
        row.find(".message_content, .status-message").hide();
        row.find(".message_edit").css("display", "block");
        row.find(".message_edit_content").autosize();
    },

    hide_edit_message: function MessageList_hide_edit_message(row) {
        row.find(".message_content, .status-message").show();
        row.find(".message_edit").hide();
        row.trigger("mouseleave");<commit_msg>message_list: Hide the message control icons when editing.<commit_after>var message_list = (function () {

var exports = {};

exports.narrowed = undefined;

exports.MessageList = function (opts) {
    if (opts.data) {
        this.muting_enabled = opts.data.muting_enabled;
        this.data = opts.data;
    } else {
        var filter = opts.filter;

        this.muting_enabled = opts.muting_enabled;
        this.data = new MessageListData({
            muting_enabled: this.muting_enabled,
            filter: filter,
        });
    }

    _.extend(opts, {
        collapse_messages: true,
    });

    var collapse_messages = opts.collapse_messages;
    var table_name = opts.table_name;
    this.view = new MessageListView(this, table_name, collapse_messages);
    this.fetch_status = FetchStatus();
    this.table_name = table_name;
    this.narrowed = this.table_name === "zfilt";
    this.num_appends = 0;

    return this;
};

exports.MessageList.prototype = {
    add_messages: function MessageList_add_messages(messages, opts) {
        var self = this;

        // This adds all messages to our data, but only returns
        // the currently viewable ones.
        var info = this.data.add_messages(messages);

        var top_messages = info.top_messages;
        var bottom_messages = info.bottom_messages;
        var interior_messages = info.interior_messages;

        if (interior_messages.length > 0) {
            self.view.rerender_the_whole_thing();
            return true;
        }
        if (top_messages.length > 0) {
            self.view.prepend(top_messages);
        }

        if (bottom_messages.length > 0) {
            self.append_to_view(bottom_messages, opts);
        }

        if (self === exports.narrowed && !self.empty()) {
            // If adding some new messages to the message tables caused
            // our current narrow to no longer be empty, hide the empty
            // feed placeholder text.
            narrow.hide_empty_narrow_message();
        }

        if (self === exports.narrowed && !self.empty() &&
            self.selected_id() === -1) {
            // And also select the newly arrived message.
            self.select_id(self.selected_id(), {then_scroll: true, use_closest: true});
        }
    },

    get: function (id) {
        return this.data.get(id);
    },

    num_items: function () {
        return this.data.num_items();
    },

    empty: function () {
        return this.data.empty();
    },

    first: function () {
        return this.data.first();
    },

    last: function () {
        return this.data.last();
    },

    prev: function () {
        return this.data.prev();
    },

    next: function () {
        return this.data.next();
    },

    is_at_end: function () {
        return this.data.is_at_end();
    },

    nth_most_recent_id: function (n) {
        return this.data.nth_most_recent_id(n);
    },

    is_search: function () {
        return this.data.is_search();
    },

    clear: function  MessageList_clear(opts) {
        opts = _.extend({clear_selected_id: true}, opts);

        this.data.clear();
        this.view.clear_rendering_state(true);

        if (opts.clear_selected_id) {
            this.data.clear_selected_id();
        }
    },

    selected_id: function () {
        return this.data.selected_id();
    },

    select_id: function MessageList_select_id(id, opts) {
        opts = _.extend({
            then_scroll: false,
            target_scroll_offset: undefined,
            use_closest: false,
            empty_ok: false,
            mark_read: true,
            force_rerender: false,
        }, opts, {
            id: id,
            msg_list: this,
            previously_selected: this.data.selected_id(),
        });

        function convert_id(str_id) {
            var id = parseFloat(str_id);
            if (isNaN(id)) {
                blueslip.fatal("Bad message id " + str_id);
            }
            return id;
        }

        id = convert_id(id);

        var closest_id = this.closest_id(id);

        var error_data;

        // The name "use_closest" option is a bit legacy.  We
        // are always gonna move to the closest visible id; the flag
        // just says whether we call blueslip.error or not.  The caller
        // sets use_closest to true when it expects us to move the
        // pointer as needed, so only generate an error if the flag is
        // false.
        if (!opts.use_closest && closest_id !== id) {
            error_data = {
                table_name: this.table_name,
                id: id,
                closest_id: closest_id,
            };
            blueslip.error("Selected message id not in MessageList",
                           error_data);
        }

        if (closest_id === -1 && !opts.empty_ok) {
            error_data = {
                table_name: this.table_name,
                id: id,
                items_length: this.data.num_items(),
            };
            blueslip.fatal("Cannot select id -1", error_data);
        }

        id = closest_id;
        opts.id = id;
        this.data.set_selected_id(id);

        if (opts.force_rerender) {
            this.rerender();
        } else if (!opts.from_rendering) {
            this.view.maybe_rerender();
        }

        $(document).trigger($.Event('message_selected.zulip', opts));
    },

    reselect_selected_id: function MessageList_select_closest_id() {
        this.select_id(this.data.selected_id(), {from_rendering: true});
    },

    selected_message: function MessageList_selected_message() {
        return this.get(this.data.selected_id());
    },

    selected_row: function MessageList_selected_row() {
        return this.get_row(this.data.selected_id());
    },

    closest_id: function (id) {
        return this.data.closest_id(id);
    },

    advance_past_messages: function (msg_ids) {
        return this.data.advance_past_messages(msg_ids);
    },

    selected_idx: function () {
        return this.data.selected_idx();
    },

    subscribed_bookend_content: function (stream_name) {
        return i18n.t("You subscribed to stream __stream__",
                      {stream: stream_name});
    },

    unsubscribed_bookend_content: function (stream_name) {
        return i18n.t("You unsubscribed from stream __stream__",
                      {stream: stream_name});
    },

    not_subscribed_bookend_content: function (stream_name) {
        return i18n.t("You are not subscribed to stream __stream__",
                      {stream: stream_name});
    },

    // Maintains a trailing bookend element explaining any changes in
    // your subscribed/unsubscribed status at the bottom of the
    // message list.
    update_trailing_bookend: function MessageList_update_trailing_bookend() {
        this.view.clear_trailing_bookend();
        if (!this.narrowed) {
            return;
        }
        var stream_name = narrow_state.stream();
        if (stream_name === undefined) {
            return;
        }
        var trailing_bookend_content;
        var show_button = true;
        var subscribed = stream_data.is_subscribed(stream_name);
        if (subscribed) {
            trailing_bookend_content = this.subscribed_bookend_content(stream_name);
        } else {
            if (!this.last_message_historical) {
                trailing_bookend_content = this.unsubscribed_bookend_content(stream_name);

                // For invite only streams or streams that no longer
                // exist, hide the resubscribe button
                // Hide button for guest users
                var sub = stream_data.get_sub(stream_name);
                if (sub !== undefined) {
                    show_button = !page_params.is_guest && !sub.invite_only;
                } else {
                    show_button = false;
                }
            } else {
                trailing_bookend_content = this.not_subscribed_bookend_content(stream_name);
            }
        }
        if (trailing_bookend_content !== undefined) {
            this.view.render_trailing_bookend(trailing_bookend_content, subscribed, show_button);
        }
    },

    unmuted_messages: function (messages) {
        return this.data.unmuted_messages(messages);
    },

    append: function MessageList_append(messages, opts) {
        var viewable_messages = this.data.append(messages);
        this.append_to_view(viewable_messages, opts);
    },

    append_to_view: function (messages, opts) {
        opts = _.extend({messages_are_new: false}, opts);

        this.num_appends += 1;
        this.view.append(messages, opts.messages_are_new);
    },

    remove_and_rerender: function MessageList_remove_and_rerender(messages) {
        this.data.remove(messages);
        this.rerender();
    },

    show_edit_message: function MessageList_show_edit_message(row, edit_obj) {
        row.find(".message_edit_form").empty().append(edit_obj.form);
        row.find(".message_content, .status-message, .message_controls").hide();
        row.find(".message_edit").css("display", "block");
        row.find(".message_edit_content").autosize();
    },

    hide_edit_message: function MessageList_hide_edit_message(row) {
        row.find(".message_content, .status-message, .message_controls").show();
        row.find(".message_edit").hide();
        row.trigger("mouseleave");
{'fraction_non_alphanumeric': 0.10723631508678237, 'fraction_numerical': 0.0014953271028037382, 'mean_word_length': 2.051328010428548, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3484082', 'n_tokens_mistral': 5505, 'n_tokens_neox': 5334, 'n_words': 1126}