mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
97732 Context help service, changes to directive and component
This commit is contained in:
@@ -50,6 +50,7 @@ import { sidebarReducer, SidebarState } from './shared/sidebar/sidebar.reducer';
|
||||
import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer';
|
||||
import { ThemeState, themeReducer } from './shared/theme-support/theme.reducer';
|
||||
import { correlationIdReducer } from './correlation-id/correlation-id.reducer';
|
||||
import { contextHelpReducer, ContextHelpState } from './shared/context-help.reducer';
|
||||
|
||||
export interface AppState {
|
||||
router: fromRouter.RouterReducerState;
|
||||
@@ -71,6 +72,7 @@ export interface AppState {
|
||||
epeopleRegistry: EPeopleRegistryState;
|
||||
groupRegistry: GroupRegistryState;
|
||||
correlationId: string;
|
||||
contextHelp: ContextHelpState;
|
||||
}
|
||||
|
||||
export const appReducers: ActionReducerMap<AppState> = {
|
||||
@@ -92,7 +94,8 @@ export const appReducers: ActionReducerMap<AppState> = {
|
||||
communityList: CommunityListReducer,
|
||||
epeopleRegistry: ePeopleRegistryReducer,
|
||||
groupRegistry: groupRegistryReducer,
|
||||
correlationId: correlationIdReducer
|
||||
correlationId: correlationIdReducer,
|
||||
contextHelp: contextHelpReducer,
|
||||
};
|
||||
|
||||
export const routerStateSelector = (state: AppState) => state.router;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<div class="page-internal-server-error container">
|
||||
<h1>500</h1>
|
||||
<h2><small *dsContextHelp="{content: 'context-help.multi-para.test'}">{{"500.page-internal-server-error" | translate}}</small></h2>
|
||||
<h2><small *dsContextHelp="{content: 'context-help.multi-para.test', id: 'server-error'}">{{"500.page-internal-server-error" | translate}}</small></h2>
|
||||
<br/>
|
||||
<p>{{"500.help" | translate}}</p>
|
||||
<br/>
|
||||
|
@@ -10,12 +10,16 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
<i [ngClass]="{'ds-context-help-icon fas fa-question-circle shadow-sm': true,
|
||||
<i *ngIf="shouldShowIcon$ | async"
|
||||
[ngClass]="{'ds-context-help-icon fas fa-question-circle shadow-sm': true,
|
||||
'ds-context-help-icon-right': iconPlacement !== 'left',
|
||||
'ds-context-help-icon-left': iconPlacement === 'left'}"
|
||||
[ngbTooltip]="help"
|
||||
[placement]="tooltipPlacement"
|
||||
autoClose="outside"
|
||||
triggers="manual"
|
||||
container="'body'"
|
||||
triggers="click:blur">
|
||||
#tooltip="ngbTooltip"
|
||||
(click)="onClick()">
|
||||
</i>
|
||||
<ng-container *ngTemplateOutlet="templateRef"></ng-container>
|
||||
|
@@ -1,11 +1,16 @@
|
||||
import { Component, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { Component, Input, OnInit, TemplateRef, OnDestroy, AfterViewInit, ViewChild } from '@angular/core';
|
||||
import { PlacementArray } from '@ng-bootstrap/ng-bootstrap/util/positioning';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PlacementDir } from './placement-dir.model';
|
||||
import content from '*.scss';
|
||||
import { ContextHelpService } from '../context-help.service';
|
||||
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { hasValueOperator } from '../empty.util';
|
||||
import { ContextHelp } from '../context-help.model';
|
||||
|
||||
/*
|
||||
/**
|
||||
* This component renders an info icon next to the wrapped element which
|
||||
* produces a tooltip when clicked.
|
||||
*/
|
||||
@@ -14,28 +19,39 @@ import { PlacementDir } from './placement-dir.model';
|
||||
templateUrl: './context-help-wrapper.component.html',
|
||||
styleUrls: ['./context-help-wrapper.component.scss'],
|
||||
})
|
||||
export class ContextHelpWrapperComponent {
|
||||
/*
|
||||
export class ContextHelpWrapperComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
/**
|
||||
* Template reference for the wrapped element.
|
||||
*/
|
||||
@Input() templateRef: TemplateRef<any>;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Identifier for the context help tooltip.
|
||||
*/
|
||||
@Input() id: string;
|
||||
|
||||
/**
|
||||
* Indicate where the tooltip should show up, relative to the info icon.
|
||||
*/
|
||||
@Input() tooltipPlacement?: PlacementArray;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Indicate whether the info icon should appear to the left or to
|
||||
* the right of the wrapped element.
|
||||
*/
|
||||
@Input() iconPlacement?: PlacementDir;
|
||||
|
||||
/*
|
||||
/**
|
||||
* If true, don't process text to render links.
|
||||
*/
|
||||
@Input() dontParseLinks?: boolean;
|
||||
|
||||
@ViewChild('tooltip', { static: false }) tooltip: NgbTooltip;
|
||||
|
||||
shouldShowIcon$: Observable<boolean>;
|
||||
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
// TODO: dependent on evaluation order of input setters?
|
||||
parsedContent$: Observable<(string | {href: string, text: string})[]> = observableOf([]);
|
||||
@Input() set content(content : string) {
|
||||
@@ -46,9 +62,48 @@ export class ContextHelpWrapperComponent {
|
||||
);
|
||||
}
|
||||
|
||||
constructor(private translateService: TranslateService) { }
|
||||
constructor(
|
||||
private translateService: TranslateService,
|
||||
private contextHelpService: ContextHelpService
|
||||
) { }
|
||||
|
||||
/*
|
||||
ngOnInit() {
|
||||
this.shouldShowIcon$ = this.contextHelpService.shouldShowIcons$();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.subs = [
|
||||
this.contextHelpService.getContextHelp$(this.id)
|
||||
.pipe(hasValueOperator())
|
||||
.subscribe((ch: ContextHelp) => {
|
||||
if (ch.isTooltipVisible && !this.tooltip.isOpen()) {
|
||||
this.tooltip.open();
|
||||
} else if (!ch.isTooltipVisible && this.tooltip.isOpen()) {
|
||||
this.tooltip.close()
|
||||
}
|
||||
}),
|
||||
|
||||
this.tooltip.shown.subscribe(() => {
|
||||
this.contextHelpService.showTooltip(this.id);
|
||||
}),
|
||||
|
||||
this.tooltip.hidden.subscribe(() => {
|
||||
this.contextHelpService.hideTooltip(this.id);
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
for (let sub of this.subs) {
|
||||
sub.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.contextHelpService.toggleTooltip(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Markdown-style links, splitting up a given text
|
||||
* into link-free pieces of text and objects of the form
|
||||
* {href: string, text: string} (which represent links).
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { type } from './ngrx/type';
|
||||
import { ContextHelpModel } from './context-help.model';
|
||||
import { ContextHelp } from './context-help.model';
|
||||
|
||||
export const ContextHelpActionTypes = {
|
||||
'CONTEXT_HELP_TOGGLE_ICONS': type('dspace/context-help/CONTEXT_HELP_TOGGLE_ICONS'),
|
||||
@@ -23,9 +23,9 @@ export class ContextHelpToggleIconsAction implements Action {
|
||||
*/
|
||||
export class ContextHelpAddAction implements Action {
|
||||
type = ContextHelpActionTypes.CONTEXT_HELP_ADD;
|
||||
model: ContextHelpModel;
|
||||
model: ContextHelp;
|
||||
|
||||
constructor (model: ContextHelpModel) {
|
||||
constructor (model: ContextHelp) {
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,28 @@
|
||||
import { ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Input, OnChanges, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
TemplateRef,
|
||||
ViewContainerRef,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { PlacementArray } from '@ng-bootstrap/ng-bootstrap/util/positioning';
|
||||
import { ContextHelpWrapperComponent } from './context-help-wrapper/context-help-wrapper.component';
|
||||
import { PlacementDir } from './context-help-wrapper/placement-dir.model';
|
||||
import { ContextHelpService } from './context-help.service';
|
||||
|
||||
export interface ContextHelpDirectiveInput {
|
||||
content: string;
|
||||
id: string;
|
||||
tooltipPlacement?: PlacementArray;
|
||||
iconPlacement?: PlacementDir;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Directive to add a clickable tooltip icon to an element.
|
||||
* The tooltip icon's position is configurable ('left' or 'right')
|
||||
* and so is the position of the tooltip itself (PlacementArray).
|
||||
@@ -17,14 +30,15 @@ export interface ContextHelpDirectiveInput {
|
||||
@Directive({
|
||||
selector: '[dsContextHelp]',
|
||||
})
|
||||
export class ContextHelpDirective implements OnChanges {
|
||||
/*
|
||||
export class ContextHelpDirective implements OnChanges, OnDestroy {
|
||||
/**
|
||||
* Expects an object with the following fields:
|
||||
* - content: a string referring to an entry in the i18n files
|
||||
* - tooltipPlacement: a PlacementArray describing where the tooltip should expand, relative to the tooltip icon
|
||||
* - iconPlacement: a string 'left' or 'right', describing where the tooltip icon should be placed, relative to the element
|
||||
*/
|
||||
@Input() dsContextHelp: string | ContextHelpDirectiveInput;
|
||||
@Input() dsContextHelp: ContextHelpDirectiveInput;
|
||||
mostRecentId: string | undefined = undefined;
|
||||
|
||||
protected wrapper: ComponentRef<ContextHelpWrapperComponent>;
|
||||
|
||||
@@ -32,19 +46,31 @@ export class ContextHelpDirective implements OnChanges {
|
||||
private templateRef: TemplateRef<any>,
|
||||
private viewContainerRef: ViewContainerRef,
|
||||
private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private contextHelpService: ContextHelpService
|
||||
){}
|
||||
|
||||
ngOnChanges() {
|
||||
const input: ContextHelpDirectiveInput = typeof(this.dsContextHelp) === 'string'
|
||||
? {content: this.dsContextHelp}
|
||||
: this.dsContextHelp;
|
||||
this.clearMostRecentId();
|
||||
this.mostRecentId = this.dsContextHelp.id;
|
||||
this.contextHelpService.add({id: this.dsContextHelp.id}); // TODO: tooltipVisible field
|
||||
|
||||
const factory
|
||||
= this.componentFactoryResolver.resolveComponentFactory(ContextHelpWrapperComponent);
|
||||
this.wrapper = this.viewContainerRef.createComponent(factory);
|
||||
this.wrapper.instance.templateRef = this.templateRef;
|
||||
this.wrapper.instance.content = input.content;
|
||||
this.wrapper.instance.tooltipPlacement = input.tooltipPlacement;
|
||||
this.wrapper.instance.iconPlacement = input.iconPlacement;
|
||||
this.wrapper.instance.content = this.dsContextHelp.content;
|
||||
this.wrapper.instance.id = this.dsContextHelp.id;
|
||||
this.wrapper.instance.tooltipPlacement = this.dsContextHelp.tooltipPlacement;
|
||||
this.wrapper.instance.iconPlacement = this.dsContextHelp.iconPlacement;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.clearMostRecentId();
|
||||
}
|
||||
|
||||
private clearMostRecentId(): void {
|
||||
if (this.mostRecentId !== undefined) {
|
||||
this.contextHelpService.remove(this.mostRecentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export class ContextHelpModel {
|
||||
export class ContextHelp {
|
||||
id: string;
|
||||
tooltipVisible?: boolean = false;
|
||||
isTooltipVisible?: boolean = false;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { ContextHelpModel } from './context-help.model';
|
||||
import { ContextHelp } from './context-help.model';
|
||||
import { ContextHelpAction, ContextHelpActionTypes } from './context-help.actions';
|
||||
|
||||
export type ContextHelpModels = {
|
||||
[id: string]: ContextHelpModel;
|
||||
[id: string]: ContextHelp;
|
||||
};
|
||||
|
||||
export interface ContextHelpState {
|
||||
@@ -10,7 +10,10 @@ export interface ContextHelpState {
|
||||
models: ContextHelpModels;
|
||||
}
|
||||
|
||||
export function contextHelpReducer(state: ContextHelpState, action: ContextHelpAction): ContextHelpState {
|
||||
// TODO
|
||||
const initialState: ContextHelpState = {allIconsVisible: true, models: {}};
|
||||
|
||||
export function contextHelpReducer(state: ContextHelpState = initialState, action: ContextHelpAction): ContextHelpState {
|
||||
switch (action.type) {
|
||||
case ContextHelpActionTypes.CONTEXT_HELP_TOGGLE_ICONS: {
|
||||
return {...state, allIconsVisible: true};
|
||||
@@ -41,7 +44,7 @@ export function contextHelpReducer(state: ContextHelpState, action: ContextHelpA
|
||||
function modifyTooltipVisibility(state: ContextHelpState, id: string, modify: (vis: boolean) => boolean)
|
||||
: ContextHelpState {
|
||||
const {[id]: matchingModel, ...otherModels} = state.models;
|
||||
const modifiedModel = {...matchingModel, tooltipVisible: modify(matchingModel.tooltipVisible)};
|
||||
const modifiedModel = {...matchingModel, isTooltipVisible: modify(matchingModel.isTooltipVisible)};
|
||||
const newModels = {...otherModels, [id]: modifiedModel};
|
||||
return {...state, models: newModels};
|
||||
}
|
||||
|
@@ -1,33 +1,100 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ContextHelpModel } from './context-help.model';
|
||||
import { ContextHelp } from './context-help.model';
|
||||
import { Store, createFeatureSelector, createSelector, select, MemoizedSelector } from '@ngrx/store';
|
||||
import { ContextHelpState } from './context-help.reducer';
|
||||
import {
|
||||
ContextHelpToggleIconsAction,
|
||||
ContextHelpAddAction,
|
||||
ContextHelpRemoveAction,
|
||||
ContextHelpShowTooltipAction,
|
||||
ContextHelpHideTooltipAction,
|
||||
ContextHelpToggleTooltipAction
|
||||
} from './context-help.actions';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
const contextHelpStateSelector =
|
||||
createFeatureSelector<ContextHelpState>('contextHelp');
|
||||
const allIconsVisibleSelector = createSelector(
|
||||
contextHelpStateSelector,
|
||||
(state: ContextHelpState): boolean => state.allIconsVisible
|
||||
);
|
||||
const contextHelpSelector =
|
||||
(id: string): MemoizedSelector<ContextHelpState, ContextHelp> => createSelector(
|
||||
contextHelpStateSelector,
|
||||
(state: ContextHelpState) => state.models[id]
|
||||
);
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ContextHelpService {
|
||||
constructor() { }
|
||||
constructor(private store: Store<ContextHelpState>) { }
|
||||
|
||||
/**
|
||||
* Observable keeping track of whether context help icons should be visible globally.
|
||||
*/
|
||||
shouldShowIcons$(): Observable<boolean> {
|
||||
return this.store.pipe(select(allIconsVisibleSelector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Observable that tracks the state for a specific context help icon.
|
||||
*
|
||||
* @param id: id of the context help icon.
|
||||
*/
|
||||
getContextHelp$(id: string): Observable<ContextHelp> {
|
||||
return this.store.pipe(select(contextHelpSelector(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of all context help icons.
|
||||
*/
|
||||
toggleIcons() {
|
||||
|
||||
this.store.dispatch(new ContextHelpToggleIconsAction());
|
||||
}
|
||||
|
||||
add(contextHelp: ContextHelpModel) {
|
||||
|
||||
/**
|
||||
* Registers a new context help icon to the store.
|
||||
*
|
||||
* @param contextHelp: the initial state of the new help icon.
|
||||
*/
|
||||
add(contextHelp: ContextHelp) {
|
||||
this.store.dispatch(new ContextHelpAddAction(contextHelp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a context help icon from the store.
|
||||
*
|
||||
* @id: the id of the help icon to be removed.
|
||||
*/
|
||||
remove(id: string) {
|
||||
|
||||
}
|
||||
|
||||
showTooltip(id: string) {
|
||||
|
||||
}
|
||||
|
||||
hideTooltip(id: string) {
|
||||
|
||||
this.store.dispatch(new ContextHelpRemoveAction(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the tooltip of a single context help icon.
|
||||
*
|
||||
* @id: the id of the help icon for which the visibility will be toggled.
|
||||
*/
|
||||
toggleTooltip(id: string) {
|
||||
this.store.dispatch(new ContextHelpToggleTooltipAction(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the tooltip of a single context help icon.
|
||||
*
|
||||
* @id: the id of the help icon that will be made visible.
|
||||
*/
|
||||
showTooltip(id: string) {
|
||||
this.store.dispatch(new ContextHelpShowTooltipAction(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the tooltip of a single context help icon.
|
||||
*
|
||||
* @id: the id of the help icon that will be made invisible.
|
||||
*/
|
||||
hideTooltip(id: string) {
|
||||
this.store.dispatch(new ContextHelpHideTooltipAction(id));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user