Files
xFrameworkTest/src/app/pages/components/model-presenter/model-presenter.page.ts
T

805 lines
18 KiB
TypeScript

import {
nameof,
assign,
XParam,
isFunction,
XResourceIDs,
XModelProperty,
XModalButtonRole,
XModelKeyProvider,
isNullOrUndefined,
isNullOrEmptyString,
} from 'x-framework-core';
import { Subject } from 'rxjs';
import {
XListItem,
XIconNames,
XPopoverComponent,
XListItemSlideOption,
XModelPresenterAction,
XModelPresenterActionModel,
} from 'x-framework-components';
import { Component } from '@angular/core';
import { XMarkdownMode } from 'x-framework-components';
import { VPageComponent } from '../../../views/v-page/v-page.component';
import { AppResourceIDs } from 'src/app/config/app.localization.config';
export interface DataMODEL {
firstName: string;
lastName: string;
email: string;
contacts: Array<{
type: 'mobile' | 'phone';
title: string;
number: string;
}>;
checkList: {
todo1: boolean;
todo2: boolean;
todo3: boolean;
todo4: Array<{
action: string;
dueData: Date;
}>;
};
}
@Component({
selector: 'app-model-presenter',
templateUrl: './model-presenter.page.html',
styleUrls: ['./model-presenter.page.scss'],
})
// tslint:disable-next-line:component-class-suffix
export class ModelPresenterPage extends VPageComponent {
//
//#region Props ...
//
//#region Page Props ...
titleRes = AppResourceIDs.model_presenter;
toolbarTitle = this.resourceProvider(this.titleRes);
toolbarSubTitle = this.resourceProvider(
AppResourceIDs.model_presenter_description
);
toolbarShowSubTitle = true;
//#endregion
//
// Prepare All Resource IDs ...
readonly ResourceIDs = Object.assign(
Object.assign({}, XResourceIDs),
AppResourceIDs
) as any;
//
readonly IconNames = Object.assign({}, XIconNames);
//#endregion
//
readonly MarkdownModes = Object.assign({}, XMarkdownMode);
//
//#region Model Presenter ...
dataModel: DataMODEL = {
firstName: 'Hadi',
lastName: 'Khazaee Asl',
email: 'hadi_khazaee_asl@yahoo.com',
contacts: [
{
type: 'mobile',
title: 'Personal',
number: '09121694056',
},
{
type: 'phone',
title: 'saherelm office',
number: '02632757987',
},
],
checkList: {
todo1: true,
todo2: false,
todo3: true,
todo4: [
{
action: 'start',
dueData: new Date(),
},
{
action: 'end',
dueData: new Date(),
},
],
},
};
actionProvider = new Subject<XModelPresenterActionModel>();
availableModelKeys: string[] = [
nameof<DataMODEL>('lastName'),
nameof<DataMODEL>('firstName'),
nameof<DataMODEL>('email'),
nameof<DataMODEL>('contacts'),
nameof<DataMODEL>('checkList'),
//
// Contacts ...
// `${nameof<DataMODEL>('contacts')}.type`,
`${nameof<DataMODEL>('contacts')}.title`,
// `${nameof<DataMODEL>('contacts')}.number`,
//
// Checklist ...
`${nameof<DataMODEL>('checkList')}.todo1`,
`${nameof<DataMODEL>('checkList')}.todo2`,
`${nameof<DataMODEL>('checkList')}.todo3`,
`${nameof<DataMODEL>('checkList')}.todo4`,
//
`${nameof<DataMODEL>('checkList')}.todo4.action`,
`${nameof<DataMODEL>('checkList')}.todo4.dueData`,
];
hiddenModelKeys: string[] = [`${nameof<DataMODEL>('contacts')}.type`];
hiddenLabelModelKeys: string[] = [`${nameof<DataMODEL>('contacts')}.number`];
//
sortOrederModelKeys: string[] = [
nameof<DataMODEL>('firstName'),
nameof<DataMODEL>('lastName'),
nameof<DataMODEL>('email'),
nameof<DataMODEL>('contacts'),
nameof<DataMODEL>('checkList'),
//
// Contacts ...
`${nameof<DataMODEL>('contacts')}.number`,
`${nameof<DataMODEL>('contacts')}.title`,
//
// Checklist ...
`${nameof<DataMODEL>('checkList')}.todo4.dueData`,
`${nameof<DataMODEL>('checkList')}.todo4.action`,
];
//
modelKeyProvider: XModelKeyProvider<any> = (key) => {
//
let result = key as string;
//
switch (key) {
//
case nameof<DataMODEL>('firstName'):
result = this.resourceProvider(this.AppResourceIDs.first_name);
break;
//
case nameof<DataMODEL>('lastName'):
result = this.resourceProvider(this.AppResourceIDs.last_name);
break;
//
case nameof<DataMODEL>('contacts'):
result = this.resourceProvider(this.AppResourceIDs.content);
break;
//
default:
result = key as string;
break;
}
//
return result;
};
//#endregion
//
// Content ...
readonly contentFa = `
# ${this.toolbarTitle}
این مولفه جهت نمایش و ویرایش یک شی یا مدل در نمایی ساختار یافته بکار می رود.
`;
readonly contentEn = `
# ${this.toolbarTitle}
this component used to view and edit data models in an structural view.
`;
//
readonly sample1 =
'```html' +
`
<x-model-presenter
class="v-card"
[isInPage]="true"
[model]="dataModel"
[wrapWithCard]="true"
[color]="ColorNames.Light"
[cardTitle]="'Object Editor'"
[cardColor]="ColorNames.Light"
[valueColor]="ColorNames.Dark"
[startupState]="'collapse-all'"
[headerColor]="ColorNames.Light"
[actionProvider]="actionProvider"
[hiddenModelKeys]="hiddenModelKeys"
[modelKeyProvider]="modelKeyProvider"
[labelColor]="ColorNames.TertiaryShade"
[availableModelKeys]="availableModelKeys"
[sortOrderModelKeys]="sortOrederModelKeys"
[propertyActionTemplate]="propertyActionRef"
[hiddenLabelModelKeys]="hiddenLabelModelKeys"
(onModelChanged)="handleModelChanged($event)"
[headerHighlightColor]="ColorNames.WarningTint"
></x-model-presenter>
` +
'```';
readonly sample2 =
'```html' +
`
<!-- Property Action Template -->
<ng-template
#propertyActionRef
let-key="key"
let-prefix="prefix"
let-value="value"
>
<!-- is Small Screen -->
<ng-container *ngIf="isMobileUi$ | async">
<!-- Property Selector -->
<x-icon
[clickable]="true"
[foregroundColor]="true"
[color]="ColorNames.Dark"
[name]="IconNames.menu_vertical"
(clicked)="handlePropertyActionMenuClicked(key, prefix, value)"
></x-icon>
</ng-container>
<!-- is Big Screen -->
<ng-container *ngIf="isNotMobileUi$ | async">
<!-- Property Selector -->
<x-icon
[clickable]="true"
[foregroundColor]="true"
[name]="IconNames.edit"
(clicked)="handlePropertyEdit(key, prefix, value)"
[color]="(notNullOrUndefinedValue(value) | async) ? ColorNames.Tertiary : ColorNames.Danger"
></x-icon>
<!-- Property Clear -->
<x-icon
[clickable]="true"
[foregroundColor]="true"
[name]="IconNames.clear"
[color]="ColorNames.Danger"
[uiDisabled]="nullOrUndefinedValue(value) | async"
(clicked)="handlePropertyClear(key, prefix, value)"
></x-icon>
</ng-container>
</ng-template>
` +
'```';
readonly sample3 =
'```javascript' +
`
export interface DataMODEL {
firstName: string;
lastName: string;
email: string;
contacts: Array<{
type: 'mobile' | 'phone';
title: string;
number: string;
}>;
checkList: {
todo1: boolean;
todo2: boolean;
todo3: boolean;
todo4: Array<{
action: string;
dueData: Date;
}>;
};
}
` +
'```';
readonly sample4 =
'```javascript' +
`
dataModel: DataMODEL = {
firstName: 'Hadi',
lastName: 'Khazaee Asl',
email: 'hadi_khazaee_asl@yahoo.com',
contacts: [
{
type: 'mobile',
title: 'Personal',
number: '09121694056',
},
{
type: 'phone',
title: 'saherelm office',
number: '02632757987',
},
],
checkList: {
todo1: true,
todo2: false,
todo3: true,
todo4: [
{
action: 'start',
dueData: new Date(),
},
{
action: 'end',
dueData: new Date(),
},
],
},
};
actionProvider = new Subject<XModelPresenterActionModel>();
availableModelKeys: string[] = [
nameof<DataMODEL>('lastName'),
nameof<DataMODEL>('firstName'),
nameof<DataMODEL>('email'),
nameof<DataMODEL>('contacts'),
nameof<DataMODEL>('checkList'),
//
// Contacts ...
\`\${nameof<DataMODEL>('contacts')}.type\`,
\`\${nameof<DataMODEL>('contacts')}.title\`,
\`\${nameof<DataMODEL>('contacts')}.number\`,
//
// Checklist ...
\`\${nameof<DataMODEL>('checkList')}.todo1\`,
\`\${nameof<DataMODEL>('checkList')}.todo2\`,
\`\${nameof<DataMODEL>('checkList')}.todo3\`,
\`\${nameof<DataMODEL>('checkList')}.todo4\`,
//
\`\${nameof<DataMODEL>('checkList')}.todo4.action\`,
\`\${nameof<DataMODEL>('checkList')}.todo4.dueData\`,
];
hiddenModelKeys: string[] = [\`\${nameof<DataMODEL>('contacts')}.type\`];
hiddenLabelModelKeys: string[] = [\`\${nameof<DataMODEL>('contacts')}.number\`];
//
sortOrederModelKeys: string[] = [
nameof<DataMODEL>('firstName'),
nameof<DataMODEL>('lastName'),
nameof<DataMODEL>('email'),
nameof<DataMODEL>('contacts'),
nameof<DataMODEL>('checkList'),
//
// Contacts ...
\`\${nameof<DataMODEL>('contacts')}.number\`,
\`\${nameof<DataMODEL>('contacts')}.title\`,
//
// Checklist ...
\`\${nameof<DataMODEL>('checkList')}.todo4.dueData\`,
\`\${nameof<DataMODEL>('checkList')}.todo4.action\`,
];
//
modelKeyProvider: XModelPresenterModelKeyProvider<any> = (key) => {
//
let result = key as string;
//
switch (key) {
//
case nameof<DataMODEL>('firstName'):
result = this.resourceProvider(this.AppResourceIDs.first_name);
break;
//
case nameof<DataMODEL>('lastName'):
result = this.resourceProvider(this.AppResourceIDs.last_name);
break;
//
case nameof<DataMODEL>('contacts'):
result = this.resourceProvider(this.AppResourceIDs.content);
break;
//
default:
result = key as string;
break;
}
//
return result;
};
` +
'```';
readonly sample5 =
'```javascript' +
`
async handlePropertyActionMenuClicked(
key: string,
prefix: string,
value: any
) {
//
if (isNullOrEmptyString(key)) {
return;
}
//
const onlyIcon = false;
const slideOptions: XListItemSlideOption[] = [];
//
// Edit ...
slideOptions.push({
id: 'property_edit',
icon: this.IconNames.edit,
title: this.ResourceIDs.edit,
color: isNullOrUndefined(value)
? this.ColorNames.Danger
: this.ColorNames.Tertiary,
slot: 'start',
onlyIcon,
handler: async () => {
await this.handlePropertyEdit(key, prefix, value);
},
});
//
// Clear ...
slideOptions.push({
id: 'property_clear',
icon: this.IconNames.clear,
title: this.ResourceIDs.clear,
color: this.ColorNames.Danger,
slot: 'start',
disabled: isNullOrUndefined(value),
onlyIcon,
handler: async () => {
await this.handlePropertyClear(key, prefix, value);
},
});
//
// Menu Items ...
const item: XListItem<any> = {
data: '',
slideOptions,
};
//
const popOver = await this.managerService.dialogService.presentPopover({
component: XPopoverComponent,
componentProps: assign({}, { key: XParam.Item, value: item }),
translucent: true,
showBackdrop: true,
event,
});
//
const { data } = await popOver.onWillDismiss();
if (!data || !data.id || !data.data) {
return;
}
//
const optionId = data.id.toString() as string;
const option =
item && item.slideOptions
? item.slideOptions.find((so) => so.id === optionId)
: null;
if (!option) {
return;
}
//
const handler = option.handler;
if (!handler || !isFunction(handler)) {
return;
}
//
// Run Handler ...
await handler();
}
async handlePropertyEdit(key: string, prefix: string, value: any) {
//
if (isNullOrEmptyString(key)) {
return;
}
//
await this.managerService.dialogService.presentAlert({
header: 'Change Value:',
message: 'Enter new Value:',
inputs: [
{
type: 'text',
name: 'value',
label: 'Value',
placeholder: isNullOrUndefined(value) ? '' : \`\${value.toString()}\`,
},
],
buttons: [
{
text: 'Change',
role: XModalButtonRole.Selected,
cssClass: ['btn-selected'],
handler: async (value) => {
//
let newValue = '';
if (value && value.value) {
newValue = value.value;
}
//
console.log('new value to set: ', newValue);
//
this.actionProvider.next({
action: XModelPresenterAction.SetProperty,
payload: {
key: key,
value: newValue,
keyPrefix: prefix,
} as XModelPresenterProperty,
});
},
},
{
text: 'Cancel',
role: XModalButtonRole.Cancel,
cssClass: ['btn-cancel'],
},
],
});
}
async handlePropertyClear(key: string, prefix: string, value: any) {
//
if (isNullOrEmptyString(key) || isNullOrUndefined(value)) {
return;
}
//
await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
//
this.actionProvider.next({
action: XModelPresenterAction.ClearProperty,
payload: {
key,
keyPrefix: prefix,
} as XModelPresenterProperty,
});
});
}
async handleModelChanged(event: any) {
console.log('handle model changed: ', event);
}
` +
'```';
// readonly sample3 =
// '```html' +
// `
// ` +
// '```';
//
//#region UI Providers ...
//
// Provide content based on current locale ...
getContent(title: string) {
//
if (isNullOrEmptyString(title)) {
return '';
}
//
const currentLocale = this.managerService.currentLocale;
//
const varName =
title +
(currentLocale === 'en-US'
? 'En'
: currentLocale === 'fa-IR'
? 'Fa'
: '');
const result = this[`${varName}`];
//
return result || '';
}
//#endregion
//
//#region UI Handlers ...
//
//#region Model Presenter Handlers ...
async handlePropertyActionMenuClicked(
key: string,
prefix: string,
value: any
) {
//
if (isNullOrEmptyString(key)) {
return;
}
//
const onlyIcon = false;
const slideOptions: XListItemSlideOption[] = [];
//
// Edit ...
slideOptions.push({
id: 'property_edit',
icon: this.IconNames.edit,
title: this.ResourceIDs.edit,
color: isNullOrUndefined(value)
? this.ColorNames.Danger
: this.ColorNames.Tertiary,
slot: 'start',
onlyIcon,
handler: async () => {
await this.handlePropertyEdit(key, prefix, value);
},
});
//
// Clear ...
slideOptions.push({
id: 'property_clear',
icon: this.IconNames.clear,
title: this.ResourceIDs.clear,
color: this.ColorNames.Danger,
slot: 'start',
disabled: isNullOrUndefined(value),
onlyIcon,
handler: async () => {
await this.handlePropertyClear(key, prefix, value);
},
});
//
// Menu Items ...
const item: XListItem<any> = {
data: '',
slideOptions,
};
//
const popOver = await this.managerService.dialogService.presentPopover({
component: XPopoverComponent,
componentProps: assign({}, { key: XParam.Item, value: item }),
translucent: true,
showBackdrop: true,
event,
});
//
const { data } = await popOver.onWillDismiss();
if (!data || !data.id || !data.data) {
return;
}
//
const optionId = data.id.toString() as string;
const option =
item && item.slideOptions
? item.slideOptions.find((so) => so.id === optionId)
: null;
if (!option) {
return;
}
//
const handler = option.handler;
if (!handler || !isFunction(handler)) {
return;
}
//
// Run Handler ...
await handler();
}
async handlePropertyEdit(key: string, prefix: string, value: any) {
//
if (isNullOrEmptyString(key)) {
return;
}
//
await this.managerService.dialogService.presentAlert({
header: 'Change Value:',
message: 'Enter new Value:',
inputs: [
{
type: 'text',
name: 'value',
label: 'Value',
placeholder: isNullOrUndefined(value) ? '' : `${value.toString()}`,
},
],
buttons: [
{
text: 'Change',
role: XModalButtonRole.Selected,
cssClass: ['btn-selected'],
handler: async (value) => {
//
let newValue = '';
if (value && value.value) {
newValue = value.value;
}
//
console.log('new value to set: ', newValue);
//
this.actionProvider.next({
action: XModelPresenterAction.SetProperty,
payload: {
prefix,
key: key,
value: newValue,
} as XModelProperty,
});
},
},
{
text: 'Cancel',
role: XModalButtonRole.Cancel,
cssClass: ['btn-cancel'],
},
],
});
}
async handlePropertyClear(key: string, prefix: string, value: any) {
//
if (isNullOrEmptyString(key) || isNullOrUndefined(value)) {
return;
}
//
await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
//
this.actionProvider.next({
action: XModelPresenterAction.ClearProperty,
payload: {
key,
prefix,
} as XModelProperty,
});
});
}
async handleModelChanged(event: any) {
console.log('handle model changed: ', event);
}
//#endregion
//#endregion
}