Browse Source

add all new components

Federica 1 year ago
parent
commit
466ab000f3

+ 2 - 0
src/app/app.config.ts

@@ -4,6 +4,7 @@ import { TranslateService } from '@ngx-translate/core';
 import { forkJoin } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { EntitiesSelectItemGroup } from './components/entities-select/entities-select.component';
+import { LemsSelectItemGroup } from './components/lems-select/lems-select.component';
 import { ViewMode, ViewModeId } from './models/evt-models';
 import { Attributes, EditorialConventionLayout } from './models/evt-models';
 
@@ -91,6 +92,7 @@ export interface EditionConfig {
         lemmas: LemmatizedEntitiesListsConfig;
         relations: LemmatizedEntitiesListsConfig;
     }>;
+    lemsSelectItems: LemsSelectItemGroup[];
     entitiesSelectItems: EntitiesSelectItemGroup[];
     notSignificantVariants: string[];
     lemNotSignificantVariants: string[];

+ 2 - 0
src/app/app.module.ts

@@ -37,6 +37,7 @@ import { EditionStmtComponent } from './components/edition-stmt/edition-stmt.com
 import { EditorialDeclComponent } from './components/editorial-decl/editorial-decl.component';
 import { EncodingDescComponent } from './components/encoding-desc/encoding-desc.component';
 import { EntitiesSelectComponent } from './components/entities-select/entities-select.component';
+import { LemsSelectComponent } from './components/lems-select/lems-select.component';
 import { ExtentComponent } from './components/extent/extent.component';
 import { FileDescComponent } from './components/file-desc/file-desc.component';
 import { GComponent } from './components/g/g.component';
@@ -158,6 +159,7 @@ export function initializeApp(appConfig: AppConfig) {
     EditorialDeclComponent,
     EncodingDescComponent,
     EntitiesSelectComponent,
+    LemsSelectComponent,
     EvtInfoComponent,
     ExtentComponent,
     FileDescComponent,

+ 23 - 1
src/app/components/content-viewer/content-viewer.component.ts

@@ -8,6 +8,8 @@ import { GenericElement } from '../../models/evt-models';
 import { ComponentRegisterService } from '../../services/component-register.service';
 import { EntitiesSelectService } from '../../services/entities-select.service';
 import { EntitiesSelectItem } from '../entities-select/entities-select.component';
+import { LemsSelectService } from '../../services/lems-select.service';
+import { LemsSelectItem } from '../lems-select/lems-select.component';
 
 @Component({
   selector: 'evt-content-viewer',
@@ -32,6 +34,15 @@ export class ContentViewerComponent implements OnDestroy {
   @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
   itemsToHighlightChange = new BehaviorSubject<EntitiesSelectItem[]>([]);
 
+  private ithlems: LemsSelectItem[];
+  @Input() set itemsLemsToHighlight(i: LemsSelectItem[]) {
+    this.ithlems = i;
+    this.itemsLemsToHighlightChange.next(i);
+  }
+  get itemsLemsToHighlight() { return this.ithlems; }
+
+  itemsLemsToHighlightChange = new BehaviorSubject<LemsSelectItem[]>([]);
+
   private edLevel: EditionLevelType;
   @Input() set editionLevel(el: EditionLevelType) {
     this.edLevel = el;
@@ -51,6 +62,7 @@ export class ContentViewerComponent implements OnDestroy {
   constructor(
     private componentRegister: ComponentRegisterService,
     private entitiesSelectService: EntitiesSelectService,
+    private lemsSelectService: LemsSelectService,
   ) {
   }
 
@@ -67,15 +79,18 @@ export class ContentViewerComponent implements OnDestroy {
   public inputs: Observable<{ [keyName: string]: any }> = combineLatest([
     this.contentChange,
     this.itemsToHighlightChange,
+    this.itemsLemsToHighlightChange,
     this.editionLevelChange,
     this.textFlowChange,
   ]).pipe(
-    map(([data, itemsToHighlight, editionLevel, textFlow]) => {
+    map(([data, itemsToHighlight, itemsLemsToHighlight, editionLevel, textFlow]) => {
       if (this.toBeHighlighted()) {
         return {
           data,
           highlightData: this.getHighlightData(data, itemsToHighlight),
+          highlightDataLem: this.getHighlightDataLems (data, itemsLemsToHighlight),
           itemsToHighlight,
+          itemsLemsToHighlight,
           editionLevel,
           textFlow,
         };
@@ -125,6 +140,13 @@ export class ContentViewerComponent implements OnDestroy {
     };
   }
 
+  private getHighlightDataLems(data, ithlems: LemsSelectItem[]) {
+    return {
+      highlight: ithlems?.some(i => this.lemsSelectService.matchClassAndAttributes(i.value, data?.attributes ?? {}, data?.class)) ?? false,
+      highlightColor: this.lemsSelectService.getHighlightColor(data?.attributes ?? {}, data?.class, ithlems),
+    };
+  }
+
   ngOnDestroy() {
     if (this.componentRef) {
       this.componentRef.destroy();

+ 1 - 0
src/app/components/entities-select/entities-select.component.html

@@ -36,4 +36,5 @@
             </div>
         </ng-template>
     </ng-select>
+    
 </ng-container>

+ 3 - 21
src/app/components/lemmatized-entity-ref/lemmatized-entity-ref.component.scss

@@ -17,33 +17,15 @@
 .lemmatizedEntityRef:hover:not(.noDetails),
 .lemmatizedEntityRef.highlighted,
 .lemmatizedEntityRef.opened:not(.noDetails) {
-  &.person {
-    @include lemmatizedEntityRefColors(get-ne-color(personBase), get-ne-color(personMiddle), get-ne-color(personDarker));
-  }
-  &.place {
-    @include lemmatizedEntityRefColors(get-ne-color(placeBase), get-ne-color(placeMiddle), get-ne-color(placeDarker));
-  }
-  &.org {
-    @include lemmatizedEntityRefColors(get-ne-color(orgBase), get-ne-color(orgMiddle), get-ne-color(orgDarker));
-  }
-  &.event {
-    @include lemmatizedEntityRefColors(get-ne-color(eventBase), get-ne-color(eventMiddle), get-ne-color(eventDarker));
+  &.lem {
+    @include lemmatizedEntityRefColors(get-ne-color(lemBase), get-ne-color(lemMiddle), get-ne-color(lemDarker));
   }
 }
 
 .lemmatizedEntityRefDetail {
-  &.person {
+  &.lem {
     background: get-ne-color(personBase);
   }
-  &.place {
-    background: get-ne-color(placeBase);
-  }
-  &.org {
-    background: get-ne-color(orgBase);
-  }
-  &.event {
-    background: get-ne-color(eventBase);
-  }
 }
 .not-found-msg {
   font-size: .9rem;

+ 4 - 5
src/app/components/lemmatized-entity-ref/lemmatized-entity-ref.component.ts

@@ -1,9 +1,8 @@
 import { Component, Input } from '@angular/core';
 import { map, tap } from 'rxjs/operators';
-
 import { LemmatizedEntityRef } from '../../models/evt-models';
 import { register } from '../../services/component-register.service';
-import { EntitiesSelectService } from '../../services/entities-select.service';
+import { LemsSelectService } from '../../services/lems-select.service';
 import { EVTModelService } from '../../services/evt-model.service';
 import { EVTStatusService } from '../../services/evt-status.service';
 import { EditionlevelSusceptible, Highlightable, TextFlowSusceptible } from '../components-mixins';
@@ -26,7 +25,7 @@ export class LemmatizedEntityRefComponent {
     map(ne => ne.all.entities.find(e => e.id === this.data.entityLemId) || 'notFound'),
   );
 
-  public highlighted$ = this.entitiesSelectService.selectedItems$.pipe(
+  public highlighted$ = this.lemsSelectService.selectedLemsItems$.pipe(
     tap(items => {
       if (this.data) {
         this.data.class = this.data.class || '';
@@ -36,7 +35,7 @@ export class LemmatizedEntityRefComponent {
       return items;
     }),
     map(items => items.some(i => i && this.data &&
-      this.entitiesSelectService.matchClassAndAttributes(i.value, this.data.attributes, this.data.class))),
+      this.lemsSelectService.matchClassAndAttributes(i.value, this.data.attributes, this.data.class))),
   );
 
   public opened = false;
@@ -44,7 +43,7 @@ export class LemmatizedEntityRefComponent {
   constructor(
     public evtStatusService: EVTStatusService,
     private evtModelService: EVTModelService,
-    private entitiesSelectService: EntitiesSelectService,
+    private lemsSelectService: LemsSelectService,
   ) {
   }
 

+ 6 - 19
src/app/components/lemmatized-entity-relation/lemmatized-entity-relation.component.scss

@@ -5,25 +5,12 @@
 .relation-entity {
     cursor: pointer;
 
-    // &.disabled {
-    //     cursor: default;
-    // }
-
-    // &.person {
-    //     @include lemmatizedEntityRefColors(get-ne-color(personBase), get-ne-color(personMiddle), get-ne-color(personDarker));
-    // }
-
-    // &.place {
-    //     @include lemmatizedEntityRefColors(get-ne-color(placeBase), get-ne-color(placeMiddle), get-ne-color(placeDarker));
-    // }
-
-    // &.org {
-    //     @include lemmatizedEntityRefColors(get-ne-color(orgBase), get-ne-color(orgMiddle), get-ne-color(orgDarker));
-    // }
-
-    // &.event {
-    //     @include lemmatizedEntityRefColors(get-ne-color(eventBase), get-ne-color(eventMiddle), get-ne-color(eventDarker));
-    // }
+    &.disabled {
+        cursor: default;
+    }
+    &.lem {
+        @include lemmatizedEntityRefColors(get-ne-color(lemBase), get-ne-color(lemMiddle), get-ne-color(lemDarker));
+    }
 }
 
 .relation-type {

+ 8 - 7
src/app/components/lemmatized-entity/lemmatized-entity.component.html

@@ -8,16 +8,17 @@
         </evt-icon>
         <evt-icon *ngIf="inList && !contentOpened"
             [iconInfo]="{icon: 'caret-right', additionalClasses: 'icon toggler mr-2'}"></evt-icon>
-        <!-- <evt-icon *ngIf="data.lemmatizedEntityType === 'w'"
-            [iconInfo]="{icon: 'user', additionalClasses: 'icon mr-1'}"></evt-icon> -->
         <evt-icon *ngIf="data.lemmatizedEntityType === 'lem'"
             [iconInfo]="{icon: 'map-marker', additionalClasses: 'icon mr-1'}">
         </evt-icon>
+        <evt-icon *ngIf="data.lemmatizedEntityType === 'w'"
+            [iconInfo]="{icon: 'map-marker', additionalClasses: 'icon mr-1'}">
+        </evt-icon>
         {{ data.label }}
         <evt-pinner [item]="data" renderer="LemmatizedEntity" pinType="LemmatizedEntities"></evt-pinner>
     </div>
     <div class="card-body ne-content" *ngIf="contentOpened">
-        <ul ngbNav #entityDetails="ngbNav" class="entity-details" [activeId]="selectedSection">
+        <ul ngbNav #lemDetails="ngbNav" class="lem-details" [activeId]="selectedSection">
             <li [ngbNavItem]="'info_'+data.id" [disabled]="data.content.length === 0">
                 <a ngbNavLink class="ui-font">{{'Info' | translate}}</a>
                 <ng-template ngbNavContent>
@@ -31,12 +32,12 @@
                 <a ngbNavLink class="ui-font">{{'Occurrences' | translate}}</a>
                 <ng-template ngbNavContent>
                     <div class="ne-detail-content ui-font" *ngIf="occurrences$ | async as occurrences">
-                        <span *ngIf="occurrences.length === 0">{{'noOccurrences' | translate}}</span>
+                        <span *ngIf="occurrences.length === 0">{{'noLemOccurrences' | translate}}</span>
                         <evt-lemmatized-entity-occurrence *ngFor="let occurrence of occurrences" [occurrence]="occurrence" [entityLemId]="data.id"></evt-lemmatized-entity-occurrence>
                     </div>
                 </ng-template>
             </li>
-            <li [ngbNavItem]="'relations_'+data.id">
+            <!-- <li [ngbNavItem]="'relations_'+data.id">
                 <a ngbNavLink class="ui-font">{{'Relations' | translate}}</a>
                 <ng-template ngbNavContent>
                     <div class="ne-detail-content" *ngIf="relations$ | async as relations">
@@ -45,7 +46,7 @@
                             [data]="relation" [inEntity]="true"></evt-lemmatized-entity-relation>
                     </div>
                 </ng-template>
-            </li>
+            </li> -->
             <li [ngbNavItem]="'xml_'+data.id">
                 <a ngbNavLink class="ui-font">{{'XMLSource' | translate}}</a>
                 <ng-template ngbNavContent>
@@ -56,6 +57,6 @@
                 </ng-template>
             </li>
         </ul>
-        <div [ngbNavOutlet]="entityDetails"></div>
+        <div [ngbNavOutlet]="lemDetails"></div>
     </div>
 </div>

+ 153 - 148
src/app/components/lemmatized-entity/lemmatized-entity.component.scss

@@ -2,151 +2,156 @@
 @import "../../../assets/scss/themes";
 @import "../../../assets/scss/mixins";
 
-// @mixin lemmatizedEntityColors($color-base) {
-
-//   .ne-header {
-//     position: relative;
-
-//     evt-pinner {
-//       position: absolute;
-//       top: 0;
-//       right: 0;
-//     }
-//   }
-
-//   .nav-item,
-//   .nav-item a {
-//     &:focus {
-//       outline: none !important;
-//     }
-//   }
-
-//   .entity-details .nav-link {
-//     color: #000;
-//     // background-color: $color-middle;
-//   //   border-color: $color-darker;
-
-//   //   &.active {
-//   //     background-color: $color-darker;
-//   //   }
-
-//   //   &:hover:not(.active):not(.disabled) {
-//   //     background: rgba($color-darker, .5);
-//   //   }
-
-//   //   &.disabled {
-//   //     pointer-events: auto;
-//   //     cursor: not-allowed;
-//   //   }
-//   // }
-
-//   // .ne-detail-content {
-//   //   background-color: $color-darker;
-//   // }
-
-//   .ne-occurrence {
-//     border-radius: 4px;
-//     padding: 4px 6px;
-//     background: rgba(255, 255, 255, 0.5);
-//     margin-right: 3px;
-//     font-size: .7rem;
-//     margin-bottom: 3px;
-//     display: inline-block !important;
-//     cursor: pointer;
-//     line-height: 0.9rem;
-
-//     .ne-occurrence-count {
-//       top: -1px;
-//       position: relative;
-//       margin-left: 5px;
-//       border: 1px solid transparent;
-//     }
-
-//     &:hover {
-//       background: rgba(255, 255, 255, 0.8) !important;
-
-//       .ne-occurrence-count {
-//         border: 1px solid #ccc;
-//       }
-//     }
-
-//   }
-// }
-
-// :host ::ng-deep .ne {
-//   &-container {
-//     font-size: 90%;
-//     border-top-left-radius: 0;
-
-//     &.inList {
-//       border-radius: 0;
-//       margin-bottom: 1px;
-
-//       .ne-header {
-//         padding: 5px 7px;
-//         border-top-right-radius: 0;
-//         cursor: pointer;
-//       }
-//     }
-
-//     &.contentOpened {
-//       .ne-header {
-//         border-bottom: 3px double #000 !important;
-//       }
-//     }
-
-//     &.lem {
-//       @include lemmatizedEntityColors(get-ne-color(lemBase));
-//     }
-
-//     &.w {
-//       @include lemmatizedEntityColors(get-ne-color(lemBase));
-//     }
-//   }
-
-//   &-header {
-//     padding: 3.5px 7px;
-//     border-top-left-radius: 0;
-//   }
-
-//   &-content {
-//     padding: 0;
-//     font-size: 80%;
-//   }
-
-//   &-detail-content {
-//     padding: 1rem;
-
-//     &.no-padding {
-//       padding: 0;
-//     }
-//   }
-// }
-
-// :host ::ng-deep .ne-content {
-
-//   // Override default styles
-//   .entity-details .nav-link {
-//     padding: 5px;
-//     border: none;
-//   }
-// }
-
-// :host ::ng-deep pre {
-//   padding-top: 0;
-//   margin: 0;
-
-//   /* background: #fff;*/
-//   code {
-//     font-size: 85% !important;
-//   }
-// //}
-
-// pre {
-//   white-space: pre-wrap;
-//   white-space: -moz-pre-wrap;
-//   white-space: -pre-wrap;
-//   white-space: -o-pre-wrap;
-//   word-wrap: break-word;
-//   width: 100%;
-// }
+@mixin lemmatizedEntityColors($color-base, $color-middle, $color-darker) {
+    border-color: $color-middle;
+
+    * {
+      border-color: $color-middle;
+    }
+
+  .ne-header {
+    position: relative;
+
+    evt-pinner {
+      position: absolute;
+      top: 0;
+      right: 0;
+    }
+  }
+
+  .nav-item,
+  .nav-item a {
+    &:focus {
+      outline: none !important;
+    }
+  }
+
+  .lem-details .nav-link {
+    color: #000;
+    background-color: $color-middle;
+    border-color: $color-darker;
+
+    &.active {
+      background-color: $color-darker;
+    }
+
+    // &:hover:not(.active):not(.disabled) {
+    // //   background: #000;
+    // }
+
+    &.disabled {
+      pointer-events: auto;
+      cursor: not-allowed;
+    }
+  }
+
+  .ne-detail-content {
+    background-color: $color-darker;
+  }
+
+  .ne-occurrence {
+    border-radius: 4px;
+    padding: 4px 6px;
+    background: rgba(255, 255, 255, 0.5);
+    margin-right: 3px;
+    font-size: .7rem;
+    margin-bottom: 3px;
+    display: inline-block !important;
+    cursor: pointer;
+    line-height: 0.9rem;
+
+    .ne-occurrence-count {
+      top: -1px;
+      position: relative;
+      margin-left: 5px;
+      border: 1px solid transparent;
+    }
+
+    &:hover {
+      background: rgba(255, 255, 255, 0.8) !important;
+
+      .ne-occurrence-count {
+        border: 1px solid #ccc;
+      }
+    }
+
+  }
+}
+
+:host ::ng-deep .ne {
+  &-container {
+    font-size: 90%;
+    border-top-left-radius: 0;
+
+    &.inList {
+      border-radius: 0;
+      margin-bottom: 1px;
+
+      .ne-header {
+        padding: 5px 7px;
+        border-top-right-radius: 0;
+        cursor: pointer;
+      }
+    }
+
+    &.contentOpened {
+      .ne-header {
+        border-bottom: 3px double #000 !important;
+      }
+    }
+
+    &.lem {
+      @include lemmatizedEntityColors(get-ne-color(lemBase), get-ne-color(lemMiddle), get-ne-color(lemDarker));
+    }
+
+    &.w {
+      @include lemmatizedEntityColors(get-ne-color(lemBase), get-ne-color(lemMiddle), get-ne-color(lemDarker));
+    }
+  }
+
+  &-header {
+    padding: 3.5px 7px;
+    border-top-left-radius: 0;
+  }
+
+  &-content {
+    padding: 0;
+    font-size: 80%;
+  }
+
+  &-detail-content {
+    padding: 1rem;
+
+    &.no-padding {
+      padding: 0;
+    }
+  }
+}
+
+:host ::ng-deep .ne-content {
+
+  // Override default styles
+  .lem-details .nav-link {
+    padding: 5px;
+    border: none;
+  }
+}
+
+:host ::ng-deep pre {
+  padding-top: 0;
+  margin: 0;
+
+  background: #fff;
+  code {
+    font-size: 85% !important;
+  }
+}
+
+pre {
+  white-space: pre-wrap;
+  white-space: -moz-pre-wrap;
+  white-space: -pre-wrap;
+  white-space: -o-pre-wrap;
+  word-wrap: break-word;
+  width: 100%;
+}

+ 2 - 2
src/app/components/lemmatized-entity/lemmatized-entity.component.ts

@@ -15,7 +15,7 @@ import { EVTModelService } from '../../services/evt-model.service';
 export class LemmatizedEntityComponent implements OnInit {
   @Input() data: LemmatizedEntity;
   @Input() inList: boolean;
-  occurrences$ = this.evtModelService.entitiesOccurrences$.pipe(
+  occurrences$ = this.evtModelService.lemsOccurrences$.pipe(
     map(occ => occ[this.data.id] || []),
     shareReplay(1),
   );
@@ -23,7 +23,7 @@ export class LemmatizedEntityComponent implements OnInit {
     map(el => el.filter(rel => rel.activeParts.indexOf(this.data.id) >= 0 ||
       rel.passiveParts.indexOf(this.data.id) >= 0 || rel.mutualParts.indexOf(this.data.id) >= 0)));
 
-  @ViewChild('entityDetails') entityDetails: NgbNav;
+  @ViewChild('lemDetails') lemDetails: NgbNav;
 
   public contentOpened = true;
 

+ 34 - 0
src/app/components/lems-select/lems-select.component.html

@@ -0,0 +1,34 @@
+<ng-container *ngIf="lemsTypes.length > 0">
+    <ng-select
+        [items]="lemsTypes" 
+        [multiple]="true" 
+        [closeOnSelect]="false" 
+        [searchable]="false"
+        [placeholder]="'selectLemsItems' | translate" 
+        [(ngModel)]="selectedLemTypes" 
+        [disabled]="lemsTypes.length === 0" 
+        groupBy="group"
+        (change)="updateSelectedLemTypes($event)">
+        <ng-template ng-header-tmp>
+            <div class="lems-select-toolbar">
+                <div class="w-100 text-dark select-all-btn">
+                    <input id="select-all" type="checkbox" class="mr-2" (click)="toggleLemSelection()"
+                        [checked]="selectedLemTypes?.length === lemsTypes.length"/>
+                    <label for="select-all" class="m-0">{{ 'selectLemsAll' | translate }}</label>
+                </div>
+            </div>
+        </ng-template>
+        <ng-template ng-multi-label-tmp let-items="items" let-clear="clear">
+            <ng-container *ngIf="items.length === 1">
+                <div class="ng-value" *ngFor="let item of items | slice:0:1">
+                    <evt-icon [iconInfo]="iconColor" [style.color]="item.color"></evt-icon>
+                    <span class="ng-value-label">{{item.label}}</span>
+                    <span class="ng-value-icon right" (click)="clear(item)" aria-hidden="true">×</span>
+                </div>
+            </ng-container>
+            <div class="ng-value" *ngIf="items.length > 1">
+                <span class="ng-value-label">{{items.length}} {{'selected' | translate}}</span>
+            </div>
+        </ng-template>
+    </ng-select>  
+</ng-container>

+ 29 - 0
src/app/components/lems-select/lems-select.component.scss

@@ -0,0 +1,29 @@
+// ng-select overrides
+::ng-deep .ng-select {
+    min-width: 150px;
+}
+
+::ng-deep .ng-dropdown-panel {
+    .ng-dropdown-panel-items {
+        .ng-optgroup {
+            font-size: 90%;
+            font-variant: small-caps;
+        }
+
+        .ng-option {
+            padding-left: 10px !important;
+        }
+    }
+}
+
+.lems-select-toolbar {
+    display: flex;
+
+    .btn {
+        flex-grow: 1;
+    }
+}
+
+.select-all-btn {
+    cursor: pointer;
+}

+ 24 - 0
src/app/components/lems-select/lems-select.component.spec.ts

@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { LemsSelectComponent } from './lems-select.component';
+
+describe('LemsSelectComponent', () => {
+  let component: LemsSelectComponent;
+  let fixture: ComponentFixture<LemsSelectComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      declarations: [ LemsSelectComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(LemsSelectComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 51 - 0
src/app/components/lems-select/lems-select.component.ts

@@ -0,0 +1,51 @@
+import { Component, EventEmitter, Output } from '@angular/core';
+import { AppConfig } from '../../app.config';
+import { EvtIconInfo } from '../../ui-components/icon/icon.component';
+
+export interface LemsSelectItemGroup {
+  label: string;
+  items: LemsSelectItem[];
+  disabled?: boolean;
+}
+export interface LemsSelectItem {
+  label: string;
+  value: string; // This will be used to identify the items to be selected, by indicating tag name and attributes (for XML)
+  color?: string;
+  disabled?: boolean;
+}
+
+@Component({
+  selector: 'evt-lems-select',
+  templateUrl: './lems-select.component.html',
+  styleUrls: ['./lems-select.component.scss'],
+})
+export class LemsSelectComponent {
+  @Output() selectionLemChange: EventEmitter<LemsSelectItem[]> = new EventEmitter();
+
+  lemsTypes: Array<LemsSelectItem & { group: string }> = (AppConfig.evtSettings.edition.lemsSelectItems || [])
+    .filter(g => !g.disabled)
+    .reduce((x, y) => [...x, ...y.items.filter(i => !i.disabled).map(i => ({ ...i, group: y.label }))], []);
+
+  iconColor: EvtIconInfo = {
+    icon: 'circle',
+    iconSet: 'fas',
+    additionalClasses: 'ml-2 mr-1',
+  };
+
+  public selectedLemTypes: LemsSelectItem[] = [];
+
+  updateSelectedLemTypes(lemsTypes: LemsSelectItem[]) {
+    if (Array.isArray(lemsTypes)) { // BUGFIX: There is a bug in ng-select change event and second time the parameter is an event
+      this.selectionLemChange.emit(lemsTypes);
+    }
+  }
+
+  toggleLemSelection() {
+    if (this.selectedLemTypes.length < this.lemsTypes.length) {
+      this.selectedLemTypes = this.lemsTypes;
+    } else {
+      this.selectedLemTypes = [];
+    }
+    this.selectionLemChange.emit(this.selectedLemTypes);
+  }
+}

+ 5 - 0
src/app/services/evt-model.service.ts

@@ -101,6 +101,11 @@ export class EVTModelService {
     shareReplay(1),
   );
 
+  public lemsOccurrences$: Observable<Map<LemmatizedEntityOccurrence[]>> = this.pages$.pipe(
+    map((pages) => this.lemmatizedEntitiesParser.parseLemmatizedEntitiesOccurrences(pages)),
+    shareReplay(1),
+  );
+
   // WITNESSES
   public readonly witnessesData$ = this.editionSource$.pipe(
     map((source) => this.witnessesParser.parseWitnessesData(source)),

+ 70 - 0
src/app/services/lems-select.service.ts

@@ -0,0 +1,70 @@
+import { Injectable } from '@angular/core';
+import { Subject } from 'rxjs';
+import { shareReplay } from 'rxjs/operators';
+import { AppConfig } from '../app.config';
+import { LemsSelectItem } from '../components/lems-select/lems-select.component';
+import { Attributes } from '../models/evt-models';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class LemsSelectService {
+  public updateLemsSelection$ = new Subject<LemsSelectItem[]>();
+  public selectedLemsItems$ = this.updateLemsSelection$.pipe(
+    shareReplay(1),
+  );
+
+  public getClassNameFromValue(value) {
+    return value.toLowerCase().replace(/\s/g, '').replace(/(\[.*?\])/g, '');
+  }
+
+  public getAttributesFromValue(value): Array<{ key: string, value: string }> {
+    return (value.toLowerCase().replace(/\s/g, '').match(/(\[.*?\])/g) || [])
+      .map(i => i.replace(/(\[|\]|\')/g, '').split('=')).map(i => ({ key: i[0], value: i[1] }));
+  }
+
+  public matchClassAndAttributes(valueForCheck: string, attributesToCheck: Attributes, classToCheck: string) {
+    return valueForCheck.split(',')
+      .some(v => this.matchClass(v, classToCheck) && this.matchAttributes(v, attributesToCheck));
+  }
+
+  public matchClass(classForCheck: string, classToCheck: string) {
+    return classToCheck === this.getClassNameFromValue(classForCheck);
+  }
+
+  public matchAttributes(attributesForCheck: string, attributesToCheck: Attributes) {
+    return this.getAttributesFromValue(attributesForCheck).every(a => attributesToCheck[a.key] === a.value);
+  }
+
+  public getHighlightColor(attributesToCheck: Attributes, classNameToCheck: string, selectedLemsItems?: LemsSelectItem[]) {
+    const lemsSelectItems = AppConfig.evtSettings.edition.lemsSelectItems
+      .reduce((i: LemsSelectItem[], g) => i.concat(g.items), [])
+      .reduce((x: LemsSelectItem[], y) => {
+        const multiValues: LemsSelectItem[] = [];
+        y.value.split(',').forEach(t => {
+          multiValues.push({ ...y, value: t });
+        });
+
+        return x.concat(multiValues);
+      },      []);
+
+    let bestMatch: LemsSelectItem & { score: number };
+    lemsSelectItems.forEach(item => {
+      let score = 0;
+      score += this.matchClass(item.value, classNameToCheck) ? 1 : 0;
+      const attributes = this.getAttributesFromValue(item.value);
+      score += attributes.length && this.matchAttributes(item.value, attributesToCheck) ? 1 : 0;
+      if (score > 0 && selectedLemsItems) {
+        score += selectedLemsItems.find(i => i.value === item.value) ? 1 : 0;
+      }
+      if (score > 0 && (!bestMatch || bestMatch.score < score)) {
+        bestMatch = {
+          ...item,
+          score,
+        };
+      }
+    });
+
+    return bestMatch ? bestMatch.color : '';
+  }
+}

+ 8 - 7
src/app/services/xml-parsers/lemmatized-entity-parsers.ts

@@ -154,14 +154,15 @@ export class ItemParser extends EntityParser {
 
     private getLabel(xml: XMLElement) { // TODO: refactor me, also try to use a function parameter for the label for each entity
         const itemElement = xml.querySelector<XMLElement>('item');
-        const lemElement = xml.querySelector<XMLElement>('lem');
         const wElement = xml.querySelector<XMLElement>('w');
-        let label: LemmatizedEntityLabel = 'No info';
-        if (wElement) {
-            label = replaceNewLines(wElement.textContent) || 'No info';
-        } else if (lemElement || itemElement) {
-            label += lemElement ? `${replaceNewLines(lemElement.textContent)} ` : '';
-            label += itemElement ? `${replaceNewLines(itemElement.textContent)} ` : '';
+        const lemElement = xml.querySelector<XMLElement>('lem');
+        let label: LemmatizedEntityLabel;
+        if (itemElement) {
+            label = replaceNewLines(itemElement.textContent);
+        } else if (wElement) {
+            label = wElement ? `${replaceNewLines(wElement.textContent)} ` : '';
+        } else if (lemElement) {
+            label = lemElement ? `${replaceNewLines(lemElement.textContent)} ` : '';
         }
         return label;
     }

+ 0 - 10
src/assets/config/edition_config.json

@@ -47,16 +47,6 @@
 					"color": "#A5D6A7"
 				}
 			]
-		},
-		{
-			"label": "Other",
-			"items": [
-				{
-					"value": "lemma",
-					"label": "lemmas",
-					"color": "#fcfc60"
-				}
-			]
 		}
 	],
 	"lemmatizedEntitiesLists": {

+ 5 - 4
src/assets/data/lettere/test.xml

@@ -31,10 +31,11 @@
          <div xml:id="div" n="DATINI">
             
          <div><p><pb n="99b 1" xml:id="99b_1" /> 
-         <persName type="episcopus" sameAs="bartolo di niccolò (1)" ref="#857">PERSNAME</persName>
-         <placeName type="" sameAs="" ref="#3045">PLACENAME</placeName>
-         <w norm ="forma standard" lemma= "lemma" ana ="#boh" lemmaRef="http://www.example.com/lexicon/hitvb.xml" pos="verbo" ref="#3045">W</w>
-         <lem norm ="forma standard" lemma= "lemma" ana ="#boh" lemmaRef="http://www.example.com/lexicon/hitvb.xml" pos="verbo" ref="#3045">LEM</lem>
+         <persName type="episcopus" ref="#857">PERSNAME</persName>
+         <w type="lemma" lemma="forma standard del lemma" ref="#3045">Lemma nel testo</w>
+         <w type="lemma" lemma="forma standard del lemma" ref="#3045">Lemma nel testo 1</w>
+         <w type="lemma" lemma="forma standard del lemma" ref="#3045">Lemma nel testo 2</w>
+         <w type="lemma" lemma="forma standard del lemma" ref="#3045">Lemma nel testo 3</w>
          A dì 24 di
          <app type='lemma' subtype="s.m." sameAs="gennaio" ref="#3045">
          <lem>APP, LEM</lem> 

+ 8 - 6
src/assets/data/main.xml

@@ -15022,7 +15022,7 @@
                     </place> -->
                 </listPlace>
                 <!-- ########## Lista dei POS ########## 
-                <interpGrp  type ="POS"> 
+            <interpGrp  type ="POS"> 
                <interp  xml:id ="AT0"> Articolo determinativo </interp> 
                <interp  xml:id ="AV0"> Avverbio </interp> 
                <interp  xml:id ="CJC"> Congiunzione </interp> 
@@ -15034,11 +15034,13 @@
                <interp  xml:id ="PRP"> Preposizione < /interp> 
                <interp  xml:id ="VVD"> Verbo passato </interp> 
             </interpGrp> -->
-                <list xml:id="POS">
-                    <item xml:id="AGG">
-                        <head>AGG</head>
+                <list type="listLem">
+                    <item type="lem" xml:id="3045">
+                        <lem norm ="forma standard" pos="verbo" lemmaRef="http://www.example.com/lexicon/hitvb.xml">Lemma corrispondente nella lista del main</lem>
+                        <note type="lessicographic">Questa è una nota</note>
                     </item>
-                    <item xml:id="NG">
+                    
+                    <!-- <item xml:id="NG">
                         <figure corresp="#ng">
                             <head>Nome geografico</head>
                             <figDesc/>
@@ -15061,7 +15063,7 @@
                             <head>Singolare femminile</head>
                             <figDesc/>
                         </figure>
-                    </item>
+                    </item> -->
                     <!-- lista di tutti gli altri lemmi - finire di codificare
                     <item xml:id="AGG">aggettivo</item>
                     <item xml:id="AGGSM">aggettivo/sostantivo maschile</item>

+ 4 - 0
src/assets/i18n/en.json

@@ -26,8 +26,10 @@
     "noMatches": "No matches for input given",
     "entityNotFound": "Entity not found",
     "noOccurrences": "No occurrences",
+    "noLemOccurrences": "No lem occurrences",
     "relations": "Relations",
     "selectItems": "Select items",
+    "selectLemsItems": "Select lems",
     "persons": "Persons",
     "places": "Places",
     "organizations": "Organizations",
@@ -36,6 +38,8 @@
     "measures": "Measures",
     "selectAll": "Select all",
     "clearAll": "Clear all",
+    "selectLemsAll": "Select all lems",
+    "clearLemsAll": "Clear all lems",
     "bishops": "Bishops",
     "diplomatic": "Diplomatic",
     "interpretative": "Interpretative",

+ 4 - 0
src/assets/i18n/it.json

@@ -25,8 +25,10 @@
     "noMatches": "Nessun risultato",
     "entityNotFound": "Entità non trovata",
     "noOccurrences": "Nessuna occorrenza",
+    "noLemOccurrences": "Nessuna occorrenza del lemma",
     "relations": "Relazioni",
     "selectItems": "Seleziona elementi",
+    "selectLemsItems": "Seleziona elementi linguistici",
     "persons": "Persone",
     "places": "Luoghi",
     "organizations": "Organizzazioni",
@@ -35,6 +37,8 @@
     "measures": "Misure",
     "selectAll": "Seleziona tutto",
     "clearAll": "Pulisci selezione",
+    "selectLemsAll": "Seleziona tutto",
+    "clearLemsAll": "Pulisci selezione",
     "bishops": "Vescovi",
     "diplomatic": "Diplomatica",
     "interpretative": "Interpretativa",

+ 5 - 1
src/assets/scss/_colors.scss

@@ -36,4 +36,8 @@ $editionColors: (
 
 @function get-ne-color($key) {
     @return get-color(namedEntities $key);
-}
+}
+
+// @function get-ne-color($key) {
+//     @return get-color(lemmatizedEntities $key);
+// }