2022-11-03 11:15:13 +01:00
import { HttpClient } from "@angular/common/http" ;
2022-11-03 14:55:10 +01:00
import { ChangeDetectorRef , Component , ElementRef , Input , OnDestroy , OnInit , ViewChild } from "@angular/core" ;
2022-11-03 11:15:13 +01:00
import { Subscription } from "rxjs" ;
import { Breadcrumb } from "../utils/breadcrumbs/breadcrumbs.component" ;
import { EnvProperties } from "../utils/properties/env-properties" ;
import { properties } from "src/environments/environment" ;
import { FormBuilder , FormControl } from "@angular/forms" ;
import { ActivatedRoute , Router } from "@angular/router" ;
import { Meta , Title } from "@angular/platform-browser" ;
import { Location } from "@angular/common" ;
import { StringUtils } from "../utils/string-utils.class" ;
import { SEOService } from "../sharedComponents/SEO/SEO.service" ;
import { PiwikService } from "../utils/piwik/piwik.service" ;
import { debounceTime , distinctUntilChanged } from "rxjs/operators" ;
import Timeout = NodeJS . Timeout ;
2023-04-03 11:53:40 +02:00
import { ISVocabulariesService } from "../utils/staticAutoComplete/ISVocabularies.service" ;
2024-01-08 14:36:27 +01:00
import { SearchFields } from "../utils/properties/searchFields" ;
2024-05-20 14:04:56 +02:00
import { HelperFunctions } from "../utils/HelperFunctions.class" ;
2022-11-03 11:15:13 +01:00
declare var UIkit ;
@Component ( {
selector : 'fos' ,
templateUrl : 'fos.component.html' ,
styleUrls : [ 'fos.component.less' ]
} )
export class FosComponent implements OnInit , OnDestroy {
public url : string = null ;
public pageTitle : string = "OpenAIRE | Fields of Science" ;
2023-05-15 16:28:33 +02:00
public pageDescription : string = "We have integrated a Field-of-Science (FoS) taxonomy into our dataset to organize and discover research more effectively. Using the full capabilities of the OpenAIRE Graph (full-texts, citations, references, venues) we apply AI and bring forward any multidisciplinarity potential." ;
2024-05-20 14:04:56 +02:00
public scrollPos = 0 ;
public selectedParentLevels = [ ] ;
2022-11-03 11:15:13 +01:00
public fos : any [ ] = [ ] ;
public fosOptions : string [ ] = [ ] ;
public activeSection : string ;
public keywordControl : FormControl ;
public keyword : string ;
public viewResults = [ ] ;
public result = [ ] ;
properties : EnvProperties = properties ;
public breadcrumbs : Breadcrumb [ ] = [ { name : 'home' , route : '/' } , { name : 'Fields of Science' } ] ;
private subscriptions : Subscription [ ] = [ ] ;
private observer : IntersectionObserver ;
private timeout : Timeout ;
@ViewChild ( 'tabs' ) tabs : ElementRef ;
public sliderInit : boolean = false ;
2024-01-08 14:36:27 +01:00
private searchFieldsHelper : SearchFields = new SearchFields ( ) ;
2022-11-03 11:15:13 +01:00
constructor (
2023-04-03 11:53:40 +02:00
private vocabulariesService : ISVocabulariesService ,
2022-11-03 11:15:13 +01:00
private fb : FormBuilder ,
private location : Location ,
private route : ActivatedRoute ,
private _router : Router ,
private _meta : Meta ,
private _title : Title ,
private seoService : SEOService ,
private _piwikService : PiwikService ,
private cdr : ChangeDetectorRef
) { }
ngOnInit() {
2023-07-12 14:05:25 +02:00
this . subscriptions . push ( this . _piwikService . trackView ( this . properties , this . pageTitle ) . subscribe ( ) ) ;
2022-11-03 11:15:13 +01:00
this . url = this . properties . domain + this . properties . baseLink + this . _router . url ;
this . seoService . createLinkForCanonicalURL ( this . url ) ;
this . updateUrl ( this . url ) ;
this . updateTitle ( this . pageTitle ) ;
this . updateDescription ( this . pageDescription ) ;
2023-04-03 11:53:40 +02:00
this . vocabulariesService . getFos ( properties ) . subscribe ( data = > {
2022-11-03 11:15:13 +01:00
this . fos = data [ 'fos' ] ;
this . convertFosToOptions ( ) ;
if ( typeof document !== 'undefined' ) {
setTimeout ( ( ) = > {
let slider = UIkit . slider ( this . tabs . nativeElement ) ;
slider . clsActive = 'uk-slider-active' ;
slider . updateActiveClasses ( ) ;
this . sliderInit = true ;
slider . slides . forEach ( item = > {
item . classList . remove ( 'uk-active' ) ;
} ) ;
if ( this . route . snapshot . fragment ) {
2024-05-20 14:04:56 +02:00
let splitFragment = this . route . snapshot . fragment . split ( "||" ) ;
this . activeSection = this . route . snapshot . fragment . split ( "||" ) [ 0 ] ;
let i = this . fos . findIndex ( item = > ( item . id == this . route . snapshot . fragment || this . route . snapshot . fragment . startsWith ( item . id + "||" ) ) ) ;
if ( i < 0 | | i > this . fos . length - 1 ) {
this . _router . navigate ( [ './' ] , { fragment : "" , relativeTo : this.route , state : { disableScroll : true } } ) ;
} else {
if ( splitFragment . length > 1 ) {
let level1 = this . fos [ i ] ;
let level2 = null ;
let level3 = null ;
if ( level1 . children ) {
level2 = level1 . children . find ( item = > item . code == splitFragment [ 1 ] ) ;
if ( level2 && level2 . children ) {
level3 = level2 . children . find ( item = > item . code == splitFragment [ 2 ] ) ;
this . selectedParentLevels = [ this . fos [ i ] , level2 , level3 ] ;
}
}
if ( ! level2 || ! level3 ) {
this . _router . navigate ( [ './' ] , { fragment : level1.id , relativeTo : this.route , state : { disableScroll : true } } ) ;
}
} else {
slider . show ( i ) ;
}
}
2022-11-03 11:15:13 +01:00
} else {
this . activeSection = this . fos [ 0 ] . id ;
}
this . cdr . detectChanges ( ) ;
} ) ;
}
2024-05-20 14:04:56 +02:00
2022-11-03 11:15:13 +01:00
this . subscriptions . push ( this . route . fragment . subscribe ( fragment = > {
if ( fragment ) {
2024-05-20 14:04:56 +02:00
this . activeSection = fragment . split ( "||" ) [ 0 ] ;
2022-11-03 11:15:13 +01:00
if ( this . tabs ) {
let slider = UIkit . slider ( this . tabs . nativeElement ) ;
2024-05-20 14:04:56 +02:00
let i = this . fos . findIndex ( item = > ( item . id == fragment || fragment . startsWith ( item . id + "||" ) ) ) ;
2022-11-03 11:15:13 +01:00
slider . show ( i ) ;
}
} else {
this . activeSection = this . fos [ 0 ] . id ;
}
} ) ) ;
this . keywordControl = this . fb . control ( '' ) ;
this . subscriptions . push ( this . keywordControl . valueChanges . pipe ( debounceTime ( 500 ) , distinctUntilChanged ( ) ) . subscribe ( value = > {
2024-05-20 14:04:56 +02:00
if ( this . keyword !== undefined || value ) {
this . selectedParentLevels = [ ] ;
}
this . keyword = value ;
this . findMatches ( this . keyword ) ;
if ( typeof IntersectionObserver !== 'undefined' ) {
setTimeout ( ( ) = > {
this . setObserver ( ) ;
} ) ;
}
2022-11-03 11:15:13 +01:00
} ) ) ;
} ) ;
}
public ngOnDestroy() {
for ( let sub of this . subscriptions ) {
sub . unsubscribe ( ) ;
}
if ( this . observer ) {
this . observer . disconnect ( ) ;
}
}
private setObserver() {
if ( this . observer ) {
this . observer . disconnect ( ) ;
}
this . observer = new IntersectionObserver ( ( entries ) = > {
entries . forEach ( entry = > {
if ( entry . isIntersecting ) {
if ( this . timeout ) {
clearTimeout ( this . timeout ) ;
}
this . timeout = setTimeout ( ( ) = > {
this . _router . navigate ( [ './' ] , { fragment : entry.target.id , relativeTo : this.route , state : { disableScroll : true } } ) ;
} , 200 ) ;
}
} ) ;
} , { threshold : 0.25 , rootMargin : '-100px' } ) ;
this . fos . forEach ( fos = > {
let element = document . getElementById ( fos . id ) ;
if ( element ) {
this . observer . observe ( element ) ;
}
} ) ;
}
convertFosToOptions() {
this . fosOptions = [ ] ;
this . fos . forEach ( fos = > {
this . fosOptions . push ( fos . id ) ;
if ( fos . children ) {
2024-05-20 14:04:56 +02:00
fos . children . forEach ( l2 = > {
this . fosOptions . push ( l2 . id ) ;
2024-08-01 13:06:12 +02:00
// hide L3 & L4 FoS
if ( l2 . children && properties . environment == "development" ) {
2024-05-20 14:04:56 +02:00
l2 . children . forEach ( l3 = > {
this . fosOptions . push ( l3 . id ) ;
if ( l3 . children ) {
l3 . children . forEach ( l4 = > {
this . fosOptions . push ( l4 . id ) ;
} )
}
2022-11-03 11:15:13 +01:00
} ) ;
}
} ) ;
}
} ) ;
}
findMatches ( value : string ) {
this . viewResults = JSON . parse ( JSON . stringify ( this . fos ) ) ;
let matchLevel1 : boolean = false ;
let matchLevel2 : boolean = false ;
2024-05-20 14:04:56 +02:00
let matchLevel3 : boolean = false ;
2022-11-03 11:15:13 +01:00
// 1st level search
if ( this . viewResults . length ) {
this . viewResults = this . viewResults . filter ( item = > {
matchLevel1 = ! ! item . id . includes ( value ? . toLowerCase ( ) ) ;
2024-05-20 14:04:56 +02:00
// 2nd level search
2022-11-03 11:15:13 +01:00
if ( item . children ? . length && ! matchLevel1 ) {
item . children = item . children . filter ( subItem = > {
matchLevel2 = ! ! subItem . id . includes ( value ? . toLowerCase ( ) ) ;
2024-08-01 13:06:12 +02:00
// hide L3 & L4 FoS
if ( properties . environment == "development" ) {
// 3rd level search
if ( subItem . children ? . length && ! matchLevel2 ) {
subItem . children = subItem . children . filter ( subSubItem = > {
matchLevel3 = subSubItem . id . includes ( value ? . toLowerCase ( ) ) ;
// 4th level search
if ( subSubItem . children ? . length && ! matchLevel3 ) {
subSubItem . children = subSubItem . children . filter ( level4Item = > {
return level4Item . id . toLowerCase ( ) . includes ( value ? . toLowerCase ( ) )
} ) ;
}
return subSubItem . children ? . length > 0 || matchLevel3 ;
} ) ;
}
return subItem . children ? . length > 0 ;
} else {
return matchLevel2 ;
}
2022-11-03 11:15:13 +01:00
} ) ;
}
return item . children ? . length > 0 ;
} ) ;
}
}
highlightKeyword ( name ) {
2024-05-20 14:04:56 +02:00
if ( name . toLowerCase ( ) . includes ( this . keyword . toLowerCase ( ) ) ) {
2022-11-03 11:15:13 +01:00
return name . replace ( new RegExp ( this . keyword , "gi" ) , ( matchedValue ) = > ` <mark class="highlighted"> ${ matchedValue } </mark> ` ) ;
} else {
return name ;
}
}
public urlEncodeAndQuote ( str : string ) : string {
return StringUtils . quote ( StringUtils . URIEncode ( str ) ) ;
}
private updateUrl ( url : string ) {
this . _meta . updateTag ( { content : url } , "property='og:url'" ) ;
}
private updateTitle ( title : string ) {
var _title = ( ( title . length > 50 ) ? title . substring ( 0 , 50 ) : title ) ;
this . _title . setTitle ( _title ) ;
this . _meta . updateTag ( { content : _title } , "property='og:title'" ) ;
}
private updateDescription ( description : string ) {
this . _meta . updateTag ( { content : description } , "name='description'" ) ;
this . _meta . updateTag ( { content : description } , "property='og:description'" ) ;
}
2023-08-24 17:31:04 +02:00
public buildFosQueryParam ( fos ) {
2023-10-02 12:13:22 +02:00
// return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)};
2024-01-08 14:36:27 +01:00
return ( this . searchFieldsHelper . getFosParameter ( ) == 'foslabel' ? ( { 'foslabel' : this . urlEncodeAndQuote ( fos . id + "||" + fos . label ) } ) : ( { 'fos' : this . urlEncodeAndQuote ( fos . id ) } ) ) ;
2023-08-24 17:31:04 +02:00
}
2024-05-20 14:04:56 +02:00
public backClicked() {
let id = this . selectedParentLevels [ 0 ] . id ;
this . selectedParentLevels = [ ] ;
this . cdr . detectChanges ( ) ;
if ( this . scrollPos ) {
HelperFunctions . scrollTo ( 0 , this . scrollPos ) ;
this . _router . navigate ( [ './' ] , { fragment : id , relativeTo : this.route , state : { disableScroll : true } } ) ;
} else {
this . _router . navigate ( [ './' ] , {
fragment : id ,
relativeTo : this.route ,
state : { disableScroll : false , behavior : 'auto' }
} ) ;
}
this . cdr . detectChanges ( ) ;
if ( typeof IntersectionObserver !== 'undefined' ) {
setTimeout ( ( ) = > {
this . setObserver ( ) ;
} , 200 ) ;
}
}
public moreClicked ( level1 , level2 , level3 ) {
this . scrollPos = window . scrollY ;
if ( this . observer ) {
this . observer . disconnect ( ) ;
}
this . selectedParentLevels = [ level1 , level2 , level3 ] ;
this . cdr . detectChanges ( ) ;
this . _router . navigate ( [ './' ] ,
{ fragment : this.selectedParentLevels [ 0 ] . id + "||" + this . selectedParentLevels [ 1 ] . code + "||" + this . selectedParentLevels [ 2 ] . code ,
relativeTo : this.route , state : { disableScroll : false , behavior : 'auto' } } ) ;
}
2022-11-03 11:15:13 +01:00
}