Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context list tool #624

Merged
merged 16 commits into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/src/app/context/context/context.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</igo-map-browser>

<igo-panel title="Contexts list">
<igo-context-list igoContextListBinding></igo-context-list>
<igo-context-list igoContextListBinding [map]="map"></igo-context-list>
</igo-panel>

<igo-panel title="Layers">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

import { AuthService } from '@igo2/auth';
import { TypePermission } from '../shared/context.enum';
Expand All @@ -7,7 +7,8 @@ import { DetailedContext } from '../shared/context.interface';
@Component({
selector: 'igo-context-item',
templateUrl: './context-item.component.html',
styleUrls: ['./context-item.component.scss']
styleUrls: ['./context-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ContextItemComponent {
public typePermission = TypePermission;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<igo-list [navigation]="true">
<mat-form-field *ngIf="showFilter()" class="contextFilter">
<mat-form-field *ngIf="showFilter()" [ngClass]="auth.authenticated ? 'context-filter-min-width' : 'context-filter-max-width'">
<input
matInput
type="text"
Expand All @@ -13,11 +13,54 @@
*ngIf="term.length"
aria-label="Clear"
color="warn"
(click)="term = ''">
(click)="clearFilter()">
<mat-icon svgIcon="close"></mat-icon>
</button>
</mat-form-field>

<button
*ngIf="!sortedAlpha"
mat-icon-button
[matTooltip]="'igo.context.contextManager.sortAlphabetically' | translate"
matTooltipShowDelay="500"
(click)="toggleSort(true)">
<mat-icon color="primary" svgIcon="sort-alphabetical"></mat-icon>
</button>
<button
*ngIf="sortedAlpha"
mat-icon-button
[matTooltip]="'igo.context.contextManager.sortContextOrder' | translate"
matTooltipShowDelay="500"
(click)="toggleSort(false)">
<mat-icon color="warn" svgIcon="sort-variant-remove"></mat-icon>
</button>

<button *ngIf="auth.authenticated"
mat-icon-button
[matTooltip]="'igo.context.bookmarkButton.create' | translate"
matTooltipShowDelay="500"
(click)="createContext()">
<mat-icon color="primary" svgIcon="star"></mat-icon>
</button>

<!-- <button *ngIf="authenticated"
mat-icon-button
[matTooltip]="'igo.context.contextManager.userAccount' | translate"
matTooltipShowDelay="500"
[matMenuTriggerFor]="accountMenu">
<mat-icon color="primary" svgIcon="account"></mat-icon>
</button>
<mat-menu #accountMenu="matMenu">
<ng-container *ngFor="let user of users">
<mat-checkbox
class="mat-menu-item"
[checked]="true"
(change)="userSelection()">
{{user}}
</mat-checkbox>
</ng-container>
</mat-menu> -->

<ng-template ngFor let-groupContexts [ngForOf]="contexts$ | async | keyvalue">

<igo-collapsible *ngIf="groupContexts.value.length && auth.authenticated" [title]="titleMapping[groupContexts.key] | translate">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
.contextFilter {
width: calc(100% - 20px);
.context-filter-max-width {
width: calc(100% - 60px);
margin: 5px;
padding-left: 6px;
}

.context-filter-min-width {
width: calc(100% - 95px);
margin: 5px;
padding-left: 6px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,45 @@ import {
Output,
EventEmitter,
ChangeDetectorRef,
OnInit
OnInit,
ChangeDetectionStrategy,
OnDestroy
} from '@angular/core';

import { AuthService } from '@igo2/auth';
import { LanguageService, MessageService } from '@igo2/core';
import { IgoMap } from '@igo2/geo';

import { DetailedContext, ContextsList } from '../shared/context.interface';
import { ContextListControlsEnum } from './context-list.enum';
import { Subscription, BehaviorSubject } from 'rxjs';
import { Subscription, BehaviorSubject, ReplaySubject, EMPTY, timer } from 'rxjs';
import { MatDialog } from '@angular/material';
import { ContextService } from '../shared/context.service';
import { BookmarkDialogComponent } from '../../context-map-button/bookmark-button/bookmark-dialog.component';
import { debounce } from 'rxjs/operators';

@Component({
selector: 'igo-context-list',
templateUrl: './context-list.component.html',
styleUrls: ['./context-list.component.scss']
styleUrls: ['./context-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ContextListComponent implements OnInit {
contexts$: BehaviorSubject<ContextsList> = new BehaviorSubject(undefined);
export class ContextListComponent implements OnInit, OnDestroy {
private contextsInitial: ContextsList = { ours: [] };
contexts$: BehaviorSubject<ContextsList> = new BehaviorSubject(this.contextsInitial);

change$ = new ReplaySubject<void>(1);

private change$$: Subscription;

@Input()
get contexts(): ContextsList {
return this._contexts;
}
set contexts(value: ContextsList) {
this._contexts = value;
this.contexts$.next(value);
this.cdRef.detectChanges();
this.next();
}
private _contexts: ContextsList = { ours: [] };

Expand All @@ -42,6 +56,15 @@ export class ContextListComponent implements OnInit {
}
private _selectedContext: DetailedContext;

@Input()
get map(): IgoMap {
return this._map;
}
set map(value: IgoMap) {
this._map = value;
}
private _map: IgoMap;

@Input()
get defaultContextId(): string {
return this._defaultContextId;
Expand All @@ -67,62 +90,102 @@ export class ContextListComponent implements OnInit {
public: 'igo.context.contextManager.publicContexts'
};

// public users = ['COG', '911', 'Public'];

/**
* Context filter term
*/
@Input()
set term(value: string) {
this.term$.next(value);
this._term = value;
this.next();
}
get term(): string {
return this.term$.value;
return this._term;
}
public _term: string = '';

get sortedAlpha(): boolean {
return this._sortedAlpha;
}
public term$: BehaviorSubject<string> = new BehaviorSubject('');
term$$: Subscription;
set sortedAlpha(value: boolean) {
this._sortedAlpha = value;
this.next();
}
private _sortedAlpha: boolean = undefined;

public showContextFilter = ContextListControlsEnum.default;
public showContextFilter = ContextListControlsEnum.always;

public thresholdToFilter = 5;

constructor(private cdRef: ChangeDetectorRef, public auth: AuthService) {}
constructor(
private cdRef: ChangeDetectorRef,
public auth: AuthService,
private dialog: MatDialog,
private contextService: ContextService,
private languageService: LanguageService,
private messageService: MessageService) {}

ngOnInit() {
this.term$$ = this.term$.subscribe((value) => {
if (value === '') {
this.contexts$.next(this.contexts);
this.change$$ = this.change$
.pipe(
debounce(() => {
return this.contexts.ours.length === 0 ? EMPTY : timer(50);
})
)
.subscribe(() => {
this.contexts$.next(this.filterContextsList(this.contexts));
});
}

private next() {
this.change$.next();
}

private filterContextsList(contexts: ContextsList) {
if (this.term === '') {
if (this.sortedAlpha) {
contexts = this.sortContextsList(contexts);
}
return contexts;
} else {
const ours = contexts.ours.filter((context) => {
const filterNormalized = this.term.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
const contextTitleNormalized = context.title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return contextTitleNormalized.includes(filterNormalized);
});

let updateContexts: ContextsList = {
ours
};

if (value.length) {
let ours; let publics; let shared;
ours = this.contexts.ours.filter((context) => {
const filterNormalized = value.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
if (this.contexts.public) {
const publics = contexts.public.filter((context) => {
const filterNormalized = this.term.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
const contextTitleNormalized = context.title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return contextTitleNormalized.includes(filterNormalized);
});
const updateContexts: ContextsList = {
ours
};

if (this.contexts.public) {
publics = this.contexts.public.filter((context) => {
const filterNormalized = value.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
const contextTitleNormalized = context.title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return contextTitleNormalized.includes(filterNormalized);
});
updateContexts.public = publics;
}
if (this.contexts.shared) {
shared = this.contexts.shared.filter((context) => {
const filterNormalized = value.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
const contextTitleNormalized = context.title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return contextTitleNormalized.includes(filterNormalized);
});
updateContexts.shared = shared;
}
updateContexts.public = publics;
}

if (this.contexts.shared) {
const shared = contexts.shared.filter((context) => {
const filterNormalized = this.term.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
const contextTitleNormalized = context.title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
return contextTitleNormalized.includes(filterNormalized);
});
updateContexts.shared = shared;
}

this.contexts$.next(updateContexts);
if (this.sortedAlpha) {
updateContexts = this.sortContextsList(updateContexts);
}
});
return updateContexts;
}
}

ngOnDestroy() {
this.change$$.unsubscribe();
}

public showFilter() {
Expand All @@ -141,4 +204,80 @@ export class ContextListComponent implements OnInit {
return false;
}
}

sortContextsList(contexts: ContextsList) {
if (contexts) {
const contextsList = JSON.parse(JSON.stringify(contexts));
contextsList.ours.sort((a, b) => {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});

if (contextsList.shared) {
contextsList.shared.sort((a, b) => {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});
} else if (contextsList.public) {
contextsList.public.sort((a, b) => {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});
}
return contextsList;
}
}

toggleSort(sortAlpha: boolean) {
this.sortedAlpha = sortAlpha;
}

clearFilter() {
this.term = '';
}

createContext() {
this.dialog
.open(BookmarkDialogComponent, { disableClose: false })
.afterClosed()
.subscribe(title => {
if (title) {
const context = this.contextService.getContextFromMap(this.map);
context.title = title;
this.contextService.create(context).subscribe(() => {
const translate = this.languageService.translate;
const titleD = translate.instant(
'igo.context.bookmarkButton.dialog.createTitle'
);
const message = translate.instant(
'igo.context.bookmarkButton.dialog.createMsg',
{
value: context.title
}
);
this.messageService.success(message, titleD);
this.contextService.loadContext(context.uri);
});
}
});
}

// userSelection() {
// return;
// }
}
Loading