[REF] *: BS5: Migrate modals and .btn-close for modals and alerts
- modal 'show' option doesn't exist anymore -> We need to call .show() - by default, show is not the default -> we need to call .show() explicitly. - generic close button for dismissing content like modals and alerts. - BS5 modals needs `modal-dialog` class to work - normally we need also to add `modal-content` class but as the original XML don't have this nested level of div we don't use it, but instead we add `pointer-events: auto` for all children `DIV` of `modal-dialog` -> See DocumentViewer Task ID: 2766483 Part-of: odoo/odoo#95450
This commit is contained in:
@@ -47,6 +47,12 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
|
||||
/* Act as `modal-content` */
|
||||
& > div {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.o_viewer-header {
|
||||
display: flex;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@param {mail.DocumentViewer} widget
|
||||
-->
|
||||
<t t-name="DocumentViewer.Content">
|
||||
<div class="o_viewer_content">
|
||||
<div class="o_viewer_content modal-dialog modal-fullscreen">
|
||||
<t t-set="model" t-value="widget.modelName"/>
|
||||
<div class="o_viewer-header">
|
||||
<span class="o_image_caption">
|
||||
|
||||
@@ -113,8 +113,11 @@ var OptionalProductsModal = Dialog.extend(ServicesMixin, VariantMixin, {
|
||||
self.$modal.find(".modal-body").replaceWith(self.$el);
|
||||
self.$modal.attr('open', true);
|
||||
self.$modal.removeAttr("aria-hidden");
|
||||
self.$modal.modal().appendTo(self.container);
|
||||
self.$modal.focus();
|
||||
self.$modal.appendTo(self.container);
|
||||
const modal = new Modal(self.$modal[0], {
|
||||
focus: true,
|
||||
});
|
||||
modal.show();
|
||||
self._openedResolver();
|
||||
|
||||
// Notifies OwlDialog to adjust focus/active properties on owl dialogs
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<t t-esc="props.title"/>
|
||||
</h4>
|
||||
<t t-if="!isFullscreen">
|
||||
<button type="button" class="close" aria-label="Close" tabindex="-1" t-on-click="data.close">×</button>
|
||||
<button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="data.close"></button>
|
||||
</t>
|
||||
</header>
|
||||
<!-- FIXME: WOWL there is a bug on t-portal on owl, in which t-portal don't work on multinode.
|
||||
|
||||
@@ -204,11 +204,12 @@ var Dialog = Widget.extend({
|
||||
if (self.$parentNode) {
|
||||
self.$modal.appendTo(self.$parentNode);
|
||||
}
|
||||
self.$modal.modal({
|
||||
show: true,
|
||||
const modalNode = self.$modal[0];
|
||||
const modal = new Modal(modalNode, {
|
||||
backdrop: self.backdrop,
|
||||
keyboard: false,
|
||||
});
|
||||
modal.show();
|
||||
self._openedResolver();
|
||||
if (options && options.shouldFocusButtons) {
|
||||
self._onFocusControlButton();
|
||||
|
||||
@@ -18,7 +18,7 @@ var FormRenderer = BasicRenderer.extend({
|
||||
className: "o_form_view",
|
||||
events: _.extend({}, BasicRenderer.prototype.events, {
|
||||
'click .o_notification_box .oe_field_translate': '_onTranslate',
|
||||
'click .o_notification_box .close': '_onTranslateNotificationClose',
|
||||
'click .o_notification_box .btn-close': '_onTranslateNotificationClose',
|
||||
'shown.bs.tab a[data-toggle="tab"]': '_onNotebookTabChanged',
|
||||
'click .o_form_label': '_onFieldLabelClicked',
|
||||
}),
|
||||
@@ -1367,6 +1367,8 @@ var FormRenderer = BasicRenderer.extend({
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onTranslateNotificationClose: function(ev) {
|
||||
const notificationElement = this.el.querySelector('.o_notification_box');
|
||||
Alert.getOrCreateInstance(notificationElement).close();
|
||||
delete this.alertFields[this.state.res_id];
|
||||
},
|
||||
});
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
<t t-esc="props.title"/>
|
||||
<span t-if="props.subtitle" class="o_subtitle text-muted small" t-esc="props.subtitle"/>
|
||||
</h4>
|
||||
<button type="button" class="close" aria-label="Close" tabindex="-1" t-on-click="_close">×</button>
|
||||
<button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="_close"></button>
|
||||
</header>
|
||||
<main class="modal-body">
|
||||
<t t-slot="default"/>
|
||||
@@ -1513,9 +1513,7 @@
|
||||
|
||||
<t t-name="notification-box">
|
||||
<div t-attf-class="o_notification_box mb0 alert alert-dismissible alert-{{type}}" role="alertdialog">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span class="fa fa-times"></span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" aria-label="Close"></button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="modal-content">
|
||||
<header t-if="renderHeader" class="modal-header">
|
||||
<h4 class="modal-title"><t t-out="title"/><span class="o_subtitle text-muted small" t-out="subtitle"/></h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" tabindex="-1">×</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" tabindex="-1"></button>
|
||||
</header>
|
||||
<main class="modal-body"/>
|
||||
<footer t-if="renderFooter" class="modal-footer justify-content-around justify-content-sm-start flex-wrap gap-1"/>
|
||||
|
||||
@@ -58,9 +58,7 @@
|
||||
<t t-foreach="Array.from(this.translateAlertData[this.model.root.resId])" t-as="field" t-key="field.name">
|
||||
<strong><a class="o_field_translate" t-att-name="field.name" href="#"><t t-esc="field.string"/><t t-if="!field_last">, </t></a></strong>
|
||||
</t>
|
||||
<button t-on-click="() => this.closeTranslateAlert()" type="button" class="close" aria-label="Close">
|
||||
<span class="fa fa-times"></span>
|
||||
</button>
|
||||
<button t-on-click="() => this.closeTranslateAlert()" type="button" class="btn-close" aria-label="Close"></button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ QUnit.module("Components", (hooks) => {
|
||||
Parent.components = { Dialog };
|
||||
parent = await mount(Parent, target, { env });
|
||||
assert.containsOnce(target, ".o_dialog");
|
||||
await click(target, ".o_dialog header button.close");
|
||||
await click(target, ".o_dialog header button.btn-close");
|
||||
assert.verifySteps(["close"]);
|
||||
});
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
// Basic layout with default properties
|
||||
assert.containsOnce(dialog, '.modal.o_technical_modal');
|
||||
assert.hasClass(dialog.querySelector('.modal .modal-dialog'), 'modal-lg');
|
||||
assert.containsOnce(dialog, '.modal-header > button.close');
|
||||
assert.containsOnce(dialog, '.modal-header > button.btn-close');
|
||||
assert.containsOnce(dialog, '.modal-footer > button.btn.btn-primary');
|
||||
assert.strictEqual(dialog.querySelector('.modal-body').innerText.trim(), "sup",
|
||||
"Subcomponent should match with its given text");
|
||||
@@ -261,7 +261,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
assert.containsOnce(document.body, '.o_dialog');
|
||||
assert.containsOnce(document.body, '.o_legacy_dialog');
|
||||
|
||||
await testUtils.dom.click(modals[modals.length - 1].querySelector('.close'));
|
||||
await testUtils.dom.click(modals[modals.length - 1].querySelector('.btn-close'));
|
||||
|
||||
modals = document.querySelectorAll('.modal');
|
||||
assert.notOk(modals[modals.length - 1].classList.contains('o_inactive_modal'),
|
||||
@@ -514,12 +514,12 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
"wowl"
|
||||
);
|
||||
|
||||
await testUtils.dom.click(target.querySelector(`.o_dialog .modal-header .close`));
|
||||
await testUtils.dom.click(target.querySelector(`.o_dialog .modal-header .btn-close`));
|
||||
assert.containsNone(target, ".o_dialog");
|
||||
assert.containsOnce(target, ".modal");
|
||||
assert.containsOnce(target, ".modal[tabindex='-1']");
|
||||
|
||||
await testUtils.dom.click(target.querySelector(`.modal-header .close`));
|
||||
await testUtils.dom.click(target.querySelector(`.modal-header .btn-close`));
|
||||
assert.containsNone(target, ".o_dialog");
|
||||
assert.containsNone(target, ".modal");
|
||||
});
|
||||
|
||||
@@ -339,7 +339,7 @@ QUnit.module('Legacy relational_fields', {
|
||||
assert.ok($('body').hasClass('modal-open'), 'Modal is said opened');
|
||||
|
||||
// Close second modal
|
||||
await testUtils.dom.click($modals.last().find('button[class="close"]'));
|
||||
await testUtils.dom.click($modals.last().find('button[class="btn-close"]'));
|
||||
var $modal = $('.modal');
|
||||
$focusedModal = $(document.activeElement).closest('.modal');
|
||||
|
||||
@@ -349,7 +349,7 @@ QUnit.module('Legacy relational_fields', {
|
||||
assert.ok($('body').hasClass('modal-open'), 'Modal is said opened');
|
||||
|
||||
// Close first modal
|
||||
await testUtils.dom.click($modal.find('button[class="close"]'));
|
||||
await testUtils.dom.click($modal.find('button[class="btn-close"]'));
|
||||
$modal = $('.modal-dialog.modal-lg');
|
||||
|
||||
assert.equal($modal.length, 0, 'There should be no modal');
|
||||
|
||||
@@ -6392,7 +6392,7 @@ QUnit.module('LegacyViews', {
|
||||
|
||||
await testUtils.dom.click(form.$('.o_external_button'));
|
||||
// Close modal
|
||||
await testUtils.dom.click($('.modal').last().find('button[class="close"]'));
|
||||
await testUtils.dom.click($('.modal').last().find('button[class="btn-close"]'));
|
||||
assert.notStrictEqual($(".o_content").scrollTop(), 0,
|
||||
"scroll position should not be 0 after closing modal");
|
||||
assert.containsNone(document.body, '.modal', 'There should be no modal');
|
||||
@@ -7318,7 +7318,7 @@ QUnit.module('LegacyViews', {
|
||||
assert.containsOnce(form, '.o_form_view .alert > div', "should have a translation alert");
|
||||
|
||||
// remove translation alert by click X and check alert even after form reload
|
||||
await testUtils.dom.click(form.$('.o_form_view .alert > .close'));
|
||||
await testUtils.dom.click(form.$('.o_form_view .alert > .btn-close'));
|
||||
assert.containsNone(form, '.o_form_view .alert > div', "should not have a translation alert");
|
||||
|
||||
await form.reload();
|
||||
|
||||
@@ -3986,7 +3986,7 @@ QUnit.module('LegacyViews', {
|
||||
'the name should be "xmo"');
|
||||
await testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
|
||||
nbRPCs = 0;
|
||||
await testUtils.dom.click($('.modal-header .close'));
|
||||
await testUtils.dom.click($('.modal-header .btn-close'));
|
||||
assert.containsNone(document.body, '.modal');
|
||||
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
|
||||
'title of the column should still be "xmo"');
|
||||
|
||||
@@ -3892,7 +3892,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
assert.hasClass(document.body, "modal-open");
|
||||
|
||||
// Close second modal
|
||||
await click(nextModal, "button[class='close']");
|
||||
await click(nextModal, "button[class='btn-close']");
|
||||
|
||||
assert.containsOnce(target, ".modal");
|
||||
assert.strictEqual(
|
||||
@@ -3904,7 +3904,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
assert.hasClass(document.body, "modal-open");
|
||||
|
||||
// Close first modal
|
||||
await click(originalModal, "button[class='close']");
|
||||
await click(originalModal, "button[class='btn-close']");
|
||||
assert.containsNone(target, ".modal");
|
||||
assert.doesNotHaveClass(document.body, "modal-open");
|
||||
});
|
||||
|
||||
@@ -6625,7 +6625,7 @@ QUnit.module("Views", (hooks) => {
|
||||
await click(target.querySelector(".o_external_button"));
|
||||
|
||||
// Close modal
|
||||
await click(target, '.modal-dialog button[class="close"]');
|
||||
await click(target, '.modal-dialog button[class="btn-close"]');
|
||||
assert.notStrictEqual(
|
||||
$(".o_content").scrollTop(),
|
||||
0,
|
||||
|
||||
@@ -4935,7 +4935,7 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
await editInput(target, ".modal .o_form_editable input", "ged"); // change the value
|
||||
nbRPCs = 0;
|
||||
await click(target, ".modal-header .close");
|
||||
await click(target, ".modal-header .btn-close");
|
||||
|
||||
assert.containsNone(target, ".modal");
|
||||
assert.strictEqual(
|
||||
|
||||
@@ -1139,9 +1139,7 @@ QUnit.module("Views", (hooks) => {
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Remove Configuration Tips</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-label="Close">×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you want to remove this configuration panel?</p>
|
||||
|
||||
@@ -145,7 +145,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
// open a new dialog form
|
||||
await doAction(webClient, 5, { onClose });
|
||||
|
||||
await click(target, ".modal-header button.close");
|
||||
await click(target, ".modal-header button.btn-close");
|
||||
await nextTick();
|
||||
await legacyExtraNextTick();
|
||||
assert.containsNone(target, ".modal");
|
||||
|
||||
@@ -997,7 +997,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
assert.verifySteps(["clientAction setup"]);
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".o_dialog_error");
|
||||
await click(target, ".modal-header .close");
|
||||
await click(target, ".modal-header .btn-close");
|
||||
assert.containsNone(target, ".o_dialog_error");
|
||||
await click(target, "nav .o_navbar_apps_menu .dropdown-toggle ");
|
||||
assert.containsN(target, ".dropdown-item.o_app", 3);
|
||||
|
||||
@@ -1954,7 +1954,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
"Warning modal should be opened"
|
||||
);
|
||||
|
||||
await click(document.querySelector(".modal.o_technical_modal button.close"));
|
||||
await click(document.querySelector(".modal.o_technical_modal button.btn-close"));
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
".modal.o_technical_modal",
|
||||
|
||||
@@ -163,7 +163,7 @@ var ViewEditor = Widget.extend({
|
||||
'click button[data-action=reset]': '_onResetClick',
|
||||
'click button[data-action=format]': '_onFormatClick',
|
||||
'click button[data-action=close]': '_onCloseClick',
|
||||
'click #ace-view-id > .alert-warning .close': '_onCloseWarningClick'
|
||||
'click #ace-view-id > .alert-warning .btn-close': '_onCloseWarningClick'
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,9 +51,7 @@
|
||||
<span class="o_ace_editor_resource_info"/>
|
||||
<div class="alert alert-warning alert-dismissible mt-2 mb-0" role="alert">
|
||||
Editing a built-in file through this editor is not advised, as it will prevent it from being updated during future App upgrades.
|
||||
<button type="button" class="close" aria-label="Close">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ace-view-editor"/>
|
||||
|
||||
@@ -53,14 +53,16 @@ var EventRegistrationForm = Widget.extend({
|
||||
$button.attr('disabled', true);
|
||||
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
|
||||
var $modal = $(modal);
|
||||
$modal.modal({backdrop: 'static', keyboard: false});
|
||||
$modal.find('.modal-body > div').removeClass('container'); // retrocompatibility - REMOVE ME in master / saas-19
|
||||
$modal.appendTo(document.body);
|
||||
const modalBS = new Modal($modal[0], {backdrop: 'static', keyboard: false});
|
||||
modalBS.show();
|
||||
$modal.appendTo('body').modal();
|
||||
$modal.on('click', '.js_goto_event', function () {
|
||||
$modal.modal('hide');
|
||||
$button.prop('disabled', false);
|
||||
});
|
||||
$modal.on('click', '.close', function () {
|
||||
$modal.on('click', '.btn-close', function () {
|
||||
$button.prop('disabled', false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -280,7 +280,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header align-items-center">
|
||||
<h4 class="modal-title">Attendees</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span>×</span></button>
|
||||
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<t t-set="counter_type" t-value="1"/>
|
||||
<t t-set="counter" t-value="0"/>
|
||||
|
||||
@@ -1614,7 +1614,7 @@
|
||||
<a class="nav-link spam_menu" id="character-tab" data-toggle="tab" href="#spam_character" role="tab" aria-controls="spam_character" aria-selected="false">圾 Text</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button type="button" class="close align-self-start" data-dismiss="modal"><span aria-label="Close">×</span></button>
|
||||
<button type="button" class="btn-close align-self-start" data-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body bg-100">
|
||||
<div class="tab-content" id="o_tab_content_spam">
|
||||
|
||||
@@ -380,10 +380,10 @@ publicWidget.registry.WebsiteSale = publicWidget.Widget.extend(VariantMixin, car
|
||||
var cart_alert = $('.oe_cart').parent().find('#data_warning');
|
||||
if (cart_alert.length === 0) {
|
||||
$('.oe_cart').prepend('<div class="alert alert-danger alert-dismissable" role="alert" id="data_warning">'+
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning + '</div>');
|
||||
'<button type="button" class="btn-close" data-dismiss="alert" aria-hidden="true"></button> ' + data.warning + '</div>');
|
||||
}
|
||||
else {
|
||||
cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning);
|
||||
cart_alert.html('<button type="button" class="btn-close" data-dismiss="alert" aria-hidden="true"></button> ' + data.warning);
|
||||
}
|
||||
$input.val(data.quantity);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ publicWidget.registry.ProductWishlist = publicWidget.Widget.extend(VariantMixin,
|
||||
$('.wishlist-section').prepend('<div class="mt16 alert alert-danger alert-dismissable" role="alert" id="data_warning"></div>');
|
||||
}
|
||||
var cart_alert = $('.wishlist-section').parent().find('#data_warning');
|
||||
cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + resp.warning);
|
||||
cart_alert.html('<button type="button" class="btn-close" data-bs-dismiss="alert" aria-hidden="true">×</button> ' + resp.warning);
|
||||
}
|
||||
sessionStorage.setItem('website_sale_cart_quantity', resp.cart_quantity);
|
||||
$('.my_cart_quantity').html(resp.cart_quantity || '<i class="fa fa-warning" /> ');
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
<t t-name="slide.slide.quiz.finish">
|
||||
<div>
|
||||
<button type="button" class="o_wslides_quiz_modal_close_btn close position-absolute" data-dismiss="modal" aria-label="Close">×</button>
|
||||
<button type="button" class="o_wslides_quiz_modal_close_btn btn-close position-absolute" data-dismiss="modal" aria-label="Close"></button>
|
||||
<div class="o_wslides_quiz_success_image d-none d-md-flex flex-shrink-0">
|
||||
<img class="o_wslides_quiz_modal_hero" src="/website_slides/static/src/img/quiz_modal_success.svg" alt=""/>
|
||||
</div>
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Remove Configuration Tips</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-label="Close">×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Do you want to remove this configuration panel?</p>
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"moment": "readonly",
|
||||
"py": "readonly",
|
||||
"ClipboardJS": "readonly",
|
||||
"Modal": "readonly",
|
||||
"Alert": "readonly",
|
||||
"globalThis": "readonly",
|
||||
"module": "readonly",
|
||||
"chai": "readonly",
|
||||
|
||||
Reference in New Issue
Block a user