MOBILE-2327 core: Destroy buttons moved by core-navbar-buttons

main
Dani Palou 2018-02-22 09:27:49 +01:00 committed by Pau Ferrer Ocaña
parent c1b4d435c2
commit ac6b54322c
3 changed files with 60 additions and 24 deletions

View File

@ -7,7 +7,7 @@
<button ion-button icon-only clear="true" (click)="toggleDelete()" [hidden]="!canDelete">
<ion-icon name="trash"></ion-icon>
</button>
<a *ngIf="showProfileLink" core-user-link [userId]="userId" [attr.aria-label]=" 'core.user.viewprofile' | translate">
<a [hidden]="!showProfileLink" core-user-link [userId]="userId" [attr.aria-label]=" 'core.user.viewprofile' | translate">
<img class="button core-bar-button-image" [src]="profileLink" core-external-content onError="this.src='assets/img/user-avatar.png'">
</a>
</core-navbar-buttons>

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, ContentChildren, ElementRef, QueryList } from '@angular/core';
import { Component, Input, OnInit, OnDestroy, ContentChildren, ElementRef, QueryList } from '@angular/core';
import { Button } from 'ionic-angular';
import { CoreLoggerProvider } from '../../providers/logger';
import { CoreDomUtilsProvider } from '../../providers/utils/dom';
@ -26,10 +26,12 @@ import { CoreDomUtilsProvider } from '../../providers/utils/dom';
*
* You can use the [hidden] input to hide all the inner buttons if a certain condition is met.
*
* IMPORTANT: Do not use *ngIf in the buttons inside this component, it can cause problems. Please use [hidden] instead.
*
* Example usage:
*
* <core-navbar-buttons end>
* <button ion-button icon-only *ngIf="buttonShown" [attr.aria-label]="Do something" (click)="action()">
* <button ion-button icon-only [hidden]="!buttonShown" [attr.aria-label]="Do something" (click)="action()">
* <ion-icon name="funnel"></ion-icon>
* </button>
* </core-navbar-buttons>
@ -38,33 +40,27 @@ import { CoreDomUtilsProvider } from '../../providers/utils/dom';
selector: 'core-navbar-buttons',
template: '<ng-content></ng-content>'
})
export class CoreNavBarButtonsComponent implements OnInit {
export class CoreNavBarButtonsComponent implements OnInit, OnDestroy {
protected BUTTON_HIDDEN_CLASS = 'core-navbar-button-hidden';
// If the hidden input is true, hide all buttons.
@Input('hidden') set hidden(value: boolean) {
this._hidden = value;
if (this._buttons) {
this._buttons.forEach((button: Button) => {
this.showHideButton(button);
});
}
this.showHideAllElements();
}
// Get all the buttons inside this directive.
// Get all the ion-buttons inside this directive and apply the role bar-button.
@ContentChildren(Button) set buttons(buttons: QueryList<Button>) {
this._buttons = buttons;
buttons.forEach((button: Button) => {
button.setRole('bar-button');
this.showHideButton(button);
});
}
protected element: HTMLElement;
protected _buttons: QueryList<Button>;
protected _hidden: boolean;
protected logger: any;
protected movedChildren: Node[];
constructor(element: ElementRef, logger: CoreLoggerProvider, private domUtils: CoreDomUtilsProvider) {
this.element = element.nativeElement;
@ -91,7 +87,9 @@ export class CoreNavBarButtonsComponent implements OnInit {
if (buttonsContainer) {
this.mergeContextMenus(buttonsContainer);
this.domUtils.moveChildren(this.element, buttonsContainer);
this.movedChildren = this.domUtils.moveChildren(this.element, buttonsContainer);
this.showHideAllElements();
} else {
this.logger.warn('The header was found, but it didn\'t have the right ion-buttons.', selector);
}
@ -188,15 +186,45 @@ export class CoreNavBarButtonsComponent implements OnInit {
}
/**
* Show or hide a button.
*
* @param {Button} button Button to show or hide.
* Show or hide all the elements.
*/
protected showHideButton(button: Button): void {
if (this._hidden) {
button.getNativeElement().classList.add(this.BUTTON_HIDDEN_CLASS);
} else {
button.getNativeElement().classList.remove(this.BUTTON_HIDDEN_CLASS);
protected showHideAllElements(): void {
if (this.movedChildren) {
this.movedChildren.forEach((child: Node) => {
this.showHideElement(child);
});
}
}
/**
* Show or hide an element.
*
* @param {Node} element Element to show or hide.
*/
protected showHideElement(element: Node): void {
// Check if it's an HTML Element
if (element instanceof Element) {
if (this._hidden) {
element.classList.add(this.BUTTON_HIDDEN_CLASS);
} else {
element.classList.remove(this.BUTTON_HIDDEN_CLASS);
}
}
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
// This component was destroyed, remove all the buttons that were moved.
// The buttons can be moved outside of the current page, that's why we need to manually destroy them.
// There's no need to destroy context menu items that were merged because they weren't moved from their DOM position.
if (this.movedChildren) {
this.movedChildren.forEach((child) => {
if (child.parentElement) {
child.parentElement.removeChild(child);
}
});
}
}
}

View File

@ -480,11 +480,19 @@ export class CoreDomUtilsProvider {
*
* @param {HTMLElement} oldParent The old parent.
* @param {HTMLElement} newParent The new parent.
* @return {Node[]} List of moved children.
*/
moveChildren(oldParent: HTMLElement, newParent: HTMLElement): void {
moveChildren(oldParent: HTMLElement, newParent: HTMLElement): Node[] {
const movedChildren: Node[] = [];
while (oldParent.childNodes.length > 0) {
newParent.appendChild(oldParent.childNodes[0]);
const child = oldParent.childNodes[0];
movedChildren.push(child);
newParent.appendChild(child);
}
return movedChildren;
}
/**