[TikiWiki-commits] [Git][tikiwiki/tiki][27.x] [FIX] Datepicker: Fix modal scrolling issues with calendar dates and timepicker sliders

"Merci Jacob \(@mercihabam\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <69bc22599542c_3b18d18471093@gitlab-sidekiq-low-urgency-cpu-bound-v2-5d9674946b-gkvm9.mail>

Merci Jacob pushed to branch 27.x at Tiki Wiki CMS Groupware / Tiki


Commits:
903f26c4 by UshindiG at 2026-03-19T16:13:00+00:00
[FIX] Datepicker: Fix modal scrolling issues with calendar dates and timepicker sliders
---
* [FIX] Datepicker: Improve positioning of datepicker in modals to prevent overflow

* [FIX] Datepicker: Fix modal scrolling issues with calendar dates and timepicker sliders

See merge request tikiwiki/tiki!8984

- - - - -


1 changed file:

- lib/jquery_tiki/tiki-jquery.js


Changes:

=====================================
lib/jquery_tiki/tiki-jquery.js
=====================================
@@ -1036,6 +1036,35 @@ function toggleFullScreen(area_id) {
  */
 var xhrCache = {}, lastXhr;    // for jq-ui autocomplete
 
+/**
+ * Position a jQuery UI datepicker dpDiv relative to its input, flipping above
+ * the input when there is not enough space below within the viewport.
+ * Used both at open time and on every modal scroll event.
+ *
+ * @param {HTMLElement} input  - the datepicker input element
+ * @param {jQuery}      $dpDiv - the inst.dpDiv wrapped in jQuery
+ */
+function positionPickerNearInput(input, $dpDiv) {
+    var $input      = $(input);
+    var inputOffset = $input.offset();           // position relative to document
+    var inputBottom = inputOffset.top + $input.outerHeight();
+    var pickerH     = $dpDiv.outerHeight(true);
+    var viewportH   = $(window).height();
+    var scrollTop   = $(window).scrollTop();
+
+    // Does the picker fit below the input without going off-screen?
+    var top;
+    if (inputBottom + pickerH <= scrollTop + viewportH) {
+        // enough room below → place below
+        top = inputBottom;
+    } else {
+        // not enough room below → flip above
+        top = inputOffset.top - pickerH;
+    }
+
+    $dpDiv.css({ top: top, left: inputOffset.left });
+}
+
 $.fn.tiki = function(func, type, options, excludepage) {
     var opts = {}, opt;
 
@@ -1285,30 +1314,29 @@ $.fn.tiki = function(func, type, options, excludepage) {
                             altFieldTimeOnly: false,
                             onClose: function (dateText, inst) {
                                 $.datepickerAdjustAltField(func, inst);
+                                // Move picker back to <body> so jQuery UI can reuse it cleanly
+                                // and remove the scroll listener added in beforeShow.
+                                if ($(this).closest(".modal").length > 0) {
+                                    $(this).closest(".modal").off("scroll.tikipicker");
+                                    $("body").append(inst.dpDiv);
+                                }
                             },
-                            // We temporarily position the date picker on the modal with the function below
-                            // due to current limitations, where the datepicker is appended directly to the body instead of the modal.
-                            // Needs review for a more robust solution.
-                            // @see [jQuery UI Datepicker](https://github.com/jquery/jquery-ui/blob/main/ui/widgets/datepicker.js#L2211)
+                            // Move the picker inside the modal and reposition it on scroll so it
+                            // always tracks its input field, flipping above when near the bottom.
+                            // @see https://gitlab.com/tikiwiki/tiki/-/merge_requests/8984
                             beforeShow: function (input, inst) {
-                                if ($(input).closest(".modal").length > 0) {
-                                    var $picker = $(inst.dpDiv);
-                                    var $input = $(input);
-                                    var $modalBody = $input.closest(".modal");
-                                    var updatePosition = function () {
-                                        var inputOffset = $input.offset();
-                                        var modalBodyOffset = $modalBody.offset();
-                                        var inputHeight = $input.outerHeight();
-                                        var left = inputOffset.left - modalBodyOffset.left;
-                                        var top = inputOffset.top - modalBodyOffset.top + inputHeight;
-                                        $picker.css({
-                                            position: "absolute",
-                                            left: left + "px",
-                                            top: top + "px",
-                                        });
-                                    };
-                                    updatePosition();
-                                    $modalBody.on("scroll", updatePosition);
+                                var $input = $(input);
+                                var $modal = $input.closest(".modal");
+                                if ($modal.length > 0) {
+                                    $input.after(inst.dpDiv);
+                                    // Reposition on every modal scroll, respecting viewport edges.
+                                    $modal.on("scroll.tikipicker", function () {
+                                        positionPickerNearInput(input, inst.dpDiv);
+                                    });
+                                    // Apply correct position once the picker has fully rendered.
+                                    setTimeout(function () {
+                                        positionPickerNearInput(input, inst.dpDiv);
+                                    }, 0);
                                 }
                             },
                         };
@@ -1319,9 +1347,32 @@ $.fn.tiki = function(func, type, options, excludepage) {
                             buttonText: '',
                             dateFormat: jqueryTiki.shortDateFormat,
                             showButtonPanel: true,
-                            firstDay: jqueryTiki.firstDayofWeek
+                            firstDay: jqueryTiki.firstDayofWeek,
+                            onClose: function (dateText, inst) {
+                                // Move picker back to <body> so jQuery UI can reuse it cleanly
+                                // and remove the scroll listener added in beforeShow.
+                                if ($(this).closest(".modal").length > 0) {
+                                    $(this).closest(".modal").off("scroll.tikipicker");
+                                    $("body").append(inst.dpDiv);
+                                }
+                            },
+                            // Move the picker inside the modal and reposition it on scroll so it
+                            // always tracks its input field, flipping above when near the bottom.
+                            // @see https://gitlab.com/tikiwiki/tiki/-/merge_requests/8984
+                            beforeShow: function (input, inst) {
+                                var $input = $(input);
+                                var $modal = $input.closest(".modal");
+                                if ($modal.length > 0) {
+                                    $input.after(inst.dpDiv);
+                                    $modal.on("scroll.tikipicker", function () {
+                                        positionPickerNearInput(input, inst.dpDiv);
+                                    });
+                                    setTimeout(function () {
+                                        positionPickerNearInput(input, inst.dpDiv);
+                                    }, 0);
+                                }
+                            }
                         };
-                        break;
                 }
                 $.extend(opts, options);
                 if (func === "datetimepicker") {



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/903f26c4479d0025a080f9454e1eb9f846b6cfb3

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/903f26c4479d0025a080f9454e1eb9f846b6cfb3
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.