Skip to content

Commit 0c48d3c

Browse files
author
marker dao ®
committed
DropDownEditor, Overlay: Clean links to elements on dispose and clean (T1311876)
1 parent 7ed8250 commit 0c48d3c

38 files changed

+709
-244
lines changed

packages/devextreme/js/__internal/core/m_events_strategy.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,7 @@ export class EventsStrategy {
7070
each(this._events, (eventName, event) => {
7171
event.empty();
7272
});
73+
74+
this._owner = null;
7375
}
7476
}

packages/devextreme/js/__internal/ui/color_box/m_color_box.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,12 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
148148
_createColorView(): void {
149149
this._popup.$overlayContent().addClass(COLOR_BOX_OVERLAY_CLASS);
150150

151-
const $colorView = $('<div>').appendTo(this._popup.$content());
151+
const $colorView = $('<div>');
152+
const $content = this._popup.$content();
153+
154+
if ($content) {
155+
$colorView.appendTo($content);
156+
}
152157

153158
this._colorView = this._createComponent($colorView, ColorView, this._colorViewConfig());
154159
}

packages/devextreme/js/__internal/ui/date_box/m_date_box.base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ class DateBox extends DropDownEditor<DateBoxBaseProperties> {
377377

378378
_renderPopup(): void {
379379
super._renderPopup();
380-
this._popup?.$wrapper().addClass(DATEBOX_WRAPPER_CLASS);
380+
this._popup?.$wrapper()?.addClass(DATEBOX_WRAPPER_CLASS);
381381
this._renderPopupWrapper();
382382
}
383383

@@ -411,7 +411,7 @@ class DateBox extends DropDownEditor<DateBoxBaseProperties> {
411411
const { type } = this.option();
412412

413413
this._popup.$wrapper()
414-
.addClass(`${DATEBOX_WRAPPER_CLASS}-${type}`)
414+
?.addClass(`${DATEBOX_WRAPPER_CLASS}-${type}`)
415415
.addClass(`${DATEBOX_WRAPPER_CLASS}-${this._pickerType}`)
416416
.addClass(DROPDOWNEDITOR_OVERLAY_CLASS);
417417
}

packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_button.ts

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,58 @@ export default class DropDownButton extends TextEditorButton {
2222
}
2323

2424
_attachEvents(instance): void {
25-
const { editor } = this;
26-
2725
instance.option('onClick', (e) => {
28-
// @ts-expect-error
29-
if (editor._shouldCallOpenHandler?.()) {
30-
// @ts-expect-error
31-
editor._openHandler(e);
26+
// @ts-expect-error _shouldCallOpenHandler should be typed
27+
if (this.editor?._shouldCallOpenHandler?.()) {
28+
// @ts-expect-error _openHandler should be typed
29+
this.editor?._openHandler(e);
3230
return;
3331
}
34-
// @ts-expect-error
35-
!editor.option('openOnFieldClick') && editor._openHandler(e);
32+
33+
// @ts-expect-error openOnFieldClick should be typed
34+
const { openOnFieldClick } = this.editor?.option() ?? {};
35+
36+
if (!openOnFieldClick) {
37+
// @ts-expect-error _openHandler should be typed
38+
this.editor?._openHandler(e);
39+
}
3640
});
3741

3842
eventsEngine.on(instance.$element(), 'mousedown', (e) => {
39-
if (editor.$element().is('.dx-state-focused')) {
43+
if (this.editor?.$element()?.is('.dx-state-focused')) {
4044
e.preventDefault();
4145
}
4246
});
4347
}
4448

4549
_create(): {
46-
$element: dxElementWrapper;
4750
instance: Button;
48-
} {
51+
$element: dxElementWrapper;
52+
} | undefined {
4953
const { editor } = this;
54+
55+
if (!editor) {
56+
return undefined;
57+
}
58+
5059
const $element = $('<div>');
5160
const options = this._getOptions();
5261

5362
this._addToContainer($element);
5463

55-
const instance = editor._createComponent($element, Button, extend({}, options, { elementAttr: { 'aria-label': messageLocalization.format(BUTTON_MESSAGE) } }));
64+
const instance = editor._createComponent(
65+
$element,
66+
Button,
67+
extend(
68+
{},
69+
options,
70+
{
71+
elementAttr: {
72+
'aria-label': messageLocalization.format(BUTTON_MESSAGE),
73+
},
74+
},
75+
),
76+
);
5677

5778
this._legacyRender(editor.$element(), $element, options.visible);
5879

@@ -65,7 +86,7 @@ export default class DropDownButton extends TextEditorButton {
6586
_getOptions() {
6687
const { editor } = this;
6788
const visible = this._isVisible();
68-
const isReadOnly = editor.option('readOnly');
89+
const isReadOnly = editor?.option('readOnly');
6990
const options = {
7091
focusStateEnabled: false,
7192
hoverStateEnabled: false,
@@ -82,7 +103,7 @@ export default class DropDownButton extends TextEditorButton {
82103
_isVisible(): boolean {
83104
const { editor } = this;
84105
// @ts-expect-error
85-
return super._isVisible() && editor.option('showDropDownButton');
106+
return super._isVisible() && editor?.option('showDropDownButton');
86107
}
87108

88109
// TODO: get rid of it
@@ -98,13 +119,13 @@ export default class DropDownButton extends TextEditorButton {
98119
}
99120

100121
_isSameTemplate() {
101-
return this.editor.option('dropDownButtonTemplate') === this.currentTemplate;
122+
return this.editor?.option('dropDownButtonTemplate') === this.currentTemplate;
102123
}
103124

104125
_addTemplate(options): void {
105126
if (!this._isSameTemplate()) {
106-
options.template = this.editor._getTemplateByOption('dropDownButtonTemplate');
107-
this.currentTemplate = this.editor.option('dropDownButtonTemplate');
127+
options.template = this.editor?._getTemplateByOption('dropDownButtonTemplate');
128+
this.currentTemplate = this.editor?.option('dropDownButtonTemplate');
108129
}
109130
}
110131

@@ -114,11 +135,14 @@ export default class DropDownButton extends TextEditorButton {
114135

115136
if (shouldUpdate) {
116137
const { editor, instance } = this;
117-
const $editor = editor.$element();
138+
139+
const $editor = editor?.$element();
118140
const options = this._getOptions();
141+
119142
// @ts-expect-error
120143
instance?.option(options);
121-
this._legacyRender($editor, instance?.$element(), options.visible);
144+
145+
this._legacyRender($editor, (instance as Button)?.$element(), options.visible);
122146
}
123147
}
124148
}

packages/devextreme/js/__internal/ui/drop_down_editor/m_drop_down_editor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,9 +648,13 @@ class DropDownEditor<
648648
});
649649

650650
this._attachPopupKeyHandler();
651-
652651
this._contentReadyHandler();
653-
this._setPopupContentId(this._popup.$content());
652+
653+
const $content = this._popup.$content();
654+
655+
if ($content) {
656+
this._setPopupContentId($content);
657+
}
654658

655659
this._bindInnerWidgetOptions(this._popup, 'dropDownOptions');
656660
}

packages/devextreme/js/__internal/ui/m_action_sheet.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class ActionSheet extends CollectionWidget<Properties> {
137137

138138
_renderPopupTitle(): void {
139139
this._mapPopupOption('showTitle');
140-
this._popup?.$wrapper().toggleClass(ACTION_SHEET_WITHOUT_TITLE_CLASS, !this.option('showTitle'));
140+
this._popup?.$wrapper()?.toggleClass(ACTION_SHEET_WITHOUT_TITLE_CLASS, !this.option('showTitle'));
141141
}
142142

143143
_clean() {
@@ -171,7 +171,7 @@ class ActionSheet extends CollectionWidget<Properties> {
171171

172172
this._popup.$overlayContent().attr('role', 'dialog');
173173

174-
this._popup.$wrapper().addClass(ACTION_SHEET_POPOVER_WRAPPER_CLASS);
174+
this._popup.$wrapper()?.addClass(ACTION_SHEET_POPOVER_WRAPPER_CLASS);
175175
}
176176

177177
_createPopup(): void {
@@ -225,11 +225,11 @@ class ActionSheet extends CollectionWidget<Properties> {
225225
},
226226
}));
227227

228-
this._popup.$wrapper().addClass(ACTION_SHEET_POPUP_WRAPPER_CLASS);
228+
this._popup.$wrapper()?.addClass(ACTION_SHEET_POPUP_WRAPPER_CLASS);
229229
}
230230

231231
_popupContentReadyAction(): void {
232-
this._popup.$content().append(this._$itemContainer);
232+
this._popup.$content()?.append(this._$itemContainer);
233233
this._attachClickEvent();
234234
this._attachHoldEvent();
235235

@@ -252,8 +252,14 @@ class ActionSheet extends CollectionWidget<Properties> {
252252
const cancelClickAction = this._createActionByOption('onCancelClick') || noop;
253253
const that = this;
254254

255-
this._$cancelButton = $('<div>').addClass(ACTION_SHEET_CANCEL_BUTTON_CLASS)
256-
.appendTo(this._popup?.$content());
255+
this._$cancelButton = $('<div>').addClass(ACTION_SHEET_CANCEL_BUTTON_CLASS);
256+
257+
const $content = this._popup?.$content();
258+
259+
if ($content) {
260+
this._$cancelButton.appendTo($content);
261+
}
262+
257263
this._createComponent(this._$cancelButton, Button, {
258264
disabled: false,
259265
stylingMode: ACTION_SHEET_BUTTON_DEFAULT_STYLING_MODE,

packages/devextreme/js/__internal/ui/m_dialog.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ export const custom = function (options) {
179179

180180
popupInstance.option('toolbarItems', popupToolbarItems);
181181

182-
popupInstance.$wrapper().addClass(DX_DIALOG_WRAPPER_CLASSNAME);
182+
popupInstance.$wrapper()?.addClass(DX_DIALOG_WRAPPER_CLASSNAME);
183183

184184
if (options.position) {
185185
popupInstance.option('position', options.position);
186186
}
187187

188188
popupInstance.$wrapper()
189-
.addClass(DX_DIALOG_ROOT_CLASSNAME);
189+
?.addClass(DX_DIALOG_ROOT_CLASSNAME);
190190

191191
function show() {
192192
if (devices.real().deviceType === 'phone') {

packages/devextreme/js/__internal/ui/m_drop_down_box.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ class DropDownBox<
233233
component: this,
234234
};
235235

236-
$popupContent.empty();
236+
$popupContent?.empty();
237+
238+
if (!$popupContent) {
239+
return;
240+
}
237241

238242
contentTemplate.render({
239243
container: getPublicElement($popupContent),

packages/devextreme/js/__internal/ui/m_drop_down_button.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,13 @@ class DropDownButton extends Widget<DropDownButtonProperties> {
370370
const $content = this._popup!.$content();
371371
const template = this._getTemplateByOption('dropDownContentTemplate');
372372

373-
$content.empty();
373+
$content?.empty();
374374

375375
this._popupContentId = `dx-${new Guid()}`;
376376
this.setAria('id', this._popupContentId, $content);
377377

378378
const result = template.render({
379-
container: getPublicElement($content),
379+
container: $content ? getPublicElement($content) : undefined,
380380
model: this.option('items') || this._dataController.getDataSource(),
381381
});
382382

@@ -480,8 +480,8 @@ class DropDownButton extends Widget<DropDownButtonProperties> {
480480
const $popup = $('<div>');
481481
this.$element().append($popup);
482482
this._popup = this._createComponent($popup, Popup, this._popupOptions());
483-
this._popup.$content().addClass(DROP_DOWN_BUTTON_CONTENT);
484-
this._popup.$wrapper().addClass(DROP_DOWN_BUTTON_POPUP_WRAPPER_CLASS);
483+
this._popup.$content()?.addClass(DROP_DOWN_BUTTON_CONTENT);
484+
this._popup.$wrapper()?.addClass(DROP_DOWN_BUTTON_POPUP_WRAPPER_CLASS);
485485
this._popup.$overlayContent().attr('aria-label', OVERLAY_CONTENT_LABEL);
486486
this._popup.on('hiding', this._popupHidingHandler.bind(this));
487487
this._popup.on('showing', this._popupShowingHandler.bind(this));

packages/devextreme/js/__internal/ui/m_load_panel.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ class LoadPanel extends Overlay<LoadPanelProperties> {
100100
super._render();
101101

102102
this.$element().addClass(LOADPANEL_CLASS);
103-
this.$wrapper().addClass(LOADPANEL_WRAPPER_CLASS);
103+
this.$wrapper()?.addClass(LOADPANEL_WRAPPER_CLASS);
104104
this._updateWrapperAria();
105105
}
106106

107107
_updateWrapperAria(): void {
108108
this.$wrapper()
109-
.removeAttr('aria-label')
109+
?.removeAttr('aria-label')
110110
.removeAttr('role');
111111

112112
const showIndicator = this.option('showIndicator');
@@ -134,10 +134,15 @@ class LoadPanel extends Overlay<LoadPanelProperties> {
134134
_renderContentImpl(): void {
135135
super._renderContentImpl();
136136

137-
this.$content().addClass(LOADPANEL_CONTENT_CLASS);
137+
this.$content()?.addClass(LOADPANEL_CONTENT_CLASS);
138138

139139
this._$loadPanelContentWrapper = $('<div>').addClass(LOADPANEL_CONTENT_WRAPPER_CLASS);
140-
this._$loadPanelContentWrapper.appendTo(this.$content());
140+
141+
const $content = this.$content();
142+
143+
if ($content) {
144+
this._$loadPanelContentWrapper.appendTo($content);
145+
}
141146

142147
this._togglePaneVisible();
143148

@@ -209,13 +214,13 @@ class LoadPanel extends Overlay<LoadPanelProperties> {
209214
}
210215

211216
_cleanPreviousContent(): void {
212-
this.$content().find(`.${LOADPANEL_MESSAGE_CLASS}`).remove();
213-
this.$content().find(`.${LOADPANEL_INDICATOR_CLASS}`).remove();
217+
this.$content()?.find(`.${LOADPANEL_MESSAGE_CLASS}`).remove();
218+
this.$content()?.find(`.${LOADPANEL_INDICATOR_CLASS}`).remove();
214219
delete this._$indicator;
215220
}
216221

217222
_togglePaneVisible(): void {
218-
this.$content().toggleClass(LOADPANEL_PANE_HIDDEN_CLASS, !this.option('showPane'));
223+
this.$content()?.toggleClass(LOADPANEL_PANE_HIDDEN_CLASS, !this.option('showPane'));
219224
}
220225

221226
_optionChanged(args: OptionChanged<LoadPanelProperties>): void {

0 commit comments

Comments
 (0)