Guided tour added in dataset editor details

This commit is contained in:
gpapavgeri 2020-07-31 17:39:57 +03:00
parent 9ff36a1b12
commit 24855f776b
10 changed files with 167 additions and 83 deletions

View File

@ -8,13 +8,16 @@
</div> -->
<div *ngIf="currentTourStep && !isOrbShowing">
<div class="guided-tour-user-input-mask" (click)="backdropClick($event)"></div>
<div class="guided-tour-spotlight-overlay" [style.top.px]="overlayTop" [style.left.px]="overlayLeft"
<div *ngIf="!isStepUnique" class="guided-tour-spotlight-overlay" [style.top.px]="overlayTop" [style.left.px]="overlayLeft"
[style.height.px]="overlayHeight" [style.width.px]="overlayWidth" >
</div>
<div *ngIf="isStepUnique" class="guided-tour-spotlight-overlay spotlight-overlay-step-unique" [style.top.px]="overlayTop-12" [style.left.px]="overlayLeft-3"
[style.height.px]="overlayHeight" [style.width.px]="overlayWidth" >
</div>
</div>
<div *ngIf="currentTourStep && !isOrbShowing">
<div #tourStep *ngIf="currentTourStep" class="tour-step tour-{{ currentTourStep.orientation }}" [ngClass]="{
'page-tour-step': !currentTourStep.selector
'page-tour-step': !currentTourStep.selector, 'tour-step-unique' : isStepUnique
}" [style.top.px]="(currentTourStep.selector && selectedElementRect ? topPosition : null)"
[style.left.px]="(currentTourStep.selector && selectedElementRect ? leftPosition : null)"
[style.width.px]="(currentTourStep.selector && selectedElementRect ? calculatedTourStepWidth : null)"
@ -38,7 +41,7 @@
(click)="guidedTourService.nextStep()">
{{ nextText }}
</button>
<button *ngIf="!guidedTourService.onResizeMessage" (click)="guidedTourService.skipTour()"
<button *ngIf="!guidedTourService.onResizeMessage && !isStepUnique" (click)="guidedTourService.skipTour()"
class="skip-button link-button">
{{ skipText }}
</button>

View File

@ -17,6 +17,10 @@ ngx-guided-tour {
border-radius: 44px;
}
.spotlight-overlay-step-unique {
padding: 20px;
}
.tour-orb {
position: fixed;
width: 20px;
@ -53,6 +57,10 @@ ngx-guided-tour {
}
}
.tour-step-unique {
margin-top: 15px;
}
.tour-step {
position: fixed;
&.page-tour-step {
@ -133,9 +141,9 @@ ngx-guided-tour {
border-radius: 5px;
}
.tour-progress-indicator {
padding-bottom: 15px;
}
// .tour-progress-indicator {
// padding-bottom: 15px;
// }
.tour-title {
font-weight: lighter !important;
@ -149,6 +157,7 @@ ngx-guided-tour {
line-height: 26px;
white-space:pre-line;
height: 182px;
width: 983px;
}
h3.tour-title {
@ -158,11 +167,11 @@ ngx-guided-tour {
font-size: 30px;
}
.tour-content {
min-height: 80px;
padding-bottom: 30px;
font-size: 15px;
}
// .tour-content {
// min-height: 80px;
// padding-bottom: 30px;
// font-size: 15px;
// }
.tour-buttons {
overflow: hidden; // clearfix

View File

@ -1,7 +1,7 @@
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild, ViewEncapsulation, TemplateRef, Inject } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';
import { DOCUMENT } from '@angular/common';
import { Orientation, TourStep, ProgressIndicatorLocation } from './guided-tour.constants';
import { Orientation, TourStep } from './guided-tour.constants';
import { GuidedTourService } from './guided-tour.service';
import { WindowRefService } from "./windowref.service";
@ -17,17 +17,18 @@ export class GuidedTourComponent implements AfterViewInit, OnDestroy {
@Input() public minimalTourStepWidth?= 900;
@Input() public skipText?= 'Leave Tour';
@Input() public nextText?= 'Got it!';
@Input() public doneText ?= 'Done';
@Input() public closeText ?= 'Close';
@Input() public backText ?= 'Back';
@Input() public progressIndicatorLocation?: ProgressIndicatorLocation = ProgressIndicatorLocation.InsideNextButton;
// @Input() public doneText?= 'Done';
// @Input() public closeText?= 'Close';
// @Input() public backText?= 'Back';
// @Input() public progressIndicatorLocation?: ProgressIndicatorLocation = ProgressIndicatorLocation.InsideNextButton;
@Input() public progressIndicator?: TemplateRef<any> = undefined;
@ViewChild('tourStep', { static: false }) public tourStep: ElementRef;
public highlightPadding = 4;
public currentTourStep: TourStep = null;
public selectedElementRect: DOMRect = null;
public isOrbShowing = false;
public progressIndicatorLocations = ProgressIndicatorLocation;
// public progressIndicatorLocations = ProgressIndicatorLocation;
public isStepUnique = false;
private resizeSubscription: Subscription;
private scrollSubscription: Subscription;
@ -58,11 +59,13 @@ export class GuidedTourComponent implements AfterViewInit, OnDestroy {
}
public get calculatedTourStepWidth() {
return this.tourStepWidth - this.widthAdjustmentForScreenBound;
return this.tourStepWidth;
// return this.tourStepWidth - this.widthAdjustmentForScreenBound;
}
public ngAfterViewInit(): void {
this.guidedTourService.guidedTourCurrentStepStream.subscribe((step: TourStep) => {
this.isStepUnique = this.guidedTourService.isStepUnique;
this.currentTourStep = step;
if (step && step.selector) {
const selectedElement = this.dom.querySelector(step.selector);

View File

@ -68,8 +68,8 @@ export class Orientation {
public static readonly TopRight = 'top-right';
}
export enum ProgressIndicatorLocation {
InsideNextButton = 'inside-next-button',
TopOfTourBlock = 'top-of-tour-block',
None = 'none',
}
// export enum ProgressIndicatorLocation {
// InsideNextButton = 'inside-next-button',
// TopOfTourBlock = 'top-of-tour-block',
// None = 'none',
// }

View File

@ -18,6 +18,7 @@ export class GuidedTourService {
private _onFirstStep = true;
private _onLastStep = true;
private _onResizeMessage = false;
public isStepUnique = false;
constructor(
public errorHandler: ErrorHandler,
@ -77,33 +78,33 @@ export class GuidedTourService {
}
}
public backStep(): void {
if (this._currentTour.steps[this._currentTourStepIndex].closeAction) {
this._currentTour.steps[this._currentTourStepIndex].closeAction();
}
if (this._currentTour.steps[this._currentTourStepIndex - 1]) {
this._currentTourStepIndex--;
this._setFirstAndLast();
if (this._currentTour.steps[this._currentTourStepIndex].action) {
this._currentTour.steps[this._currentTourStepIndex].action();
setTimeout(() => {
if (this._checkSelectorValidity()) {
this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
} else {
this.backStep();
}
});
} else {
if (this._checkSelectorValidity()) {
this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
} else {
this.backStep();
}
}
} else {
this.resetTour();
}
}
// public backStep(): void {
// if (this._currentTour.steps[this._currentTourStepIndex].closeAction) {
// this._currentTour.steps[this._currentTourStepIndex].closeAction();
// }
// if (this._currentTour.steps[this._currentTourStepIndex - 1]) {
// this._currentTourStepIndex--;
// this._setFirstAndLast();
// if (this._currentTour.steps[this._currentTourStepIndex].action) {
// this._currentTour.steps[this._currentTourStepIndex].action();
// setTimeout(() => {
// if (this._checkSelectorValidity()) {
// this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
// } else {
// this.backStep();
// }
// });
// } else {
// if (this._checkSelectorValidity()) {
// this._guidedTourCurrentStepSubject.next(this.getPreparedTourStep(this._currentTourStepIndex));
// } else {
// this.backStep();
// }
// }
// } else {
// this.resetTour();
// }
// }
public skipTour(): void {
if (this._currentTour.skipCallback) {
@ -144,6 +145,13 @@ export class GuidedTourService {
}
}
public checkIfStepIsUnique(tour: GuidedTour): boolean {
if(tour.steps.length === 1) {
this.isStepUnique = true;
}
return this.isStepUnique;
}
public activateOrb(): void {
this._guidedTourOrbShowingSubject.next(false);
this.dom.body.classList.add('tour-open');

View File

@ -34,6 +34,7 @@
</mat-select>
</mat-form-field>
<!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour -->
<div class="center-content" [style.display]=" (!isVisible && isAuthenticated()) ? 'block' : 'none'" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
@ -48,6 +49,7 @@
<!-- End of Search Filter -->
</div>
</div>
</div>
<div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index">
<app-dataset-listing-item-component [isPublic]="isPublic" [dataset]="item" [showDivider]="i != (listingItems.length - 1)"></app-dataset-listing-item-component>

View File

@ -7,7 +7,7 @@
<div class="row">
<div class="col-12">
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link dmp-only-tour-title" target="_blank" (click)="restartTourFromTitle()">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="title-form">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
@ -23,7 +23,7 @@
<div class="row">
<div class="col-12">
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link dmp-only-tour-desc" target="_blank" (click)="restartTourFromDesc()">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="description-form">
<mat-form-field appearance="outline">
<textarea rows="3" matInput class="description-area" placeholder="{{'DMP-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" formControlName="description"></textarea>

View File

@ -27,6 +27,8 @@ import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DatasetWizardEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { ENTER, COMMA } from '@angular/cdk/keycodes';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
@Component({
@ -57,6 +59,7 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
// isLinear = false;
lock: LockModel;
lockStatus: Boolean;
dmpText: string;
@Input() formGroup: FormGroup;
@Input() dmpId: string;
@ -79,7 +82,8 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
private formService: FormService,
private lockService: LockService,
private location: Location,
private authService: AuthService
private authService: AuthService,
private guidedTourService: GuidedTourService
) {
super();
}
@ -133,6 +137,53 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn
}
}
public dashboardTourDmpTitle: GuidedTour = {
tourId: 'only-dmp-tour',
useOrb: true,
steps: [
{
title: this.dmpText,
selector: '.dmp-only-tour-title',
content: 'Step 1',
orientation: Orientation.Bottom
}
]
};
public dashboardTourDmpDescription: GuidedTour = {
tourId: 'only-dmp-tour',
useOrb: true,
steps: [
{
title: this.dmpText,
selector: '.dmp-only-tour-desc',
content: 'Step 1',
orientation: Orientation.Bottom
}
]
};
setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
this.dashboardTourDmpTitle.steps[0].title = this.dmpText;
this.dashboardTourDmpDescription.steps[0].title = this.dmpText;
}
public restartTourFromTitle(): void {
this.setDashboardTourDmpText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTourDmpTitle);
this.guidedTourService.startTour(this.dashboardTourDmpTitle);
}
public restartTourFromDesc(): void {
this.setDashboardTourDmpText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTourDmpDescription);
this.guidedTourService.startTour(this.dashboardTourDmpDescription);
}
registerFormListeners() {
this.formGroup.get('dmp').valueChanges
.pipe(takeUntil(this._destroyed))

View File

@ -29,20 +29,26 @@
</mat-select>
</mat-form-field>
<!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour -->
<div class="center-content" [style.display]="!isVisible && isAuthenticated()? 'block' : 'none'" (click)="restartTour()">
<div class="center-content"
[style.display]="!isVisible && isAuthenticated()? 'block' : 'none'" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
</div>
<!-- End of Guided Tour -->
<!-- Search Filter-->
<mat-form-field appearance="outline" class="search-form ml-auto col-auto pr-0" floatLabel="never">
<mat-form-field appearance="outline" class="search-form ml-auto col-auto pr-0"
floatLabel="never">
<mat-icon matSuffix>search</mat-icon>
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria" [formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">{{formGroup.get('like').getError('backendError').message}}</mat-error>
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria"
[formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
</mat-form-field>
<!-- End of Search Filter -->
</div>
</div>
</div>
<div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component>

View File

@ -197,6 +197,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread
public isAuthenticated(): boolean {
return !(!this.authService.current());
}
ngAfterContentChecked(): void {
this.scrollbar = this.hasScrollbar();
}
@ -470,6 +471,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread
public restartTour(): void {
this.setDashboardTourDmpText();
this.setDashboardTourDatasetText();
this.guidedTourService.checkIfStepIsUnique(this.dashboardTour);
this.guidedTourService.startTour(this.dashboardTour);
}
}