nm-edit-text-and-attributes
src/app/shared/widgets/apps/my-text-edit/edit-text-and-attributes/edit-text-and-attributes.component.ts
providers |
EditAttributeService
|
selector | nm-edit-text-and-attributes |
styleUrls | edit-text-and-attributes.component.scss |
templateUrl | ./edit-text-and-attributes.component.html |
Widget inputs |
Widget outputs |
Properties |
|
Methods |
constructor(_widgetframeService: WidgetframeService, _editAttributeService: EditAttributeService, _halService: HalService, _notificationService: CustomNotificationService, dialog: MatDialog, translateService: TranslateService, location: Location, localStorageService: LocalStorageService, router: Router)
|
||||||||||||||||||||||||||||||
Parameters :
|
Protected configureWidget | ||||||
configureWidget(configuration: WidgetConfig)
|
||||||
Decorators : WidgetConfigure
|
||||||
Parameters :
Returns :
void
|
deleteAttribute | ||||
deleteAttribute(attribute: )
|
||||
Parameters :
Returns :
void
|
Private executeDelete | ||||
executeDelete(attribute: )
|
||||
Parameters :
Returns :
void
|
filterOptions |
filterOptions()
|
Returns :
void
|
hideAttribute | ||||
hideAttribute(attribute: )
|
||||
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
onCloseSelect |
onCloseSelect()
|
Returns :
void
|
onSelectChange |
onSelectChange()
|
Returns :
void
|
openedChange | ||||
openedChange(open: )
|
||||
Parameters :
Returns :
void
|
resetWidget |
resetWidget()
|
Returns :
any
|
setBoxWidth | ||||
setBoxWidth(index: )
|
||||
Parameters :
Returns :
string
|
Public _editAttributeService |
_editAttributeService:
|
Type : EditAttributeService
|
Public _id |
_id:
|
Type : string
|
Decorators : WidgetId
|
Public action |
action:
|
Default value : new Subject<any>()
|
Decorators : WidgetOutput
|
Private attributeListEntries |
attributeListEntries:
|
Type : string
|
Public attributes |
attributes:
|
Type : Attribute[]
|
Private boxWidth |
boxWidth:
|
Type : string
|
Public changedAttributes |
changedAttributes:
|
Default value : <any>{}
|
Public changedAttributesOutput |
changedAttributesOutput:
|
Default value : new Subject<any>()
|
Decorators : WidgetOutput
|
Public cols |
cols:
|
Type : any[]
|
Public configuration |
configuration:
|
Type : WidgetConfig
|
Decorators : WidgetConfiguration
|
Private confirmed |
confirmed:
|
Type : boolean
|
Default value : false
|
Private contentNo |
contentNo:
|
Public contentNoForEdit |
contentNoForEdit:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Public context |
context:
|
Type : string
|
Public deleteName |
deleteName:
|
Type : string
|
Default value : "delete-attribute"
|
Public dialog |
dialog:
|
Type : MatDialog
|
Public editLayout |
editLayout:
|
Type : string
|
Public filterCtrl |
filterCtrl:
|
Type : FormControl
|
Default value : new FormControl()
|
Public filteredOptions |
filteredOptions:
|
Type : Attribute[]
|
Public infoText |
infoText:
|
Type : string
|
Public infoWidth |
infoWidth:
|
Type : string
|
Public inputLink |
inputLink:
|
Type : string
|
Private loadOptionsLazy |
loadOptionsLazy:
|
Type : boolean
|
Public localStorageEntry |
localStorageEntry:
|
Type : LocalStorageEntry
|
Private maintenanceLevelId |
maintenanceLevelId:
|
Type : string
|
Public objectKeys |
objectKeys:
|
Default value : Object.keys
|
Public productLevel |
productLevel:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Private productNo |
productNo:
|
Public productNoForEdit |
productNoForEdit:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Public reload |
reload:
|
Default value : new BehaviorSubject<any>(new Date())
|
Decorators : WidgetInput
|
Public reset |
reset:
|
Default value : new BehaviorSubject<any>(new Date())
|
Decorators : WidgetInput
|
Public searchString |
searchString:
|
Type : string
|
Public selectedDataLocale |
selectedDataLocale:
|
Default value : new ReplaySubject<any>()
|
Decorators : WidgetInput
|
Private selectedDataLocaleString |
selectedDataLocaleString:
|
Public selectedUiLocale |
selectedUiLocale:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Public selection |
selection:
|
Type : any[]
|
Private sub |
sub:
|
Public targets |
targets:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Private targetsInput |
targetsInput:
|
Type : []
|
Default value : []
|
Public title |
title:
|
Type : string
|
Public translateService |
translateService:
|
Type : TranslateService
|
Private unsubscribe |
unsubscribe:
|
Default value : NgUnsubscribe.create()
|
Public uri |
uri:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Public widgetLocale |
widgetLocale:
|
Default value : new Subject<any>()
|
Decorators : WidgetInput
|
Public wikiLink |
wikiLink:
|
Type : string
|
import {
combineLatest as observableCombineLatest,
Subject,
ReplaySubject,
BehaviorSubject,
Observable,
} from "rxjs";
import { map, mergeMap, takeUntil, filter } from "rxjs/operators";
import { Component, OnDestroy } from "@angular/core";
import { FormControl } from "@angular/forms";
import { WidgetframeService } from "../../../widgetframe/widgetframe.service";
import { WidgetConfig } from "../../../widget.configuration";
import {
WidgetComponent,
WidgetConfiguration,
WidgetConfigure,
WidgetId,
WidgetInput,
WidgetOutput,
} from "../../../widget.metadata";
import { NgUnsubscribe } from "../../../../ng-unsubscribe";
import * as uriTemplates_ from "uri-templates";
import { Attribute } from "../../../../components/edit-attribute/attribute";
import { EditAttributeService } from "../../../../components/edit-attribute/edit-attribute.service";
import { HalService } from "../../../../components/hal/index";
import { CustomNotificationService } from "../../../../components/notification/customnotification.service";
import { MatDialog } from "@angular/material/dialog";
import { TranslateService } from "@ngx-translate/core";
import { ConfirmationDialogComponent } from "../../../../components/dialog/confirmationDialog.component";
import { Location } from "@angular/common";
import { Router } from "@angular/router";
import {
DeletionMode,
Scope,
} from "../../../../components/local-storage/local-storage-constants";
import {
LocalStorageEntry,
LocalStorageService,
} from "../../../../components/local-storage/local-storage.service";
const uriTemplates = uriTemplates_;
declare var $;
declare var jQuery: any;
@WidgetComponent("nm-edit-text-and-attributes")
@Component({
selector: "nm-edit-text-and-attributes",
templateUrl: "./edit-text-and-attributes.component.html",
styleUrls: ["./edit-text-and-attributes.component.scss"],
providers: [EditAttributeService],
})
export class EditTextAndAttributesWidgetComponent implements OnDestroy {
public cols: any[];
public attributes: Attribute[];
public changedAttributes = <any>{};
//needed for key value iteration
public objectKeys = Object.keys;
public selection: any[];
public inputLink: string;
public searchString: string;
public filteredOptions: Attribute[];
@WidgetConfiguration()
public configuration: WidgetConfig;
@WidgetInput()
public productNoForEdit = new Subject<any>();
@WidgetInput()
public contentNoForEdit = new Subject<any>();
@WidgetInput()
public uri = new Subject<any>();
@WidgetInput()
public reload = new BehaviorSubject<any>(new Date());
@WidgetInput()
public reset = new BehaviorSubject<any>(new Date());
@WidgetInput()
public selectedDataLocale = new ReplaySubject<any>();
@WidgetOutput("changedAttributesOutput")
public changedAttributesOutput = new Subject<any>();
@WidgetOutput("action")
public action = new Subject<any>();
@WidgetInput()
public widgetLocale = new Subject<any>();
@WidgetInput()
public selectedUiLocale = new Subject<any>();
@WidgetInput()
public targets = new Subject<any>();
@WidgetInput()
public productLevel = new Subject<any>();
@WidgetId()
public _id: string;
private unsubscribe = NgUnsubscribe.create();
private sub;
public editLayout: string;
private boxWidth: string;
private productNo;
private contentNo;
private selectedDataLocaleString;
private attributeListEntries: string;
public localStorageEntry: LocalStorageEntry;
private targetsInput = [];
private maintenanceLevelId: string;
private loadOptionsLazy: boolean;
public filterCtrl: FormControl = new FormControl();
public infoText: string;
public wikiLink: string;
public title: string;
public context: string;
public infoWidth: string;
private confirmed: boolean = false;
public deleteName: string = "delete-attribute";
constructor(
private _widgetframeService: WidgetframeService,
public _editAttributeService: EditAttributeService,
private _halService: HalService,
private _notificationService: CustomNotificationService,
public dialog: MatDialog,
public translateService: TranslateService,
private location: Location,
private localStorageService: LocalStorageService,
private router: Router
) {
this.cols = [
{ field: "description", header: "tab.head.att.name" },
{ field: "value", header: "" },
];
}
@WidgetConfigure()
protected configureWidget(configuration: WidgetConfig) {
//FIXME TODO: This should maybe be introduced in a more general global approach
// This gets rid of the URL params. Then a reload will not reload an old page state with an old productNo
if (this.router.url.includes("?")) {
this.location.replaceState(
this.router.url.substring(0, this.router.url.indexOf("?"))
);
}
this.loadOptionsLazy = configuration.configuration["loadOptionsLazy"];
this.infoText = this.configuration.configuration["infoText"];
this.wikiLink = this.configuration.configuration["wikiLink"];
this.title = configuration.configuration["title"];
this.context = configuration.configuration["context"];
this.infoWidth = configuration.configuration["infoWidth"];
this.changedAttributes.values = [];
this.changedAttributes.targets = [];
this.editLayout = configuration.configuration["edit-layout"];
this.productNoForEdit
.pipe(takeUntil(this.unsubscribe))
.subscribe((data) => {
this.productNo = data;
});
this.contentNoForEdit
.pipe(takeUntil(this.unsubscribe))
.subscribe((data) => {
if (data[0]) {
this.contentNo = data[0].identifier;
}
});
this.selectedDataLocale
.pipe(takeUntil(this.unsubscribe))
.subscribe((data) => {
this.changedAttributesOutput.next(null);
this.selectedDataLocaleString = data;
});
this.localStorageEntry = this.localStorageService.getLocalStorageEntry(
configuration.configuration["local-storage-key"],
Scope.GLOBAL,
DeletionMode.RESET
);
this.maintenanceLevelId =
configuration.configuration["maintenance-level-id"];
this.targets.pipe(takeUntil(this.unsubscribe)).subscribe((targetsInput) => {
this.targetsInput = targetsInput;
});
this.filterCtrl.valueChanges
.pipe(takeUntil(this.unsubscribe))
.subscribe(() => {
this.filterOptions();
});
this._editAttributeService
.getAttributeChangedEvent()
.pipe(takeUntil(this.unsubscribe))
.subscribe((attribute) => {
let dublicate = this.changedAttributes.values.filter(
(item) => item.identifier == attribute.identifier
);
if (dublicate.length === 1) {
dublicate.source = attribute.source;
} else {
this.changedAttributes.values.push(attribute);
if (this.targetsInput.length > 0) {
this.changedAttributes.targets = this.targetsInput;
} else {
this.changedAttributes.targets = [];
if (this.context == "content") {
this.changedAttributes.targets.push({
level: "content",
identifier: this.contentNo,
});
} else {
this.changedAttributes.targets.push({
level: "product",
identifier: this.productNo,
});
}
}
this.changedAttributes["locale"] = this.selectedDataLocaleString;
}
this.changedAttributesOutput.next(this.changedAttributes);
});
this._halService
.getActionEvents()
.pipe(
filter(
(event) => event.name === configuration.configuration["action-name"]
),
map((event) => (<any>event).response),
takeUntil(this.unsubscribe)
)
.subscribe((resp) => {
this.changedAttributes = <any>{};
this.changedAttributes.values = [];
this.changedAttributes.targets = [];
this.changedAttributesOutput.next(null);
if (resp.message !== undefined) {
if (resp.level === "ERROR") {
}
if (resp.level === "SUCCESS") {
this.changedAttributes = <any>{};
this.changedAttributes.values = [];
this.changedAttributesOutput.next(null);
}
}
});
this.reset.pipe(takeUntil(this.unsubscribe)).subscribe((reset) => {
this.resetWidget();
});
let template;
let source = observableCombineLatest(
this.uri.asObservable(),
this.selectedDataLocale.asObservable(),
this.selectedUiLocale.asObservable(),
this.reload.asObservable(),
(uri, selectedDataLocale, selectedUiLocale, reload) => {
template = uriTemplates(uri);
let uriParams = {};
if (this.localStorageEntry.exists()) {
let identifiers = JSON.parse(this.localStorageEntry.value);
uriParams["visible-attributes"] = identifiers.join();
}
uriParams["maintenance-level-id"] =
configuration.configuration["maintenance-level-id"];
uriParams["data-locale"] = selectedDataLocale;
uriParams["context"] = this.context;
uriParams["locale"] = selectedUiLocale;
return uriParams;
}
).pipe(
map((uriParams) => {
let uri = template.fill(uriParams);
return uri;
}),
mergeMap((href) => {
return this._widgetframeService.getData(href);
})
);
source.pipe(takeUntil(this.unsubscribe)).subscribe(
(data) => {
this.attributes = [].concat(data["values"]);
this.filteredOptions = [].concat(data["values"]);
this.selection = [];
for (const item of this.attributes.filter((attribut) => {
return attribut.visible === true;
})) {
this.selection.push(item.identifier);
}
if (data.hasOwnProperty("_actions")) {
let template = uriTemplates(data["_actions"].save.href);
let uriParams = {};
if (this.context == "content") {
uriParams["content"] = this.contentNo;
} else {
uriParams["productNo"] = this.productNo;
uriParams["maintenance-level-id"] = this.maintenanceLevelId;
}
data["_actions"].save.href = template.fill(uriParams);
this.action.next(data["_actions"].save);
}
},
(error) => {
this.attributes = null;
}
);
this._halService
.getActionEvents()
.pipe(
filter((event) => event.name === "delete-attribute"),
takeUntil(this.unsubscribe)
)
.subscribe((resp) => {
this._notificationService.fromJson(resp.response);
});
}
filterOptions() {
if (!this.filteredOptions) {
return;
}
let search = this.filterCtrl.value.toLowerCase();
if (search) {
let filtered = this.attributes.filter((item) => {
return (
item.description.toLowerCase().indexOf(search) > -1 ||
item.identifier.toLowerCase().indexOf(search) > -1 ||
item.visible
);
});
this.filteredOptions = filtered;
} else {
this.filteredOptions = this.attributes.slice();
}
}
openedChange(open) {
if (!open) {
this.onCloseSelect();
}
}
onCloseSelect() {
this.searchString = "";
this.filteredOptions = this.attributes;
}
onSelectChange() {
this.localStorageEntry.value = JSON.stringify(this.selection);
for (let attribute of this.attributes) {
attribute.visible = false;
for (let selectedidentifier of this.selection) {
if (attribute.identifier === selectedidentifier) {
attribute.visible = true;
}
}
}
}
deleteAttribute(attribute) {
if (this.context !== "content") {
let title = "hl.confirmation";
let message = "app.ipim-mytextedit.delete.confirmation";
let dialogRef = this.dialog.open(ConfirmationDialogComponent);
dialogRef.componentInstance["title"] = this.translateService.instant(
title
);
dialogRef.componentInstance["message"] = this.translateService.instant(
message
);
dialogRef.componentInstance[
"buttonAcceptTitle"
] = this.translateService.instant("button.accept");
dialogRef.componentInstance[
"buttonCancelTitle"
] = this.translateService.instant("button.cancel");
dialogRef
.afterClosed()
.pipe(takeUntil(this.unsubscribe))
.subscribe((confirmed) => {
if (confirmed) {
if (attribute.hasOwnProperty("_actions")) {
let template = uriTemplates(attribute._actions.delete.href);
let uriParams = {};
uriParams["productNo"] = this.productNo;
if (this.context == "content") {
uriParams["content"] = this.contentNo;
} else {
uriParams["productNo"] = this.productNo;
}
attribute._actions.delete.href = template.fill(uriParams);
this.executeDelete(attribute);
}
} else {
console.log("cancel delete");
}
});
}
}
private executeDelete(attribute) {
this._halService
.execute("delete-attribute", attribute._actions.delete)
.subscribe(
(resp) => {
if (resp.response.level === "SUCCESS") {
let foundInChanged = this.changedAttributes.values.filter(
(e) => e !== attribute
);
if (foundInChanged.length > 0) {
this.changedAttributes.values = foundInChanged;
this.changedAttributesOutput.next(this.changedAttributes);
} else {
this.changedAttributesOutput.next(null);
}
this.reload.next(new Date());
} else {
console.log(resp);
}
},
(err) => {
console.log(err);
}
);
}
hideAttribute(attribute) {
let identifiers = [];
if (this.localStorageEntry.exists()) {
identifiers = JSON.parse(this.localStorageEntry.value);
}
identifiers = identifiers.filter((e) => e !== attribute.identifier);
this.localStorageEntry.value = JSON.stringify(identifiers);
this.selection = identifiers;
attribute.visible = false;
}
resetWidget() {
this.attributes = [];
this.selection = [];
this.changedAttributes.values = [];
this.changedAttributes.targets = [];
this.changedAttributesOutput.next(null);
if (this.context != "content") {
this.uri.next(" ");
}
return null;
}
ngOnDestroy() {
this.unsubscribe.destroy();
}
setBoxWidth(index) {
return 98 / index + "%";
}
}
<nm-widgetframe
[header]="configuration.configuration['header']"
[configuration]="configuration"
[infoTitle]="title"
[infoText]="infoText"
[infoWidth]="infoWidth"
[infoPlacement]="'bottom'"
[wikiLink]="wikiLink"
widgetId="{{ _id }}"
>
<div slot="title" class="nm-widgetframe__title">{{ title | translate }}</div>
<div
slot="content"
class="nm-widgetframe__content"
*ngIf="attributes !== null"
>
<div class="nm-attribute-list" *ngIf="editLayout === 'list'">
<p-dataGrid
[value]="attributes"
[rows]="1000"
[paginator]="false"
emptyMessage=" "
>
<ng-template let-attribute pTemplate="body">
<div class="nm-attribute-list-elements" *ngIf="attribute.visible">
<div class="nm-attribute-list-description">
<nm-ellipsis [content]="attribute.description"> </nm-ellipsis>
</div>
<div
class="nm-attribute-list-value"
*ngIf="configuration.configuration['context'] != 'content'"
>
<nm-edit-attribute
[attribute]="attribute"
[editLayout]="editLayout"
[editAttributeService]="_editAttributeService"
[loadOptionsLazy]="
configuration.configuration['loadOptionsLazy']
"
></nm-edit-attribute>
</div>
<div
class="nm-attribute-list-value"
*ngIf="configuration.configuration['context'] == 'content'"
>
<nm-edit-attribute
[dataLocale]="selectedDataLocale | async"
[attribute]="attribute"
[editLayout]="editLayout"
[context]="'content'"
[editAttributeService]="_editAttributeService"
[loadOptionsLazy]="
configuration.configuration['loadOptionsLazy']
"
></nm-edit-attribute>
</div>
<div
*ngIf="attribute.group?.length > 1"
class="nm-attribute-list-addtext"
popover="{{ 'app.ipim-mytextedit.group' | translate }}{{ ':' }} {{
attribute.group
}}"
placement="top"
container="body"
triggers="mouseenter:mouseleave"
>
{{ attribute.group }}
</div>
<span class="sortidx">{{ attribute.source[0]?.sortIdx }}</span>
<div
*ngIf="
attribute.group === undefined && attribute.type !== 'TYPE_TEXT'
"
class="nm-attribute-list-addtext"
></div>
<div
class="
nm-attribute-list-status
traffic_light_grid traffic_light_grid_single
"
*ngIf="attribute.translations"
>
<ng-template #popTemplateTranslation>
<ul class="translation-status-list">
<li
*ngFor="let key of objectKeys(attribute.translations)"
class="translation-status translation-status-{{
attribute.translations[key]
}}"
>
<mat-icon *ngIf="attribute.translations[key]"
>check</mat-icon
>
<mat-icon *ngIf="!attribute.translations[key]"></mat-icon>
{{ key }}
</li>
</ul>
</ng-template>
<div
class="traffic_light dropdown-menu-right"
[popover]="popTemplateTranslation"
popoverTitle="{{
'app.ipim-mytextedit.trafficlight.popover.title' | translate
}}"
placement="top"
container="body"
triggers="mouseenter:mouseleave"
>
<span
[ngClass]="{ active: attribute.translation_status == 'RED' }"
class="red"
></span>
<span
[ngClass]="{
active: attribute.translation_status == 'YELLOW'
}"
class="yellow"
></span>
<span
[ngClass]="{
active: attribute.translation_status == 'GREEN'
}"
class="green active"
></span>
</div>
</div>
<div
*ngIf="
attribute.group === undefined && attribute.type !== 'TYPE_TEXT'
"
class="nm-attribute-list-addtext"
></div>
<button
mat-icon-button
primary
(click)="hideAttribute(attribute)"
popover="{{
configuration.configuration['remove-popover'] | translate
}}"
placement="top"
container="body"
triggers="mouseenter:mouseleave"
>
<mat-icon class="primary-color mat-24">close</mat-icon>
</button>
<nm-action-icon
*ngIf="
attribute._actions &&
attribute._actions.delete &&
context === 'content'
"
[action]="attribute._actions.delete"
[name]="deleteName"
></nm-action-icon>
<button
*ngIf="context !== 'content'"
mat-icon-button
primary
(click)="deleteAttribute(attribute)"
popover="{{
configuration.configuration['delete-popover'] | translate
}}"
placement="top"
container="body"
triggers="mouseenter:mouseleave"
[disabled]="attribute['read-only']"
>
<mat-icon class="primary-color mat-24">not_interested</mat-icon>
</button>
</div>
</ng-template>
</p-dataGrid>
</div>
<div
class="nm-select"
style="max-width: 200px; z-index: 111; position: absolute; bottom: 0px"
>
<mat-form-field>
<mat-select
style="width: 100%"
[(ngModel)]="selection"
(selectionChange)="onSelectChange()"
multiple
(openedChange)="openedChange($event)"
[placeholder]="
configuration.configuration['select-placeholder'] | translate
"
[name]=""
[id]=""
>
<mat-option>
<ngx-mat-select-search
[formControl]="filterCtrl"
placeholderLabel="{{ 'placeholder.search' | translate }}"
></ngx-mat-select-search>
</mat-option>
<mat-option
*ngFor="let attribute of filteredOptions"
[value]="attribute.identifier"
>
{{ attribute.description }}
</mat-option>
</mat-select>
</mat-form-field>
<br />
</div>
</div>
</nm-widgetframe>