From 5063d9bfd96b63f15d8d89f615a06f8c4839613a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 3 Dec 2018 14:43:01 +0000 Subject: [PATCH] Elastic: Fix various issues with datepicker in parent window --- skins/elastic/styles/widgets/jqueryui.less | 8 +- skins/elastic/ui.js | 138 ++++++++++++++------- 2 files changed, 96 insertions(+), 50 deletions(-) diff --git a/skins/elastic/styles/widgets/jqueryui.less b/skins/elastic/styles/widgets/jqueryui.less index 7b66617ee..b2ec5cfd2 100644 --- a/skins/elastic/styles/widgets/jqueryui.less +++ b/skins/elastic/styles/widgets/jqueryui.less @@ -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 diff --git a/skins/elastic/ui.js b/skins/elastic/ui.js index 51eb2a324..88a125ffc 100644 --- a/skins/elastic/ui.js +++ b/skins/elastic/ui.js @@ -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 = $('
').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 = $('
').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 + $('