From 1e8ec154516f42de2c4352a38030c4129d8c752a Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Fri, 21 Oct 2022 17:06:44 +0300 Subject: [PATCH] Add new slider-tabs component. Add slider tabs in terminology page and make content with class help texts --- monitor/methodology/methodology.module.ts | 4 +- monitor/methodology/terminology.component.ts | 311 ++++-------------- sharedComponents/tabs/slider-tab.component.ts | 16 + .../tabs/slider-tabs.component.ts | 172 ++++++++++ sharedComponents/tabs/slider-tabs.module.ts | 13 + 5 files changed, 263 insertions(+), 253 deletions(-) create mode 100644 sharedComponents/tabs/slider-tab.component.ts create mode 100644 sharedComponents/tabs/slider-tabs.component.ts create mode 100644 sharedComponents/tabs/slider-tabs.module.ts diff --git a/monitor/methodology/methodology.module.ts b/monitor/methodology/methodology.module.ts index b2e4c237..0842bad2 100644 --- a/monitor/methodology/methodology.module.ts +++ b/monitor/methodology/methodology.module.ts @@ -11,6 +11,8 @@ import {IconsModule} from "../../utils/icons/icons.module"; import {IconsService} from "../../utils/icons/icons.service"; import {graph} from "../../utils/icons/icons"; import {BreadcrumbsModule} from "../../utils/breadcrumbs/breadcrumbs.module"; +import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module"; +import {HelperModule} from "../../utils/helper/helper.module"; @NgModule({ declarations: [TerminologyComponent, SeeHowItWorksComponent], @@ -30,7 +32,7 @@ import {BreadcrumbsModule} from "../../utils/breadcrumbs/breadcrumbs.module"; component: SeeHowItWorksComponent, canDeactivate: [PreviousRouteRecorder] }, - ]), PageContentModule, HowModule, TabsModule, IconsModule, BreadcrumbsModule], + ]), PageContentModule, HowModule, SliderTabsModule, IconsModule, BreadcrumbsModule, SliderTabsModule, HelperModule], exports: [TerminologyComponent, SeeHowItWorksComponent] }) export class MethodologyModule { diff --git a/monitor/methodology/terminology.component.ts b/monitor/methodology/terminology.component.ts index dc6df2d9..c0cd77ef 100644 --- a/monitor/methodology/terminology.component.ts +++ b/monitor/methodology/terminology.component.ts @@ -1,4 +1,12 @@ -import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild} from "@angular/core"; +import { + AfterContentChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild +} from "@angular/core"; import {Subscription} from "rxjs"; import {Meta, Title} from "@angular/platform-browser"; import {ActivatedRoute, Router} from "@angular/router"; @@ -6,7 +14,8 @@ import {OpenaireEntities} from "../../utils/properties/searchFields"; import {SEOService} from "../../sharedComponents/SEO/SEO.service"; import {properties} from "../../../../environments/environment"; import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component"; -import Timeout = NodeJS.Timeout; +import {HelperService} from "../../utils/helper/helper.service"; + declare var ResizeObserver; @@ -31,217 +40,37 @@ declare var ResizeObserver; -
+
-
+
- -
-

1. Entities

-
Research Products
-
- There are four different types of research products in the - OpenAIRE Research Graph: -
-
    -
  • Publications
  • -
  • Research data
  • -
  • Research software
  • -
  • Other research products.
  • -
-
- We deduplicate (merge) different records of research products and keep the metadata of all instances. -
-
Publication
-
- Research products intended for human reading (published articles, pre-prints, conference - papers, presentations, technical reports, etc.) -
-
Research data
-
- The sources from which the description of the research data has been collected reflect and support their own granularity, we do not define it. -
-
Research software
-
- Source code or software package developed and/or used in a research context -
-
Other research product
-
- Anything that does not fall in the previous categories (e.g. workflow, methods, protocols) -
-
+
-
-

2. Inherited and Inferred Attributes

-
- We either inherit the attributes of entities via entries in the harvested metadata records or automatically generate them using our inference system (text and data mining algorithms). -
-
Organization
-
-

For research products, this refers to the - affiliated organizations of its authors

-

For projects: - the organizations participating in - the project - (i.e. beneficiaries of the grant)

-

- We are improving the organization database with the use of our OpenOrgs tool. It allows curators to disambiguate organizations (merge different names of the same organization) and identify parent-child relationships (schools, departments, etc.). -

-
-
Country
-
-

The country of the organization.

-

- Country code mapping: - - https://api.openaire.eu/vocabularies/dnet:countries -

-
-
Funder
-
-

Funders that have joined OpenAIRE, i.e. their project data have - gone through a validation process.

-

You can visit https://explore.openaire.eu/search/find - if you would like to explore the research products - and projects of all funders in OpenAIRE (the list of funders can be - seen under the "Funder" Filter shown on the left side of the page).

-

For funder who want to join OpenAIRE: https://www.openaire.eu/funders-how-to-join-guide -

-
-
Type
-
-

The sub-type of a research outcome (e.g., - a publication can be a pre-print, conference proceeding, - article, - etc.)

-

Resource type mapping: - https://api.openaire.eu/vocabularies/dnet:result_typologies - (click on the code to see the specific types for each result type) -

-
-
Access mode or access rights
-
-

The best available (across all instances) access rights of - a research product

-

Types (by best available):

-

Open: Open Access

-

Embargo: Closed for a specific period of time, then open.

-

Restricted: Definition of restricted may vary by data source, it may refer to access rights being given to registered users, potentially behind a paywall.

-

Closed: Closed access

-
-
CC license
-
-

A Creative Commons copyright license (https://creativecommons.org/) -

-
-
PID (persistent identifier)
-
-

A long-lasting reference to a resource

-

Types: http://api.openaire.eu/vocabularies/dnet:pid_types -

-
-
Context
-
-

Related research community, initiative or infrastructure.

-
-
Journal
-
-

The scientific journal an article is published in.

-
-
Publisher
-
-

The publisher of the venue (journal, book, etc.) of a research product.

-
-
Data sources (content providers)
-
-

The different data sources ingested in the OpenAIRE Research Graph.

-
Data Source Types:
-
    -
  • Repositories
  • -
  • Open Access Publishers & Journals
  • -
  • Aggregators
  • -
  • Entity Registries
  • -
  • Journal Aggregators
  • -
  • CRIS (Current Research Information System)
  • -
-
-
Repositories
-
-

Information systems where scientists upload the bibliographic metadata and payloads of their - research products (e.g. PDFs of their scientific articles, CSVs of their data, - archive with their - software), due to obligations from their organizations, their - funders, or due to community practices - (e.g. ArXiv, Europe PMC, Zenodo).

-
-
Open Access Publishers & Journals
-
-

Information systems of open access publishers or relative journals, which offer bibliographic - metadata and PDFs of their published articles.

-
-
Aggregators
-
-

Information systems that collect descriptive metadata about research products - from multiple sources - in order to enable cross-data source discovery of given research products (e,g, - DataCite, - BASE, DOAJ).

-
-
Entity Registries
-
-

Information systems created with the intent of maintaining authoritative registries of given - entities in the scholarly communication, such as OpenDOAR for the institutional repositories, re3data - for the data repositories, CORDA and other funder databases - for projects and funding information.

-
-
CRIS (Current Research Information System)
-
-

Information systems adopted by research and academic organizations to - keep track of their research - administration records and relative results; examples of CRIS content are articles - or research data funded - by projects, their principal investigators, facilities acquired - thanks to funding, etc.

-
-
+
- +

3. Constructed Attributes

@@ -403,25 +232,26 @@ declare var ResizeObserver;
` }) -export class TerminologyComponent implements OnInit, OnDestroy { +export class TerminologyComponent implements OnInit, OnDestroy, AfterViewInit, AfterContentChecked { public tab: 'entities' | 'attributes' = 'entities'; private subscriptions: any[] = []; public openaireEntities = OpenaireEntities; public breadcrumbs: Breadcrumb[] = [{name: 'home', route: '/'}, {name: 'Resources - Terminology and construction', keepFormat: true}]; - public graph_offset: number = 0; - public graph_height: number = 0; + public graph_offset: number = 0; + public graph_height: number = 0; @ViewChild("graph_element") graph_element; - public contentSections: string[] = ['entities', 'inherited-and-inferred-attributes', 'constructed-attributes']; - public activeSection: string; - private observer: IntersectionObserver; - private timeout: Timeout; + public contentSections: string[] = ['entities', 'inherited-and-inferred-attributes', 'constructed-attributes']; + public activeSection: string; + public properties = properties; + public divContents: any; constructor(private seoService: SEOService, private meta: Meta, private router: Router, private route: ActivatedRoute, private title: Title, - private cdr: ChangeDetectorRef) { + private cdr: ChangeDetectorRef, + private helper: HelperService) { } ngOnInit() { @@ -432,27 +262,25 @@ export class TerminologyComponent implements OnInit, OnDestroy { this.breadcrumbs[0].route = '/' + (params['stakeholder']?params['stakeholder']:''); this.breadcrumbs[0].name = (params['stakeholder']?'dashboard':'home'); })); - this.subscriptions.push(this.route.fragment.subscribe(fragment => { - if(fragment) { - this.activeSection = fragment; - } else { - this.activeSection = 'entities'; - } - })); + this.subscriptions.push(this.route.fragment.subscribe(fragment => { + if(fragment) { + this.activeSection = fragment; + } else { + this.activeSection = 'entities'; + } + })); + this.getDivContents(); } - - ngAfterViewInit() { + + ngAfterViewInit() { if (typeof document !== 'undefined') { if(this.graph_element) { this.observeGraphElement(); } - setTimeout(() => { - this.setObserver(); - }); } } - - ngAfterContentChecked() { + + ngAfterContentChecked() { if(this.graph_element && typeof document !== 'undefined') { this.graph_offset = this.calcGraphOffset(this.graph_element.nativeElement); } @@ -464,37 +292,16 @@ export class TerminologyComponent implements OnInit, OnDestroy { subscription.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}); - this.contentSections.forEach(section => { - let element = document.getElementById(section); - if(element) { - this.observer.observe(element); - } - }); - } - - public observeGraphElement() { - let resizeObs = new ResizeObserver(entries => { + + private getDivContents() { + this.subscriptions.push(this.helper.getDivHelpContents(this.properties, 'monitor', this.router.url).subscribe(contents => { + this.divContents = contents; + })); + } + + public observeGraphElement() { + let resizeObs = new ResizeObserver(entries => { entries.forEach(entry => { setTimeout(() => { this.graph_offset = this.calcGraphOffset(entry.target); @@ -504,9 +311,9 @@ export class TerminologyComponent implements OnInit, OnDestroy { }); this.subscriptions.push(resizeObs); resizeObs.observe(this.graph_element.nativeElement); - } - - calcGraphOffset(element) { + } + + calcGraphOffset(element) { this.graph_height = element.offsetHeight; return window.innerHeight-this.graph_height; } diff --git a/sharedComponents/tabs/slider-tab.component.ts b/sharedComponents/tabs/slider-tab.component.ts new file mode 100644 index 00000000..2060ccf2 --- /dev/null +++ b/sharedComponents/tabs/slider-tab.component.ts @@ -0,0 +1,16 @@ +import {Component, Input} from "@angular/core"; + +@Component({ + selector: 'slider-tab', + template: `` +}) +export class SliderTabComponent { + @Input("tabTitle") + public title: string; + @Input("tabId") + public id: string; + @Input() + public active: boolean = false; + @Input() + public disabled: boolean = false; +} diff --git a/sharedComponents/tabs/slider-tabs.component.ts b/sharedComponents/tabs/slider-tabs.component.ts new file mode 100644 index 00000000..d53f56cf --- /dev/null +++ b/sharedComponents/tabs/slider-tabs.component.ts @@ -0,0 +1,172 @@ +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ContentChildren, + ElementRef, EventEmitter, + Input, OnDestroy, Output, + QueryList, + ViewChild +} from "@angular/core"; +import {SliderTabComponent} from "./slider-tab.component"; +import {ActivatedRoute, Router} from "@angular/router"; +import {Subscription} from "rxjs"; +import Timeout = NodeJS.Timeout; + +declare var UIkit; + +@Component({ + selector: 'slider-tabs', + template: ` +
+
+ +
+ + +
+ `, +}) +export class SliderTabsComponent implements AfterViewInit, OnDestroy { + //TODO now it works only for scrollable, to be extended + /** + * Type of tabs: Static = Uikit tabs with @connect class, Dynamic = Active is defined by tabComponent.active input, + * Scrollable = Active is defined by the active fragment of URL and position of scroll + * */ + @Input() + public type: 'static' | 'dynamic' | 'scrollable' = 'static'; + /** + * Connect class in static type. Default: uk-switcher + * */ + @Input() + public connect = 'uk-switcher'; + /** + * Threshold between 0.0 to 1.0 for Intersection Observer + * */ + @Input() + public scrollThreshold = 0.1; + /** + * Tabs view: Horizontal is the default. + * */ + @Input() + public position: 'horizontal' | 'left' | 'right' = 'horizontal'; + /** + * Tabs background + * */ + @Input() + public background: string; + @ContentChildren(SliderTabComponent) tabs: QueryList; + @ViewChild('tabsElement') tabsElement: ElementRef; + /** + * Notify regarding new active element + * */ + @Output() activeEmitter: EventEmitter = new EventEmitter(); + public init: boolean = false; + private subscriptions: any[] = []; + private observer: IntersectionObserver; + private timeout: Timeout; + + constructor(private route: ActivatedRoute, + private router: Router, + private cdr: ChangeDetectorRef) { + } + + ngAfterViewInit() { + if (typeof document !== 'undefined' && this.tabs.length > 0) { + setTimeout(() => { + if(this.position === 'horizontal') { + let slider = UIkit.slider(this.tabsElement.nativeElement, {finite: true}); + slider.clsActive = 'uk-slider-active'; + slider.updateActiveClasses(); + this.init = true; + slider.slides.forEach(item => { + item.classList.remove('uk-active'); + }); + if (this.type === 'scrollable') { + this.scrollable(slider); + } + } else { + this.scrollable(); + } + }); + } + } + + private scrollable(slider = null) { + this.activeFragment(this.route.snapshot.fragment, slider); + this.subscriptions.push(this.route.fragment.subscribe(fragment => { + this.activeFragment(fragment,slider); + })); + this.setObserver(); + } + + 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.1}); + this.tabs.forEach(tab => { + let element = document.getElementById(tab.id); + if (element) { + this.observer.observe(element); + } + }); + } + + private activeFragment(fragment, slider) { + let index = 0; + if (fragment) { + index = this.tabs.toArray().findIndex(item => item.id == fragment); + } + if(slider) { + slider.show(index); + } + this.tabs.forEach((tab, i) => { + if (index === i) { + tab.active = true; + this.activeEmitter.emit(tab.id); + } else { + tab.active = false; + } + }); + this.cdr.detectChanges(); + } + + ngOnDestroy() { + this.subscriptions.forEach(subscription => { + if (subscription instanceof Subscription) { + subscription.unsubscribe(); + } + }); + if (this.observer) { + this.observer.disconnect(); + } + } +} diff --git a/sharedComponents/tabs/slider-tabs.module.ts b/sharedComponents/tabs/slider-tabs.module.ts new file mode 100644 index 00000000..4bdc8e9b --- /dev/null +++ b/sharedComponents/tabs/slider-tabs.module.ts @@ -0,0 +1,13 @@ +import {NgModule} from "@angular/core"; +import {CommonModule} from "@angular/common"; +import {SliderTabsComponent} from "./slider-tabs.component"; +import {SliderTabComponent} from "./slider-tab.component"; +import {RouterModule} from "@angular/router"; + +@NgModule({ + imports: [CommonModule, RouterModule], + declarations: [SliderTabsComponent, SliderTabComponent], + exports: [SliderTabsComponent, SliderTabComponent] +}) +export class SliderTabsModule {} +