Elastic: Fix various issues with datepicker in parent window

pull/6566/head
Aleksander Machniak 6 years ago
parent 3502d9cb2b
commit 5063d9bfd9

@ -14,7 +14,10 @@
.ui-widget-overlay {
background-color: @color-dialog-overlay-background;
opacity: 1 !important; // override jQuery-UI opacity, the color above is semi-transparent
z-index: 10; // above Bootstrap's form controls
&.datepicker {
z-index: 119; // above Bootstrap's form controls, below datepicker
}
}
.ui-widget {
@ -287,10 +290,11 @@
.ui-datepicker {
// Always display datepicker centered, overwriting widgets position
margin: ~"calc(50vh - 13em) calc(50vw - 10em) !important";
margin: ~"calc(50vh - 10em) calc(50vw - 10em) !important";
top: 0 !important;
left: 0 !important;
box-shadow: none;
user-select: none;
&:not(.ui-datepicker-inline) {
z-index: 120 !important; // fixes datepicker over input-group and dialogs

@ -78,6 +78,8 @@ function rcube_elastic_ui()
this.searchbar_init = searchbar_init;
this.pretty_checkbox = pretty_checkbox;
this.pretty_select = pretty_select;
this.datepicker_init = datepicker_init;
this.bootstrap_style = bootstrap_style;
// Detect screen size/mode
@ -727,54 +729,12 @@ function rcube_elastic_ui()
}
// Add date format placeholder to datepicker inputs
var func, format;
if (format = rcmail.env.date_format_localized) {
var func, format = rcmail.env.date_format_localized;
if (format) {
func = function(input) { $(input).filter('.datepicker').attr('placeholder', format); };
$('input.datepicker').each(function() { func(this); });
rcmail.addEventListener('insert-edit-field', func);
}
// Datepicker widget improvements: overlay element, styling updates on calendar element update
// The widget does not provide any event system, so we use MutationObserver
if (window.MutationObserver) {
var overlay, hidden = true;
$('.ui-datepicker').each(function() {
var input = this, callback = function(data) {
$.each(data, function(i, v) {
// add/remove overlay on widget show/hide
if (v.type == 'attributes') {
var is_hidden = $(v.target).attr('aria-hidden') == 'true';
if (is_hidden != hidden) {
if (!is_hidden) {
overlay = $('<div>').attr('class', 'ui-widget-overlay')
.appendTo((is_framed ? parent : window).document.body)
.click(function(e) {
$(this).remove();
if (is_framed) {
$.datepicker._hideDatepicker();
}
});
}
else if (overlay) {
overlay.remove();
}
hidden = is_hidden;
}
}
// apply styles if widget content changed
else if (v.addedNodes.length) {
bootstrap_style(v.target);
}
});
};
if (is_framed) {
$(this).detach().appendTo(parent.document.body);
}
(new MutationObserver(callback)).observe(this, {childList: true, subtree: false, attributes: true, attributeFilter: ['aria-hidden']});
});
}
};
/**
@ -1382,6 +1342,68 @@ function rcube_elastic_ui()
}
};
function datepicker_init(datepicker)
{
// Datepicker widget improvements: overlay element, styling updates on calendar element update
// The widget does not provide any event system, so we use MutationObserver
if (window.MutationObserver) {
$(datepicker).not('[data-observed]').each(function() {
var overlay, hidden = true,
win = is_framed ? parent : window,
callback = function(data) {
$.each(data, function(i, v) {
// add/remove overlay on widget show/hide
if (v.type == 'attributes') {
var is_hidden = $(v.target).attr('aria-hidden') == 'true';
if (is_hidden != hidden) {
if (!is_hidden) {
overlay = $('<div>').attr('class', 'ui-widget-overlay datepicker')
.appendTo(win.document.body)
.click(function(e) {
$(this).remove();
if (is_framed) {
$.datepicker._hideDatepicker();
}
});
}
else if (overlay) {
overlay.remove();
}
hidden = is_hidden;
}
}
else if (v.addedNodes.length) {
// apply styles when widget content changed
win.UI.bootstrap_style(v.target);
// Month/Year change handlers do not work from parent, fix it
if (is_framed) {
win.$('select.ui-datepicker-month', v.target).on('change', function() {
$.datepicker._selectMonthYear($.datepicker._lastInput, this, "M");
});
win.$('select.ui-datepicker-year', v.target).on('change', function() {
$.datepicker._selectMonthYear($.datepicker._lastInput, this, "Y");
});
}
}
});
};
$(this).attr('data-observed', '1');
if (is_framed) {
// move the datepicker to parent window
$(this).detach().appendTo(parent.document.body);
// create fake element, so the valid one is not removed by datepicker code
$('<div id="ui-datepicker-div" class="hidden">').appendTo(document.body);
}
(new MutationObserver(callback)).observe(this, {childList: true, subtree: false, attributes: true, attributeFilter: ['aria-hidden']});
});
}
};
/**
* Handler for some Roundcube core popups
*/
@ -3404,7 +3426,7 @@ function rcube_elastic_ui()
.popover({
// because of focus issues we can't always use body,
// if select is in a dialog, popover has to be a child of this dialog
container: dialog || 'body',
container: dialog || document.body,
content: list[0],
placement: 'bottom',
trigger: 'manual',
@ -3430,6 +3452,9 @@ function rcube_elastic_ui()
if (rcube_event.is_keyboard(e)) {
list.find('a.active:first').focus();
}
// don't propagate mousedown event
list.on('mousedown', function(e) { e.stopPropagation(); });
})
.popover('show');
};
@ -3854,9 +3879,26 @@ if (window.rcmail) {
else {
// rcmail does not exists e.g. on the error template inside a frame
// we fake the engine a little
var rcmail = parent.rcmail;
var rcube_webmail = parent.rcube_webmail;
var bw = {};
var rcmail = parent.rcmail,
rcube_webmail = parent.rcube_webmail,
bw = {};
}
var UI = new rcube_elastic_ui();
// Improve non-inline datepickers
if ($ && $.datepicker) {
var __newInst = $.datepicker._newInst;
$.extend($.datepicker, {
_newInst: function(target, inline) {
var inst = __newInst.call(this, target, inline);
if (!inst.inline) {
UI.datepicker_init(inst.dpDiv);
}
return inst;
}
});
}

Loading…
Cancel
Save