Add new slider-tabs component. Add slider tabs in terminology page and make content with class help texts
This commit is contained in:
parent
ada4017fe5
commit
1e8ec15451
|
@ -11,6 +11,8 @@ import {IconsModule} from "../../utils/icons/icons.module";
|
||||||
import {IconsService} from "../../utils/icons/icons.service";
|
import {IconsService} from "../../utils/icons/icons.service";
|
||||||
import {graph} from "../../utils/icons/icons";
|
import {graph} from "../../utils/icons/icons";
|
||||||
import {BreadcrumbsModule} from "../../utils/breadcrumbs/breadcrumbs.module";
|
import {BreadcrumbsModule} from "../../utils/breadcrumbs/breadcrumbs.module";
|
||||||
|
import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module";
|
||||||
|
import {HelperModule} from "../../utils/helper/helper.module";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [TerminologyComponent, SeeHowItWorksComponent],
|
declarations: [TerminologyComponent, SeeHowItWorksComponent],
|
||||||
|
@ -30,7 +32,7 @@ import {BreadcrumbsModule} from "../../utils/breadcrumbs/breadcrumbs.module";
|
||||||
component: SeeHowItWorksComponent,
|
component: SeeHowItWorksComponent,
|
||||||
canDeactivate: [PreviousRouteRecorder]
|
canDeactivate: [PreviousRouteRecorder]
|
||||||
},
|
},
|
||||||
]), PageContentModule, HowModule, TabsModule, IconsModule, BreadcrumbsModule],
|
]), PageContentModule, HowModule, SliderTabsModule, IconsModule, BreadcrumbsModule, SliderTabsModule, HelperModule],
|
||||||
exports: [TerminologyComponent, SeeHowItWorksComponent]
|
exports: [TerminologyComponent, SeeHowItWorksComponent]
|
||||||
})
|
})
|
||||||
export class MethodologyModule {
|
export class MethodologyModule {
|
||||||
|
|
|
@ -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 {Subscription} from "rxjs";
|
||||||
import {Meta, Title} from "@angular/platform-browser";
|
import {Meta, Title} from "@angular/platform-browser";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
|
@ -6,7 +14,8 @@ import {OpenaireEntities} from "../../utils/properties/searchFields";
|
||||||
import {SEOService} from "../../sharedComponents/SEO/SEO.service";
|
import {SEOService} from "../../sharedComponents/SEO/SEO.service";
|
||||||
import {properties} from "../../../../environments/environment";
|
import {properties} from "../../../../environments/environment";
|
||||||
import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component";
|
import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component";
|
||||||
import Timeout = NodeJS.Timeout;
|
import {HelperService} from "../../utils/helper/helper.service";
|
||||||
|
|
||||||
|
|
||||||
declare var ResizeObserver;
|
declare var ResizeObserver;
|
||||||
|
|
||||||
|
@ -31,217 +40,37 @@ declare var ResizeObserver;
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-section" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-fade; delay: 250">
|
<div *ngIf="divContents" class="uk-section" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-fade; delay: 250">
|
||||||
<div class="uk-section uk-container uk-container-large" uk-scrollspy-class>
|
<div class="uk-section uk-container uk-container-large" uk-scrollspy-class>
|
||||||
<div id="parentContainer" class="uk-grid uk-grid-large" uk-grid>
|
<div id="parentContainer" class="uk-grid uk-grid-large" uk-grid>
|
||||||
<div class="uk-width-1-4@m uk-visible@m">
|
<div class="uk-width-1-4@m uk-visible@m">
|
||||||
<div class="uk-sticky" uk-sticky="bottom: !#parentContainer; offset: 100;">
|
<div class="uk-sticky" uk-sticky="bottom: !#parentContainer; offset: 100;">
|
||||||
<ul class="uk-tab uk-tab-left">
|
<slider-tabs type="scrollable" position="left">
|
||||||
<li class="uk-margin-small-bottom" [class.uk-active]="activeSection === 'entities'">
|
<slider-tab tabId="entities" tabTitle="1. Entities"></slider-tab>
|
||||||
<a routerLink="./" fragment="entities">1. Entities</a>
|
<slider-tab tabId="inherited-and-inferred-attributes" tabTitle="2. Inherited and Inferred Attributes"></slider-tab>
|
||||||
</li>
|
<slider-tab tabId="constructed-attributes" tabTitle="3. Constructed Attributes"></slider-tab>
|
||||||
<li class="uk-margin-small-bottom" [class.uk-active]="activeSection === 'inherited-and-inferred-attributes'">
|
</slider-tabs>
|
||||||
<a routerLink="./" fragment="inherited-and-inferred-attributes">2. Inherited and Inferred Attributes</a>
|
|
||||||
</li>
|
|
||||||
<li class="uk-margin-small-bottom" [class.uk-active]="activeSection === 'constructed-attributes'">
|
|
||||||
<a routerLink="./" fragment="constructed-attributes">3. Constructed Attributes</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-width-1-1 uk-hidden@m">
|
<div class="uk-width-1-1 uk-hidden@m">
|
||||||
<div class="uk-sticky uk-background-default" uk-sticky>
|
<div class="uk-sticky uk-background-default" uk-sticky>
|
||||||
<ul class="uk-tab">
|
<slider-tabs type="scrollable" position="horizontal">
|
||||||
<li [class.uk-active]="activeSection === 'entities'">
|
<slider-tab tabId="entities" tabTitle="1. Entities"></slider-tab>
|
||||||
<a routerLink="./" fragment="entities">1. Entities</a>
|
<slider-tab tabId="inherited-and-inferred-attributes" tabTitle="2. Inherited and Inferred Attributes"></slider-tab>
|
||||||
</li>
|
<slider-tab tabId="constructed-attributes" tabTitle="3. Constructed Attributes"></slider-tab>
|
||||||
<li [class.uk-active]="activeSection === 'inherited-and-inferred-attributes'">
|
</slider-tabs>
|
||||||
<a routerLink="./" fragment="inherited-and-inferred-attributes">2. Inherited and Inferred Attributes</a>
|
|
||||||
</li>
|
|
||||||
<li [class.uk-active]="activeSection === 'constructed-attributes'">
|
|
||||||
<a routerLink="./" fragment="constructed-attributes">3. Constructed Attributes</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-width-expand@m uk-margin-left">
|
<div class="uk-width-expand@m">
|
||||||
<div id="entities" class="uk-margin-large-bottom">
|
<div id="entities" class="uk-margin-large-bottom">
|
||||||
<!-- Helptext below here -->
|
<helper [texts]="divContents.entities"></helper>
|
||||||
<div>
|
|
||||||
<h4>1. Entities</h4>
|
|
||||||
<h6 class="uk-text-primary">Research Products</h6>
|
|
||||||
<div>
|
|
||||||
There are four different types of research products in the
|
|
||||||
OpenAIRE Research Graph:
|
|
||||||
</div>
|
|
||||||
<ul class="uk-list uk-list-bullet uk-list-primary">
|
|
||||||
<li>Publications</li>
|
|
||||||
<li>Research data</li>
|
|
||||||
<li>Research software</li>
|
|
||||||
<li>Other research products.</li>
|
|
||||||
</ul>
|
|
||||||
<div class="uk-margin-small-top">
|
|
||||||
We deduplicate (merge) different records of research products and keep the metadata of all instances.
|
|
||||||
</div>
|
|
||||||
<h6>Publication</h6>
|
|
||||||
<div>
|
|
||||||
Research products intended for human reading (published articles, pre-prints, conference
|
|
||||||
papers, presentations, technical reports, etc.)
|
|
||||||
</div>
|
|
||||||
<h6>Research data</h6>
|
|
||||||
<div>
|
|
||||||
The sources from which the description of the research data has been collected reflect and support their own granularity, we do not define it.
|
|
||||||
</div>
|
|
||||||
<h6>Research software</h6>
|
|
||||||
<div>
|
|
||||||
Source code or software package developed and/or used in a research context
|
|
||||||
</div>
|
|
||||||
<h6>Other research product</h6>
|
|
||||||
<div>
|
|
||||||
Anything that does not fall in the previous categories (e.g. workflow, methods, protocols)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="inherited-and-inferred-attributes" class="uk-margin-large-bottom">
|
<div id="inherited-and-inferred-attributes" class="uk-margin-large-bottom">
|
||||||
<!-- Helptext below here -->
|
<!-- Helptext below here -->
|
||||||
<div>
|
<helper [texts]="divContents['inherited-and-inferred-attributes']"></helper>
|
||||||
<h4>2. Inherited and Inferred Attributes</h4>
|
|
||||||
<div class="uk-margin-medium-top">
|
|
||||||
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).
|
|
||||||
</div>
|
|
||||||
<h6>Organization</h6>
|
|
||||||
<div>
|
|
||||||
<p><span class="uk-text-bold">For research products,</span> this refers to the
|
|
||||||
affiliated organizations of its authors</p>
|
|
||||||
<p><span class="uk-text-bold">For projects:</span>
|
|
||||||
the organizations participating in
|
|
||||||
the project
|
|
||||||
(i.e. beneficiaries of the grant)</p>
|
|
||||||
<p>
|
|
||||||
We are improving the organization database with the use of our <a href="https://orgs.openaire.eu/" target="_blank">OpenOrgs</a> tool. It allows curators to disambiguate organizations (merge different names of the same organization) and identify parent-child relationships (schools, departments, etc.).
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>Country</h6>
|
|
||||||
<div>
|
|
||||||
<p>The country of the organization.</p>
|
|
||||||
<p>
|
|
||||||
<span class="uk-text-bold">Country code mapping: </span>
|
|
||||||
<a href="https://api.openaire.eu/vocabularies/dnet:countries" target="_blank">
|
|
||||||
https://api.openaire.eu/vocabularies/dnet:countries</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>Funder</h6>
|
|
||||||
<div>
|
|
||||||
<p>Funders that have joined OpenAIRE, i.e. their project data have
|
|
||||||
gone through a validation process.</p>
|
|
||||||
<p>You can visit <a class="https://explore.openaire.eu/search/find" target="_blank">https://explore.openaire.eu/search/find</a>
|
|
||||||
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).</p>
|
|
||||||
<p><span class="uk-text-bold">For funder who want to join OpenAIRE: </span><a
|
|
||||||
href="https://www.openaire.eu/funders-how-to-join-guide" target="_blank">https://www.openaire.eu/funders-how-to-join-guide</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>Type</h6>
|
|
||||||
<div>
|
|
||||||
<p>The sub-type of a research outcome (e.g.,
|
|
||||||
a publication can be a pre-print, conference proceeding,
|
|
||||||
article,
|
|
||||||
etc.)</p>
|
|
||||||
<p><span class="uk-text-bold">Resource type mapping: </span>
|
|
||||||
<a href="https://api.openaire.eu/vocabularies/dnet:result_typologies" target="_blank">https://api.openaire.eu/vocabularies/dnet:result_typologies</a>
|
|
||||||
(click on the code to see the specific types for each result type)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>Access mode or access rights</h6>
|
|
||||||
<div>
|
|
||||||
<p>The best available (across all instances) access rights of
|
|
||||||
a research product</p>
|
|
||||||
<p>Types (by best available):</p>
|
|
||||||
<p><span class="uk-text-bold">Open:</span> Open Access</p>
|
|
||||||
<p><span class="uk-text-bold">Embargo:</span> Closed for a specific period of time, then open.</p>
|
|
||||||
<p><span class="uk-text-bold">Restricted:</span> Definition of restricted may vary by data source, it may refer to access rights being given to registered users, potentially behind a paywall.</p>
|
|
||||||
<p><span class="uk-text-bold">Closed:</span> Closed access</p>
|
|
||||||
</div>
|
|
||||||
<h6>CC license</h6>
|
|
||||||
<div>
|
|
||||||
<p>A Creative Commons copyright license <a href="(https://creativecommons.org/)" target="_blank">(https://creativecommons.org/)</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>PID (persistent identifier)</h6>
|
|
||||||
<div>
|
|
||||||
<p>A long-lasting reference to a resource</p>
|
|
||||||
<p><span class="uk-text-bold">Types: </span> <a
|
|
||||||
href="http://api.openaire.eu/vocabularies/dnet:pid_types" target="_blank">http://api.openaire.eu/vocabularies/dnet:pid_types</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<h6>Context</h6>
|
|
||||||
<div>
|
|
||||||
<p>Related research community, initiative or infrastructure.</p>
|
|
||||||
</div>
|
|
||||||
<h6>Journal</h6>
|
|
||||||
<div>
|
|
||||||
<p>The scientific journal an article is published in.</p>
|
|
||||||
</div>
|
|
||||||
<h6>Publisher</h6>
|
|
||||||
<div>
|
|
||||||
<p>The publisher of the venue (journal, book, etc.) of a research product.</p>
|
|
||||||
</div>
|
|
||||||
<h6>Data sources (content providers)</h6>
|
|
||||||
<div>
|
|
||||||
<p>The different data sources ingested in the OpenAIRE Research Graph.</p>
|
|
||||||
<div class="uk-text-bold">Data Source Types:</div>
|
|
||||||
<ul class="uk-list uk-list-disc">
|
|
||||||
<li>Repositories</li>
|
|
||||||
<li>Open Access Publishers & Journals</li>
|
|
||||||
<li>Aggregators</li>
|
|
||||||
<li>Entity Registries</li>
|
|
||||||
<li>Journal Aggregators</li>
|
|
||||||
<li>CRIS (Current Research Information System)</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<h6>Repositories</h6>
|
|
||||||
<div>
|
|
||||||
<p>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).</p>
|
|
||||||
</div>
|
|
||||||
<h6>Open Access Publishers & Journals</h6>
|
|
||||||
<div>
|
|
||||||
<p>Information systems of open access publishers or relative journals, which offer bibliographic
|
|
||||||
metadata and PDFs of their published articles.</p>
|
|
||||||
</div>
|
|
||||||
<h6>Aggregators</h6>
|
|
||||||
<div>
|
|
||||||
<p>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).</p>
|
|
||||||
</div>
|
|
||||||
<h6>Entity Registries</h6>
|
|
||||||
<div>
|
|
||||||
<p>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.</p>
|
|
||||||
</div>
|
|
||||||
<h6>CRIS (Current Research Information System)</h6>
|
|
||||||
<div>
|
|
||||||
<p>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.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="constructed-attributes" class="uk-margin-large-bottom">
|
<div id="constructed-attributes" class="uk-margin-large-bottom">
|
||||||
<!-- Helptext below here -->
|
<helper [texts]="divContents['constructed-attributes']"></helper>
|
||||||
<div>
|
<div>
|
||||||
<h4>3. Constructed Attributes</h4>
|
<h4>3. Constructed Attributes</h4>
|
||||||
<div class="uk-margin-medium-top">
|
<div class="uk-margin-medium-top">
|
||||||
|
@ -403,7 +232,7 @@ declare var ResizeObserver;
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class TerminologyComponent implements OnInit, OnDestroy {
|
export class TerminologyComponent implements OnInit, OnDestroy, AfterViewInit, AfterContentChecked {
|
||||||
public tab: 'entities' | 'attributes' = 'entities';
|
public tab: 'entities' | 'attributes' = 'entities';
|
||||||
private subscriptions: any[] = [];
|
private subscriptions: any[] = [];
|
||||||
public openaireEntities = OpenaireEntities;
|
public openaireEntities = OpenaireEntities;
|
||||||
|
@ -413,15 +242,16 @@ export class TerminologyComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild("graph_element") graph_element;
|
@ViewChild("graph_element") graph_element;
|
||||||
public contentSections: string[] = ['entities', 'inherited-and-inferred-attributes', 'constructed-attributes'];
|
public contentSections: string[] = ['entities', 'inherited-and-inferred-attributes', 'constructed-attributes'];
|
||||||
public activeSection: string;
|
public activeSection: string;
|
||||||
private observer: IntersectionObserver;
|
public properties = properties;
|
||||||
private timeout: Timeout;
|
public divContents: any;
|
||||||
|
|
||||||
constructor(private seoService: SEOService,
|
constructor(private seoService: SEOService,
|
||||||
private meta: Meta,
|
private meta: Meta,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private title: Title,
|
private title: Title,
|
||||||
private cdr: ChangeDetectorRef) {
|
private cdr: ChangeDetectorRef,
|
||||||
|
private helper: HelperService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -439,6 +269,7 @@ export class TerminologyComponent implements OnInit, OnDestroy {
|
||||||
this.activeSection = 'entities';
|
this.activeSection = 'entities';
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
this.getDivContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
|
@ -446,9 +277,6 @@ export class TerminologyComponent implements OnInit, OnDestroy {
|
||||||
if(this.graph_element) {
|
if(this.graph_element) {
|
||||||
this.observeGraphElement();
|
this.observeGraphElement();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
|
||||||
this.setObserver();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,33 +292,12 @@ export class TerminologyComponent implements OnInit, OnDestroy {
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(this.observer) {
|
|
||||||
this.observer.disconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setObserver() {
|
private getDivContents() {
|
||||||
if(this.observer) {
|
this.subscriptions.push(this.helper.getDivHelpContents(this.properties, 'monitor', this.router.url).subscribe(contents => {
|
||||||
this.observer.disconnect();
|
this.divContents = contents;
|
||||||
}
|
}));
|
||||||
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() {
|
public observeGraphElement() {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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: `
|
||||||
|
<div #tabsElement class="uk-position-relative" [class.uk-slider]="position === 'horizontal'"
|
||||||
|
[ngClass]="background">
|
||||||
|
<div [class.uk-slider-container-tabs]="position === 'horizontal'">
|
||||||
|
<ul class="uk-tab" [class.uk-flex-nowrap]="position === 'horizontal'"
|
||||||
|
[class.uk-slider-items]="position === 'horizontal'"
|
||||||
|
[class.uk-tab-left]="position === 'left'" [class.uk-tab-right]="position === 'right'"
|
||||||
|
[attr.uk-tab]="type === 'static'?('connect: .' + connect):null">
|
||||||
|
<ng-container *ngIf="type === 'scrollable'">
|
||||||
|
<li *ngFor="let tab of tabs.toArray()" class="uk-text-capitalize" [class.uk-active]="tab.active">
|
||||||
|
<a routerLink="./" [fragment]="tab.id">{{tab.title}}</a>
|
||||||
|
</li>
|
||||||
|
</ng-container>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<a *ngIf="position === 'horizontal'" class="uk-position-center-left uk-blur-background" uk-slider-item="previous"><span
|
||||||
|
uk-icon="chevron-left"></span></a>
|
||||||
|
<a *ngIf="position === 'horizontal'" class="uk-position-center-right uk-blur-background" uk-slider-item="next"><span
|
||||||
|
uk-icon="chevron-right"></span></a>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
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<SliderTabComponent>;
|
||||||
|
@ViewChild('tabsElement') tabsElement: ElementRef;
|
||||||
|
/**
|
||||||
|
* Notify regarding new active element
|
||||||
|
* */
|
||||||
|
@Output() activeEmitter: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {}
|
||||||
|
|
Loading…
Reference in New Issue