// 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); } */ }