diff --git a/demo/src/app/context/context/context.component.html b/demo/src/app/context/context/context.component.html index 0a7b6724f..21543d2fb 100644 --- a/demo/src/app/context/context/context.component.html +++ b/demo/src/app/context/context/context.component.html @@ -20,7 +20,7 @@ - + diff --git a/packages/context/src/lib/context-manager/context-item/context-item.component.ts b/packages/context/src/lib/context-manager/context-item/context-item.component.ts index feedd5b96..1ecc97c6d 100644 --- a/packages/context/src/lib/context-manager/context-item/context-item.component.ts +++ b/packages/context/src/lib/context-manager/context-item/context-item.component.ts @@ -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'; @@ -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; diff --git a/packages/context/src/lib/context-manager/context-list/context-list.component.html b/packages/context/src/lib/context-manager/context-list/context-list.component.html index 71330f6ee..eebde1504 100644 --- a/packages/context/src/lib/context-manager/context-list/context-list.component.html +++ b/packages/context/src/lib/context-manager/context-list/context-list.component.html @@ -1,5 +1,5 @@ - + + (click)="clearFilter()"> + + + + + + + diff --git a/packages/context/src/lib/context-manager/context-list/context-list.component.scss b/packages/context/src/lib/context-manager/context-list/context-list.component.scss index 5bee87524..127d90524 100644 --- a/packages/context/src/lib/context-manager/context-list/context-list.component.scss +++ b/packages/context/src/lib/context-manager/context-list/context-list.component.scss @@ -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; } diff --git a/packages/context/src/lib/context-manager/context-list/context-list.component.ts b/packages/context/src/lib/context-manager/context-list/context-list.component.ts index 19d323bac..9486e137e 100644 --- a/packages/context/src/lib/context-manager/context-list/context-list.component.ts +++ b/packages/context/src/lib/context-manager/context-list/context-list.component.ts @@ -4,22 +4,36 @@ 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 = new BehaviorSubject(undefined); +export class ContextListComponent implements OnInit, OnDestroy { + private contextsInitial: ContextsList = { ours: [] }; + contexts$: BehaviorSubject = new BehaviorSubject(this.contextsInitial); + + change$ = new ReplaySubject(1); + + private change$$: Subscription; @Input() get contexts(): ContextsList { @@ -27,8 +41,8 @@ export class ContextListComponent implements OnInit { } set contexts(value: ContextsList) { this._contexts = value; - this.contexts$.next(value); this.cdRef.detectChanges(); + this.next(); } private _contexts: ContextsList = { ours: [] }; @@ -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; @@ -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 = 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() { @@ -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; + // } } diff --git a/packages/context/src/lib/context-manager/context-manager.module.ts b/packages/context/src/lib/context-manager/context-manager.module.ts index 66cbe3068..a31d6bfd5 100644 --- a/packages/context/src/lib/context-manager/context-manager.module.ts +++ b/packages/context/src/lib/context-manager/context-manager.module.ts @@ -9,7 +9,9 @@ import { MatFormFieldModule, MatInputModule, MatCheckboxModule, - MatRadioModule + MatRadioModule, + MatDialogModule, + MatMenuModule } from '@angular/material'; import { IgoAuthModule } from '@igo2/auth'; @@ -21,6 +23,7 @@ import { IgoStopPropagationModule } from '@igo2/common'; +import { BookmarkDialogComponent } from './../context-map-button/bookmark-button/bookmark-dialog.component'; import { MapContextDirective } from './shared/map-context.directive'; import { LayerContextDirective } from './shared/layer-context.directive'; import { ContextListComponent } from './context-list/context-list.component'; @@ -31,6 +34,7 @@ import { ContextEditComponent } from './context-edit/context-edit.component'; import { ContextEditBindingDirective } from './context-edit/context-edit-binding.directive'; import { ContextPermissionsComponent } from './context-permissions/context-permissions.component'; import { ContextPermissionsBindingDirective } from './context-permissions/context-permissions-binding.directive'; +import { IgoContextMapButtonModule } from '../context-map-button/context-map-button.module'; const CONTEXT_DIRECTIVES = [ MapContextDirective, @@ -50,12 +54,18 @@ const CONTEXT_DIRECTIVES = [ MatListModule, MatCheckboxModule, MatRadioModule, + MatDialogModule, + MatMenuModule, IgoAuthModule, IgoListModule, IgoKeyValueModule, IgoCollapsibleModule, IgoStopPropagationModule, - IgoLanguageModule + IgoLanguageModule, + IgoContextMapButtonModule + ], + entryComponents: [ + BookmarkDialogComponent ], exports: [ ContextListComponent, diff --git a/packages/context/src/lib/context-map-button/context-map-button.module.ts b/packages/context/src/lib/context-map-button/context-map-button.module.ts index 10454df26..51ddcfa1c 100644 --- a/packages/context/src/lib/context-map-button/context-map-button.module.ts +++ b/packages/context/src/lib/context-map-button/context-map-button.module.ts @@ -42,7 +42,7 @@ import { UserButtonComponent } from './user-button/user-button.component'; MatDialogModule, MatInputModule ], - exports: [BookmarkButtonComponent, PoiButtonComponent, UserButtonComponent], + exports: [BookmarkButtonComponent, PoiButtonComponent, UserButtonComponent, BookmarkDialogComponent], declarations: [ BookmarkButtonComponent, BookmarkDialogComponent, diff --git a/packages/context/src/locale/en.context.json b/packages/context/src/locale/en.context.json index a6e47e90c..0f1189f98 100644 --- a/packages/context/src/locale/en.context.json +++ b/packages/context/src/locale/en.context.json @@ -51,7 +51,10 @@ "publicContexts": "Public contexts", "save": "Save this context", "sharedContexts": "Shared contexts", - "filterPlaceHolder": "Filer the contexts list" + "filterPlaceHolder": "Filer the contexts list", + "sortAlphabetically": "Sort the context's list alphabetically", + "sortContextOrder": "Replace contexts according to the initial list", + "userAccount": "User account" }, "permission": { "addBtn": "Add", diff --git a/packages/context/src/locale/fr.context.json b/packages/context/src/locale/fr.context.json index 6d1956189..e40b4e038 100644 --- a/packages/context/src/locale/fr.context.json +++ b/packages/context/src/locale/fr.context.json @@ -51,7 +51,10 @@ "publicContexts": "Contextes publics", "save": "Sauvegarder ce contexte", "sharedContexts": "Contextes partagés", - "filterPlaceHolder": "Filtrer la liste des contextes" + "filterPlaceHolder": "Filtrer la liste des contextes", + "sortAlphabetically": "Trier la liste des contextes en ordre alphabétique", + "sortContextOrder": "Replacer les contextes selon la liste initial", + "userAccount": "Profils utilisateurs" }, "permission": { "addBtn": "Ajouter", diff --git a/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.html b/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.html index 940d4c831..8cb8e5fbd 100644 --- a/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.html +++ b/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.html @@ -1,5 +1,6 @@ diff --git a/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.ts b/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.ts index 3d34cbfed..b5ca17564 100644 --- a/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.ts +++ b/packages/integration/src/lib/context/context-manager-tool/context-manager-tool.component.ts @@ -3,6 +3,8 @@ import { Component } from '@angular/core'; import { ToolComponent } from '@igo2/common'; import { ToolState } from '../../tool/tool.state'; +import { MapState } from '../../map/map.state'; +import { IgoMap } from '@igo2/geo'; @ToolComponent({ name: 'contextManager', @@ -14,7 +16,10 @@ import { ToolState } from '../../tool/tool.state'; templateUrl: './context-manager-tool.component.html' }) export class ContextManagerToolComponent { - constructor(private toolState: ToolState) {} + + get map(): IgoMap { return this.mapState.map; } + + constructor(private toolState: ToolState, private mapState: MapState) {} editContext() { this.toolState.toolbox.activateTool('contextEditor');