zulip/static/js/overlays.js

246 lines
6.8 KiB
JavaScript

let active_overlay;
let close_handler;
let open_overlay_name;
function reset_state() {
active_overlay = undefined;
close_handler = undefined;
open_overlay_name = undefined;
}
exports.is_active = function () {
return !!open_overlay_name;
};
exports.is_modal_open = function () {
return $(".modal").hasClass("in");
};
exports.info_overlay_open = function () {
return open_overlay_name === 'informationalOverlays';
};
exports.settings_open = function () {
return open_overlay_name === 'settings';
};
exports.streams_open = function () {
return open_overlay_name === 'subscriptions';
};
exports.lightbox_open = function () {
return open_overlay_name === 'lightbox';
};
exports.drafts_open = function () {
return open_overlay_name === 'drafts';
};
exports.recent_topics_open = function () {
return open_overlay_name === 'recent_topics';
};
// To address bugs where mouse might apply to the streams/settings
// overlays underneath an open modal within those settings UI, we add
// this inline style to '.overlay.show', overriding the
// "pointer-events: all" style in app_components.scss.
//
// This is kinda hacky; it only works for modals within overlays, and
// we need to make sure it gets re-enabled when the modal closes.
exports.disable_background_mouse_events = function () {
$('.overlay.show').attr("style", "pointer-events: none");
};
// This removes only the inline-style of the element that
// was added in disable_background_mouse_events and
// enables the background mouse events.
exports.enable_background_mouse_events = function () {
$('.overlay.show').attr("style", null);
};
exports.active_modal = function () {
if (!exports.is_modal_open()) {
blueslip.error("Programming error — Called active_modal when there is no modal open");
return;
}
return '#' + $(".modal.in").attr("id");
};
exports.open_overlay = function (opts) {
popovers.hide_all();
if (!opts.name || !opts.overlay || !opts.on_close) {
blueslip.error('Programming error in open_overlay');
return;
}
if (active_overlay || open_overlay_name || close_handler) {
blueslip.error('Programming error — trying to open ' + opts.name +
' before closing ' + open_overlay_name);
return;
}
blueslip.debug('open overlay: ' + opts.name);
// Our overlays are kind of crufty...we have an HTML id
// attribute for them and then a data-overlay attribute for
// them. Make sure they match.
if (opts.overlay.attr('data-overlay') !== opts.name) {
blueslip.error('Bad overlay setup for ' + opts.name);
return;
}
open_overlay_name = opts.name;
active_overlay = opts.overlay;
opts.overlay.addClass('show');
opts.overlay.attr("aria-hidden", "false");
$('.app').attr("aria-hidden", "true");
$('.fixed-app').attr("aria-hidden", "true");
$('.header').attr("aria-hidden", "true");
close_handler = function () {
opts.on_close();
reset_state();
};
};
exports.open_modal = function (selector) {
if (selector === undefined) {
blueslip.error('Undefined selector was passed into open_modal');
return;
}
if (selector[0] !== '#') {
blueslip.error('Non-id-based selector passed in to open_modal: ' + selector);
return;
}
if (exports.is_modal_open()) {
blueslip.error('open_modal() was called while ' + exports.active_modal() +
' modal was open.');
return;
}
blueslip.debug('open modal: ' + selector);
const elem = $(selector).expectOne();
elem.modal("show").attr("aria-hidden", false);
// Disable background mouse events when modal is active
exports.disable_background_mouse_events();
// Remove previous alert messages from modal, if exists.
elem.find(".alert").hide();
elem.find(".alert-notification").html("");
};
exports.close_overlay = function (name) {
if (name !== open_overlay_name) {
blueslip.error("Trying to close " + name + " when " + open_overlay_name + " is open.");
return;
}
if (name === undefined) {
blueslip.error('Undefined name was passed into close_overlay');
return;
}
blueslip.debug('close overlay: ' + name);
active_overlay.removeClass("show");
active_overlay.attr("aria-hidden", "true");
$('.app').attr("aria-hidden", "false");
$('.fixed-app').attr("aria-hidden", "false");
$('.header').attr("aria-hidden", "false");
if (!close_handler) {
blueslip.error("Overlay close handler for " + name + " not properly setup.");
return;
}
close_handler();
};
exports.close_active = function () {
if (!open_overlay_name) {
blueslip.warn('close_active() called without checking is_active()');
return;
}
exports.close_overlay(open_overlay_name);
};
exports.close_modal = function (selector) {
if (selector === undefined) {
blueslip.error('Undefined selector was passed into close_modal');
return;
}
if (!exports.is_modal_open()) {
blueslip.warn('close_active_modal() called without checking is_modal_open()');
return;
}
if (exports.active_modal() !== selector) {
blueslip.error("Trying to close " + selector +
" modal when " + exports.active_modal() + " is open.");
return;
}
blueslip.debug('close modal: ' + selector);
const elem = $(selector).expectOne();
elem.modal("hide").attr("aria-hidden", true);
// Enable mouse events for the background as the modal closes.
exports.enable_background_mouse_events();
};
exports.close_active_modal = function () {
if (!exports.is_modal_open()) {
blueslip.warn('close_active_modal() called without checking is_modal_open()');
return;
}
$(".modal.in").modal("hide").attr("aria-hidden", true);
};
exports.close_for_hash_change = function () {
$(".overlay.show").removeClass("show");
reset_state();
};
exports.open_settings = function () {
exports.open_overlay({
name: 'settings',
overlay: $("#settings_overlay_container"),
on_close: function () {
hashchange.exit_overlay();
},
});
};
exports.initialize = function () {
$("body").on("click", ".overlay, .overlay .exit", (e) => {
let $target = $(e.target);
// if the target is not the .overlay element, search up the node tree
// until it is found.
if ($target.is(".exit, .exit-sign, .overlay-content, .exit span")) {
$target = $target.closest("[data-overlay]");
} else if (!$target.is(".overlay")) {
// not a valid click target then.
return;
}
const target_name = $target.attr("data-overlay");
exports.close_overlay(target_name);
e.preventDefault();
e.stopPropagation();
});
};
window.overlays = exports;