Skip to content

Commit 127e497

Browse files
marker-daomarker dao ®
andauthored
DropDownEditor, Overlay: Clean links to elements on dispose and clean (T1311876) (#31886)
Co-authored-by: marker dao ® <[email protected]>
1 parent 7ed8250 commit 127e497

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+874
-336
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/core/widget/widget.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ class Widget<
336336
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
337337
const $focusTarget = $element && $element.length ? $element : this._focusTarget();
338338

339-
$focusTarget.toggleClass(FOCUSED_STATE_CLASS, isFocused);
339+
$focusTarget?.toggleClass(FOCUSED_STATE_CLASS, isFocused);
340340
}
341341

342342
_hasFocusClass(element?: dxElementWrapper): boolean {
@@ -413,7 +413,7 @@ class Widget<
413413
_cleanFocusState(): void {
414414
const $element = this._focusTarget();
415415

416-
$element.removeAttr('tabIndex');
416+
$element?.removeAttr('tabIndex');
417417
this._toggleFocusClass(false);
418418
this._detachFocusEvents();
419419
this._detachKeyboardEvents();

packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ class CollectionWidget<
558558
return shouldSkipRefreshId;
559559
}
560560

561-
_refreshActiveDescendant($target?: dxElementWrapper): void {
561+
_refreshActiveDescendant($target?: dxElementWrapper | null): void {
562562
const { focusedElement } = this.option();
563563

564564
if (isDefined(focusedElement)) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,13 @@ 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 $content = this._popup.$content();
152+
153+
if (!$content) {
154+
return;
155+
}
156+
157+
const $colorView = $('<div>').appendTo($content);
152158

153159
this._colorView = this._createComponent($colorView, ColorView, this._colorViewConfig());
154160
}

packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class ContextMenu extends MenuBase {
181181

182182
_itemContainer(): dxElementWrapper {
183183
// @ts-expect-error
184-
return this._overlay ? this._overlay.$content() : $();
184+
return this._overlay?.$content() ?? $();
185185
}
186186

187187
_eventBindingTarget(): dxElementWrapper {
@@ -425,6 +425,11 @@ class ContextMenu extends MenuBase {
425425

426426
// @ts-expect-error
427427
const $overlayContent = this._overlay.$content();
428+
429+
if (!$overlayContent) {
430+
return;
431+
}
432+
428433
$overlayContent.addClass(DX_CONTEXT_MENU_CLASS);
429434

430435
this._addCustomCssClass($overlayContent);
@@ -669,7 +674,7 @@ class ContextMenu extends MenuBase {
669674

670675
_getItemsContainers(): dxElementWrapper {
671676
// @ts-expect-error
672-
return this._overlay.$content().find(`.${DX_MENU_ITEMS_CONTAINER_CLASS}`);
677+
return this._overlay?.$content()?.find(`.${DX_MENU_ITEMS_CONTAINER_CLASS}`) ?? $();
673678
}
674679

675680
_searchActiveItem(target): dxElementWrapper {
@@ -977,7 +982,7 @@ class ContextMenu extends MenuBase {
977982
_hideAllShownSubmenus(): void {
978983
const shownSubmenus = extend([], this._shownSubmenus);
979984
// @ts-expect-error
980-
const $expandedItems = this._overlay.$content().find(`.${DX_MENU_ITEM_EXPANDED_CLASS}`);
985+
const $expandedItems = this._overlay?.$content()?.find(`.${DX_MENU_ITEM_EXPANDED_CLASS}`) ?? $();
981986

982987
$expandedItems.removeClass(DX_MENU_ITEM_EXPANDED_CLASS);
983988

@@ -1051,8 +1056,7 @@ class ContextMenu extends MenuBase {
10511056
if (position) {
10521057
if (!this._overlay) {
10531058
this._renderContextMenuOverlay();
1054-
// @ts-expect-error
1055-
this._overlay.$content().addClass(this._widgetClass());
1059+
(this._overlay as unknown as Overlay).$content()?.addClass(this._widgetClass());
10561060
this._renderFocusState();
10571061
this._attachHoverEvents();
10581062
this._attachClickEvent();

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/drawer/m_drawer.rendering.strategy.overlap.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,22 @@ class OverlapStrategy extends DrawerStrategy {
161161
} else if (revealMode === 'expand') {
162162
// @ts-expect-error
163163
this._initialPosition = drawer.isHorizontalDirection() ? { left: 0 } : { top: 0 };
164-
// @ts-expect-error
165-
move($panelOverlayContent, this._initialPosition);
166164

167-
animation.size({
168-
complete: () => {
169-
whenAnimationCompleted.resolve();
170-
},
171-
duration: drawer.option('animationDuration'),
172-
direction: targetPanelPosition,
173-
$element: $panelOverlayContent,
174-
size: panelSize,
175-
marginTop,
176-
});
165+
if ($panelOverlayContent) {
166+
// @ts-expect-error
167+
move($panelOverlayContent, this._initialPosition);
168+
169+
animation.size({
170+
complete: () => {
171+
whenAnimationCompleted?.resolve();
172+
},
173+
duration: drawer.option('animationDuration'),
174+
direction: targetPanelPosition,
175+
$element: $panelOverlayContent,
176+
size: panelSize,
177+
marginTop,
178+
});
179+
}
177180
}
178181
} else if (revealMode === 'slide') {
179182
// @ts-expect-error
@@ -183,8 +186,10 @@ class OverlapStrategy extends DrawerStrategy {
183186
} else if (revealMode === 'expand') {
184187
// @ts-expect-error
185188
this._initialPosition = drawer.isHorizontalDirection() ? { left: 0 } : { top: 0 };
186-
// @ts-expect-error
187-
move($panelOverlayContent, this._initialPosition);
189+
if ($panelOverlayContent) {
190+
// @ts-expect-error
191+
move($panelOverlayContent, this._initialPosition);
192+
}
188193
// @ts-expect-error
189194
if (drawer.isHorizontalDirection()) {
190195
$($panelOverlayContent).css('width', panelSize);

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

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,59 @@ export default class DropDownButton extends TextEditorButton {
2121
this.currentTemplate = null;
2222
}
2323

24-
_attachEvents(instance): void {
25-
const { editor } = this;
26-
24+
_attachEvents(instance: Button): void {
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: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,8 @@ class DropDownEditor<
648648
});
649649

650650
this._attachPopupKeyHandler();
651-
652651
this._contentReadyHandler();
652+
653653
this._setPopupContentId(this._popup.$content());
654654

655655
this._bindInnerWidgetOptions(this._popup, 'dropDownOptions');
@@ -690,7 +690,7 @@ class DropDownEditor<
690690
this.close();
691691
}
692692

693-
_setPopupContentId($popupContent: dxElementWrapper): void {
693+
_setPopupContentId($popupContent?: dxElementWrapper | null): void {
694694
this._popupContentId = `dx-${new Guid()}`;
695695
this.setAria('id', this._popupContentId, $popupContent);
696696
}
@@ -848,14 +848,13 @@ class DropDownEditor<
848848
}
849849

850850
_clean(): void {
851-
delete this._openOnFieldClickAction;
852-
delete this._$templateWrapper;
851+
this._$popup?.remove();
852+
853+
this._openOnFieldClickAction = undefined;
854+
this._$templateWrapper = undefined;
855+
this._popup = undefined;
856+
this._$popup = undefined;
853857

854-
if (this._$popup) {
855-
this._$popup.remove();
856-
delete this._$popup;
857-
delete this._popup;
858-
}
859858
super._clean();
860859
}
861860

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

Lines changed: 16 additions & 8 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() {
@@ -169,9 +169,8 @@ class ActionSheet extends CollectionWidget<Properties> {
169169
target: this.option('target'),
170170
}));
171171

172-
this._popup.$overlayContent().attr('role', 'dialog');
173-
174-
this._popup.$wrapper().addClass(ACTION_SHEET_POPOVER_WRAPPER_CLASS);
172+
this._popup.$overlayContent()?.attr('role', 'dialog');
173+
this._popup.$wrapper()?.addClass(ACTION_SHEET_POPOVER_WRAPPER_CLASS);
175174
}
176175

177176
_createPopup(): void {
@@ -225,11 +224,11 @@ class ActionSheet extends CollectionWidget<Properties> {
225224
},
226225
}));
227226

228-
this._popup.$wrapper().addClass(ACTION_SHEET_POPUP_WRAPPER_CLASS);
227+
this._popup.$wrapper()?.addClass(ACTION_SHEET_POPUP_WRAPPER_CLASS);
229228
}
230229

231230
_popupContentReadyAction(): void {
232-
this._popup.$content().append(this._$itemContainer);
231+
this._popup.$content()?.append(this._$itemContainer);
233232
this._attachClickEvent();
234233
this._attachHoldEvent();
235234

@@ -250,10 +249,19 @@ class ActionSheet extends CollectionWidget<Properties> {
250249

251250
if (this.option('showCancelButton')) {
252251
const cancelClickAction = this._createActionByOption('onCancelClick') || noop;
252+
253+
const $content = this._popup?.$content();
254+
255+
if (!$content) {
256+
return;
257+
}
258+
253259
const that = this;
254260

255-
this._$cancelButton = $('<div>').addClass(ACTION_SHEET_CANCEL_BUTTON_CLASS)
256-
.appendTo(this._popup?.$content());
261+
this._$cancelButton = $('<div>')
262+
.addClass(ACTION_SHEET_CANCEL_BUTTON_CLASS)
263+
.appendTo($content);
264+
257265
this._createComponent(this._$cancelButton, Button, {
258266
disabled: false,
259267
stylingMode: ACTION_SHEET_BUTTON_DEFAULT_STYLING_MODE,

0 commit comments

Comments
 (0)