After changing the setting modal_backdrop to "static", i can still close modal windows by clicking the backdrop.
The modal_keyboard setting works, just not modal_backdrop.

This is an issue when using bootstrap theme as primary default theme, not a sub-theme.

Comments

aaronbauman created an issue. See original summary.

aaronbauman’s picture

Issue summary: View changes
aaronbauman’s picture

Status: Active » Needs review
StatusFileSize
new506 bytes

In this patch: fix handling of the "backdrop" setting in modal.jquery.ui.bridge.js, which was incorrectly mapped to the "modal" option.

markhalliwell’s picture

Status: Needs review » Postponed (maintainer needs more info)

which was incorrectly mapped to the "modal" option

Why is it "incorrect"?

aaronbauman’s picture

The "backdrop" option from theme config is a select list of 3 possible values - true, false, or "static".
The "modal" option is a boolean value, indicating whether to use modal or dialog.

Currently, the "backdrop" option is ignored entirely when creating the options to pass through to bootstrap modal API. Instead, the "modal" option is passed through.

Instead of being ignored, the "backdrop" option from theme config should be mapped to the "backdrop" pass-through options.

markhalliwell’s picture

Instead of being ignored, the "backdrop" option from theme config should be mapped to the "backdrop" pass-through options.

I'm still not following. How does "theme config" make its way into this scenario? This file is the modal.jquery.ui.bridge.js code. Meaning that it's only intent is to map jQuery UI options (e.g. options.modal) to the supported Bootstrap options (e.g. mappedOptions.backdrop). There is no options.backdrop, or at least there shouldn't be.

If whatever code that implements said jQuery UI dialog options doesn't explicitly provide the modal option, then it falls back to what the theme config specifies.

markhalliwell’s picture

Title: modal_backdrop: static setting doesn't work » Add a disclaimer for passed/mapped jQuery UI options
Category: Bug report » Task
Status: Postponed (maintainer needs more info) » Needs work

If anything, I think the real "issue" here is that there needs to be a disclaimer stating something to the effect of: "Note: these settings may be manually overridden depending on which options were explicitly specified by the code from core/contrib and then mapped using the jQuery UI Bridge."

aaronbauman’s picture

The theme config setting is "modal_backdrop", which is assigned to Modal.DEFAULTS.backdrop in bootstrap/js/modal.js:

      // Extend defaults to take into account for theme settings.
      Modal.DEFAULTS = $.extend({}, BootstrapModal.DEFAULTS, {
        animation: !!settings.modal_animation,
        backdrop: settings.modal_backdrop === 'static' ? 'static' : !!settings.modal_backdrop,
        keyboard: !!settings.modal_keyboard,
        show: !!settings.modal_show,
        size: settings.modal_size
      });

Modal.DEFAULTS is subsequently used to define options for the plugin definition, also in bootstrap/js/modal.js:

          options = $.extend({}, Modal.DEFAULTS, data && data.options, $this.data(), options);

and finally, these options make their way to modal.jquery.ui.bridge.js via the option() setter:

          /**
           * Handler for $.fn.dialog('option').
           */
          option: function () {
            var clone = {options: $.extend({}, this.options)};

            // Apply the parent option method to the clone of current options.
            this.super.apply(clone, arguments);

            // Merge in the cloned mapped options.
            $.extend(true, this.options, this.mapDialogOptions(clone.options));
          },

Hence, the "options" in this patch are some of the pass-through values from theme settings.
If options.modal is used where options.backdrop should be used instead, then it's impossible to set a "static" backdrop.

Here's a call debugging frame at the appropriate line that will hopefully illustrate this more clearly:

If you go ahead and test theme settings for modal, you will see that the "backdrop" setting does not work.
With this patch, the "backdrop" setting does work.

markhalliwell’s picture

I think you're missing the point...

If options.modal is provided at all, it is an explicit override. jQuery UI doesn't have the concept of a "static" backdrop. Thus, whatever was set in via the theme settings is irrelevant.

aaronbauman’s picture

StatusFileSize
new85.72 KB
new710.3 KB
new76.72 KB

My point, as stated in the original title, is that the modal_backdrop option "static" -- provided by this module -- does not work as described, using vanilla bootstrap theme and default settings.

I'm not sure how to convince you of this other than to please ask you, again, to try for yourself if you don't believe me.

Here's what my current settings look like:

Here's a gif of unpatched bootrap *not* working:

You can see, when the mouse is clicked on the backdrop region, the modal disappears.

And here's a gif of the patched bootstrap version working:

Without the patch, "static" works the same as "true".
With the patch, "static" works as expected.

aaronbauman’s picture

Maybe the solution is that the "modal" option needs to take into account the "closeOnEscape" option?
Or, why does "closeOnEscape" have special treatment for the "modal" option, but not vice versa?

markhalliwell’s picture

Or, why does "closeOnEscape" have special treatment for the "modal" option, but not vice versa?

Because, "static" really only comes into play when the closeOnEscape jQuery UI dialog option is explicitly specified.

As you can see, it explicitly sets options.modal to static which is later mapped again:

if (!options.closeOnEscape && options.modal) {
  mappedOptions.backdrop = options.modal = 'static';
}

This is because jQuery UI's "modals" can, by default, be closed by clicking on the backdrop. The default functionality is not the same as Bootstrap's. The reason this doesn't just assume "static" is that the modal itself may not be constructed (from code/dialog options) to include a closing mechanism of some sort. Thus, the only way to actually "close" the modal is to click the backdrop.

If you want to ensure that that the modal is truly "static", add the following attribute data-dialog-options="{"closeOnEscape":false}" so it triggers the above code the way it was designed.

I'm not saying this is 100% "perfect" or "ideal", but there are simply limitations to bridges. This is one of them.

Furthermore, it is a bridge that is specifically designed to ensure that jQuery UI's dialog options are accounted for, not Bootstraps.

aaronbauman’s picture

If you want to ensure that that the modal is truly "static", add the following attribute data-dialog-options="{"closeOnEscape":false}" so it triggers the above code the way it was designed.

I don't understand how that's supposed to work, because I'm already using that option and it's always subsequently overwritten by the "modal" option case handling. Do I have to use a different data-dialog-type option?
I've already using "dialog", which doesn't respect the "closeOnEscape" setting either.

markhalliwell’s picture

I'm already using that option and it's always subsequently overwritten by the "modal" option case handling.

No, it's not "overwritten". They're the same. Please re-read my previous comment and the if statement logic.

aaronbauman’s picture

OK, I see at least part of the problem: closeOnEscape is being set to the string "false", and always evaluates to true.

aaronbauman’s picture

StatusFileSize
new1023.65 KB

Here's a gif of step-through:

aaronbauman’s picture

OK, I finally got it to work with the following attribute on the ajax link:
data-dialog-options="{"closeOnEscape":""}"

markhalliwell’s picture

That... shouldn't be happening.

Core uses jQuery's data method to parse the options:
http://cgit.drupalcode.org/drupal/tree/core/misc/ajax.js#n129

And as you can see here, it's parsed as a boolean, not a string:
https://codepen.io/markcarver/pen/zaEmKo?editors=1011

markhalliwell’s picture

imclean’s picture

I'm experiencing the same issue using a Bootstrap sub theme.

#12 still allows closing by clicking on the backdrop:

data-dialog-options="{"closeOnEscape":false}"

#17 prevents modal from being closed by clicking on the backdrop:

data-dialog-options="{"closeOnEscape":""}"

This option also hides the close button "X" in the top right, which may be normal behaviour but I was hoping to keep it.

imclean’s picture

In case it matters how the link is generated:

      $build['modal_link'] = [
        '#type' => 'inline_template',
        '#template' => '{{ mytemplate|raw }}',
        '#context' => [
          'mytemplate' => '<a class="btn btn-primary use-ajax" data-dialog-options="{&quot;dialogClass&quot;:&quot;my-class&quot;,&quot;title&quot;:&quot;Modal Title&quot,&quot;closeOnEscape&quot;:&quot;&quot;}" data-dialog-type="modal" href="/my/path">Modal Link</a>',
        ]
      ];
markhalliwell’s picture

First... why would you create a link like that?! That is a horrible way to do that.

Inline templates are only meant for user (GUI) based templates (think views field rewrites). They're not intended to be a replacement for actual Twig templates. Also, you're already in PHP, where you can use the proper #type:

  $dialogOptions = [
    'dialogClass' => 'my-class', // Deprecated BTW, really shouldn't be using it.
    'title' => t('Modal Title'),
    'closeOnEscape' => FALSE,
  ];

  $build['modal_link'] = [
    '#type' => 'link',
    '#title' => t('Modal Link'),
    '#url' => Url::fromUserInput('/my/path'),
    '#attributes' => [
      'class' => ['btn', 'btn-primary', 'use-ajax'],
      'data-dialog-options' => Json::encode($dialogOptions),
      'data-dialog-type' => 'modal',
    ],
  ];

Second... the primary issue, in this issue, is that setting closeOnEscape to an actual false boolean doesn't work. I've determined that this is actually a legitimate core bug: #3014136: Opening dialog via AJAX casts dialogOptions values to strings.

I'm leaving this issue open, however, because I still think some general verbiage needs to be added to better explain how options are mapped.

imclean’s picture

Yeah it's not pretty. It's actually mixed up with some Vuejs, which could also be extracted.

Thanks for the update, I'll check out the core issue.

markhalliwell’s picture

Title: Add a disclaimer for passed/mapped jQuery UI options » Mapped option closeOnEscape doesn't work as expected
Component: Documentation » Code
Category: Task » Bug report
Status: Active » Fixed
StatusFileSize
new23.48 KB

I've been going over the code (and previous examples given) and think there could be a little better support while waiting on #3014136: Opening dialog via AJAX casts dialogOptions values to strings.

  • markcarver committed 25f0d89 on 8.x-3.x
    Issue #2978392 by markcarver, aaronbauman: Mapped option closeOnEscape...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.