Skip to content

Commit d3e32c4

Browse files
committed
destroy widgets within overlay using AjaxDestroy. Moving AjaxDestroy to its own file is required to avoid a circular import dependency within ajax.js and overlay.js
1 parent 14b0ccb commit d3e32c4

File tree

7 files changed

+109
-93
lines changed

7 files changed

+109
-93
lines changed

src/ajax.js

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
http_request
2727
} from './request.js';
2828
import {spinner} from './spinner.js';
29+
import {AjaxDestroy} from './ajaxdestroy.js';
2930

3031
/**
3132
* Ajax utility mixin.
@@ -547,47 +548,6 @@ export class AjaxDispatcher extends AjaxUtil {
547548
}
548549
}
549550

550-
/**
551-
* DOM parser for destroying JavaScript instances attached to DOM elements
552-
* going to be removed.
553-
*/
554-
export class AjaxDestroy extends Parser {
555-
556-
parse(node) {
557-
let instances = node._ajax_attached;
558-
if (instances !== undefined) {
559-
for (let instance of instances) {
560-
// XXX: maybe introduce skip_destroy flag for instances
561-
// that do not need to be destroyed
562-
if (instance.destroy !== undefined) {
563-
instance.destroy();
564-
} else {
565-
console.warn('ts.ajax bound but no destroy method defined: ' + instance.constructor.name);
566-
}
567-
}
568-
}
569-
570-
let attrs = this.node_attrs(node);
571-
if (attrs['ajax:bind']) { // unbind events bound from AjaxDispatcher
572-
let evts = attrs['ajax:bind'];
573-
$(node).off(evts);
574-
}
575-
node._ajax_attached = null;
576-
let dd = bootstrap.Dropdown.getInstance(node);
577-
let tt = bootstrap.Tooltip.getInstance(node);
578-
if (dd) {
579-
dd.dispose();
580-
}
581-
if (tt) {
582-
tt.dispose();
583-
}
584-
$(node).empty(); // remove retained comments
585-
$(node).off(); // remove event listeners
586-
$(node).removeData(); // remove cached data
587-
node = null;
588-
}
589-
}
590-
591551
/**
592552
* Handle for DOM manipulation and Ajax continuation operations.
593553
*/
@@ -613,8 +573,7 @@ export class AjaxHandle extends AjaxUtil {
613573
context;
614574
if (mode === 'replace') {
615575
let old_context = $(selector);
616-
this.destroy(old_context.children());
617-
old_context.empty();
576+
this.destroy(old_context);
618577
old_context.replaceWith(payload);
619578
context = $(selector);
620579
if (context.length) {
@@ -1161,7 +1120,7 @@ export class Ajax extends AjaxUtil {
11611120
}
11621121

11631122
let ajax = new Ajax();
1164-
export {ajax};
1123+
export {ajax, AjaxDestroy};
11651124

11661125
$.fn.tsajax = function() {
11671126
ajax.bind(this);

src/ajaxdestroy.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {Parser} from "./parser";
2+
import $ from 'jquery';
3+
4+
/**
5+
* DOM parser for destroying JavaScript instances attached to DOM elements
6+
* going to be removed.
7+
*/
8+
export class AjaxDestroy extends Parser {
9+
10+
parse(node) {
11+
let instances = node._ajax_attached;
12+
if (instances !== undefined) {
13+
for (let instance of instances) {
14+
if (instance.destroy !== undefined) {
15+
instance.destroy();
16+
} else {
17+
console.warn('ts.ajax bound but no destroy method defined: ' + instance.constructor.name);
18+
}
19+
}
20+
}
21+
22+
let attrs = this.node_attrs(node);
23+
if (attrs['ajax:bind']) { // unbind events bound from AjaxDispatcher
24+
let evts = attrs['ajax:bind'];
25+
$(node).off(evts);
26+
}
27+
if (window.bootstrap) {
28+
let dd = window.bootstrap.Dropdown.getInstance(node);
29+
let tt = window.bootstrap.Tooltip.getInstance(node);
30+
if (dd) {
31+
dd.dispose();
32+
}
33+
if (tt) {
34+
tt.dispose();
35+
}
36+
}
37+
$(node).empty(); // remove retained comments
38+
$(node).off(); // remove event listeners
39+
$(node).removeData(); // remove cached data
40+
node = null;
41+
}
42+
}
43+
44+
/**
45+
* Destroys an AJAX-bound element.
46+
*
47+
* @param {HTMLElement|jQuery} elem - The element to destroy. Can be a jQuery object or a DOM element.
48+
* @returns {void}
49+
*/
50+
export function ajax_destroy(elem) {
51+
elem = elem instanceof $ ? elem.get(0) : elem;
52+
let handle = new AjaxDestroy();
53+
handle.walk(elem);
54+
}

src/overlay.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
set_default,
66
uuid4
77
} from './utils.js';
8+
import {ajax_destroy} from './ajaxdestroy.js';
89

910
export class Overlay extends Events {
1011

@@ -23,7 +24,7 @@ export class Overlay extends Events {
2324

2425
compile() {
2526
compile_template(this, `
26-
<div class="modal fade ${this.css}" id="${this.uid}" t-elem="elem" data-bs-backdrop="static">
27+
<div class="modal ${this.css}" id="${this.uid}" t-elem="elem">
2728
<div class="modal-dialog">
2829
<div class="modal-content">
2930
<div class="modal-header">
@@ -44,7 +45,6 @@ export class Overlay extends Events {
4445
$('body').addClass('modal-open');
4546
this.container.append(this.elem);
4647
this.elem.show();
47-
this.elem.modal('show');
4848
this.is_open = true;
4949
this.trigger('on_open');
5050
}
@@ -53,9 +53,9 @@ export class Overlay extends Events {
5353
if ($('.modal:visible').length === 1) {
5454
$('body').removeClass('modal-open');
5555
}
56-
this.elem.modal('hide');
57-
this.elem.remove();
56+
ajax_destroy(this.elem);
5857
this.is_open = false;
58+
this.elem.removeData('overlay').remove();
5959
this.trigger('on_close');
6060
}
6161
}
@@ -84,7 +84,7 @@ export class Message extends Overlay {
8484
opts.content = opts.message ? opts.message : opts.content;
8585
opts.css = opts.flavor ? opts.flavor : opts.css;
8686
super(opts);
87-
this.compile_actions()
87+
this.compile_actions();
8888
}
8989

9090
compile_actions() {

tests/test_overlay.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,14 @@ QUnit.module('treibstoff.overlay', hooks => {
5252

5353
let body = $('body');
5454
assert.true(body.hasClass('modal-open'));
55-
assert.deepEqual(body.css('padding-right'), '13px');
56-
assert.deepEqual(body.css('overflow-x'), 'hidden');
55+
// assert.deepEqual(body.css('overflow-x'), 'hidden');
5756

5857
ol.close();
5958
assert.deepEqual(container.children().length, 0);
6059
assert.false(ol.elem.is(':visible'));
6160

6261
assert.false(body.hasClass('modal-open'));
63-
assert.deepEqual(body.css('padding-right'), '0px');
64-
assert.deepEqual(body.css('overflow-x'), 'auto');
62+
// assert.deepEqual(body.css('overflow-x'), 'auto');
6563
});
6664

6765
QUnit.test('Test Overlay events', assert => {

tests/test_widget.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ QUnit.module('treibstoff.widget', hooks => {
189189
assert.step('External on_click');
190190
});
191191

192-
assert.deepEqual(button.unselected_class, 'btn-default');
192+
assert.deepEqual(button.unselected_class, 'btn-primary');
193193
assert.deepEqual(button.selected_class, 'btn-success');
194194

195195
button.selected = true;

treibstoff/bundle/treibstoff.bundle.js

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,45 @@ var ts = (function (exports, $) {
554554
}
555555
}
556556

557+
class AjaxDestroy extends Parser {
558+
parse(node) {
559+
let instances = node._ajax_attached;
560+
if (instances !== undefined) {
561+
for (let instance of instances) {
562+
if (instance.destroy !== undefined) {
563+
instance.destroy();
564+
} else {
565+
console.warn('ts.ajax bound but no destroy method defined: ' + instance.constructor.name);
566+
}
567+
}
568+
}
569+
let attrs = this.node_attrs(node);
570+
if (attrs['ajax:bind']) {
571+
let evts = attrs['ajax:bind'];
572+
$(node).off(evts);
573+
}
574+
if (window.bootstrap) {
575+
let dd = window.bootstrap.Dropdown.getInstance(node);
576+
let tt = window.bootstrap.Tooltip.getInstance(node);
577+
if (dd) {
578+
dd.dispose();
579+
}
580+
if (tt) {
581+
tt.dispose();
582+
}
583+
}
584+
$(node).empty();
585+
$(node).off();
586+
$(node).removeData();
587+
node = null;
588+
}
589+
}
590+
function ajax_destroy(elem) {
591+
elem = elem instanceof $ ? elem.get(0) : elem;
592+
let handle = new AjaxDestroy();
593+
handle.walk(elem);
594+
}
595+
557596
class Overlay extends Events {
558597
constructor(opts) {
559598
super();
@@ -569,7 +608,7 @@ var ts = (function (exports, $) {
569608
}
570609
compile() {
571610
compile_template(this, `
572-
<div class="modal fade ${this.css}" id="${this.uid}" t-elem="elem" data-bs-backdrop="static">
611+
<div class="modal ${this.css}" id="${this.uid}" t-elem="elem">
573612
<div class="modal-dialog">
574613
<div class="modal-content">
575614
<div class="modal-header">
@@ -589,17 +628,16 @@ var ts = (function (exports, $) {
589628
$('body').addClass('modal-open');
590629
this.container.append(this.elem);
591630
this.elem.show();
592-
this.elem.modal('show');
593631
this.is_open = true;
594632
this.trigger('on_open');
595633
}
596634
close() {
597635
if ($('.modal:visible').length === 1) {
598636
$('body').removeClass('modal-open');
599637
}
600-
this.elem.modal('hide');
601-
this.elem.remove();
638+
ajax_destroy(this.elem);
602639
this.is_open = false;
640+
this.elem.removeData('overlay').remove();
603641
this.trigger('on_close');
604642
}
605643
}
@@ -1190,38 +1228,6 @@ var ts = (function (exports, $) {
11901228
}
11911229
}
11921230
}
1193-
class AjaxDestroy extends Parser {
1194-
parse(node) {
1195-
let instances = node._ajax_attached;
1196-
if (instances !== undefined) {
1197-
for (let instance of instances) {
1198-
if (instance.destroy !== undefined) {
1199-
instance.destroy();
1200-
} else {
1201-
console.warn('ts.ajax bound but no destroy method defined: ' + instance.constructor.name);
1202-
}
1203-
}
1204-
}
1205-
let attrs = this.node_attrs(node);
1206-
if (attrs['ajax:bind']) {
1207-
let evts = attrs['ajax:bind'];
1208-
$(node).off(evts);
1209-
}
1210-
node._ajax_attached = null;
1211-
let dd = bootstrap.Dropdown.getInstance(node);
1212-
let tt = bootstrap.Tooltip.getInstance(node);
1213-
if (dd) {
1214-
dd.dispose();
1215-
}
1216-
if (tt) {
1217-
tt.dispose();
1218-
}
1219-
$(node).empty();
1220-
$(node).off();
1221-
$(node).removeData();
1222-
node = null;
1223-
}
1224-
}
12251231
class AjaxHandle extends AjaxUtil {
12261232
constructor(ajax) {
12271233
super();
@@ -1241,8 +1247,7 @@ var ts = (function (exports, $) {
12411247
context;
12421248
if (mode === 'replace') {
12431249
let old_context = $(selector);
1244-
this.destroy(old_context.children());
1245-
old_context.empty();
1250+
this.destroy(old_context);
12461251
old_context.replaceWith(payload);
12471252
context = $(selector);
12481253
if (context.length) {

treibstoff/bundle/treibstoff.bundle.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)