<commit_before>var hotkeys = (function () {

var exports = {};

function do_narrow_action(action) {
    action(current_msg_list.selected_id(), {trigger: 'hotkey'});
    return true;
}

var actions_dropdown_hotkeys = [
    'down_arrow',
    'up_arrow',
    'vim_up',
    'vim_down',
    'enter',
];

// Note that multiple keys can map to the same event_name, which
// we'll do in cases where they have the exact same semantics.
// DON'T FORGET: update keyboard_shortcuts.html

var keydown_shift_mappings = {
    // these can be triggered by shift + key only
    9: {name: 'shift_tab', message_view_only: false}, // tab
    32: {name: 'shift_spacebar', message_view_only: true},  // space bar
};

var keydown_unshift_mappings = {
    // these can be triggered by key only (without shift)
    9: {name: 'tab', message_view_only: false}, // tab
    27: {name: 'escape', message_view_only: false}, // escape
    32: {name: 'spacebar', message_view_only: true}, // space bar
    33: {name: 'page_up', message_view_only: true}, // page up
    34: {name: 'page_down', message_view_only: true}, // page down
    35: {name: 'end', message_view_only: true}, // end
    36: {name: 'home', message_view_only: true}, // home
    37: {name: 'left_arrow', message_view_only: false}, // left arrow
    39: {name: 'right_arrow', message_view_only: false}, // right arrow
    38: {name: 'up_arrow', message_view_only: false}, // up arrow
    40: {name: 'down_arrow', message_view_only: false}, // down arrow
};

var keydown_ctrl_mappings = {
    219: {name: 'escape', message_view_only: false}, // '['
};

var keydown_either_mappings = {
    // these can be triggered by key or shift + key
    // Note that codes for letters are still case sensitive!
    //
    // We may want to revisit both of these.  For backspace, we don't
    // have any specific mapping behavior; we are just trying to disable
    // the normal browser features for certain OSes when we are in the
    // compose box, and the little bit of backspace-related code here is
    // dubious, but may apply to shift-backspace.
    // For enter, there is some possibly that shift-enter is intended to
    // have special behavior for folks that are used to shift-enter behavior
    // in other apps, but that's also slightly dubious.
    8: {name: 'backspace', message_view_only: true}, // backspace
    13: {name: 'enter', message_view_only: false}, // enter
};

var keypress_mappings = {
    42: {name: 'star_message', message_view_only: true}, // '*'
    43: {name: 'thumbs_up_emoji', message_view_only: true}, // '+'
    45: {name: 'toggle_message_collapse', message_view_only: true}, // '-'
    47: {name: 'search', message_view_only: false}, // '/'
    58: {name: 'toggle_reactions_popover', message_view_only: true}, // ':'
    63: {name: 'show_shortcuts', message_view_only: false}, // '?'
    64: {name: 'compose_reply_with_mention', message_view_only: true}, // '@'
    65: {name: 'stream_cycle_backward', message_view_only: true}, // 'A'
    67: {name: 'compose_private_message', message_view_only: true}, // 'C'
    68: {name: 'stream_cycle_forward', message_view_only: true}, // 'D'
    71: {name: 'G_end', message_view_only: true}, // 'G'
    74: {name: 'vim_page_down', message_view_only: true}, // 'J'
    75: {name: 'vim_page_up', message_view_only: true}, // 'K'
    77: {name: 'toggle_mute', message_view_only: true}, // 'M'
    80: {name: 'narrow_private', message_view_only: true}, // 'P'
    82: {name: 'respond_to_author', message_view_only: true}, // 'R'
    83: {name: 'narrow_by_subject', message_view_only: true}, //'S'
    86: {name: 'view_selected_stream', message_view_only: false}, //'V'
    99: {name: 'compose', message_view_only: true}, // 'c'
    100: {name: 'open_drafts', message_view_only: false}, // 'd'
    103: {name: 'gear_menu', message_view_only: true}, // 'g'
    105: {name: 'message_actions', message_view_only: true}, // 'i'
    106: {name: 'vim_down', message_view_only: true}, // 'j'
    107: {name: 'vim_up', message_view_only: true}, // 'k'
    110: {name: 'n_key', message_view_only: false}, // 'n'
    113: {name: 'query_streams', message_view_only: false}, // 'q'
    114: {name: 'reply_message', message_view_only: true}, // 'r'
    115: {name: 'narrow_by_recipient', message_view_only: true}, // 's'
    117: {name: 'show_sender_info', message_view_only: true}, // 'u'
    118: {name: 'show_lightbox', message_view_only: true}, // 'v'
    119: {name: 'query_users', message_view_only: false}, // 'w'
};

exports.get_keydown_hotkey = function (e) {
    if (e.metaKey || e.altKey) {
        return;
    }

    var hotkey;
    if (e.ctrlKey) {
        hotkey = keydown_ctrl_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
        return;
    }

    if (e.shiftKey) {
        hotkey = keydown_shift_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
    }

    if (!e.shiftKey) {
        hotkey = keydown_unshift_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
    }

    return keydown_either_mappings[e.which];
};

exports.get_keypress_hotkey = function (e) {
    if (e.metaKey || e.ctrlKey || e.altKey) {
        return;
    }

    return keypress_mappings[e.which];
};

exports.processing_text = function () {
    var selector = 'input:focus,select:focus,textarea:focus,#compose-send-button:focus,.editable-section:focus';
    return $(selector).length > 0;
};

exports.is_editing_stream_name = function (e) {
    return $(e.target).is(".editable-section");
};

// Returns true if we handled it, false if the browser should.
exports.process_escape_key = function (e) {
    var row;

    if (exports.is_editing_stream_name(e)) {
        return false;
    }

    if (overlays.is_modal_open()) {
        overlays.close_active_modal();
        return true;
    }

    if (overlays.is_active()) {
        overlays.close_active();
        return true;
    }

    if (gear_menu.is_open()) {
        gear_menu.close();
        return true;
    }

    if (message_edit.is_editing(current_msg_list.selected_id())) {
        message_edit.end(current_msg_list.selected_row());
        return true;
    }

    if (exports.processing_text()) {
        if ($(".message_edit_content").filter(":focus").length > 0) {
            row = $(".message_edit_content").filter(":focus").closest(".message_row");
            row.find('.message_edit_content').blur();
            message_edit.end(row);
            return true;
        }

        if ($(".message_edit_topic").filter(":focus").length > 0) {<commit_msg>hotkeys: Fix ESC removing message feed focus in Firefox.<commit_after>var hotkeys = (function () {

var exports = {};

function do_narrow_action(action) {
    action(current_msg_list.selected_id(), {trigger: 'hotkey'});
    return true;
}

var actions_dropdown_hotkeys = [
    'down_arrow',
    'up_arrow',
    'vim_up',
    'vim_down',
    'enter',
];

// Note that multiple keys can map to the same event_name, which
// we'll do in cases where they have the exact same semantics.
// DON'T FORGET: update keyboard_shortcuts.html

var keydown_shift_mappings = {
    // these can be triggered by shift + key only
    9: {name: 'shift_tab', message_view_only: false}, // tab
    32: {name: 'shift_spacebar', message_view_only: true},  // space bar
};

var keydown_unshift_mappings = {
    // these can be triggered by key only (without shift)
    9: {name: 'tab', message_view_only: false}, // tab
    27: {name: 'escape', message_view_only: false}, // escape
    32: {name: 'spacebar', message_view_only: true}, // space bar
    33: {name: 'page_up', message_view_only: true}, // page up
    34: {name: 'page_down', message_view_only: true}, // page down
    35: {name: 'end', message_view_only: true}, // end
    36: {name: 'home', message_view_only: true}, // home
    37: {name: 'left_arrow', message_view_only: false}, // left arrow
    39: {name: 'right_arrow', message_view_only: false}, // right arrow
    38: {name: 'up_arrow', message_view_only: false}, // up arrow
    40: {name: 'down_arrow', message_view_only: false}, // down arrow
};

var keydown_ctrl_mappings = {
    219: {name: 'escape', message_view_only: false}, // '['
};

var keydown_either_mappings = {
    // these can be triggered by key or shift + key
    // Note that codes for letters are still case sensitive!
    //
    // We may want to revisit both of these.  For backspace, we don't
    // have any specific mapping behavior; we are just trying to disable
    // the normal browser features for certain OSes when we are in the
    // compose box, and the little bit of backspace-related code here is
    // dubious, but may apply to shift-backspace.
    // For enter, there is some possibly that shift-enter is intended to
    // have special behavior for folks that are used to shift-enter behavior
    // in other apps, but that's also slightly dubious.
    8: {name: 'backspace', message_view_only: true}, // backspace
    13: {name: 'enter', message_view_only: false}, // enter
};

var keypress_mappings = {
    42: {name: 'star_message', message_view_only: true}, // '*'
    43: {name: 'thumbs_up_emoji', message_view_only: true}, // '+'
    45: {name: 'toggle_message_collapse', message_view_only: true}, // '-'
    47: {name: 'search', message_view_only: false}, // '/'
    58: {name: 'toggle_reactions_popover', message_view_only: true}, // ':'
    63: {name: 'show_shortcuts', message_view_only: false}, // '?'
    64: {name: 'compose_reply_with_mention', message_view_only: true}, // '@'
    65: {name: 'stream_cycle_backward', message_view_only: true}, // 'A'
    67: {name: 'compose_private_message', message_view_only: true}, // 'C'
    68: {name: 'stream_cycle_forward', message_view_only: true}, // 'D'
    71: {name: 'G_end', message_view_only: true}, // 'G'
    74: {name: 'vim_page_down', message_view_only: true}, // 'J'
    75: {name: 'vim_page_up', message_view_only: true}, // 'K'
    77: {name: 'toggle_mute', message_view_only: true}, // 'M'
    80: {name: 'narrow_private', message_view_only: true}, // 'P'
    82: {name: 'respond_to_author', message_view_only: true}, // 'R'
    83: {name: 'narrow_by_subject', message_view_only: true}, //'S'
    86: {name: 'view_selected_stream', message_view_only: false}, //'V'
    99: {name: 'compose', message_view_only: true}, // 'c'
    100: {name: 'open_drafts', message_view_only: false}, // 'd'
    103: {name: 'gear_menu', message_view_only: true}, // 'g'
    105: {name: 'message_actions', message_view_only: true}, // 'i'
    106: {name: 'vim_down', message_view_only: true}, // 'j'
    107: {name: 'vim_up', message_view_only: true}, // 'k'
    110: {name: 'n_key', message_view_only: false}, // 'n'
    113: {name: 'query_streams', message_view_only: false}, // 'q'
    114: {name: 'reply_message', message_view_only: true}, // 'r'
    115: {name: 'narrow_by_recipient', message_view_only: true}, // 's'
    117: {name: 'show_sender_info', message_view_only: true}, // 'u'
    118: {name: 'show_lightbox', message_view_only: true}, // 'v'
    119: {name: 'query_users', message_view_only: false}, // 'w'
};

exports.get_keydown_hotkey = function (e) {
    if (e.metaKey || e.altKey) {
        return;
    }

    var hotkey;
    if (e.ctrlKey) {
        hotkey = keydown_ctrl_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
        return;
    }

    if (e.shiftKey) {
        hotkey = keydown_shift_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
    }

    if (!e.shiftKey) {
        hotkey = keydown_unshift_mappings[e.which];
        if (hotkey) {
            return hotkey;
        }
    }

    return keydown_either_mappings[e.which];
};

exports.get_keypress_hotkey = function (e) {
    if (e.metaKey || e.ctrlKey || e.altKey) {
        return;
    }

    return keypress_mappings[e.which];
};

exports.processing_text = function () {
    var selector = 'input:focus,select:focus,textarea:focus,#compose-send-button:focus,.editable-section:focus';
    return $(selector).length > 0;
};

exports.is_editing_stream_name = function (e) {
    return $(e.target).is(".editable-section");
};

// Returns true if we handled it, false if the browser should.
exports.process_escape_key = function (e) {
    var row;

    if (exports.is_editing_stream_name(e)) {
        return false;
    }

    if (overlays.is_modal_open()) {
        overlays.close_active_modal();
        return true;
    }

    if (overlays.is_active()) {
        overlays.close_active();
        return true;
    }

    if (gear_menu.is_open()) {
        gear_menu.close();
        return true;
    }

    if (message_edit.is_editing(current_msg_list.selected_id())) {
        // Using this definition of "row" instead of "current_msg_list.selected_row()"
        // because it returns a more complete object.
        // Necessary for refocusing on message list in Firefox.
        row = $(".message_edit_content").filter(":focus").closest(".message_row");
        row.find('.message_edit_content').blur();
        message_edit.end(row);
        return true;
    }

    if (exports.processing_text()) {
        if ($(".message_edit_content").filter(":focus").length > 0) {
            row = $(".message_edit_content").filter(":focus").closest(".message_row");
            row.find('.message_edit_content').blur();
            message_edit.end(row);
            return true;
        }

        if ($(".message_edit_topic").filter(":focus").length > 0) {
{'fraction_non_alphanumeric': 0.15178637473185885, 'fraction_numerical': 0.015829573193283528, 'mean_word_length': 3.110671936758893, 'pattern_counts': {'":': 7, '<': 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': '2087862', 'n_tokens_mistral': 4723, 'n_tokens_neox': 4528, 'n_words': 1168}