MOBILE-3931 performance: Fix memory leak on context menu

main
Pau Ferrer Ocaña 2022-02-17 09:02:54 +01:00
parent 6a862730e2
commit 9bab09dace
3 changed files with 17 additions and 7 deletions

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter, OnChanges, SimpleChange } from '@angular/core'; import { Component, Input, Output, OnInit, OnDestroy, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
import { CoreLogger } from '@singletons/logger';
import { CoreContextMenuComponent } from '../context-menu/context-menu'; import { CoreContextMenuComponent } from '../context-menu/context-menu';
/** /**
@ -35,7 +36,6 @@ import { CoreContextMenuComponent } from '../context-menu/context-menu';
export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChanges { export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChanges {
@Input() content?: string; // Content of the item. @Input() content?: string; // Content of the item.
@Input() iconDescription?: string; // Name of the icon to be shown on the left side of the item.
@Input() iconAction?: string; // Name of the icon to show on the right side of the item. Represents the action to do on click. @Input() iconAction?: string; // Name of the icon to show on the right side of the item. Represents the action to do on click.
// If is "spinner" an spinner will be shown. // If is "spinner" an spinner will be shown.
// If is "toggle" a toggle switch will be shown. // If is "toggle" a toggle switch will be shown.
@ -58,6 +58,11 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
@Output() onClosed?: EventEmitter<() => void>; // Will emit an event when the popover is closed because the item was clicked. @Output() onClosed?: EventEmitter<() => void>; // Will emit an event when the popover is closed because the item was clicked.
@Output() toggleChange = new EventEmitter<boolean>();// Will emit an event when toggle changes to enable 2-way data binding. @Output() toggleChange = new EventEmitter<boolean>();// Will emit an event when toggle changes to enable 2-way data binding.
/**
* @deprecated since 4.0.
*/
@Input() iconDescription?: string; // Name of the icon to be shown on the left side of the item. Not used anymore.
protected hasAction = false; protected hasAction = false;
protected destroyed = false; protected destroyed = false;
@ -88,6 +93,11 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
if (!this.destroyed) { if (!this.destroyed) {
this.ctxtMenu.addItem(this); this.ctxtMenu.addItem(this);
} }
if (this.iconDescription !== undefined) {
CoreLogger.getInstance('CoreContextMenuItemComponent')
.warn('iconDescription Input is deprecated and should not be used');
}
} }
/** /**

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit, OnDestroy, ElementRef, ChangeDetectorRef } from '@angular/core'; import { Component, Input, OnInit, OnDestroy, ElementRef, ChangeDetectorRef } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
import { auditTime } from 'rxjs/operators'; import { auditTime } from 'rxjs/operators';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
@ -42,11 +42,12 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
protected itemsChangedStream: Subject<void>; // Stream to update the hideMenu boolean when items change. protected itemsChangedStream: Subject<void>; // Stream to update the hideMenu boolean when items change.
protected parentContextMenu?: CoreContextMenuComponent; protected parentContextMenu?: CoreContextMenuComponent;
protected expanded = false; protected expanded = false;
protected itemsSubscription: Subscription;
constructor(elementRef: ElementRef, changeDetector: ChangeDetectorRef) { constructor(elementRef: ElementRef, changeDetector: ChangeDetectorRef) {
// Create the stream and subscribe to it. We ignore successive changes during 250ms. // Create the stream and subscribe to it. We ignore successive changes during 250ms.
this.itemsChangedStream = new Subject<void>(); this.itemsChangedStream = new Subject<void>();
this.itemsChangedStream.pipe(auditTime(250)).subscribe(() => { this.itemsSubscription = this.itemsChangedStream.pipe(auditTime(250)).subscribe(() => {
// Hide the menu if all items are hidden. // Hide the menu if all items are hidden.
this.hideMenu = !this.items.some((item) => !item.hidden); this.hideMenu = !this.items.some((item) => !item.hidden);
@ -63,7 +64,7 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
} }
/** /**
* Component being initialized. * @inheritdoc
*/ */
ngOnInit(): void { ngOnInit(): void {
this.icon = this.icon || 'ellipsis-vertical'; this.icon = this.icon || 'ellipsis-vertical';
@ -197,10 +198,11 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
} }
/** /**
* Component destroyed. * @inheritdoc
*/ */
ngOnDestroy(): void { ngOnDestroy(): void {
this.removeMergedItems(); this.removeMergedItems();
this.itemsSubscription.unsubscribe();
} }
} }

View File

@ -6,8 +6,6 @@
[href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden" [href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden"
[detail]="(item.href && !item.iconAction) || null" role="menuitem" [button]="(item.href && !item.iconAction)" [detail]="(item.href && !item.iconAction) || null" role="menuitem" [button]="(item.href && !item.iconAction)"
[showBrowserWarning]="item.showBrowserWarning"> [showBrowserWarning]="item.showBrowserWarning">
<ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" aria-hidden="true" slot="start">
</ion-icon>
<ion-label> <ion-label>
<p class="item-heading"> <p class="item-heading">
<core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text> <core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text>