// TODO frha:
// * Denna är inte färig-implementerad. Allt som rör att hantera flera collapsible är lämnat till senare. Detta gäller
// t.ex. att scrolla till rätt collapsible, att stänga andra collapsible när denna öppnas för att endast ha ett visst antal öppna
// Spinnern inte heller implementerad. Oklart om denna har någon effekt
// Angular imports //
import {
Component, OnInit, Input, Output, EventEmitter, OnChanges
} from '@angular/core';
// Components //
// import * as _ from 'underscore';
// Interfaces //
// Services //
// Directives //
// Pipes //
// För utskrift
/**
* Visar ett block som kan fällas ut och ihop (kollapsa) vid tryckning.
*
* Går att inom ett specifik förälderelement (container) säga hur många fbCollapsible som kan vara öppet samtidigt.
* I ett överliggande element sätt följande attribut:
* fb-collapisble-container fb-collapisble-container-max-expanded="2" (där "2" bestämmer hur många som kan vara öppna)
* MaeklarObjekt.html använder detta som exempel.
*
* OBS! Tidigare var innehållet i collapsible wrappat i en div med klassen "second". Detta behövs inte längre
*
* Syntax:
*
* Parametrar fb-collapsible:
* @param showFullView Anger om fullview ska visas eller ej
* @param headingTitle Titel som visas i heading för blocket
* @param headingIconClass Ikon som visas i heading för blocket
* @param showHeadingIcon Anger om ikon ska visas eller ej
* @param expandOnInit Anger om blocket som default ska vara expanderat eller ej
* @param headingNotifieringsBubblaNumber Om denna är angiven visas det angivna numret i heading som en bubbla till vänster
* @param headingIconClass Ikon som visas i heading för blocket
*/
@Component({
selector: 'fb-collapsible',
templateUrl: './fb-collapsible.component.html'
})
export class FbCollapsibleComponent implements OnInit, OnChanges {
@Input() showFullView: boolean = false; // Anger om blocket ska vara expanderat eller ej. Hette tidigare fullViewCondition
@Input() headingTitle: string; // Titel i heading för blocket.
@Input() headingIconClass: string; // Class för icon i heading. Hette tidigare headingStatusIcon
@Input() showHeadingIcon: boolean = true; // Anger om icon ska visas. Hette tidigare headingStatusIconCondition, visa iconsclass som default
@Input() headingInfoTooltip: string; // TODO frha implementera detta
@Input() expandOnInit: boolean;
@Input() headingNotifieringsBubblaNumber: number; // Vissar en bubbla med siffran i till vänster om heading. Hette tidigare antalHaendelser
// TODO frha
// OBS1! I impementationen ska inte control eller fullView togglas för att ändra status.
// Anropa istället toogleShowFullView, så vi inte behöver använda watches och har enhetligt beteende.
// Se ex https://angular.io/guide/component-interaction#parent-calls-an-viewchild
// @Input() control: any;
@Output() callOnExpand: EventEmitter = new EventEmitter();
showContent: boolean; // Används för att toogla klasserna på elementen då vi vill ha viss fördröjning på dem
private showFullViewOld: boolean;
private preventScrollToHeader: boolean = false;
ngOnInit(): void {
this.showFullViewOld = this.showFullView;
if (!!this.expandOnInit) {
this.preventScrollToHeader = true;
this.showFullView = true;
this.onShowFullViewConditionChange();
}
}
ngOnChanges(): void {
this.onShowFullViewConditionChange();
console.log('ngOnchange', this.showFullView);
}
toogleShowFullView(preventScrollToHeader: boolean = false): void {
this.preventScrollToHeader = !!preventScrollToHeader;
this.showFullView = !this.showFullView;
this.onShowFullViewConditionChange();
}
private updateShowContent(): void {
this.showContent = this.showFullView;
// spinnerEl.hide();
}
private onShowFullViewConditionChange(): void {
if (this.showFullView !== this.showFullViewOld) {
//const scrollToHeader: boolean = this.showFullView && this.showFullView !== this.showFullViewOld
// && !this.preventScrollToHeader;
this.preventScrollToHeader = false;
// TODO frha: Hantera när man vill blockera scroll to header vid initiering, se FB-6896
// scope.preventScrollToHeader = scope.preventScrollToHeader !== null ? scope.preventScrollToHeader : false;
if (this.showFullView && !!this.callOnExpand) {
this.callOnExpand.emit();
}
// this.setVisibles(scrollToHeader);
// Agera efter om vi ska delaya visandet av innehåll eller ej
if (this.showFullView && this.showFullView !== this.showFullViewOld) {
setTimeout(() => {
this.updateShowContent();
}, 0);
} else {
this.updateShowContent();
}
setTimeout(() => {
// $rootScope.$emit("fbCollapsible_expanded"); // TODO frha
}, 0);
this.showFullViewOld = this.showFullView;
}
}
// TODO frha: implementera den funktionalitet som legat här (kommenterad kod)
// private setVisibles(scrollToHeader: boolean): void {
// const relativePos = getRelativePositionInScrollContainer();
// if (this.showFullView) {
// group.activeScrollEl.stop(true);
// group.activeScrollEl = scrollContainerEl;
// spinnerEl.show();
// addScopeToGroupOnce(group, scope);
// if (group.maxExpanded !== -1 && group.scopes.length > group.maxExpanded) {
// var closeFirstScope = group.scopes[0];
// removeScopeFromGroup(group, closeFirstScope);
// closeFirstScope.toogleShowFullView() // Hette tidigare (och i äldre collapsible) onHeadingClick();
// }
// } else {
// spinnerEl.hide();
// removeScopeFromGroup(group, scope);
// }
// if (hasScrollContainerEl && scrollToHeader) {
// fixateToScrollPosition(relativePos, 8);
// }
// }
// TODO frha: Allt detta är funktionalitet för grupper, detta behöver migreras senare
// Denna funktionalitet och kod (nedan) från fbCollapsible som inte migrerats
// Hanteringen borde göras om så att om de ska grupperas borde detta förmodligen vara ett
// strukturellt direktiv (istället för attribut) som har access till sina barn och där en output
// kallas när man expanderar ett block istället för funktionaliteten som är nu
// Vi ska definitivt ha ett sätt att hitta föräldern istället för så som det ser ut nu
// Även scroll-container borde vara kopplat till detta.
/*
var DEFAULT_GROUP_BY_CONTAINER_EL = angular.element('');
var spinnerEl = element.find('.fb-spinner.fb-collapsible-spinner > .fb-spinner');
var groups: fb.IFbCollapsibleScopeGroup[] = [];
var containerEl = findContainer(element);
var scrollContainerEl = findScrollContainer(containerEl);
var hasScrollContainerEl = scrollContainerEl.length > 0;
var group = findOrCreateGroup(containerEl);
var requestAnimationFrame = ($window.requestAnimationFrame ||
$window['mozRequestAnimationFrame'] ||
window['webkitRequestAnimationFrame'] ||
$window['msRequestAnimationFrame']
|| window.requestAnimationFrame
).bind($window);
function findOrCreateGroup(containerEl: JQuery) {
var groupByContainerDomEl = containerEl.length === 0 ? DEFAULT_GROUP_BY_CONTAINER_EL[0] : containerEl[0];
var group = _.find(groups, function (g: fb.IFbCollapsibleScopeGroup) {
return g.containerEl === groupByContainerDomEl;
});
if (!group) {
var maxOpen = parseInt(containerEl.attr('fb-collapisble-container-max-expanded')) || -1
group = { containerEl: groupByContainerDomEl, scopes: [], maxExpanded: maxOpen, activeScrollEl: $() };
groups.push(group);
}
return group;
}
function findContainer(fromEl: JQuery) {
var specifiedContainer = fromEl.closest(":has(*[fb-collapisble-container])").children('[fb-collapisble-container]');
if (specifiedContainer.length > 0) {
return specifiedContainer;
}
var sideDrawerContainerEl = fromEl.closest('fb-side-drawer .view:visible');
if (sideDrawerContainerEl.length > 0) {
return sideDrawerContainerEl;
}
var mainContent = fromEl.closest('#mainContentInnerWrapper');
if (mainContent.length > 0) {
return mainContent;
}
return $();
}
function addScopeToGroupOnce(group: fb.IFbCollapsibleScopeGroup, scope: fb.IFbCollapsibleScope) {
if (group.scopes.indexOf(scope) === -1) {
group.scopes.push(scope);
}
}
function removeScopeFromGroup(group: fb.IFbCollapsibleScopeGroup, scope: fb.IFbCollapsibleScope) {
var index = group.scopes.indexOf(scope);
if (index >= 0) {
group.scopes.splice(index, 1);
}
}
function removeGroupIfEmpty(group: fb.IFbCollapsibleScopeGroup) {
if (group.scopes.length === 0) {
var groupIndex = groups.indexOf(group);
if (groupIndex !== -1) {
groups.splice(groups.indexOf(group), 1);
}
}
}
function findScrollContainer(fromEl: JQuery) {
if (fromEl.hasClass('scroll-container')) {
return fromEl;
}
var scrollContainerAboveEl = fromEl.closest('.scroll-container');
if (scrollContainerAboveEl.length > 0) {
return scrollContainerAboveEl;
}
var scrollContainerEl = fromEl.find('.scroll-container');
if (scrollContainerEl.length > 0) {
return scrollContainerEl;
}
var sideDrawerMainContainerEl = fromEl.find('fb-side-drawer-main > .main:visible');
if (sideDrawerMainContainerEl.length > 0) {
return sideDrawerMainContainerEl;
}
var mainContent = fromEl.closest('#mainContent');
return mainContent;
}
scope.$on('$destroy', function () {
removeScopeFromGroup(group, scope);
removeGroupIfEmpty(group);
});
function getRelativePositionInScrollContainer() {
return hasScrollContainerEl
? element.offset().top - scrollContainerEl.offset().top
: 0;
}
function scrollIntoView() {
var relPos = getRelativePositionInScrollContainer();
var atTheTopScrollPosition = scrollContainerEl.scrollTop() + relPos - 15;
var scrollContainerHeight = scrollContainerEl.height();
scrollContainerEl.animate({
scrollTop: atTheTopScrollPosition
}, {
duration: 400,
progress: function (promise, progress: number) {
if (progress > 0) {
var currentHeight = element.height();
var currentRelPos = getRelativePositionInScrollContainer();
if (currentRelPos + currentHeight <= scrollContainerHeight) {
scrollContainerEl.stop(true);
}
}
}
});
}
function fixateToScrollPosition(wantedRelativePos: number, maxterations: number) {
if (group.activeScrollEl[0] !== scrollContainerEl[0]) {
return;
}
var currentRelativePos = getRelativePositionInScrollContainer();
var diff = wantedRelativePos - currentRelativePos;
var scrollTop = scrollContainerEl.scrollTop();
var nextScrollTop = scrollTop - diff;
if (currentRelativePos !== wantedRelativePos) {
scrollContainerEl.scrollTop(nextScrollTop);
}
if (nextScrollTop < 0 || nextScrollTop > scrollContainerEl[0].scrollHeight) {
maxterations = 0;
}
if (maxterations > 0) {
requestAnimationFrame(fixateToScrollPosition.bind(null, wantedRelativePos, maxterations - 1));
return;
}
$timeout(scrollIntoView, 120);
}
*/
}