96004 lines
2.5 MiB
Plaintext
96004 lines
2.5 MiB
Plaintext
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\public-api.ts
|
|
|
|
/*
|
|
* Public API Surface of x-framework-components
|
|
*/
|
|
|
|
//
|
|
//#region Export Components ...
|
|
//
|
|
//#region Component Modules ...
|
|
export * from './lib/x-ide/x-ide.module';
|
|
export * from './lib/x-fab/x-fab.module';
|
|
export * from './lib/x-map/x-map.module';
|
|
export * from './lib/x-icon/x-icon.module';
|
|
export * from './lib/x-card/x-card.module';
|
|
export * from './lib/x-list/x-list.module';
|
|
export * from './lib/x-form/x-form.module';
|
|
export * from './lib/x-grid/x-grid.module';
|
|
export * from './lib/x-page/x-page.module';
|
|
export * from './lib/x-tabs/x-tabs.module';
|
|
export * from './lib/x-tree/x-tree.module';
|
|
export * from './lib/x-theme/x-theme.module';
|
|
export * from './lib/x-table/x-table.module';
|
|
export * from './lib/x-frame/x-frame.module';
|
|
export * from './lib/x-empty/x-empty.module';
|
|
export * from './lib/x-color/x-color.module';
|
|
export * from './lib/dialogs/x-dialog.module';
|
|
export * from './lib/x-button/x-button.module';
|
|
export * from './lib/x-slider/x-slider.module';
|
|
export * from './lib/x-slotter/x-slotter.module';
|
|
export * from './lib/x-spinner/x-spinner.module';
|
|
export * from './lib/x-stepper/x-stepper.module';
|
|
export * from './lib/x-counter/x-counter.module';
|
|
export * from './lib/x-markdown/x-markdown.module';
|
|
export * from './lib/x-thumbnail/x-thumbnail.module';
|
|
export * from './lib/x-data-pager/x-data-pager.module';
|
|
export * from './lib/x-search-bar/x-search-bar.module';
|
|
export * from './lib/x-action-bar/x-action-bar.module';
|
|
export * from './lib/x-file-upload/x-file-upload.module';
|
|
export * from './lib/x-progress-bar/x-progress-bar.module';
|
|
export * from './lib/x-color-picker/x-color-picker.module';
|
|
export * from './lib/x-data-scroller/x-data-scroller.module';
|
|
export * from './lib/x-image-cropper/x-image-cropper.module';
|
|
export * from './lib/x-tab-navigator/x-tab-navigator.module';
|
|
export * from './lib/x-avatar-upload/x-avatar-upload.module';
|
|
export * from './lib/x-file-drop-area/x-file-drop-area.module';
|
|
export * from './lib/x-screen-capture/x-screen-capture.module';
|
|
export * from './lib/x-model-presenter/x-model-presenter.module';
|
|
export * from './lib/x-expandable-list/x-expandable-list.module';
|
|
export * from './lib/x-expandable-panel/x-expandable-panel.module';
|
|
export * from './lib/x-description-list/x-description-list.module';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Component ItSelfd ...
|
|
export * from './lib/x-ide/x-ide.component';
|
|
export * from './lib/x-fab/x-fab.component';
|
|
export * from './lib/x-map/x-map.component';
|
|
export * from './lib/x-form/x-form.component';
|
|
export * from './lib/x-icon/x-icon.component';
|
|
export * from './lib/x-card/x-card.component';
|
|
export * from './lib/x-list/x-list.component';
|
|
export * from './lib/x-grid/x-grid.component';
|
|
export * from './lib/x-page/x-page.component';
|
|
export * from './lib/x-tabs/x-tabs.component';
|
|
export * from './lib/x-tree/x-tree.component';
|
|
export * from './lib/x-color/x-color.component';
|
|
export * from './lib/x-empty/x-empty.component';
|
|
export * from './lib/x-frame/x-frame.component';
|
|
export * from './lib/x-table/x-table.component';
|
|
export * from './lib/x-button/x-button.component';
|
|
export * from './lib/x-slider/x-slider.component';
|
|
export * from './lib/x-tabs/x-tab/x-tab.component';
|
|
export * from './lib/x-spinner/x-spinner.component';
|
|
export * from './lib/x-slotter/x-slotter.component';
|
|
export * from './lib/x-stepper/x-stepper.component';
|
|
export * from './lib/x-counter/x-counter.component';
|
|
export * from './lib/x-markdown/x-markdown.component';
|
|
export * from './lib/x-stepper/x-step/x-step.component';
|
|
export * from './lib/x-slotter/x-slot/x-slot.component';
|
|
export * from './lib/x-thumbnail/x-thumbnail.component';
|
|
export * from './lib/x-slider/x-slide/x-slide.component';
|
|
export * from './lib/x-page/x-footer/x-footer.component';
|
|
export * from './lib/x-data-pager/x-data-pager.component';
|
|
export * from './lib/x-search-bar/x-search-bar.component';
|
|
export * from './lib/x-action-bar/x-action-bar.component';
|
|
export * from './lib/x-page/x-toolbar/x-toolbar.component';
|
|
export * from './lib/dialogs/x-popover/x-popover.component';
|
|
export * from './lib/x-file-upload/x-file-upload.component';
|
|
export * from './lib/x-progress-bar/x-progress-bar.component';
|
|
export * from './lib/x-color-picker/x-color-picker.component';
|
|
export * from './lib/x-page/x-navigator/x-navigator.component';
|
|
export * from './lib/x-data-scroller/x-data-scroller.component';
|
|
export * from './lib/x-map/x-map-dialog/x-map-dialog.component';
|
|
export * from './lib/x-image-cropper/x-image-cropper.component';
|
|
export * from './lib/x-tab-navigator/x-tab-navigator.component';
|
|
export * from './lib/x-avatar-upload/x-avatar-upload.component';
|
|
export * from './lib/x-file-drop-area/x-file-drop-area.component';
|
|
export * from './lib/x-screen-capture/x-screen-capture.component';
|
|
export * from './lib/x-expandable-panel/x-panel/x-panel.component';
|
|
export * from './lib/x-expandable-list/x-expandable-list.component';
|
|
export * from './lib/x-model-presenter/x-model-presenter.component';
|
|
export * from './lib/x-expandable-panel/x-expandable-panel.component';
|
|
export * from './lib/x-description-list/x-description-list.component';
|
|
export * from './lib/x-theme/x-theme-manager/x-theme-manager.component';
|
|
export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.component';
|
|
export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.component';
|
|
export * from './lib/x-model-presenter/x-model-presenter-item/x-model-presenter-item.component';
|
|
export * from './lib/x-description-list/x-description-list-item/x-description-list-item.component';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Component Typings ...
|
|
export * from './lib/x-ide/x-ide.typings';
|
|
export * from './lib/x-fab/x-fab.typings';
|
|
export * from './lib/x-map/x-map.typings';
|
|
export * from './lib/x-grid/x-grid.typings';
|
|
export * from './lib/x-form/x-form.typings';
|
|
export * from './lib/x-icon/x-icon.typings';
|
|
export * from './lib/x-card/x-card.typings';
|
|
export * from './lib/x-list/x-list.typings';
|
|
export * from './lib/x-page/x-page.typings';
|
|
export * from './lib/x-tabs/x-tabs.typings';
|
|
export * from './lib/x-tree/x-tree.typings';
|
|
export * from './lib/x-empty/x-empty.typings';
|
|
export * from './lib/x-frame/x-frame.typings';
|
|
export * from './lib/x-page/x-page.container';
|
|
export * from './lib/x-color/x-color.typings';
|
|
export * from './lib/x-theme/x-theme-typings';
|
|
export * from './lib/x-table/x-table.typings';
|
|
export * from './lib/x-button/x-button.typings';
|
|
export * from './lib/x-slider/x-slider.typings';
|
|
export * from './lib/x-stepper/x-stepper.typings';
|
|
export * from './lib/x-slotter/x-slotter.typings';
|
|
export * from './lib/x-counter/x-counter.typings';
|
|
export * from './lib/x-markdown/x-markdown.typings';
|
|
export * from './lib/x-thumbnail/x-thumbnail.typings';
|
|
export * from './lib/x-page/x-footer/x-footer.typings';
|
|
export * from './lib/x-data-pager/x-data-pager.typings';
|
|
export * from './lib/x-action-bar/x-action-bar.typings';
|
|
export * from './lib/x-search-bar/x-search-bar.typings';
|
|
export * from './lib/x-page/x-toolbar/x-toolbar.typings';
|
|
export * from './lib/dialogs/x-popover/x-popover.typings';
|
|
export * from './lib/x-file-upload/x-file-upload.typings';
|
|
export * from './lib/x-progress-bar/x-progress-bar.typings';
|
|
export * from './lib/x-color-picker/x-color-picker.typings';
|
|
export * from './lib/x-page/x-navigator/x-navigator.typings';
|
|
export * from './lib/x-data-scroller/x-data-scroller.typings';
|
|
export * from './lib/x-image-cropper/x-image-cropper.typings';
|
|
export * from './lib/x-tab-navigator/x-tab-navigator.typings';
|
|
export * from './lib/x-avatar-upload/x-avatar-upload.typings';
|
|
export * from './lib/x-map/x-map-dialog/x-map-dialog.typings';
|
|
export * from './lib/x-file-drop-area/x-file-drop-area.typings';
|
|
export * from './lib/x-screen-capture/x-screen-capture.typings';
|
|
export * from './lib/x-screen-capture/x-screen-capture.container';
|
|
export * from './lib/x-expandable-list/x-expandable-list.typings';
|
|
export * from './lib/x-model-presenter/x-model-presenter.typings';
|
|
export * from './lib/x-expandable-panel/x-expandable-panel.typings';
|
|
export * from './lib/x-description-list/x-description-list.typings';
|
|
export * from './lib/x-theme/x-theme-manager/x-theme-manager.typings';
|
|
export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.typings';
|
|
export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings';
|
|
export * from './lib/x-model-presenter/x-model-presenter-item/x-model-presenter-item.typings';
|
|
export * from './lib/x-description-list/x-description-list-item/x-description-list-item.typings';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Component Tools ...
|
|
export * from './lib/x-map/x-map.tools';
|
|
export * from './lib/x-form/x-form.tools';
|
|
export * from './lib/x-theme/x-theme.tools';
|
|
export * from './lib/dialogs/x-popover/x-popover.tools';
|
|
export * from './lib/x-form/validators/x-form-validators';
|
|
export * from './lib/dialogs/x-popover/x-popover.service';
|
|
export * from './lib/x-slider/x-slide.animation.providers';
|
|
export * from './lib/x-page/x-navigator/x-navigator.tools';
|
|
export * from './lib/x-tab-navigator/x-tab-navigator.tools';
|
|
export * from './lib/x-map/x-map-dialog/x-map-dialog.service';
|
|
export * from './lib/x-image-cropper/x-image-cropper.service';
|
|
export * from './lib/x-screen-capture/x-screen-capture.service';
|
|
export * from './lib/x-expandable-list/x-expandable-list.tools';
|
|
export * from './lib/x-color-picker/directives/x-color-text.directive';
|
|
export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.service';
|
|
export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service';
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Classes ...
|
|
//
|
|
export * from './lib/classes/x-base-page';
|
|
export * from './lib/classes/x-base-component';
|
|
export * from './lib/classes/i-x-base.container';
|
|
export * from './lib/classes/i-x-file.container';
|
|
export * from './lib/classes/i-x-toolbar-footer';
|
|
export * from './lib/classes/x-base-action.model';
|
|
export * from './lib/classes/x-base-dialog.service';
|
|
export * from './lib/classes/x-base.dialog.component';
|
|
export * from './lib/classes/x-base.observable.tools';
|
|
export * from './lib/classes/x-base.dialog.component';
|
|
export * from './lib/classes/i-x-card-empty.container';
|
|
export * from './lib/classes/i-x-base-dialog.container';
|
|
export * from './lib/classes/i-x-next-prev-reset.container';
|
|
//
|
|
export * from './lib/dialogs/x-dialog/x-dialog.typings';
|
|
export * from './lib/dialogs/x-dialog/x-dialog.component';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tokens ...
|
|
export * from './lib/tokens/x-injectable-tokens';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Config ...
|
|
export * from './lib/config/x-framework-components.config';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Modules ...
|
|
export * from './lib/modules/x-material.module';
|
|
export * from './lib/x-framework-components.module';
|
|
export * from './lib/modules/x-base-component.module';
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\test.ts
|
|
|
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
|
|
import 'zone.js';
|
|
import 'zone.js/testing';
|
|
import { getTestBed } from '@angular/core/testing';
|
|
import {
|
|
BrowserDynamicTestingModule,
|
|
platformBrowserDynamicTesting
|
|
} from '@angular/platform-browser-dynamic/testing';
|
|
|
|
declare const require: {
|
|
context(path: string, deep?: boolean, filter?: RegExp): {
|
|
keys(): string[];
|
|
<T>(id: string): T;
|
|
};
|
|
};
|
|
|
|
// First, initialize the Angular testing environment.
|
|
getTestBed().initTestEnvironment(
|
|
BrowserDynamicTestingModule,
|
|
platformBrowserDynamicTesting()
|
|
);
|
|
// Then we find all the tests.
|
|
const context = require.context('./', true, /\.spec\.ts$/);
|
|
// And load the modules.
|
|
context.keys().map(context);
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-framework-components.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { IonicModule } from '@ionic/angular';
|
|
import { CommonModule } from '@angular/common';
|
|
import { RouterModule } from '@angular/router';
|
|
import { XIDEModule } from './x-ide/x-ide.module';
|
|
import { XFabModule } from './x-fab/x-fab.module';
|
|
import { XMapModule } from './x-map/x-map.module';
|
|
import { XIconModule } from './x-icon/x-icon.module';
|
|
import { XCardModule } from './x-card/x-card.module';
|
|
import { XListModule } from './x-list/x-list.module';
|
|
import { XFormModule } from './x-form/x-form.module';
|
|
import { XGridModule } from './x-grid/x-grid.module';
|
|
import { XPageModule } from './x-page/x-page.module';
|
|
import { XTabsModule } from './x-tabs/x-tabs.module';
|
|
import { XFrameModule } from './x-frame/x-frame.module';
|
|
import { XEmptyModule } from './x-empty/x-empty.module';
|
|
import { XTableModule } from './x-table/x-table.module';
|
|
import { XFrameworkCoreModule } from 'x-framework-core';
|
|
import { XThemeModule } from './x-theme/x-theme.module';
|
|
import { XColorModule } from './x-color/x-color.module';
|
|
import { XSliderModule } from './x-slider/x-slider.module';
|
|
import { XButtonModule } from './x-button/x-button.module';
|
|
import { XDialogsModule } from './dialogs/x-dialog.module';
|
|
import { XMaterialModule } from './modules/x-material.module';
|
|
import { XSlotterModule } from './x-slotter/x-slotter.module';
|
|
import { XSpinnerModule } from './x-spinner/x-spinner.module';
|
|
import { XStepperModule } from './x-stepper/x-stepper.module';
|
|
import { XCounterModule } from './x-counter/x-counter.module';
|
|
import { XFrameworkServicesModule } from 'x-framework-services';
|
|
import { XMarkdownModule } from './x-markdown/x-markdown.module';
|
|
import { XThumbnailModule } from './x-thumbnail/x-thumbnail.module';
|
|
import { XActionBarModule } from './x-action-bar/x-action-bar.module';
|
|
import { XSearchBarModule } from './x-search-bar/x-search-bar.module';
|
|
import { XDataPagerModule } from './x-data-pager/x-data-pager.module';
|
|
import { XBaseComponentModule } from './modules/x-base-component.module';
|
|
import { XFileUploadModule } from './x-file-upload/x-file-upload.module';
|
|
import { XColorPickerModule } from './x-color-picker/x-color-picker.module';
|
|
import { XProgressBarModule } from './x-progress-bar/x-progress-bar.module';
|
|
import { XImageCropperModule } from './x-image-cropper/x-image-cropper.module';
|
|
import { XTabNavigatorModule } from './x-tab-navigator/x-tab-navigator.module';
|
|
import { XAvatarUploadModule } from './x-avatar-upload/x-avatar-upload.module';
|
|
import { XDataScrollerModule } from './x-data-scroller/x-data-scroller.module';
|
|
import { XFileDropAreaModule } from './x-file-drop-area/x-file-drop-area.module';
|
|
import { XScreenCaptureModule } from './x-screen-capture/x-screen-capture.module';
|
|
import { XExpandableListModule } from './x-expandable-list/x-expandable-list.module';
|
|
import { XModelPresenterModule } from './x-model-presenter/x-model-presenter.module';
|
|
import { XExpandablePanelModule } from './x-expandable-panel/x-expandable-panel.module';
|
|
import { XDescriptionListModule } from './x-description-list/x-description-list.module';
|
|
|
|
@NgModule({
|
|
declarations: [],
|
|
imports: [
|
|
//
|
|
IonicModule,
|
|
RouterModule,
|
|
CommonModule,
|
|
|
|
//
|
|
XDialogsModule,
|
|
|
|
//
|
|
XMaterialModule,
|
|
XBaseComponentModule,
|
|
|
|
//
|
|
XFrameworkCoreModule,
|
|
XFrameworkServicesModule,
|
|
|
|
//
|
|
XIDEModule,
|
|
XFabModule,
|
|
XMapModule,
|
|
XPageModule,
|
|
XIconModule,
|
|
XFormModule,
|
|
XCardModule,
|
|
XListModule,
|
|
XTabsModule,
|
|
XGridModule,
|
|
XFrameModule,
|
|
XEmptyModule,
|
|
XColorModule,
|
|
XTableModule,
|
|
XThemeModule,
|
|
XButtonModule,
|
|
XSliderModule,
|
|
XSlotterModule,
|
|
XSpinnerModule,
|
|
XStepperModule,
|
|
XCounterModule,
|
|
XMarkdownModule,
|
|
XDataPagerModule,
|
|
XSearchBarModule,
|
|
XThumbnailModule,
|
|
XActionBarModule,
|
|
XFileUploadModule,
|
|
XProgressBarModule,
|
|
XColorPickerModule,
|
|
XDataScrollerModule,
|
|
XTabNavigatorModule,
|
|
XImageCropperModule,
|
|
XFileDropAreaModule,
|
|
XAvatarUploadModule,
|
|
XScreenCaptureModule,
|
|
XExpandableListModule,
|
|
XModelPresenterModule,
|
|
XExpandablePanelModule,
|
|
XDescriptionListModule,
|
|
],
|
|
exports: [
|
|
//
|
|
IonicModule,
|
|
RouterModule,
|
|
CommonModule,
|
|
|
|
//
|
|
XDialogsModule,
|
|
|
|
//
|
|
XMaterialModule,
|
|
XBaseComponentModule,
|
|
|
|
//
|
|
XFrameworkCoreModule,
|
|
XFrameworkServicesModule,
|
|
|
|
//
|
|
XIDEModule,
|
|
XFabModule,
|
|
XMapModule,
|
|
XPageModule,
|
|
XIconModule,
|
|
XFormModule,
|
|
XCardModule,
|
|
XListModule,
|
|
XTabsModule,
|
|
XGridModule,
|
|
XEmptyModule,
|
|
XFrameModule,
|
|
XColorModule,
|
|
XTableModule,
|
|
XThemeModule,
|
|
XButtonModule,
|
|
XSliderModule,
|
|
XSlotterModule,
|
|
XSpinnerModule,
|
|
XStepperModule,
|
|
XCounterModule,
|
|
XMarkdownModule,
|
|
XDataPagerModule,
|
|
XSearchBarModule,
|
|
XActionBarModule,
|
|
XThumbnailModule,
|
|
XFileUploadModule,
|
|
XProgressBarModule,
|
|
XColorPickerModule,
|
|
XDataScrollerModule,
|
|
XTabNavigatorModule,
|
|
XImageCropperModule,
|
|
XFileDropAreaModule,
|
|
XAvatarUploadModule,
|
|
XScreenCaptureModule,
|
|
XExpandableListModule,
|
|
XModelPresenterModule,
|
|
XExpandablePanelModule,
|
|
XDescriptionListModule,
|
|
],
|
|
})
|
|
export class XFrameworkComponentsModule { }
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-base-dialog.container.ts
|
|
|
|
import { XResourceIdentifier, XStandardType } from 'x-framework-core';
|
|
|
|
export interface XBaseDialogConfig {
|
|
title?: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-base.container.ts
|
|
|
|
import { Observable } from 'rxjs';
|
|
import { Component } from '@angular/core';
|
|
import { XBaseComponent } from './x-base-component';
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXBaseContainer {}
|
|
|
|
export abstract class XBaseContainer implements IXBaseContainer {}
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XBaseContainerComponent extends XBaseComponent {
|
|
//
|
|
//#region Abstracts ...
|
|
public abstract extractProps(container?: any): Observable<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Props Actions ...
|
|
public async extractPropsAsync(container?: any): Promise<any> {
|
|
return await this.getValueAsync(this.extractProps(container));
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
export interface IXBaseComponentContainer {}
|
|
|
|
export abstract class XBaseComponentContainer
|
|
implements IXBaseComponentContainer {}
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XBaseComponentContainerComponent extends XBaseComponent {
|
|
//
|
|
//#region Abstracts ...
|
|
public abstract extractProps(container?: any): Observable<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Props Actions ...
|
|
public async extractPropsAsync(container?: any): Promise<any> {
|
|
return await this.getValueAsync(this.extractProps(container));
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-card-empty.container.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from './i-x-base.container';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
} from '../x-card/x-card.typings';
|
|
import {
|
|
XEmptyContainer,
|
|
XEmptyActionModel,
|
|
IXComponentEmptyContainer,
|
|
} from '../x-empty/x-empty.typings';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarActionModel,
|
|
XActionBarActionFiredModel,
|
|
XComponentActionBarContainer,
|
|
IXComponentActionBarContainer,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import {
|
|
XSearchBarActionModel,
|
|
XSearchBarTypeIdentifier,
|
|
XSearchBarEventIdentifier,
|
|
XComponentSearchBarContainer,
|
|
IXComponentSearchBarContainer,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Observable, Subject, forkJoin } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region XCardEmptyContainer ...
|
|
//
|
|
type TXCardEmptyContainer = IXComponentCardContainer &
|
|
IXComponentEmptyContainer;
|
|
export interface IXCardEmptyContainer extends TXCardEmptyContainer { }
|
|
|
|
//
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardEmptyContainer
|
|
extends XBaseContainer
|
|
implements IXCardEmptyContainer {
|
|
//
|
|
//#region XComponentCard ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentEmpty ...
|
|
//
|
|
readonly showEmpty: XStandardType<boolean> = true;
|
|
readonly emptyHasRefresh: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.hasRefresh;
|
|
|
|
//
|
|
readonly emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.emptyPropertyProvider.actionProvider;
|
|
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.emptyPropertyProvider.cssClass;
|
|
readonly emptyColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.color;
|
|
readonly emptyForegroundColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.foregroundColor;
|
|
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.messageColor;
|
|
readonly emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.foregroundMessageColor;
|
|
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.refreshButtonColor;
|
|
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.foregroundRefreshButtonColor;
|
|
readonly emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.emptyPropertyProvider.message;
|
|
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.emptyPropertyProvider.refreshIcon;
|
|
readonly emptyRefresh: EventEmitter<void> =
|
|
this.emptyPropertyProvider.refresh;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected emptyPropertyProvider: XEmptyContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardEmptyContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardEmptyContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentEmpty ...
|
|
//
|
|
@Input()
|
|
showEmpty: XStandardType<boolean> = this.propertyProvider.showEmpty;
|
|
|
|
@Input()
|
|
emptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.emptyHasRefresh;
|
|
|
|
@Input()
|
|
emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.emptyActionProvider;
|
|
|
|
@Input()
|
|
emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.emptyCssClass;
|
|
|
|
@Input()
|
|
emptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyColor;
|
|
|
|
@Input()
|
|
emptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundColor;
|
|
|
|
@Input()
|
|
emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyMessageColor;
|
|
|
|
@Input()
|
|
emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundMessageColor;
|
|
|
|
@Input()
|
|
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyRefreshButtonColor;
|
|
|
|
@Input()
|
|
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundRefreshButtonColor;
|
|
|
|
@Input()
|
|
emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.emptyMessage;
|
|
|
|
@Input()
|
|
emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.emptyRefreshIcon;
|
|
|
|
@Output()
|
|
emptyRefresh: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardEmptyContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardEmptyContainer
|
|
): Observable<IXCardEmptyContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentEmpty ...
|
|
//
|
|
showEmpty: this.getValue(
|
|
container ? container.showEmpty : this.showEmpty
|
|
),
|
|
emptyHasRefresh: this.getValue(
|
|
container ? container.emptyHasRefresh : this.emptyHasRefresh
|
|
),
|
|
|
|
//
|
|
emptyCssClass: this.getValue(
|
|
container ? container.emptyCssClass : this.emptyCssClass
|
|
),
|
|
emptyColor: this.getValue(
|
|
container ? container.emptyColor : this.emptyColor
|
|
),
|
|
emptyForegroundColor: this.getValue(
|
|
container ? container.emptyForegroundColor : this.emptyForegroundColor
|
|
),
|
|
emptyMessageColor: this.getValue(
|
|
container ? container.emptyMessageColor : this.emptyMessageColor
|
|
),
|
|
emptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundMessageColor
|
|
: this.emptyForegroundMessageColor
|
|
),
|
|
emptyRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyRefreshButtonColor
|
|
: this.emptyRefreshButtonColor
|
|
),
|
|
emptyForegroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundRefreshButtonColor
|
|
: this.emptyForegroundRefreshButtonColor
|
|
),
|
|
emptyMessage: this.getValue(
|
|
container ? container.emptyMessage : this.emptyMessage
|
|
),
|
|
emptyRefreshIcon: this.getValue(
|
|
container ? container.emptyRefreshIcon : this.emptyRefreshIcon
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
emptyActionProvider: container
|
|
? container.emptyActionProvider
|
|
: this.emptyActionProvider,
|
|
|
|
//
|
|
emptyRefresh: this.emptyRefresh,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XCardActionBarContainer ...
|
|
type TXCardActionBarContainer = IXComponentCardContainer & IXComponentActionBarContainer;
|
|
export interface IXCardActionBarContainer extends TXCardActionBarContainer { }
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardActionBarContainer extends XBaseContainer implements IXCardActionBarContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region ComponentCard Props ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentActionBar Props ...
|
|
readonly showActionBar: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.showActionBar;
|
|
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.actionBarPropertyProvider.actionBarActionProvider;
|
|
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.actionBarPropertyProvider.actionBarCssClass;
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.actionBarPropertyProvider.actionBarColor;
|
|
readonly actionBarForegroundColor: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.actionBarForegroundColor;
|
|
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.actionBarPropertyProvider.actionBarActions;
|
|
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.actionBarPropertyProvider.actionBarActionFired;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected actionBarPropertyProvider: XComponentActionBarContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardActionBarContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardActionBarContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region ComponentCard Props ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentActionBar Props ...
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
@Input()
|
|
actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
|
|
@Output()
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.propertyProvider.actionBarActionFired;
|
|
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardActionBarContainer,
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
public extractProps(container?: IXCardActionBarContainer): Observable<IXCardActionBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentActionBar ...
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
actionBarActions: this.getValue(
|
|
container ? container.actionBarActions : this.actionBarActions
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
actionBarActionProvider: container
|
|
? container.actionBarActionProvider
|
|
: this.actionBarActionProvider,
|
|
|
|
//
|
|
actionBarActionFired: this.actionBarActionFired,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XCardEmptyActionSearchBarContainer ...
|
|
//
|
|
type TXCardEmptyActionSearchBarContainer = IXCardEmptyContainer &
|
|
IXComponentActionBarContainer &
|
|
IXComponentSearchBarContainer;
|
|
export interface IXCardEmptyActionSearchBarContainer
|
|
extends IXBaseContainer,
|
|
TXCardEmptyActionSearchBarContainer { }
|
|
|
|
//
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardEmptyActionSearchBarContainer
|
|
extends XCardEmptyContainer
|
|
implements IXCardEmptyActionSearchBarContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
readonly showActionBar: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.showActionBar;
|
|
|
|
//
|
|
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.actionBarPropertyProvider.actionBarActionProvider;
|
|
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.actionBarPropertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.actionBarPropertyProvider.actionBarColor;
|
|
readonly actionBarForegroundColor: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.actionBarPropertyProvider.actionBarActions;
|
|
|
|
//
|
|
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.actionBarPropertyProvider.actionBarActionFired;
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
readonly showSearchBar: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.showSearchBar;
|
|
|
|
//
|
|
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.searchBarPropertyProvider.searchBarActionProvider;
|
|
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.searchBarPropertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
readonly searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarColor;
|
|
readonly searchBarForegroundColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchInputColor;
|
|
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarType;
|
|
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarTitle;
|
|
readonly searchBarValue: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarValue;
|
|
readonly searchBarEnterKeyHint: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarEnterKeyHint;
|
|
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarKeyboardType;
|
|
readonly searchBarSpellcheck: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarSpellcheck;
|
|
readonly searchBarDebounce: XStandardType<number> =
|
|
this.searchBarPropertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
readonly searchBarShowCancelButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowCancelButton;
|
|
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
|
|
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
|
|
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarShowClearButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowClearButton;
|
|
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIcon;
|
|
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
|
|
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarQueryChange: EventEmitter<string> =
|
|
this.searchBarPropertyProvider.searchBarQueryChange;
|
|
readonly searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarOnEvent;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected emptyPropertyProvider: XEmptyContainer,
|
|
protected actionBarPropertyProvider: XComponentActionBarContainer,
|
|
protected searchBarPropertyProvider: XComponentSearchBarContainer
|
|
) {
|
|
super(cardPropertyProvider, emptyPropertyProvider);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardEmptyActionSearchBarContainerComponent
|
|
extends XCardEmptyContainerComponent
|
|
implements IXCardEmptyActionSearchBarContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
|
|
//
|
|
@Output()
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
@Input()
|
|
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
|
|
|
|
//
|
|
@Input()
|
|
searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.searchBarActionProvider;
|
|
|
|
@Input()
|
|
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
|
|
@Input()
|
|
searchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchInputColor;
|
|
|
|
@Input()
|
|
searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarType;
|
|
|
|
@Input()
|
|
searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarTitle;
|
|
|
|
@Input()
|
|
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
|
|
|
|
@Input()
|
|
searchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.searchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarKeyboardType;
|
|
|
|
@Input()
|
|
searchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarSpellcheck;
|
|
|
|
@Input()
|
|
searchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowCancelButton;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowClearButton;
|
|
|
|
@Input()
|
|
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardEmptyActionSearchBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardEmptyActionSearchBarContainer
|
|
): Observable<IXCardEmptyActionSearchBarContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
actionBarActions: this.getValue(
|
|
container ? container.actionBarActions : this.actionBarActions
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
showSearchBar: this.getValue(
|
|
container ? container.showSearchBar : this.showSearchBar
|
|
),
|
|
searchBarCssClass: this.getValue(
|
|
container ? container.searchBarCssClass : this.searchBarCssClass
|
|
),
|
|
searchBarColor: this.getValue(
|
|
container ? container.searchBarColor : this.searchBarColor
|
|
),
|
|
searchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundColor
|
|
: this.searchBarForegroundColor
|
|
),
|
|
searchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchInputColor
|
|
: this.searchBarSearchInputColor
|
|
),
|
|
searchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundSearchInputColor
|
|
: this.searchBarForegroundSearchInputColor
|
|
),
|
|
|
|
//
|
|
searchBarType: this.getValue(
|
|
container ? container.searchBarType : this.searchBarType
|
|
),
|
|
searchBarTitle: this.getValue(
|
|
container ? container.searchBarTitle : this.searchBarTitle
|
|
),
|
|
searchBarValue: this.getValue(
|
|
container ? container.searchBarValue : this.searchBarValue
|
|
),
|
|
searchBarEnterKeyHint: this.getValue(
|
|
container
|
|
? container.searchBarEnterKeyHint
|
|
: this.searchBarEnterKeyHint
|
|
),
|
|
searchBarKeyboardType: this.getValue(
|
|
container
|
|
? container.searchBarKeyboardType
|
|
: this.searchBarKeyboardType
|
|
),
|
|
searchBarSpellcheck: this.getValue(
|
|
container
|
|
? container.searchBarSpellcheck
|
|
: this.searchBarSpellcheck
|
|
),
|
|
searchBarDebounce: this.getValue(
|
|
container ? container.searchBarDebounce : this.searchBarDebounce
|
|
),
|
|
|
|
//
|
|
searchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.searchBarShowCancelButton
|
|
: this.searchBarShowCancelButton
|
|
),
|
|
searchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIcon
|
|
: this.searchBarCancelButtonIcon
|
|
),
|
|
searchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonTitle
|
|
: this.searchBarCancelButtonTitle
|
|
),
|
|
searchBarCancelButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIconColor
|
|
: this.searchBarCancelButtonIconColor
|
|
),
|
|
|
|
//
|
|
searchBarShowClearButton: this.getValue(
|
|
container
|
|
? container.searchBarShowClearButton
|
|
: this.searchBarShowClearButton
|
|
),
|
|
searchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIcon
|
|
: this.searchBarClearButtonIcon
|
|
),
|
|
searchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIconColor
|
|
: this.searchBarClearButtonIconColor
|
|
),
|
|
|
|
//
|
|
searchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIcon
|
|
: this.searchBarSearchButtonIcon
|
|
),
|
|
searchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIconColor
|
|
: this.searchBarSearchButtonIconColor
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionBarActionProvider: container
|
|
? container.actionBarActionProvider
|
|
: this.actionBarActionProvider,
|
|
actionBarActionFired: this.actionBarActionFired,
|
|
|
|
//
|
|
searchBarActionProvider: container
|
|
? container.searchBarActionProvider
|
|
: this.searchBarActionProvider,
|
|
|
|
//
|
|
searchBarQueryChange: this.searchBarQueryChange,
|
|
searchBarOnEvent: this.searchBarOnEvent,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-file.container.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
Injectable,
|
|
ElementRef,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XExceptionIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XExceptionIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
} from '../x-card/x-card.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import {
|
|
XFileDropAreaActionModel,
|
|
XComponentFileDropAreaContainer,
|
|
IXComponentFileDropAreaContainer,
|
|
} from '../x-file-drop-area/x-file-drop-area.typings';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XBaseContainer, XBaseContainerComponent } from './i-x-base.container';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Max Allowed Files ...
|
|
export interface IXMaxAllowedFilesContainer {
|
|
maxAllowedFiles: XStandardType<number>;
|
|
maxAllowedFilesException: XStandardType<XExceptionIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMaxAllowedFilesContainer
|
|
implements Readonly<IXMaxAllowedFilesContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly maxAllowedFiles: XStandardType<number> = this.config.maxUploadFiles;
|
|
|
|
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxAllowedFilesExceeded;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Max Allowed File Size ...
|
|
export interface IXMaxAllowedSizeContainer {
|
|
maxAllowedSize: XStandardType<number>;
|
|
maxAllowedSizeException: XStandardType<XExceptionIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMaxAllowedSizeContainer
|
|
implements Readonly<IXMaxAllowedSizeContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly maxAllowedSize: XStandardType<number> = this.config.maxAllowedSize;
|
|
|
|
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxFilesSizeExceeded;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Min Allowed File Size ...
|
|
export interface IXMinAllowedFileSizeContainer {
|
|
minAllowedFileSize: XStandardType<number>;
|
|
minAllowedFileSizeException: XStandardType<XExceptionIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMinAllowedFileSizeContainer
|
|
implements Readonly<IXMinAllowedFileSizeContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly minAllowedFileSize: XStandardType<number> =
|
|
this.config.minAllowedFileSize;
|
|
|
|
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MinFilesSizeExceeded;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Max Allowed Size ...
|
|
export interface IXMaxAllowedFileSizeContainer {
|
|
maxAllowedFileSize: XStandardType<number>;
|
|
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMaxAllowedFileSizeContainer
|
|
implements Readonly<IXMaxAllowedFileSizeContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly maxAllowedFileSize: XStandardType<number> =
|
|
this.config.maxAllowedFileSize;
|
|
|
|
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxFilesSizeExceeded;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Regular File ...
|
|
export interface IXFileRegularContainer {
|
|
emptyFileException: XStandardType<XExceptionIdentifier>;
|
|
notAllowedFileException: XStandardType<XExceptionIdentifier>;
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFileRegularContainer implements Readonly<IXFileRegularContainer> {
|
|
//
|
|
//#region Props ...
|
|
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.EmptyFile;
|
|
|
|
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.InavlidFile;
|
|
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Combine ...
|
|
type XCombinedType = IXFileRegularContainer &
|
|
IXMaxAllowedFilesContainer &
|
|
IXMaxAllowedSizeContainer &
|
|
IXMinAllowedFileSizeContainer &
|
|
IXMaxAllowedFileSizeContainer;
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface IXFileContainer extends XCombinedType {}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFileContainer implements Readonly<IXFileContainer> {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.EmptyFile;
|
|
|
|
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.InavlidFile;
|
|
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
|
|
|
|
//
|
|
readonly maxAllowedFiles: XStandardType<number> = this.config.maxUploadFiles;
|
|
|
|
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxAllowedFilesExceeded;
|
|
|
|
//
|
|
readonly maxAllowedSize: XStandardType<number> = this.config.maxAllowedSize;
|
|
|
|
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxFilesSizeExceeded;
|
|
|
|
//
|
|
readonly minAllowedFileSize: XStandardType<number> =
|
|
this.config.minAllowedFileSize;
|
|
|
|
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MinFilesSizeExceeded;
|
|
|
|
//
|
|
readonly maxAllowedFileSize: XStandardType<number> =
|
|
this.config.maxAllowedFileSize;
|
|
|
|
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
XExceptionIDs.MaxFilesSizeExceeded;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
private config: XFrameworkComponentsConfig
|
|
) {}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XFileContainerComponent ...
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XFileContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXFileContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.emptyFileException;
|
|
|
|
@Input()
|
|
notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.notAllowedFileException;
|
|
|
|
@Input()
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.allowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFiles: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFiles;
|
|
|
|
@Input()
|
|
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFilesException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
|
|
|
|
@Input()
|
|
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedSizeException;
|
|
|
|
//
|
|
@Input()
|
|
minAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.minAllowedFileSize;
|
|
|
|
@Input()
|
|
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.minAllowedFileSizeException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFileContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFileContainer
|
|
): Observable<IXFileContainer> {
|
|
return forkJoin({
|
|
//
|
|
emptyFileException: this.getValue(
|
|
container ? container.emptyFileException : this.emptyFileException
|
|
),
|
|
notAllowedFileException: this.getValue(
|
|
container
|
|
? container.notAllowedFileException
|
|
: this.notAllowedFileException
|
|
),
|
|
allowedExtensions: this.getValue(
|
|
container ? container.allowedExtensions : this.allowedExtensions
|
|
),
|
|
maxAllowedFiles: this.getValue(
|
|
container ? container.maxAllowedFiles : this.maxAllowedFiles
|
|
),
|
|
maxAllowedFilesException: this.getValue(
|
|
container
|
|
? container.maxAllowedFilesException
|
|
: this.maxAllowedFilesException
|
|
),
|
|
maxAllowedSize: this.getValue(
|
|
container ? container.maxAllowedSize : this.maxAllowedSize
|
|
),
|
|
maxAllowedSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedSizeException
|
|
: this.maxAllowedSizeException
|
|
),
|
|
minAllowedFileSize: this.getValue(
|
|
container ? container.minAllowedFileSize : this.minAllowedFileSize
|
|
),
|
|
minAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.minAllowedFileSizeException
|
|
: this.minAllowedFileSizeException
|
|
),
|
|
maxAllowedFileSize: this.getValue(
|
|
container ? container.maxAllowedFileSize : this.maxAllowedFileSize
|
|
),
|
|
maxAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedFileSizeException
|
|
: this.maxAllowedFileSizeException
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XCardFileContainer ...
|
|
//
|
|
type TXCardFileContainer = IXComponentCardContainer & IXFileContainer;
|
|
export interface IXCardFileContainer extends TXCardFileContainer {}
|
|
|
|
//
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardFileContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXCardFileContainer>
|
|
{
|
|
//
|
|
//#region XComponentCard ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XFile ...
|
|
//
|
|
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.emptyFileException;
|
|
|
|
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.notAllowedFileException;
|
|
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.filePropertyProvider.allowedExtensions;
|
|
|
|
//
|
|
readonly maxAllowedFiles: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFiles;
|
|
|
|
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFilesException;
|
|
|
|
//
|
|
readonly maxAllowedSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedSize;
|
|
|
|
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedSizeException;
|
|
|
|
//
|
|
readonly minAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.minAllowedFileSize;
|
|
|
|
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.minAllowedFileSizeException;
|
|
|
|
//
|
|
readonly maxAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFileSize;
|
|
|
|
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected filePropertyProvider: XFileContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardFileContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardFileContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
//
|
|
@Input()
|
|
emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.emptyFileException;
|
|
|
|
@Input()
|
|
notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.notAllowedFileException;
|
|
|
|
@Input()
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.allowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFiles: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFiles;
|
|
|
|
@Input()
|
|
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFilesException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
|
|
|
|
@Input()
|
|
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedSizeException;
|
|
|
|
//
|
|
@Input()
|
|
minAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.minAllowedFileSize;
|
|
|
|
@Input()
|
|
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.minAllowedFileSizeException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardFileContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardFileContainer
|
|
): Observable<IXCardFileContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
emptyFileException: this.getValue(
|
|
container ? container.emptyFileException : this.emptyFileException
|
|
),
|
|
notAllowedFileException: this.getValue(
|
|
container
|
|
? container.notAllowedFileException
|
|
: this.notAllowedFileException
|
|
),
|
|
allowedExtensions: this.getValue(
|
|
container ? container.allowedExtensions : this.allowedExtensions
|
|
),
|
|
maxAllowedFiles: this.getValue(
|
|
container ? container.maxAllowedFiles : this.maxAllowedFiles
|
|
),
|
|
maxAllowedFilesException: this.getValue(
|
|
container
|
|
? container.maxAllowedFilesException
|
|
: this.maxAllowedFilesException
|
|
),
|
|
maxAllowedSize: this.getValue(
|
|
container ? container.maxAllowedSize : this.maxAllowedSize
|
|
),
|
|
maxAllowedSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedSizeException
|
|
: this.maxAllowedSizeException
|
|
),
|
|
minAllowedFileSize: this.getValue(
|
|
container ? container.minAllowedFileSize : this.minAllowedFileSize
|
|
),
|
|
minAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.minAllowedFileSizeException
|
|
: this.minAllowedFileSizeException
|
|
),
|
|
maxAllowedFileSize: this.getValue(
|
|
container ? container.maxAllowedFileSize : this.maxAllowedFileSize
|
|
),
|
|
maxAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedFileSizeException
|
|
: this.maxAllowedFileSizeException
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XCardFileFileDropAreaContainer ...
|
|
//
|
|
type TXCardFileFileDropContainer = IXComponentCardContainer &
|
|
IXFileContainer &
|
|
IXComponentFileDropAreaContainer;
|
|
export interface IXCardFileFileDropContainer
|
|
extends TXCardFileFileDropContainer {}
|
|
|
|
//
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardFileFileDropContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXCardFileFileDropContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region ComponentCard ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
//
|
|
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.emptyFileException;
|
|
|
|
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.notAllowedFileException;
|
|
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.filePropertyProvider.allowedExtensions;
|
|
|
|
//
|
|
readonly maxAllowedFiles: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFiles;
|
|
|
|
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFilesException;
|
|
|
|
//
|
|
readonly maxAllowedSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedSize;
|
|
|
|
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedSizeException;
|
|
|
|
//
|
|
readonly minAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.minAllowedFileSize;
|
|
|
|
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.minAllowedFileSizeException;
|
|
|
|
//
|
|
readonly maxAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFileSize;
|
|
|
|
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Drop ...
|
|
//
|
|
readonly showFileDropArea: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.showFileDropArea;
|
|
|
|
//
|
|
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.fileDropPropertyProvider.fileDropAreaActionProvider;
|
|
|
|
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.fileDropPropertyProvider.fileDropAreaCssClass;
|
|
|
|
//
|
|
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaColor;
|
|
|
|
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaForegroundColor;
|
|
|
|
//
|
|
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaIcon;
|
|
|
|
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaMessage;
|
|
|
|
//
|
|
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaDisableFileCheck;
|
|
|
|
//
|
|
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
|
|
readonly fileDropAreaAllowedExtensions: XStandardType<
|
|
XOneOrManyType<string>
|
|
> = this.fileDropPropertyProvider.fileDropAreaAllowedExtensions;
|
|
|
|
//
|
|
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaDragDisabled;
|
|
|
|
readonly fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.fileDropPropertyProvider.fileDropAreaContentTemplate;
|
|
|
|
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
this.fileDropPropertyProvider.fileDropAreaFilesChangeEmiter;
|
|
|
|
//
|
|
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaSuccessColor;
|
|
|
|
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaErrorColor;
|
|
|
|
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaAccentColor;
|
|
|
|
//
|
|
//#region ComponentsCard ...
|
|
readonly fileDropAreaIsInPage: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaIsInPage;
|
|
readonly fileDropAreaWrapWithCard: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaWrapWithCard;
|
|
readonly fileDropAreaCardShowFooter: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardShowFooter;
|
|
readonly fileDropAreaCardShowActions: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardShowActions;
|
|
readonly fileDropAreaCardColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardColor;
|
|
readonly fileDropAreaCardForegroundColor: XStandardType<boolean> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardForegroundColor;
|
|
readonly fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardTitle;
|
|
readonly fileDropAreaCardActionProvider: Subject<XCardActionModel> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardActionProvider;
|
|
readonly fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardSubTitle;
|
|
readonly fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.fileDropPropertyProvider.fileDropAreaCardCssClass;
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected fileDropPropertyProvider: XComponentFileDropAreaContainer,
|
|
protected filePropertyProvider: XFileContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardFileFileDropContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardFileContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
//
|
|
@Input()
|
|
emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.emptyFileException;
|
|
|
|
@Input()
|
|
notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.notAllowedFileException;
|
|
|
|
@Input()
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.allowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFiles: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFiles;
|
|
|
|
@Input()
|
|
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFilesException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
|
|
|
|
@Input()
|
|
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedSizeException;
|
|
|
|
//
|
|
@Input()
|
|
minAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.minAllowedFileSize;
|
|
|
|
@Input()
|
|
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.minAllowedFileSizeException;
|
|
|
|
//
|
|
@Input()
|
|
maxAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
|
|
//
|
|
//#region FileDrop ...
|
|
//
|
|
@Input()
|
|
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.propertyProvider.fileDropAreaActionProvider;
|
|
|
|
@Input()
|
|
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaCssClass;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaColor;
|
|
|
|
@Input()
|
|
fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.fileDropAreaIcon;
|
|
|
|
@Input()
|
|
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaMessage;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDisableFileCheck;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
|
|
@Input()
|
|
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaAllowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDragDisabled;
|
|
|
|
@Input()
|
|
fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.fileDropAreaContentTemplate;
|
|
|
|
@Output()
|
|
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaSuccessColor;
|
|
|
|
@Input()
|
|
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaErrorColor;
|
|
|
|
@Input()
|
|
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaAccentColor;
|
|
|
|
//
|
|
@Input()
|
|
showFileDropArea: XStandardType<boolean> =
|
|
this.propertyProvider.showFileDropArea;
|
|
|
|
//
|
|
//#region ComponentsCard ...
|
|
@Input()
|
|
fileDropAreaIsInPage: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaIsInPage;
|
|
|
|
@Input()
|
|
fileDropAreaWrapWithCard: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaWrapWithCard;
|
|
|
|
@Input()
|
|
fileDropAreaCardShowFooter: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardShowFooter;
|
|
|
|
@Input()
|
|
fileDropAreaCardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardShowActions;
|
|
|
|
@Input()
|
|
fileDropAreaCardColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardColor;
|
|
|
|
@Input()
|
|
fileDropAreaCardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardForegroundColor;
|
|
|
|
@Input()
|
|
fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardTitle;
|
|
|
|
@Input()
|
|
fileDropAreaCardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.fileDropAreaCardActionProvider;
|
|
|
|
@Input()
|
|
fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardSubTitle;
|
|
|
|
@Input()
|
|
fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaCardCssClass;
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardFileFileDropContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardFileFileDropContainer
|
|
): Observable<IXCardFileFileDropContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
emptyFileException: this.getValue(
|
|
container ? container.emptyFileException : this.emptyFileException
|
|
),
|
|
notAllowedFileException: this.getValue(
|
|
container
|
|
? container.notAllowedFileException
|
|
: this.notAllowedFileException
|
|
),
|
|
allowedExtensions: this.getValue(
|
|
container ? container.allowedExtensions : this.allowedExtensions
|
|
),
|
|
maxAllowedFiles: this.getValue(
|
|
container ? container.maxAllowedFiles : this.maxAllowedFiles
|
|
),
|
|
maxAllowedFilesException: this.getValue(
|
|
container
|
|
? container.maxAllowedFilesException
|
|
: this.maxAllowedFilesException
|
|
),
|
|
maxAllowedSize: this.getValue(
|
|
container ? container.maxAllowedSize : this.maxAllowedSize
|
|
),
|
|
maxAllowedSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedSizeException
|
|
: this.maxAllowedSizeException
|
|
),
|
|
minAllowedFileSize: this.getValue(
|
|
container ? container.minAllowedFileSize : this.minAllowedFileSize
|
|
),
|
|
minAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.minAllowedFileSizeException
|
|
: this.minAllowedFileSizeException
|
|
),
|
|
maxAllowedFileSize: this.getValue(
|
|
container ? container.maxAllowedFileSize : this.maxAllowedFileSize
|
|
),
|
|
maxAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedFileSizeException
|
|
: this.maxAllowedFileSizeException
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region FileDrop ...
|
|
//
|
|
fileDropAreaCssClass: this.getValue(
|
|
container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass
|
|
),
|
|
fileDropAreaColor: this.getValue(
|
|
container ? container.fileDropAreaColor : this.fileDropAreaColor
|
|
),
|
|
fileDropAreaForegroundColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaForegroundColor
|
|
: this.fileDropAreaForegroundColor
|
|
),
|
|
fileDropAreaIcon: this.getValue(
|
|
container ? container.fileDropAreaIcon : this.fileDropAreaIcon
|
|
),
|
|
fileDropAreaMessage: this.getValue(
|
|
container ? container.fileDropAreaMessage : this.fileDropAreaMessage
|
|
),
|
|
fileDropAreaDisableFileCheck: this.getValue(
|
|
container
|
|
? container.fileDropAreaDisableFileCheck
|
|
: this.fileDropAreaDisableFileCheck
|
|
),
|
|
fileDropAreaSupportsMultipleFiles: this.getValue(
|
|
container
|
|
? container.fileDropAreaSupportsMultipleFiles
|
|
: this.fileDropAreaSupportsMultipleFiles
|
|
),
|
|
fileDropAreaAllowedExtensions: this.getValue(
|
|
container
|
|
? container.fileDropAreaAllowedExtensions
|
|
: this.fileDropAreaAllowedExtensions
|
|
),
|
|
fileDropAreaDragDisabled: this.getValue(
|
|
container
|
|
? container.fileDropAreaDragDisabled
|
|
: this.fileDropAreaDragDisabled
|
|
),
|
|
fileDropAreaContentTemplate: this.getValue(
|
|
container
|
|
? container.fileDropAreaContentTemplate
|
|
: this.fileDropAreaContentTemplate
|
|
),
|
|
fileDropAreaSuccessColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaSuccessColor
|
|
: this.fileDropAreaSuccessColor
|
|
),
|
|
fileDropAreaErrorColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaErrorColor
|
|
: this.fileDropAreaErrorColor
|
|
),
|
|
fileDropAreaAccentColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaAccentColor
|
|
: this.fileDropAreaAccentColor
|
|
),
|
|
showFileDropArea: this.getValue(
|
|
container ? container.showFileDropArea : this.showFileDropArea
|
|
),
|
|
fileDropAreaIsInPage: this.getValue(
|
|
container ? container.fileDropAreaIsInPage : this.fileDropAreaIsInPage
|
|
),
|
|
fileDropAreaWrapWithCard: this.getValue(
|
|
container
|
|
? container.fileDropAreaWrapWithCard
|
|
: this.fileDropAreaWrapWithCard
|
|
),
|
|
fileDropAreaCardShowFooter: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardShowFooter
|
|
: this.fileDropAreaCardShowFooter
|
|
),
|
|
fileDropAreaCardShowActions: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardShowActions
|
|
: this.fileDropAreaCardShowActions
|
|
),
|
|
fileDropAreaCardColor: this.getValue(
|
|
container ? container.fileDropAreaCardColor : this.fileDropAreaCardColor
|
|
),
|
|
fileDropAreaCardForegroundColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardForegroundColor
|
|
: this.fileDropAreaCardForegroundColor
|
|
),
|
|
fileDropAreaCardTitle: this.getValue(
|
|
container ? container.fileDropAreaCardTitle : this.fileDropAreaCardTitle
|
|
),
|
|
fileDropAreaCardSubTitle: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardSubTitle
|
|
: this.fileDropAreaCardSubTitle
|
|
),
|
|
fileDropAreaCardCssClass: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardCssClass
|
|
: this.fileDropAreaCardCssClass
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
fileDropAreaActionProvider: container
|
|
? container.fileDropAreaActionProvider
|
|
: this.fileDropAreaActionProvider,
|
|
|
|
//
|
|
fileDropAreaCardActionProvider: container
|
|
? container.fileDropAreaCardActionProvider
|
|
: this.fileDropAreaCardActionProvider,
|
|
|
|
//
|
|
fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-next-prev-reset.container.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
Output,
|
|
NgZone,
|
|
Renderer2,
|
|
Component,
|
|
Injectable,
|
|
ElementRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from './i-x-base.container';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
} from '../x-card/x-card.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { Observable, forkJoin, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { IXButtonContainer, XButtonType } from '../x-button/x-button.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XSlotNameIdentifier, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
export enum XNPRButtonType {
|
|
Next = 'next',
|
|
Prev = 'prev',
|
|
Reset = 'reset',
|
|
}
|
|
|
|
//
|
|
export type XNPRButtonTypeIdentifier = XNPRButtonType | string;
|
|
|
|
//
|
|
//#region Next ...
|
|
export interface IXNextHost {
|
|
canNext: XStandardType<boolean>;
|
|
onNext: EventEmitter<string>;
|
|
}
|
|
|
|
export interface IXNextContainer extends IXBaseContainer {
|
|
//
|
|
//#region Next ...
|
|
hasNext: XStandardType<boolean>;
|
|
disableNext: XStandardType<boolean>;
|
|
nextConfirmer: () => XStandardType<boolean>;
|
|
nextPosition: XStandardType<XSlotNameIdentifier>;
|
|
nextCssClass: XStandardType<XOneOrManyType<string>>;
|
|
nextButton: XStandardType<Partial<IXButtonContainer>>;
|
|
//#endregion
|
|
}
|
|
|
|
export const defaultNextButton: Partial<IXButtonContainer> = {
|
|
title: XResourceIDs.next,
|
|
type: XButtonType.Raised,
|
|
color: XColorWithBrightness.Primary,
|
|
};
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export abstract class XNextContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXNextContainer>
|
|
{
|
|
//
|
|
//#region Next ...
|
|
readonly hasNext: XStandardType<boolean>;
|
|
readonly disableNext: XStandardType<boolean>;
|
|
readonly nextConfirmer: () => XStandardType<boolean>;
|
|
readonly nextPosition: XStandardType<XSlotNameIdentifier> = XSlotName.START;
|
|
readonly nextCssClass: XStandardType<XOneOrManyType<string>> =
|
|
'ion-text-start';
|
|
readonly nextButton: XStandardType<Partial<IXButtonContainer>> = {
|
|
...defaultNextButton,
|
|
};
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
export interface IXPrevHost {
|
|
canPrev: XStandardType<boolean>;
|
|
onPrev: EventEmitter<string>;
|
|
}
|
|
|
|
export interface IXPrevContainer extends IXBaseContainer {
|
|
//
|
|
//#region Prev ...
|
|
hasPrev: XStandardType<boolean>;
|
|
disablePrev: XStandardType<boolean>;
|
|
prevConfirmer: () => XStandardType<boolean>;
|
|
prevPosition: XStandardType<XSlotNameIdentifier>;
|
|
prevCssClass: XStandardType<XOneOrManyType<string>>;
|
|
prevButton: XStandardType<Partial<IXButtonContainer>>;
|
|
//#endregion
|
|
}
|
|
|
|
export const defaultPrevButton: Partial<IXButtonContainer> = {
|
|
type: XButtonType.Raised,
|
|
title: XResourceIDs.previous,
|
|
color: XColorWithBrightness.Primary,
|
|
};
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export abstract class XPrevContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXPrevContainer>
|
|
{
|
|
//
|
|
//#region Prev ...
|
|
readonly hasPrev: XStandardType<boolean>;
|
|
readonly disablePrev: XStandardType<boolean>;
|
|
readonly prevConfirmer: () => XStandardType<boolean>;
|
|
readonly prevPosition: XStandardType<XSlotNameIdentifier> = XSlotName.END;
|
|
readonly prevCssClass: XStandardType<XOneOrManyType<string>> = 'ion-text-end';
|
|
readonly prevButton: XStandardType<Partial<IXButtonContainer>> = {
|
|
...defaultPrevButton,
|
|
};
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
export interface IXResetHost {
|
|
canReset: XStandardType<boolean>;
|
|
onReset: EventEmitter<string>;
|
|
}
|
|
|
|
export interface IXResetContainer extends IXBaseContainer {
|
|
//
|
|
//#region Reset ...
|
|
hasReset: XStandardType<boolean>;
|
|
disableReset: XStandardType<boolean>;
|
|
resetConfirmer: () => XStandardType<boolean>;
|
|
resetPosition: XStandardType<XSlotNameIdentifier>;
|
|
resetCssClass: XStandardType<XOneOrManyType<string>>;
|
|
resetButton: XStandardType<Partial<IXButtonContainer>>;
|
|
//#endregion
|
|
}
|
|
|
|
export const defaultResetButton: Partial<IXButtonContainer> = {
|
|
type: XButtonType.Raised,
|
|
title: XResourceIDs.reset,
|
|
color: XColorWithBrightness.Warning,
|
|
};
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export abstract class XResetContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXResetContainer>
|
|
{
|
|
//
|
|
//#region Reset ...
|
|
readonly hasReset: XStandardType<boolean>;
|
|
readonly disableReset: XStandardType<boolean>;
|
|
readonly resetConfirmer: () => XStandardType<boolean>;
|
|
readonly resetPosition: XStandardType<XSlotNameIdentifier> = XSlotName.CENTER;
|
|
readonly resetCssClass: XStandardType<XOneOrManyType<string>> =
|
|
'ion-text-center';
|
|
readonly resetButton: XStandardType<Partial<IXButtonContainer>> = {
|
|
...defaultResetButton,
|
|
};
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Combined ...
|
|
//
|
|
//#region Host ...
|
|
//
|
|
type XCompleteHostInterface = IXNextHost & IXPrevHost & IXResetHost;
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface IXNextPrevResetHostContainer extends XCompleteHostInterface {}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XNextPrevResetHostContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXNextPrevResetHostContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Next ...
|
|
readonly canNext: XStandardType<boolean> = true;
|
|
readonly onNext: EventEmitter<string> = new EventEmitter<string>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
readonly canPrev: XStandardType<boolean> = true;
|
|
readonly onPrev: EventEmitter<string> = new EventEmitter<string>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
readonly canReset: XStandardType<boolean> = true;
|
|
readonly onReset: EventEmitter<string> = new EventEmitter<string>();
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XNextPrevResetHostContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXNextPrevResetHostContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Next ...
|
|
@Input()
|
|
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
|
|
|
|
@Output()
|
|
onNext: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
@Input()
|
|
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
|
|
|
|
@Output()
|
|
onPrev: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
@Input()
|
|
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
|
|
|
|
@Output()
|
|
onReset: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XNextPrevResetHostContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXNextPrevResetHostContainer
|
|
): Observable<IXNextPrevResetHostContainer> {
|
|
return forkJoin({
|
|
//
|
|
canNext: this.getValue(container ? container.canNext : this.canNext),
|
|
canPrev: this.getValue(container ? container.canPrev : this.canPrev),
|
|
canReset: this.getValue(container ? container.canReset : this.canReset),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
onNext: this.onNext,
|
|
onPrev: this.onPrev,
|
|
onReset: this.onReset,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XCardHost
|
|
//
|
|
type TXCardEmptyContainer = IXComponentCardContainer &
|
|
IXNextPrevResetHostContainer;
|
|
export interface IXCardNextPrevResetHostContainer
|
|
extends TXCardEmptyContainer {}
|
|
|
|
//
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardNextPrevResetHostContainer
|
|
extends XBaseContainer
|
|
implements IXCardNextPrevResetHostContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XNextPrevResetHost ...
|
|
//
|
|
//#region Next ...
|
|
readonly canNext: XStandardType<boolean> =
|
|
this.nextPrevResetHostPropertyProvider.canNext;
|
|
readonly onNext: EventEmitter<string> =
|
|
this.nextPrevResetHostPropertyProvider.onNext;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
readonly canPrev: XStandardType<boolean> =
|
|
this.nextPrevResetHostPropertyProvider.canPrev;
|
|
readonly onPrev: EventEmitter<string> =
|
|
this.nextPrevResetHostPropertyProvider.onPrev;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
readonly canReset: XStandardType<boolean> =
|
|
this.nextPrevResetHostPropertyProvider.canReset;
|
|
readonly onReset: EventEmitter<string> =
|
|
this.nextPrevResetHostPropertyProvider.onReset;
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected nextPrevResetHostPropertyProvider: XNextPrevResetHostContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XCardNextPrevResetHostContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardNextPrevResetHostContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XNextPrevResetHost ...
|
|
//
|
|
//#region Next ...
|
|
@Input()
|
|
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
|
|
|
|
@Output()
|
|
onNext: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
@Input()
|
|
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
|
|
|
|
@Output()
|
|
onPrev: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
@Input()
|
|
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
|
|
|
|
@Output()
|
|
onReset: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardNextPrevResetHostContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardNextPrevResetHostContainer
|
|
): Observable<IXCardNextPrevResetHostContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XNextPrevResetHost ...
|
|
//
|
|
canNext: this.getValue(container ? container.canNext : this.canNext),
|
|
canPrev: this.getValue(container ? container.canPrev : this.canPrev),
|
|
canReset: this.getValue(container ? container.canReset : this.canReset),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
onNext: this.onNext,
|
|
onPrev: this.onPrev,
|
|
onReset: this.onReset,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Interface ...
|
|
//
|
|
type TXNextPrevResetContainer = IXNextContainer &
|
|
IXPrevContainer &
|
|
IXResetContainer;
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface IXNextPrevResetContainer
|
|
extends IXBaseContainer,
|
|
TXNextPrevResetContainer {}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XNextPrevResetContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXNextPrevResetContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Next ...
|
|
hasNext: XStandardType<boolean> = this.nextPropertyProvider.hasNext;
|
|
disableNext: XStandardType<boolean> = this.nextPropertyProvider.disableNext;
|
|
nextConfirmer: () => XStandardType<boolean> =
|
|
this.nextPropertyProvider.nextConfirmer;
|
|
nextPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.nextPropertyProvider.nextPosition;
|
|
nextCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.nextPropertyProvider.nextCssClass;
|
|
nextButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.nextPropertyProvider.nextButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
hasPrev: XStandardType<boolean> = this.prevPropertyProvider.hasPrev;
|
|
disablePrev: XStandardType<boolean> = this.prevPropertyProvider.disablePrev;
|
|
prevConfirmer: () => XStandardType<boolean> =
|
|
this.prevPropertyProvider.prevConfirmer;
|
|
prevPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.prevPropertyProvider.prevPosition;
|
|
prevCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.prevPropertyProvider.prevCssClass;
|
|
prevButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.prevPropertyProvider.prevButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
hasReset: XStandardType<boolean> = this.resetpropertyProvider.hasReset;
|
|
disableReset: XStandardType<boolean> =
|
|
this.resetpropertyProvider.disableReset;
|
|
resetConfirmer: () => XStandardType<boolean> =
|
|
this.resetpropertyProvider.resetConfirmer;
|
|
resetPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.resetpropertyProvider.resetPosition;
|
|
resetCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.resetpropertyProvider.resetCssClass;
|
|
resetButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.resetpropertyProvider.resetButton;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected prevPropertyProvider: XPrevContainer,
|
|
protected nextPropertyProvider: XNextContainer,
|
|
protected resetpropertyProvider: XResetContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XNextPrevResetContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXNextPrevResetContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Next ...
|
|
@Input()
|
|
hasNext: XStandardType<boolean> = this.propertyProvider.hasNext;
|
|
|
|
@Input()
|
|
disableNext: XStandardType<boolean> = this.propertyProvider.disableNext;
|
|
|
|
@Input()
|
|
nextConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.nextConfirmer;
|
|
|
|
@Input()
|
|
nextPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.nextPosition;
|
|
|
|
@Input()
|
|
nextCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.nextCssClass;
|
|
|
|
@Input()
|
|
nextButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.nextButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
@Input()
|
|
hasPrev: XStandardType<boolean> = this.propertyProvider.hasPrev;
|
|
|
|
@Input()
|
|
disablePrev: XStandardType<boolean> = this.propertyProvider.disablePrev;
|
|
|
|
@Input()
|
|
prevConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.prevConfirmer;
|
|
|
|
@Input()
|
|
prevPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.prevPosition;
|
|
|
|
@Input()
|
|
prevCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.prevCssClass;
|
|
|
|
@Input()
|
|
prevButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.prevButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
@Input()
|
|
hasReset: XStandardType<boolean> = this.propertyProvider.hasReset;
|
|
|
|
@Input()
|
|
disableReset: XStandardType<boolean> = this.propertyProvider.disableReset;
|
|
|
|
@Input()
|
|
resetConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.resetConfirmer;
|
|
|
|
@Input()
|
|
resetPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.resetPosition;
|
|
|
|
@Input()
|
|
resetCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.resetCssClass;
|
|
|
|
@Input()
|
|
resetButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.resetButton;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XNextPrevResetContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXNextPrevResetContainer
|
|
): Observable<IXNextPrevResetContainer> {
|
|
return forkJoin({
|
|
//
|
|
hasNext: this.getValue(container ? container.hasNext : this.hasNext),
|
|
disableNext: this.getValue(
|
|
container ? container.disableNext : this.disableNext
|
|
),
|
|
nextConfirmer: this.getValue(
|
|
container ? container.nextConfirmer : this.nextConfirmer
|
|
),
|
|
nextPosition: this.getValue(
|
|
container ? container.nextPosition : this.nextPosition
|
|
),
|
|
nextCssClass: this.getValue(
|
|
container ? container.nextCssClass : this.nextCssClass
|
|
),
|
|
nextButton: this.getValue(
|
|
container ? container.nextButton : this.nextButton
|
|
),
|
|
hasPrev: this.getValue(container ? container.hasPrev : this.hasPrev),
|
|
disablePrev: this.getValue(
|
|
container ? container.disablePrev : this.disablePrev
|
|
),
|
|
prevConfirmer: this.getValue(
|
|
container ? container.prevConfirmer : this.prevConfirmer
|
|
),
|
|
prevPosition: this.getValue(
|
|
container ? container.prevPosition : this.prevPosition
|
|
),
|
|
prevCssClass: this.getValue(
|
|
container ? container.prevCssClass : this.prevCssClass
|
|
),
|
|
prevButton: this.getValue(
|
|
container ? container.prevButton : this.prevButton
|
|
),
|
|
hasReset: this.getValue(container ? container.hasReset : this.hasReset),
|
|
disableReset: this.getValue(
|
|
container ? container.disableReset : this.disableReset
|
|
),
|
|
resetConfirmer: this.getValue(
|
|
container ? container.resetConfirmer : this.resetConfirmer
|
|
),
|
|
resetPosition: this.getValue(
|
|
container ? container.resetPosition : this.resetPosition
|
|
),
|
|
resetCssClass: this.getValue(
|
|
container ? container.resetCssClass : this.resetCssClass
|
|
),
|
|
resetButton: this.getValue(
|
|
container ? container.resetButton : this.resetButton
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region IXNextPrevResetAndHostContainer ...
|
|
type TXNextPrevResetAndHostContainer = IXNextPrevResetContainer &
|
|
IXCardNextPrevResetHostContainer;
|
|
export interface IXNextPrevResetAndHostContainer
|
|
extends IXBaseContainer,
|
|
TXNextPrevResetAndHostContainer {}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XNextPrevResetAndHostContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXNextPrevResetAndHostContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Inteface ...
|
|
//
|
|
//#region Next ...
|
|
hasNext: XStandardType<boolean> = this.nextPrevResetPropertyProvider.hasNext;
|
|
disableNext: XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.disableNext;
|
|
nextConfirmer: () => XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.nextConfirmer;
|
|
nextPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.nextPrevResetPropertyProvider.nextPosition;
|
|
nextCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.nextPrevResetPropertyProvider.nextCssClass;
|
|
nextButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.nextPrevResetPropertyProvider.nextButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
hasPrev: XStandardType<boolean> = this.nextPrevResetPropertyProvider.hasPrev;
|
|
disablePrev: XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.disablePrev;
|
|
prevConfirmer: () => XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.prevConfirmer;
|
|
prevPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.nextPrevResetPropertyProvider.prevPosition;
|
|
prevCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.nextPrevResetPropertyProvider.prevCssClass;
|
|
prevButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.nextPrevResetPropertyProvider.prevButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
hasReset: XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.hasReset;
|
|
disableReset: XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.disableReset;
|
|
resetConfirmer: () => XStandardType<boolean> =
|
|
this.nextPrevResetPropertyProvider.resetConfirmer;
|
|
resetPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.nextPrevResetPropertyProvider.resetPosition;
|
|
resetCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.nextPrevResetPropertyProvider.resetCssClass;
|
|
resetButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.nextPrevResetPropertyProvider.resetButton;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Host ...
|
|
//
|
|
//#region Next ...
|
|
readonly canNext: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.canNext;
|
|
readonly onNext: EventEmitter<string> =
|
|
this.cardNextPrevResetPropertyProvider.onNext;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
readonly canPrev: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.canPrev;
|
|
readonly onPrev: EventEmitter<string> =
|
|
this.cardNextPrevResetPropertyProvider.onPrev;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
readonly canReset: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.canReset;
|
|
readonly onReset: EventEmitter<string> =
|
|
this.cardNextPrevResetPropertyProvider.onReset;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentCard ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.wrapWithCard;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.cardShowActions;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardNextPrevResetPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardNextPrevResetPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardNextPrevResetPropertyProvider.cardTitle;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardNextPrevResetPropertyProvider.cardActionProvider;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardNextPrevResetPropertyProvider.cardSubTitle;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardNextPrevResetPropertyProvider.cardCssClass;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected nextPrevResetPropertyProvider: XNextPrevResetContainer,
|
|
protected cardNextPrevResetPropertyProvider: XCardNextPrevResetHostContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XNextPrevResetAndHostContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXNextPrevResetAndHostContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region XComponentCard ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XNextPrevResetHost ...
|
|
//
|
|
//#region Next ...
|
|
@Input()
|
|
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
|
|
|
|
@Output()
|
|
onNext: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
@Input()
|
|
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
|
|
|
|
@Output()
|
|
onPrev: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
@Input()
|
|
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
|
|
|
|
@Output()
|
|
onReset: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Next ...
|
|
@Input()
|
|
hasNext: XStandardType<boolean> = this.propertyProvider.hasNext;
|
|
|
|
@Input()
|
|
disableNext: XStandardType<boolean> = this.propertyProvider.disableNext;
|
|
|
|
@Input()
|
|
nextConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.nextConfirmer;
|
|
|
|
@Input()
|
|
nextPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.nextPosition;
|
|
|
|
@Input()
|
|
nextCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.nextCssClass;
|
|
|
|
@Input()
|
|
nextButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.nextButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prev ...
|
|
@Input()
|
|
hasPrev: XStandardType<boolean> = this.propertyProvider.hasPrev;
|
|
|
|
@Input()
|
|
disablePrev: XStandardType<boolean> = this.propertyProvider.disablePrev;
|
|
|
|
@Input()
|
|
prevConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.prevConfirmer;
|
|
|
|
@Input()
|
|
prevPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.prevPosition;
|
|
|
|
@Input()
|
|
prevCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.prevCssClass;
|
|
|
|
@Input()
|
|
prevButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.prevButton;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reset ...
|
|
@Input()
|
|
hasReset: XStandardType<boolean> = this.propertyProvider.hasReset;
|
|
|
|
@Input()
|
|
disableReset: XStandardType<boolean> = this.propertyProvider.disableReset;
|
|
|
|
@Input()
|
|
resetConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.resetConfirmer;
|
|
|
|
@Input()
|
|
resetPosition: XStandardType<XSlotNameIdentifier> =
|
|
this.propertyProvider.resetPosition;
|
|
|
|
@Input()
|
|
resetCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.resetCssClass;
|
|
|
|
@Input()
|
|
resetButton: XStandardType<Partial<IXButtonContainer>> =
|
|
this.propertyProvider.resetButton;
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XNextPrevResetAndHostContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXNextPrevResetAndHostContainer
|
|
): Observable<IXNextPrevResetAndHostContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XNextPrevResetHost ...
|
|
//
|
|
canNext: this.getValue(container ? container.canNext : this.canNext),
|
|
canPrev: this.getValue(container ? container.canPrev : this.canPrev),
|
|
canReset: this.getValue(container ? container.canReset : this.canReset),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Interface ...
|
|
//
|
|
hasNext: this.getValue(container ? container.hasNext : this.hasNext),
|
|
disableNext: this.getValue(
|
|
container ? container.disableNext : this.disableNext
|
|
),
|
|
nextConfirmer: this.getValue(
|
|
container ? container.nextConfirmer : this.nextConfirmer
|
|
),
|
|
nextPosition: this.getValue(
|
|
container ? container.nextPosition : this.nextPosition
|
|
),
|
|
nextCssClass: this.getValue(
|
|
container ? container.nextCssClass : this.nextCssClass
|
|
),
|
|
nextButton: this.getValue(
|
|
container ? container.nextButton : this.nextButton
|
|
),
|
|
hasPrev: this.getValue(container ? container.hasPrev : this.hasPrev),
|
|
disablePrev: this.getValue(
|
|
container ? container.disablePrev : this.disablePrev
|
|
),
|
|
prevConfirmer: this.getValue(
|
|
container ? container.prevConfirmer : this.prevConfirmer
|
|
),
|
|
prevPosition: this.getValue(
|
|
container ? container.prevPosition : this.prevPosition
|
|
),
|
|
prevCssClass: this.getValue(
|
|
container ? container.prevCssClass : this.prevCssClass
|
|
),
|
|
prevButton: this.getValue(
|
|
container ? container.prevButton : this.prevButton
|
|
),
|
|
hasReset: this.getValue(container ? container.hasReset : this.hasReset),
|
|
disableReset: this.getValue(
|
|
container ? container.disableReset : this.disableReset
|
|
),
|
|
resetConfirmer: this.getValue(
|
|
container ? container.resetConfirmer : this.resetConfirmer
|
|
),
|
|
resetPosition: this.getValue(
|
|
container ? container.resetPosition : this.resetPosition
|
|
),
|
|
resetCssClass: this.getValue(
|
|
container ? container.resetCssClass : this.resetCssClass
|
|
),
|
|
resetButton: this.getValue(
|
|
container ? container.resetButton : this.resetButton
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
onNext: this.onNext,
|
|
onPrev: this.onPrev,
|
|
onReset: this.onReset,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-toolbar-footer.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBackSlotIdentifier,
|
|
XLogoSlotIdentifier,
|
|
XMenuSlotIdentifier,
|
|
XTitleSlotIdentifier,
|
|
XContentSlotIdentifier,
|
|
} from '../x-page/x-page.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XFooterActionModel,
|
|
XComponentFooterContainer,
|
|
IXComponentFooterContainer,
|
|
} from '../x-page/x-footer/x-footer.typings';
|
|
import {
|
|
XToolbarActionModel,
|
|
XComponentToolbarContainer,
|
|
IXComponentToolbarContainer,
|
|
} from '../x-page/x-toolbar/x-toolbar.typings';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XBaseContainer, XBaseContainerComponent } from './i-x-base.container';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Container ...
|
|
type TXToolbarFooterContainer = IXComponentToolbarContainer &
|
|
IXComponentFooterContainer;
|
|
export interface IXToolbarFooterContainer extends TXToolbarFooterContainer {}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XToolbarFooterContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXToolbarFooterContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Toolbar ...
|
|
//
|
|
readonly showToolbar: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.showToolbar;
|
|
|
|
//
|
|
readonly toolbarActionProvider: Subject<XToolbarActionModel> =
|
|
this.toolbarPropertyProvider.toolbarActionProvider;
|
|
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.toolbarPropertyProvider.toolbarCssClass;
|
|
|
|
//
|
|
readonly toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarColor;
|
|
|
|
//
|
|
readonly toolbarShowProgressBar: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowProgressBar;
|
|
readonly toolbarProgressBarColor: XStandardType<XColorIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarProgressBarColor;
|
|
|
|
//
|
|
readonly toolbarShowTitle: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowTitle;
|
|
readonly toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarTitleSlot;
|
|
readonly toolbarTitle: XStandardType<string> =
|
|
this.toolbarPropertyProvider.toolbarTitle;
|
|
|
|
//
|
|
readonly toolbarShowSubTitle: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowSubTitle;
|
|
readonly toolbarSubTitle: XStandardType<string> =
|
|
this.toolbarPropertyProvider.toolbarSubTitle;
|
|
|
|
//
|
|
readonly toolbarShowLogo: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowLogo;
|
|
readonly toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarLogoSlot;
|
|
readonly toolbarLogoUrl: XStandardType<string> =
|
|
this.toolbarPropertyProvider.toolbarLogoUrl;
|
|
|
|
//
|
|
readonly toolbarHasBack: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarHasBack;
|
|
readonly toolbarShowBack: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowBack;
|
|
readonly toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarBackSlot;
|
|
readonly toolbarBackHandler?: () => XStandardType<void> =
|
|
this.toolbarPropertyProvider.toolbarBackHandler;
|
|
readonly toolbarDefaultHref: string =
|
|
this.toolbarPropertyProvider.toolbarDefaultHref;
|
|
|
|
//
|
|
readonly toolbarHasMenu: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarHasMenu;
|
|
readonly toolbarShowMenu: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarShowMenu;
|
|
readonly toolbarAutoHideMenu: XStandardType<boolean> =
|
|
this.toolbarPropertyProvider.toolbarAutoHideMenu;
|
|
readonly toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarMenuSlot;
|
|
|
|
//
|
|
readonly toolbarStartSlotButtonsTemplate: TemplateRef<any> =
|
|
this.toolbarPropertyProvider.toolbarStartSlotButtonsTemplate;
|
|
readonly toolbarEndSlotButtonsTemplate: TemplateRef<any> =
|
|
this.toolbarPropertyProvider.toolbarEndSlotButtonsTemplate;
|
|
|
|
//
|
|
readonly toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.toolbarPropertyProvider.toolbarContentSlot;
|
|
readonly toolbarContentTemplate: TemplateRef<any> =
|
|
this.toolbarPropertyProvider.toolbarContentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
//
|
|
readonly showFooter: XStandardType<boolean> =
|
|
this.footerPropertyProvider.showFooter;
|
|
|
|
//
|
|
readonly footerActionProvider: Subject<XFooterActionModel> =
|
|
this.footerPropertyProvider.footerActionProvider;
|
|
readonly footerCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.footerPropertyProvider.footerCssClass;
|
|
|
|
//
|
|
readonly footerColor: XStandardType<XColorIdentifier> =
|
|
this.footerPropertyProvider.footerColor;
|
|
readonly footerContentTemplate: TemplateRef<any> =
|
|
this.footerPropertyProvider.footerContentTemplate;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected toolbarPropertyProvider: XComponentToolbarContainer,
|
|
protected footerPropertyProvider: XComponentFooterContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XToolbarFooterContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXToolbarFooterContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Toolbar ...
|
|
//
|
|
@Input()
|
|
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
|
|
|
|
//
|
|
@Input()
|
|
toolbarActionProvider: Subject<XToolbarActionModel> =
|
|
this.propertyProvider.toolbarActionProvider;
|
|
|
|
@Input()
|
|
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.toolbarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowProgressBar;
|
|
|
|
@Input()
|
|
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarProgressBarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowTitle;
|
|
|
|
@Input()
|
|
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.propertyProvider.toolbarTitleSlot;
|
|
|
|
@Input()
|
|
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowSubTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowSubTitle;
|
|
|
|
@Input()
|
|
toolbarSubTitle: XStandardType<string> =
|
|
this.propertyProvider.toolbarSubTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowLogo: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowLogo;
|
|
|
|
@Input()
|
|
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
|
|
this.propertyProvider.toolbarLogoSlot;
|
|
|
|
@Input()
|
|
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
|
|
|
|
@Input()
|
|
toolbarShowBack: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowBack;
|
|
|
|
@Input()
|
|
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
|
|
this.propertyProvider.toolbarBackSlot;
|
|
|
|
@Input()
|
|
toolbarBackHandler?: () => XStandardType<void> =
|
|
this.propertyProvider.toolbarBackHandler;
|
|
|
|
@Input()
|
|
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
|
|
|
|
@Input()
|
|
toolbarShowMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowMenu;
|
|
|
|
@Input()
|
|
toolbarAutoHideMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarAutoHideMenu;
|
|
|
|
@Input()
|
|
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
|
|
this.propertyProvider.toolbarMenuSlot;
|
|
|
|
//
|
|
@Input()
|
|
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarStartSlotButtonsTemplate;
|
|
|
|
@Input()
|
|
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarEndSlotButtonsTemplate;
|
|
|
|
//
|
|
@Input()
|
|
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.propertyProvider.toolbarContentSlot;
|
|
|
|
@Input()
|
|
toolbarContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarContentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
//
|
|
@Input()
|
|
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
|
|
|
|
//
|
|
@Input()
|
|
footerActionProvider: Subject<XFooterActionModel> =
|
|
this.propertyProvider.footerActionProvider;
|
|
|
|
@Input()
|
|
footerCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.footerCssClass;
|
|
|
|
//
|
|
@Input()
|
|
footerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.footerColor;
|
|
|
|
@Input()
|
|
footerContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.footerContentTemplate;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XToolbarFooterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXToolbarFooterContainer
|
|
): Observable<IXToolbarFooterContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region Toolbar ...
|
|
showToolbar: this.getValue(
|
|
container ? container.showToolbar : this.showToolbar
|
|
),
|
|
toolbarCssClass: this.getValue(
|
|
container ? container.toolbarCssClass : this.toolbarCssClass
|
|
),
|
|
toolbarColor: this.getValue(
|
|
container ? container.toolbarColor : this.toolbarColor
|
|
),
|
|
toolbarShowProgressBar: this.getValue(
|
|
container
|
|
? container.toolbarShowProgressBar
|
|
: this.toolbarShowProgressBar
|
|
),
|
|
toolbarProgressBarColor: this.getValue(
|
|
container
|
|
? container.toolbarProgressBarColor
|
|
: this.toolbarProgressBarColor
|
|
),
|
|
toolbarShowTitle: this.getValue(
|
|
container ? container.toolbarShowTitle : this.toolbarShowTitle
|
|
),
|
|
toolbarTitleSlot: this.getValue(
|
|
container ? container.toolbarTitleSlot : this.toolbarTitleSlot
|
|
),
|
|
toolbarTitle: this.getValue(
|
|
container ? container.toolbarTitle : this.toolbarTitle
|
|
),
|
|
toolbarShowSubTitle: this.getValue(
|
|
container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle
|
|
),
|
|
toolbarSubTitle: this.getValue(
|
|
container ? container.toolbarSubTitle : this.toolbarSubTitle
|
|
),
|
|
toolbarShowLogo: this.getValue(
|
|
container ? container.toolbarShowLogo : this.toolbarShowLogo
|
|
),
|
|
toolbarLogoSlot: this.getValue(
|
|
container ? container.toolbarLogoSlot : this.toolbarLogoSlot
|
|
),
|
|
toolbarLogoUrl: this.getValue(
|
|
container ? container.toolbarLogoUrl : this.toolbarLogoUrl
|
|
),
|
|
toolbarHasBack: this.getValue(
|
|
container ? container.toolbarHasBack : this.toolbarHasBack
|
|
),
|
|
toolbarShowBack: this.getValue(
|
|
container ? container.toolbarShowBack : this.toolbarShowBack
|
|
),
|
|
toolbarBackSlot: this.getValue(
|
|
container ? container.toolbarBackSlot : this.toolbarBackSlot
|
|
),
|
|
toolbarBackHandler: this.getValue(
|
|
container ? container.toolbarBackHandler : this.toolbarBackHandler
|
|
),
|
|
toolbarDefaultHref: this.getValue(
|
|
container ? container.toolbarDefaultHref : this.toolbarDefaultHref
|
|
),
|
|
toolbarHasMenu: this.getValue(
|
|
container ? container.toolbarHasMenu : this.toolbarHasMenu
|
|
),
|
|
toolbarShowMenu: this.getValue(
|
|
container ? container.toolbarShowMenu : this.toolbarShowMenu
|
|
),
|
|
toolbarAutoHideMenu: this.getValue(
|
|
container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu
|
|
),
|
|
toolbarMenuSlot: this.getValue(
|
|
container ? container.toolbarMenuSlot : this.toolbarMenuSlot
|
|
),
|
|
toolbarStartSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarStartSlotButtonsTemplate
|
|
: this.toolbarStartSlotButtonsTemplate
|
|
),
|
|
toolbarEndSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarEndSlotButtonsTemplate
|
|
: this.toolbarEndSlotButtonsTemplate
|
|
),
|
|
toolbarContentSlot: this.getValue(
|
|
container ? container.toolbarContentSlot : this.toolbarContentSlot
|
|
),
|
|
toolbarContentTemplate: this.getValue(
|
|
container
|
|
? container.toolbarContentTemplate
|
|
: this.toolbarContentTemplate
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
showFooter: this.getValue(
|
|
container ? container.showFooter : this.showFooter
|
|
),
|
|
footerCssClass: this.getValue(
|
|
container ? container.footerCssClass : this.footerCssClass
|
|
),
|
|
footerColor: this.getValue(
|
|
container ? container.footerColor : this.footerColor
|
|
),
|
|
footerContentTemplate: this.getValue(
|
|
container ? container.footerContentTemplate : this.footerContentTemplate
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
toolbarActionProvider: container
|
|
? container.toolbarActionProvider
|
|
: this.toolbarActionProvider,
|
|
|
|
//
|
|
footerActionProvider: container
|
|
? container.footerActionProvider
|
|
: this.footerActionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-action.model.ts
|
|
|
|
export interface XBaseActionModel<T> {
|
|
action: T;
|
|
payload?: any;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-component.ts
|
|
|
|
import {
|
|
Input,
|
|
OnInit,
|
|
Inject,
|
|
Output,
|
|
NgZone,
|
|
OnDestroy,
|
|
Component,
|
|
Renderer2,
|
|
OnChanges,
|
|
ElementRef,
|
|
EventEmitter,
|
|
AfterViewInit,
|
|
SimpleChanges,
|
|
AfterContentInit,
|
|
AfterViewChecked,
|
|
ChangeDetectorRef,
|
|
AfterContentChecked,
|
|
} from '@angular/core';
|
|
import {
|
|
tap,
|
|
map,
|
|
first,
|
|
filter,
|
|
takeUntil,
|
|
concatMap,
|
|
catchError,
|
|
} from 'rxjs/operators';
|
|
import {
|
|
keys,
|
|
XTask,
|
|
XColor,
|
|
XParam,
|
|
toArray,
|
|
getValue,
|
|
notValue,
|
|
isNumber,
|
|
XUiEvent,
|
|
hasChild,
|
|
XRenderer,
|
|
isFunction,
|
|
XException,
|
|
formatDate,
|
|
isValueDate,
|
|
applyLocale,
|
|
toObservable,
|
|
XResourceIDs,
|
|
XExceptionIDs,
|
|
XStandardType,
|
|
fromUtcString,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
stringFormatter,
|
|
getDefaultValue,
|
|
XFormControlState,
|
|
isNullOrUndefined,
|
|
getErrorException,
|
|
getDateFormatString,
|
|
isNullOrEmptyString,
|
|
XResourceIdentifier,
|
|
XExceptionIdentifier,
|
|
XModalButtonRoleIdentifier,
|
|
nameof,
|
|
generateUuid,
|
|
XKey,
|
|
} from 'x-framework-core';
|
|
import { NgModel } from '@angular/forms';
|
|
import { NavigationExtras } from '@angular/router';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { IXBaseObservableTools } from './x-base.observable.tools';
|
|
import { Subject, of, Observable, throwError, forkJoin } from 'rxjs';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
import { XBaseActionModel } from './x-base-action.model';
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XBaseComponent
|
|
extends XRenderer
|
|
implements
|
|
OnInit,
|
|
OnDestroy,
|
|
OnChanges,
|
|
AfterViewInit,
|
|
AfterViewChecked,
|
|
AfterContentInit,
|
|
AfterContentChecked,
|
|
IXBaseObservableTools
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
public readonly isMobileUi$ = this.managerService.isMobileUi$;
|
|
public readonly isNotMobileUi$ = this.managerService.isNotMobileUi$;
|
|
|
|
//
|
|
public readonly ResourceIDs = Object.assign({}, XResourceIDs);
|
|
public readonly ExceptionIDs = Object.assign({}, XExceptionIDs);
|
|
|
|
//
|
|
public TaskRepo: XTask<any>[] = [];
|
|
public RunningTasks: XTask<any>[] = [];
|
|
|
|
//
|
|
public unsubscriber = new Subject();
|
|
|
|
//
|
|
protected applyThemeColors = false;
|
|
|
|
/**
|
|
* Unique Component Identifier ...
|
|
*/
|
|
readonly uuid = generateUuid('X[' + this.constructor.name + ']');
|
|
|
|
//
|
|
//#region Component reload ...
|
|
private SHOW_COMPONENT: boolean = true;
|
|
set showComponent(v: boolean) {
|
|
//
|
|
if (this.SHOW_COMPONENT !== v) {
|
|
this.onComponentVisibilityChanged(v);
|
|
}
|
|
|
|
//
|
|
this.SHOW_COMPONENT = v;
|
|
}
|
|
get showComponent() {
|
|
return this.SHOW_COMPONENT;
|
|
}
|
|
async reloadComponent(delay?: number) {
|
|
//
|
|
if (!isNullOrUndefined(delay) && delay < 100) {
|
|
delay = 100;
|
|
}
|
|
|
|
//
|
|
this.showComponent = false;
|
|
this.detectChanges();
|
|
return this.waitForElement(this.element.nativeElement.tagName).then(
|
|
(el) => {
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
this.showComponent = true;
|
|
this.detectChanges();
|
|
}, delay);
|
|
}
|
|
);
|
|
}
|
|
onComponentVisibilityChanged(visible: boolean) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Loading ...
|
|
/**
|
|
* Notifiy Loading Changed ...
|
|
*/
|
|
@Output()
|
|
loadingNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
private LOADING: boolean = false;
|
|
|
|
/**
|
|
* Loading State of Component Representation ...
|
|
*/
|
|
@Input()
|
|
set loading(v: boolean) {
|
|
//
|
|
this.LOADING = v;
|
|
this.onLoading(v);
|
|
this.loadingNotifier.emit({ id: this.uuid, state: v });
|
|
}
|
|
get loading() {
|
|
return this.LOADING;
|
|
}
|
|
|
|
onLoading(state: boolean) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Disabled ...
|
|
/**
|
|
* Notifiy Ui Disabled Changed ...
|
|
*/
|
|
@Output()
|
|
uiDisabledNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
private UI_DISABLED: boolean = false;
|
|
|
|
/**
|
|
* Set UI State Disables / Enabled of Component ...
|
|
*/
|
|
@Input()
|
|
set uiDisabled(v: boolean) {
|
|
//
|
|
this.UI_DISABLED = v;
|
|
this.onUiDisabled(v);
|
|
this.uiDisabledNotifier.emit({ id: this.uuid, state: v });
|
|
}
|
|
get uiDisabled() {
|
|
return this.UI_DISABLED;
|
|
}
|
|
|
|
onUiDisabled(state: boolean) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Error ...
|
|
/**
|
|
* Notify Error Changed ...
|
|
*/
|
|
errorNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
private ERROR: XException = undefined;
|
|
|
|
/**
|
|
* Set Specified Error of Component if Exists ...
|
|
*/
|
|
@Input()
|
|
set error(v: XException) {
|
|
//
|
|
this.ERROR = v;
|
|
this.onError(v);
|
|
|
|
//
|
|
const hasError = isNullOrUndefined(v);
|
|
this.errorNotifier.emit({ id: this.uuid, state: hasError });
|
|
}
|
|
get error() {
|
|
return this.ERROR;
|
|
}
|
|
|
|
onError(error: XException) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Lock ...
|
|
/**
|
|
* Notify Lock Changed ...
|
|
*/
|
|
@Output()
|
|
lockNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
private LOCK: boolean = false;
|
|
|
|
/**
|
|
* Specified Component Locked or not ...
|
|
*/
|
|
@Input()
|
|
set lock(v: boolean) {
|
|
//
|
|
this.LOCK = v;
|
|
this.onLock(v);
|
|
this.lockNotifier.emit({ id: this.uuid, state: v });
|
|
}
|
|
get lock() {
|
|
return this.LOCK;
|
|
}
|
|
|
|
onLock(state: boolean) {}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef
|
|
) {
|
|
super(config, element, renderer, ruler, zone);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracted ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
ngOnInit(): void {
|
|
//
|
|
this.clearTasks();
|
|
this.registerComponentHandlers();
|
|
|
|
//
|
|
this.onInit();
|
|
}
|
|
|
|
ngAfterViewInit(): void {
|
|
//
|
|
this.registerViewHandlers();
|
|
|
|
//
|
|
// Apply theme Colors only when it's required ...
|
|
if (this.applyThemeColors) {
|
|
this.managerService.themeManagerService
|
|
.applyCurrentTheme(this.element)
|
|
.then(() => this.detectChanges());
|
|
}
|
|
|
|
//
|
|
// Handle Apply Manager Service UI State Changed Events is Base Components ...
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.uiStateChanged.asObservable()
|
|
).subscribe((state) => {
|
|
//
|
|
if (state === XUiEvent.StartLoading && !this.loading) {
|
|
this.loading = true;
|
|
} else if (state === XUiEvent.StopLoading && this.loading) {
|
|
this.loading = false;
|
|
} else if (state === XUiEvent.Disabled && !this.uiDisabled) {
|
|
this.uiDisabled = true;
|
|
} else if (state === XUiEvent.Enabled && this.uiDisabled) {
|
|
this.uiDisabled = false;
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
|
|
//
|
|
// Set UUID attribute ...
|
|
this.setAttribute('xFramework', this.uuid);
|
|
|
|
//
|
|
this.afterViewInit();
|
|
}
|
|
|
|
ngAfterViewChecked(): void {
|
|
this.afterViewChecked();
|
|
}
|
|
|
|
ngAfterContentInit(): void {
|
|
this.afterContentInit();
|
|
}
|
|
|
|
ngAfterContentChecked(): void {
|
|
this.afterContentChecked();
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
//
|
|
this.clearTasks();
|
|
this.unregisterHandlers();
|
|
|
|
//
|
|
this.onDestroy();
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges): void {
|
|
//
|
|
const changeKeys = keys(changes);
|
|
|
|
//
|
|
let isChanged = false;
|
|
let applyChanges = false;
|
|
|
|
//
|
|
// Error Changes ...
|
|
isChanged = changeKeys.includes(nameof<XBaseComponent>('error'));
|
|
if (isChanged) {
|
|
//
|
|
const hasError = !isNullOrUndefined(this.error);
|
|
if (hasError) {
|
|
this.addClass('x-has-error');
|
|
} else {
|
|
this.removeClass('x-has-error');
|
|
}
|
|
|
|
//
|
|
applyChanges = true;
|
|
this.onError(this.error);
|
|
this.errorNotifier.emit({ id: this.uuid, state: hasError });
|
|
}
|
|
|
|
//
|
|
// Loading Changes ...
|
|
isChanged = changeKeys.includes(nameof<XBaseComponent>('loading'));
|
|
if (isChanged) {
|
|
//
|
|
if (this.loading) {
|
|
this.addClass('x-loading');
|
|
} else {
|
|
this.removeClass('x-loading');
|
|
}
|
|
|
|
//
|
|
applyChanges = true;
|
|
this.onLoading(this.loading);
|
|
this.loadingNotifier.emit({ id: this.uuid, state: this.loading });
|
|
}
|
|
|
|
//
|
|
// uiDisabled Changes ...
|
|
isChanged = changeKeys.includes(nameof<XBaseComponent>('uiDisabled'));
|
|
if (isChanged) {
|
|
//
|
|
if (this.uiDisabled) {
|
|
this.addClass('x-disabled');
|
|
} else {
|
|
this.removeClass('x-disabled');
|
|
}
|
|
|
|
//
|
|
applyChanges = true;
|
|
this.onUiDisabled(this.uiDisabled);
|
|
this.uiDisabledNotifier.emit({ id: this.uuid, state: this.uiDisabled });
|
|
}
|
|
|
|
//
|
|
// Lock Change ...
|
|
isChanged = changeKeys.includes(nameof<XBaseComponent>('lock'));
|
|
if (isChanged) {
|
|
//
|
|
if (this.lock) {
|
|
this.addClass('x-locked');
|
|
} else {
|
|
this.removeClass('x-locked');
|
|
}
|
|
|
|
//
|
|
applyChanges = true;
|
|
this.onLock(this.lock);
|
|
this.lockNotifier.emit({ id: this.uuid, state: this.lock });
|
|
}
|
|
|
|
//
|
|
if (applyChanges) {
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
this.onChange(changeKeys);
|
|
}
|
|
|
|
//
|
|
//#region Ionic LifeCycles ...
|
|
ionViewWillEnter() {
|
|
this.willEnter();
|
|
}
|
|
|
|
ionViewDidEnter() {
|
|
this.didEnter();
|
|
}
|
|
|
|
ionViewWillLeave() {
|
|
this.willLeave();
|
|
}
|
|
|
|
ionViewDidLeave() {
|
|
this.didLeave();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracted LifeCycles ...
|
|
public onInit() {}
|
|
|
|
public willEnter() {}
|
|
|
|
public didEnter() {}
|
|
|
|
public afterViewInit() {}
|
|
|
|
public afterViewChecked() {}
|
|
|
|
public afterContentInit() {}
|
|
|
|
public afterContentChecked() {}
|
|
|
|
public onChange(changeKeys: string[]) {}
|
|
|
|
public willLeave() {}
|
|
|
|
public didLeave() {}
|
|
|
|
public onDestroy() {}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Providers ...
|
|
public registerInstanceHandlers(): void {}
|
|
public registerViewHandlers(): void {}
|
|
|
|
/**
|
|
* Retrieve Specified Property Names ...
|
|
*/
|
|
getFieldName<T>(obj: T, name: XKey<T>): string {
|
|
return name.toString();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Notifier Handlers ...
|
|
public onResize(event?: Event) {}
|
|
|
|
/**
|
|
* notify a Task Start ...
|
|
*
|
|
* @param name task name
|
|
*/
|
|
public onTaskStart(name: string, task: XTask<any>) {}
|
|
|
|
/**
|
|
* notify an error on running task ...
|
|
*
|
|
* @param name task name
|
|
* @param task task object
|
|
*/
|
|
public onTaskFailed(name: string, task: XTask<any>) {}
|
|
|
|
/**
|
|
* notify a task finished successfully ...
|
|
*
|
|
* @param name task name
|
|
* @param task task object
|
|
*/
|
|
public onTaskFinished(name: string, task: XTask<any>) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handlers ...
|
|
/**
|
|
* Clear Error of Component ...
|
|
*/
|
|
public clearError() {
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
this.error = null;
|
|
this.managerService.error = null;
|
|
}, 500);
|
|
}
|
|
|
|
/**
|
|
* show error ...
|
|
*/
|
|
public showError(
|
|
exception:
|
|
| Error
|
|
| string
|
|
| XException
|
|
| XExceptionIDs
|
|
| XExceptionIdentifier
|
|
| any = undefined,
|
|
next?: () => void
|
|
) {
|
|
//
|
|
let mException: any = getErrorException(exception);
|
|
if (isNullOrUndefined(mException) && !isNullOrUndefined(this.error)) {
|
|
mException = this.error;
|
|
} else if (isNullOrUndefined(mException)) {
|
|
mException = XExceptionIDs.ActionFailed;
|
|
}
|
|
|
|
//
|
|
this.managerService.notificationService.presentErrorNotification({
|
|
exception: mException,
|
|
dissmissable: true,
|
|
onWillDismiss: () => {
|
|
//
|
|
this.clearError();
|
|
|
|
//
|
|
if (next && isFunction(next)) {
|
|
next();
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* handle error state ...
|
|
*/
|
|
public async handleErrorState(
|
|
exception?: XExceptionIdentifier,
|
|
presentNotification: boolean = true,
|
|
redirectToUrl?: string,
|
|
returnUrl?: string,
|
|
params?: NavigationExtras,
|
|
duration: number = this.config.defaultNotificationDelay,
|
|
replaceUrl = true
|
|
) {
|
|
//
|
|
//#region Inside Content ...
|
|
let errorMessage =
|
|
this.managerService.localizationService.getErrorMessage(exception);
|
|
|
|
//
|
|
if (
|
|
exception.hasOwnProperty('payload') &&
|
|
hasChild((exception as any)['payload'])
|
|
) {
|
|
//
|
|
const payload = (exception as any)['payload'] as Array<string>;
|
|
|
|
//
|
|
const localizedPayload = payload.map((pl) => {
|
|
//
|
|
if (isValueDate(pl)) {
|
|
//
|
|
const plDate = fromUtcString(pl);
|
|
const locale = this.managerService.currentLocale;
|
|
|
|
//
|
|
const result = formatDate(
|
|
plDate,
|
|
locale,
|
|
getDateFormatString(locale)
|
|
);
|
|
|
|
//
|
|
return result;
|
|
} else {
|
|
return this.applyLocale(pl);
|
|
}
|
|
});
|
|
|
|
//
|
|
errorMessage = stringFormatter(errorMessage, localizedPayload);
|
|
}
|
|
|
|
//
|
|
if (!params || !params.state) {
|
|
params = {
|
|
...params,
|
|
state: {},
|
|
};
|
|
}
|
|
|
|
//
|
|
params.state[XParam.ReturnUrl] = returnUrl;
|
|
params.state[XParam.Exception] = exception;
|
|
|
|
//
|
|
if (presentNotification) {
|
|
//
|
|
if (duration < 500 || duration > 10000) {
|
|
duration = this.config.defaultNotificationDelay;
|
|
}
|
|
|
|
//
|
|
await this.managerService.notificationService.presentDangerNotification({
|
|
message: errorMessage,
|
|
dissmissable: true,
|
|
opt: {
|
|
duration,
|
|
},
|
|
});
|
|
}
|
|
|
|
//
|
|
if (redirectToUrl && !isNullOrEmptyString(redirectToUrl)) {
|
|
await this.managerService.navigateByUrlReplace(
|
|
redirectToUrl,
|
|
params,
|
|
replaceUrl
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
/**
|
|
* show success ...
|
|
*/
|
|
public showSuccess(message?: XResourceIdentifier, next?: () => void) {
|
|
//
|
|
if (!message) {
|
|
message = XResourceIDs.success_msg;
|
|
}
|
|
|
|
//
|
|
this.managerService.notificationService.presentSuccessNotification({
|
|
message,
|
|
dissmissable: true,
|
|
onWillDismiss: () => {
|
|
//
|
|
if (next && isFunction(next)) {
|
|
next();
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present an action modal with yes and no button ...
|
|
*
|
|
* @param header the action title resource/msg ...
|
|
* @param yesHandler the handler which must run when user accept action ...
|
|
* @param yesRole the yes button role ...
|
|
* @param noHandler the handler which must run when user reject action ...
|
|
* @param noRole the no button role ...
|
|
*/
|
|
public async presentYesNoDialog(
|
|
header: XResourceIdentifier,
|
|
yesHandler: () => void,
|
|
yesRole?: XModalButtonRoleIdentifier,
|
|
noHandler?: () => void,
|
|
noRole?: XModalButtonRoleIdentifier
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(header)) {
|
|
header = this.ResourceIDs.are_you_sure;
|
|
}
|
|
|
|
//
|
|
await this.managerService.dialogService.presentActionModal({
|
|
header,
|
|
buttons: [],
|
|
keyboardClose: true,
|
|
backdropDismiss: true,
|
|
hasNo: true,
|
|
noRole,
|
|
noHandler,
|
|
hasYes: true,
|
|
yesRole,
|
|
yesHandler,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present an action modal with yes and no button ...
|
|
*
|
|
* @param yesHandler the handler which must run when user accept action ...
|
|
* @param yesRole the yes button role ...
|
|
* @param noHandler the handler which must run when user reject action ...
|
|
* @param noRole the no button role ...
|
|
*/
|
|
public async presentDefaultYesNoDialog(
|
|
yesHandler: () => void,
|
|
yesRole?: XModalButtonRoleIdentifier,
|
|
noHandler?: () => void,
|
|
noRole?: XModalButtonRoleIdentifier
|
|
) {
|
|
//
|
|
await this.managerService.dialogService.presentActionModal({
|
|
header: this.ResourceIDs.are_you_sure,
|
|
buttons: [],
|
|
keyboardClose: true,
|
|
backdropDismiss: true,
|
|
hasNo: true,
|
|
noRole,
|
|
noHandler,
|
|
hasYes: true,
|
|
yesRole,
|
|
yesHandler,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* lock page for an action
|
|
*
|
|
* @param isLoading specify state
|
|
*/
|
|
public async setLoadingState(isLoading: boolean) {
|
|
//
|
|
this.loading = isLoading;
|
|
this.uiDisabled = isLoading;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* handle Default Action for Closing open Dialog ...
|
|
*/
|
|
public handleDefaultDialogCloseAction() {
|
|
//
|
|
this.managerService.dialogService.modalController.dismiss({
|
|
dismissed: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Release all Subscription ...
|
|
*/
|
|
public releaseUnsubscriber() {
|
|
this.unregisterHandlers();
|
|
}
|
|
|
|
/**
|
|
* apply localization on numbers of a text ...
|
|
*
|
|
* @param content the text
|
|
*/
|
|
public applyLocale(content: string | any) {
|
|
return applyLocale(
|
|
content || isNumber(content) ? content.toString() : '',
|
|
this.managerService.localizationService.locale
|
|
);
|
|
}
|
|
|
|
/**
|
|
* apply locale and get current resource translated value ...
|
|
*
|
|
* @param id tes resource id
|
|
*/
|
|
public resourceProvider(id: XResourceIdentifier): string {
|
|
return (
|
|
this.managerService.localizationService.getValue(id) || id.toString()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* default join strings ...
|
|
*/
|
|
public combinedResourceProvider(...ids: XResourceIdentifier[]) {
|
|
return this.managerService.localizationService.combine(
|
|
this.managerService.currentLocale,
|
|
' ',
|
|
...ids
|
|
);
|
|
}
|
|
|
|
/**
|
|
* get translation of exception id ...
|
|
*
|
|
* @param id exception id
|
|
*/
|
|
public exceptionResourceProvider(id: XExceptionIdentifier) {
|
|
return this.managerService.localizationService.getErrorMessage(id);
|
|
}
|
|
|
|
/**
|
|
* retrieve property value ...
|
|
*
|
|
* @param object the context object ...
|
|
* @param prop the property name ...
|
|
*/
|
|
public getPropValue<T>(object: T, prop: keyof T) {
|
|
return getValue(object, prop);
|
|
}
|
|
|
|
/**
|
|
* retrieve desiered color name based on form control state ...
|
|
*
|
|
* @param status form status
|
|
*/
|
|
public getIconColor(status: XFormControlState) {
|
|
switch (status) {
|
|
case 'DISABLED':
|
|
case 'PENDING':
|
|
default:
|
|
return XColor.Warning;
|
|
|
|
case 'VALID':
|
|
return XColor.Primary;
|
|
|
|
case 'INVALID':
|
|
return XColor.Danger;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* determines an element contains child nodes or not ...
|
|
*
|
|
* @param ref the element refrence
|
|
*/
|
|
public hasChildNodes(ref: ElementRef) {
|
|
return ref && (ref.nativeElement as HTMLElement).children.length > 0;
|
|
}
|
|
|
|
public getLengthError(model: NgModel, identifier: string) {
|
|
//
|
|
if (!model || !model.errors) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const errorObject = model.getError(identifier);
|
|
const requiredLength = errorObject.requiredLength;
|
|
const actualLength = errorObject.actualLength;
|
|
|
|
//
|
|
return `(${actualLength}/${requiredLength})`;
|
|
}
|
|
|
|
/**
|
|
* usefull for doing nothing ...
|
|
*/
|
|
public nothing() {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Methods ...
|
|
/**
|
|
* check a task is Exists or not ...
|
|
*
|
|
* @param name task name
|
|
*/
|
|
public async hasTask(name: string) {
|
|
//
|
|
const hasTask = this.TaskRepo.findIndex((t) => t.name === name) > -1;
|
|
return hasTask;
|
|
}
|
|
|
|
/**
|
|
* retrieve a task by it's name ...
|
|
*
|
|
* @param name task name
|
|
*/
|
|
public async getTask(name: string) {
|
|
//
|
|
const isExists = await this.hasTask(name);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const task = this.TaskRepo.find((t) => t.name === name);
|
|
return task;
|
|
}
|
|
|
|
/**
|
|
* add or update a task in Task Repo ...
|
|
*
|
|
* @param task the task object
|
|
*/
|
|
public async addOrUpdateTask(task: XTask<any>) {
|
|
//
|
|
if (!task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isExists = await this.hasTask(task.name);
|
|
if (!isExists) {
|
|
this.TaskRepo.push(task);
|
|
} else {
|
|
await this.updateTask(task);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a New Task to Task Repo ...
|
|
*
|
|
* @param task task object
|
|
*/
|
|
public async addTask(task: XTask<any>) {
|
|
//
|
|
if (!task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isExists = await this.hasTask(task.name);
|
|
if (isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.TaskRepo.push(task);
|
|
}
|
|
|
|
/**
|
|
* Update a Task in Task Repo ...
|
|
*
|
|
* @param task the task object
|
|
*/
|
|
public async updateTask(task: XTask<any>) {
|
|
//
|
|
const isExists = await this.hasTask(task.name);
|
|
if (!isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.removeTask(task.name);
|
|
this.TaskRepo.push(task);
|
|
}
|
|
|
|
/**
|
|
* remove a task by it's name ...
|
|
*
|
|
* @param name the task name
|
|
*/
|
|
public async removeTask(name: string) {
|
|
//
|
|
const isExists = await this.hasTask(name);
|
|
if (!isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (this.managerService.taskManagerService.has(name)) {
|
|
this.managerService.taskManagerService.delete(name);
|
|
}
|
|
|
|
//
|
|
this.TaskRepo = this.TaskRepo.filter((t) => t.name !== name);
|
|
}
|
|
|
|
/**
|
|
* call a task for running on task manager ...
|
|
*
|
|
* @param name task name
|
|
*/
|
|
public async dispatchTask(name: string) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const task = await this.getTask(name);
|
|
if (!task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.managerService.taskManagerService.add(task);
|
|
}
|
|
|
|
/**
|
|
* check a Task is running or not by it's name
|
|
*
|
|
* @param name task name
|
|
*/
|
|
public async isTaskRunning(name: string) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
name = toNormalString(name);
|
|
|
|
//
|
|
return (
|
|
this.RunningTasks.findIndex((rt) => name === toNormalString(rt.name)) > -1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* clear all tasks for component ...
|
|
*/
|
|
public async clearTasks() {
|
|
//
|
|
this.TaskRepo = [];
|
|
this.RunningTasks = [];
|
|
}
|
|
|
|
/**
|
|
* do some actions related to Task Repo when a Task Start ...
|
|
*
|
|
* @param name task name
|
|
* @param task task object
|
|
*/
|
|
private async handlTaskStart(name: string, task: XTask<any>) {
|
|
//
|
|
const isRunning = await this.isTaskRunning(name);
|
|
if (isRunning) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.RunningTasks.push(task);
|
|
}
|
|
|
|
/**
|
|
* do some actions related to Task Repo when a Task Failed ...
|
|
*
|
|
* @param name task name
|
|
* @param task task object
|
|
*/
|
|
private async handleTaskFailed(name: string, task: XTask<any>) {
|
|
//
|
|
const isRunning = await this.isTaskRunning(name);
|
|
if (!isRunning) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const tName = toNormalString(task.name);
|
|
this.RunningTasks = this.RunningTasks.filter(
|
|
(t) => tName !== toNormalString(t.name)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* do some actions related to Task Repo when a Task Finished ...
|
|
*
|
|
* @param name task name
|
|
* @param task task object
|
|
*/
|
|
private async handleTaskFinished(name: string, task: XTask<any>) {
|
|
//
|
|
const isRunning = await this.isTaskRunning(name);
|
|
if (!isRunning) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const tName = toNormalString(task.name);
|
|
this.TaskRepo = this.TaskRepo.filter(
|
|
(t) => tName !== toNormalString(t.name)
|
|
);
|
|
this.RunningTasks = this.RunningTasks.filter(
|
|
(t) => tName !== toNormalString(t.name)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Observable Actions ...
|
|
/**
|
|
* Check if items has childs or not ...
|
|
*
|
|
* @param items a list item ...
|
|
*/
|
|
public hasChild(items: XOneOrManyType<any>) {
|
|
return hasChild(items);
|
|
}
|
|
|
|
/**
|
|
* convert an standard UI Value to Observable for consuming ...
|
|
*
|
|
* @param value the standard UI Value
|
|
*/
|
|
public getValue<T>(value: XStandardType<T>) {
|
|
return toObservable<T>(value);
|
|
}
|
|
|
|
/**
|
|
* get stream Observble of specified standard value
|
|
*/
|
|
public getValueStream<T>(value: XStandardType<T>) {
|
|
return this.applyTakeUntilWrapper(this.getValue(value));
|
|
}
|
|
|
|
/**
|
|
* retrieve an standard type var in promise
|
|
*
|
|
* @param value an standard type var
|
|
*/
|
|
public async getValueAsync<T>(value: XStandardType<T>) {
|
|
//
|
|
if (!value) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return await this.toPromise(this.getValue(value));
|
|
}
|
|
|
|
/**
|
|
* convert to array ...
|
|
*
|
|
* @param value an standard type one or many arg ...
|
|
*/
|
|
public getArrayValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return this.getValue(value).pipe(map((valueType) => toArray(valueType)));
|
|
}
|
|
|
|
/**
|
|
* convert to array ...
|
|
*
|
|
* @param value an standard type one or many arg ...
|
|
*/
|
|
public async getArrayValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return await this.getValueAsync(this.getArrayValue(value));
|
|
}
|
|
|
|
/**
|
|
* check a value has child or not ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public hasChildValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
//
|
|
return this.getValue(value).pipe(
|
|
map((valueType) => hasChild(toArray(valueType)))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check a value has child or not ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async hasChildValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
//
|
|
const valueType = await this.getValueAsync(value);
|
|
if (!valueType) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return hasChild(toArray(valueType));
|
|
}
|
|
|
|
/**
|
|
* count a value's child ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public countChildsValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return this.getValue(value).pipe(
|
|
map((valueType) => toArray(valueType).length)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* count a value's child ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async countChildsValueAsync<T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) {
|
|
//
|
|
const valueType = await this.getValueAsync(value);
|
|
if (!valueType) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
return toArray(valueType).length;
|
|
}
|
|
|
|
/**
|
|
* providing string resources ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public getResourceValue(value: XStandardType<XResourceIdentifier>) {
|
|
//
|
|
return !value
|
|
? of('')
|
|
: this.getValue(value).pipe(
|
|
map((val) => {
|
|
return this.resourceProvider(val) || (value as string);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* providing string resources ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async getResourceValueAsync(
|
|
value: XStandardType<XResourceIdentifier>
|
|
) {
|
|
//
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const val = await this.getValueAsync(value);
|
|
return this.resourceProvider(val) || (val as string);
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public notEmptyValue(value: XStandardType<string | any>) {
|
|
return this.getValue(value).pipe(map((val) => !isNullOrEmptyString(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public async notEmptyValueAsync(value: any) {
|
|
return await this.toPromise(this.notEmptyValue(value));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has not content and empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public emptyValue(value: XStandardType<string | any>) {
|
|
return this.getValue(value).pipe(map((val) => isNullOrEmptyString(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has not content and empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public async emptyValueAsync(value: XStandardType<string | any>) {
|
|
return await this.toPromise(this.emptyValue(value));
|
|
}
|
|
|
|
/**
|
|
* apply not operator to a boolean ...
|
|
*/
|
|
public notValue(value: XStandardType<boolean>) {
|
|
return notValue(this.getValue(value));
|
|
}
|
|
|
|
/**
|
|
* apply not operator to a boolean ...
|
|
*/
|
|
public async notValueAsync(value: XStandardType<boolean>) {
|
|
return await this.getValueAsync(this.notValue(value));
|
|
}
|
|
|
|
/**
|
|
* check all input args be same as value ...
|
|
*
|
|
* @param value any value which going to check with all args to be same as them ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public mustBeValue(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return forkJoin(values.map((v) => toObservable(v))).pipe(
|
|
map((res) => {
|
|
return res.every((i) => i === value);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check all input args be same as value ...
|
|
*
|
|
* @param value any value which going to check with all args to be same as them ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public async mustBeValueAsync(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return (
|
|
await Promise.all(values.map(async (v) => await this.getValueAsync(v)))
|
|
).every((v) => v === value);
|
|
}
|
|
|
|
/**
|
|
* check all input args contains at least one value ...
|
|
*
|
|
* @param value any value which going to check with all args to find one same ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public atLeastHasOneValue(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return forkJoin(values.map((v) => toObservable(v))).pipe(
|
|
map((res) => {
|
|
return res.includes(value);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check all input args contains at least one value ...
|
|
*
|
|
* @param value any value which going to check with all args to find one same ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public async atLeastHasOneValueAsync(
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) {
|
|
//
|
|
return (
|
|
await Promise.all(values.map(async (v) => await this.getValueAsync(v)))
|
|
).includes(value);
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public notNullOrUndefinedValue(value: XStandardType<any>) {
|
|
return this.getValue(value).pipe(map((val) => !isNullOrUndefined(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public async notNullOrUndefinedValueAsync(value: XStandardType<any>) {
|
|
return await this.toPromise(this.notNullOrUndefinedValue(value));
|
|
}
|
|
|
|
/**
|
|
* determines a given value content must empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public nullOrUndefinedValue(value: XStandardType<any>) {
|
|
return this.getValue(value).pipe(map((val) => isNullOrUndefined(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value content must empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public async nullOrUndefinedValueAsync(value: XStandardType<any>) {
|
|
return await this.toPromise(this.nullOrUndefinedValue(value));
|
|
}
|
|
|
|
/**
|
|
* retrieve an optional value ...
|
|
*
|
|
* @param value the optional standard value ...
|
|
*/
|
|
public getOptionalValue<T>(value?: XStandardType<T>): Observable<T> {
|
|
//
|
|
if (value) {
|
|
return this.getValue(value);
|
|
}
|
|
|
|
//
|
|
return this.getValue(getDefaultValue(value));
|
|
}
|
|
|
|
/**
|
|
* retrieve an optional value ...
|
|
*
|
|
* @param value the optional standard value ...
|
|
*/
|
|
public async getOptionalValueAsync<T>(value?: XStandardType<T>) {
|
|
return await this.toPromise(this.getOptionalValue(value));
|
|
}
|
|
|
|
/**
|
|
* convert all values as observable of them ...
|
|
*
|
|
* @param values the standard list of specific type ...
|
|
* @returns observable of values array of specific type ...
|
|
*/
|
|
public getValues<T>(values?: XOneOrManyType<XStandardType<T>>) {
|
|
//
|
|
interface ForkSourceType<T> {
|
|
[index: number]: XStandardType<T>;
|
|
}
|
|
|
|
//
|
|
return this.getArrayValue(values).pipe(
|
|
concatMap((values) => {
|
|
//
|
|
if (!hasChild(values)) {
|
|
return this.getValue([] as T[]);
|
|
} else {
|
|
//
|
|
const forkSource: ForkSourceType<T> = {};
|
|
values.forEach((value, index) => {
|
|
forkSource[index] = this.getValue(value);
|
|
});
|
|
|
|
//
|
|
return forkJoin(forkSource).pipe(
|
|
map((forkResult) => {
|
|
//
|
|
const respObj = forkResult as any;
|
|
const mKeys = Object.keys(forkResult)
|
|
.map((key) => key)
|
|
.sort((a, b) => +a - +b);
|
|
const result = mKeys.map((mKey: any) => respObj[mKey] as T);
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* convert all values as observable of them ...
|
|
*
|
|
* @param values the standard list of specific type ...
|
|
* @returns observable of values array of specific type ...
|
|
*/
|
|
public async getValuesAsync<T>(values?: XOneOrManyType<XStandardType<T>>) {
|
|
return await this.toPromise(this.getValues(values));
|
|
}
|
|
|
|
/**
|
|
* apply take until wrapper arround an observable ...
|
|
*
|
|
* @param task the observable object
|
|
*/
|
|
public applyTakeUntilWrapper<T>(task: Observable<T>): Observable<T> {
|
|
return task.pipe(takeUntil(this.unsubscriber));
|
|
}
|
|
|
|
/**
|
|
* apply inside component loading wrapper arround an observable ...
|
|
*
|
|
* @param task the observable object
|
|
*/
|
|
public applyLoadingWrapper<T>(task: Observable<T>): Observable<T> {
|
|
return of(null).pipe(
|
|
tap((_) => {
|
|
this.uiDisabled = true;
|
|
this.loading = true;
|
|
}),
|
|
concatMap((_) =>
|
|
task.pipe(
|
|
tap(() => {
|
|
this.uiDisabled = false;
|
|
this.loading = false;
|
|
})
|
|
)
|
|
),
|
|
catchError((err) => {
|
|
//
|
|
this.uiDisabled = false;
|
|
this.loading = false;
|
|
return throwError(err);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* apply get first result of an observable ...
|
|
*
|
|
* @param task the observable object
|
|
*/
|
|
public applyFirstWrapper<T>(task: Observable<T>): Observable<T> {
|
|
return task.pipe(first());
|
|
}
|
|
|
|
/**
|
|
* convert an observable to promise object ...
|
|
*
|
|
* @param task the observable object
|
|
*/
|
|
public toPromise<T>(task: Observable<T>): Promise<T> {
|
|
return this.applyFirstWrapper(task).toPromise();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* Call Change Detector's Detect Change method ...
|
|
*/
|
|
detectChanges() {
|
|
this.changeDetector.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
/**
|
|
* Register All Required Subscriptions ...
|
|
*/
|
|
private registerComponentHandlers() {
|
|
//
|
|
this.registerUiHandlers();
|
|
this.registerTaskManager();
|
|
this.registerInstanceHandlers();
|
|
}
|
|
|
|
/**
|
|
* Release all Subscriptions based on the Component ...
|
|
*/
|
|
private unregisterHandlers() {
|
|
//
|
|
this.unsubscriber.next();
|
|
this.unsubscriber.complete();
|
|
}
|
|
|
|
/**
|
|
* register Ui Event Handlers ...
|
|
*/
|
|
private registerUiHandlers() {
|
|
//
|
|
this.applyTakeUntilWrapper(this.ruler.change()).subscribe((resizeEvent) =>
|
|
this.onResize(resizeEvent)
|
|
);
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.themeManagerService.notifyChanges.asObservable()
|
|
).subscribe(() => {
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Register Task Handlers for Finish and Error of Tasks ...
|
|
*/
|
|
private registerTaskManager() {
|
|
//
|
|
// Task Start ...
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.taskManagerService.taskStart.asObservable()
|
|
)
|
|
.pipe(filter((task) => !isNullOrUndefined(task)))
|
|
.subscribe((task) => {
|
|
//
|
|
this.onTaskStart(task.name, task);
|
|
|
|
//
|
|
this.handlTaskStart(task.name, task);
|
|
});
|
|
|
|
//
|
|
// Task Error ...
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.taskManagerService.taskError.asObservable()
|
|
)
|
|
.pipe(filter((task) => !isNullOrUndefined(task)))
|
|
.subscribe((task) => {
|
|
//
|
|
this.onTaskFailed(task.name, task);
|
|
|
|
//
|
|
this.handleTaskFailed(task.name, task);
|
|
});
|
|
|
|
//
|
|
// Task Finished ...
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.taskManagerService.taskFinished.asObservable()
|
|
)
|
|
.pipe(filter((task) => !isNullOrUndefined(task)))
|
|
.subscribe((task) => {
|
|
//
|
|
this.onTaskFinished(task.name, task);
|
|
|
|
//
|
|
this.handleTaskFinished(task.name, task);
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-dialog.service.ts
|
|
|
|
import {
|
|
XBaseService,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
XResourceIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
MatDialog,
|
|
MatDialogRef,
|
|
MatDialogConfig,
|
|
} from '@angular/material/dialog';
|
|
import {
|
|
IXBaseDialogConfig,
|
|
IXBaseDialogResult,
|
|
XBaseDialogComponent,
|
|
IXBaseDialogActionModel,
|
|
} from './x-base.dialog.component';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { EventEmitter, Inject, Injectable, Output } from '@angular/core';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export abstract class XBaseDialogService<
|
|
TItem,
|
|
TActionProviderModel extends IXBaseDialogActionModel,
|
|
TConfig extends IXBaseDialogConfig<TActionProviderModel>,
|
|
TDialogCompnent extends XBaseDialogComponent<
|
|
TItem,
|
|
TActionProviderModel,
|
|
TConfig
|
|
>
|
|
> extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
private MOBILE_CLASS_NAME = 'mobile';
|
|
private DIALOG_REF: MatDialogRef<TDialogCompnent>;
|
|
|
|
//
|
|
isMobile$ = this.managerService.isMobileUi$;
|
|
|
|
// tslint:disable-next-line:no-output-on-prefix
|
|
@Output()
|
|
onResult = new EventEmitter<IXBaseDialogResult>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
abstract defaultTitleResourceIdentifier: XResourceIdentifier;
|
|
|
|
abstract openDialogAndReturnRef(
|
|
config: MatDialogConfig
|
|
): MatDialogRef<TDialogCompnent>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected dialog: MatDialog,
|
|
protected managerService: XManagerService,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig
|
|
) {
|
|
super(config);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* Open Select Map Dialog ...
|
|
*/
|
|
async openDialog(config?: TConfig) {
|
|
//
|
|
// Prevent Double Bubble ...
|
|
if (this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare Config ...
|
|
if (!config) {
|
|
config = {} as TConfig;
|
|
}
|
|
|
|
//
|
|
//#region Default Config for Map Component ...
|
|
//
|
|
// Set Default Title ...
|
|
if (config && !config.title) {
|
|
config.title = this.defaultTitleResourceIdentifier;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Prepare Dialog Config ...
|
|
const data: MatDialogConfig = {
|
|
data: config,
|
|
};
|
|
|
|
//
|
|
data.panelClass = 'fullscreen-dialog';
|
|
|
|
//
|
|
// Show Cropper inside a Dialog ...
|
|
this.DIALOG_REF = this.openDialogAndReturnRef(data);
|
|
this.DIALOG_REF.disableClose = true;
|
|
|
|
//
|
|
// Attach Mobile Class ...
|
|
this.isMobile$.subscribe((isMobile) => {
|
|
//
|
|
if (isMobile) {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
} else {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
// Handle Backdrop ...
|
|
this.DIALOG_REF.backdropClick().subscribe(() => {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
|
|
//
|
|
this.closeDialog();
|
|
});
|
|
|
|
//
|
|
// Handle Dialog Result ...
|
|
this.DIALOG_REF.afterClosed().subscribe((model: IXBaseDialogResult) => {
|
|
//
|
|
if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
} else {
|
|
//
|
|
// Handle Results ...
|
|
this.onResult.emit(model);
|
|
}
|
|
|
|
//
|
|
this.closeDialog();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Close Select Map Dialog ...
|
|
*/
|
|
closeDialog() {
|
|
//
|
|
// Prevent Go Forward ...
|
|
if (!this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Close Dialog ...
|
|
this.DIALOG_REF.close();
|
|
this.DIALOG_REF = null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-page.ts
|
|
|
|
import {
|
|
NgZone,
|
|
Inject,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
EventEmitter,
|
|
HostListener,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XCanDeactivate,
|
|
XResourceIdentifier,
|
|
XBehaviourEventType,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import { Subject, Observable } from 'rxjs';
|
|
import { XBaseComponent } from './x-base-component';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XBasePage
|
|
extends XBaseComponent
|
|
implements XCanDeactivate
|
|
{
|
|
/**
|
|
* Since Page Components Manipulate Angular Router ...
|
|
* and Angular Router has Deactivate Guards ...
|
|
* and it Works where component is Locked ...
|
|
* this Param Specified for Deactivation Guard to Do Unlock by Confirmation or not ...
|
|
*/
|
|
protected confirmUnlock: boolean = true;
|
|
|
|
/**
|
|
* Specified when Page Component is Locked, make Guards available for Prevent Back ...
|
|
*/
|
|
protected preventBackHandlingWhenHasLock: boolean = true;
|
|
|
|
//
|
|
@Output()
|
|
backPreventNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
//
|
|
private PREVENT_BACK = false;
|
|
get isBackPreveted() {
|
|
return this.PREVENT_BACK;
|
|
}
|
|
set preventBack(v: boolean) {
|
|
//
|
|
if (v && !this.PREVENT_BACK) {
|
|
this.managerService.historyService.pushEmptyState();
|
|
} else if (v && this.PREVENT_BACK) {
|
|
this.managerService.historyService.replaceEmptyState();
|
|
}
|
|
|
|
//
|
|
this.PREVENT_BACK = v;
|
|
|
|
//
|
|
if (v) {
|
|
this.addClass('x-back-prevented');
|
|
} else {
|
|
this.addClass('x-back-prevented');
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
this.onBackPrevent(v);
|
|
this.backPreventNotifier.emit({ id: this.uuid, state: v });
|
|
}
|
|
|
|
//
|
|
onBackPrevent(state: boolean) {}
|
|
|
|
//
|
|
private IS_PARSING_PARAMS = false;
|
|
private NOT_PREVENT_REFRESH = true;
|
|
|
|
//
|
|
public titleRes?: XResourceIdentifier;
|
|
|
|
//
|
|
public scrollEventSimulator = new Subject<XBehaviourEventType>();
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Guards ...
|
|
public canDeactivate(
|
|
component: XCanDeactivate,
|
|
route: ActivatedRouteSnapshot,
|
|
state: RouterStateSnapshot
|
|
): boolean | Observable<boolean> | Promise<boolean> {
|
|
return this.handleCanDeactivateGuard(component, route, state);
|
|
}
|
|
|
|
@HostListener('window:beforeunload', ['$event'])
|
|
beforeUnloadHandler($event: any) {
|
|
//
|
|
if (!this.NOT_PREVENT_REFRESH) {
|
|
$event.returnValue = true;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
this.handleParseParams();
|
|
this.registerPageHandlers();
|
|
}
|
|
|
|
public afterViewInit(): void {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// Register Lock Notifier for Prevent Handling ...
|
|
this.applyTakeUntilWrapper(this.lockNotifier.asObservable()).subscribe(
|
|
(event) => {
|
|
//
|
|
if (isNullOrUndefined(event)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (this.preventBackHandlingWhenHasLock) {
|
|
this.preventBack = event.state;
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
);
|
|
}
|
|
|
|
public onChange(changeKeys: string[]): void {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
let isChanged = false;
|
|
let applyChanges = false;
|
|
|
|
//
|
|
// Looking for Lock Changes ...
|
|
isChanged = changeKeys.includes(nameof<XBasePage>('lock'));
|
|
if (isChanged) {
|
|
//
|
|
applyChanges = true;
|
|
if (this.preventBackHandlingWhenHasLock) {
|
|
this.preventBack = this.lock;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (applyChanges) {
|
|
this.detectChanges();
|
|
}
|
|
}
|
|
|
|
public onBack() {}
|
|
|
|
didEnter() {
|
|
super.didEnter();
|
|
|
|
//
|
|
this.handleResourcePresenting();
|
|
}
|
|
|
|
willLeave() {
|
|
super.willLeave();
|
|
|
|
//
|
|
this.clearError();
|
|
this.clearTasks();
|
|
}
|
|
|
|
public parseParams() {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Notifiers ...
|
|
public simulateScrollStart() {
|
|
this.scrollEventSimulator.next('scrollStart');
|
|
}
|
|
|
|
public simulateScrollEnd() {
|
|
this.scrollEventSimulator.next('scrollEnd');
|
|
}
|
|
|
|
public simulateScrolling() {
|
|
this.scrollEventSimulator.next('scrolling');
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Protected ...
|
|
/**
|
|
* Do Lock Breakes Works ...
|
|
*
|
|
* @param acceptCb
|
|
* @param cancelCb
|
|
*/
|
|
protected async presentDeactiveGuardDialog(
|
|
acceptCb?: () => XStandardType<void>,
|
|
cancelCb?: () => XStandardType<void>
|
|
) {
|
|
if (this.lock) {
|
|
//
|
|
const a = await this.managerService.dialogService.presentActionModal({
|
|
header: XResourceIDs.locked_msg,
|
|
hasAccept: true,
|
|
acceptHandler: () => {
|
|
//
|
|
if (acceptCb) {
|
|
acceptCb();
|
|
}
|
|
|
|
//
|
|
this.lock = false;
|
|
},
|
|
hasCancel: true,
|
|
cancelHandler: () => {
|
|
//
|
|
if (cancelCb) {
|
|
cancelCb();
|
|
}
|
|
|
|
//
|
|
this.lock = true;
|
|
},
|
|
buttons: [],
|
|
});
|
|
|
|
//
|
|
await a.onDidDismiss();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private handleParseParams() {
|
|
//
|
|
if (this.IS_PARSING_PARAMS) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.IS_PARSING_PARAMS = true;
|
|
|
|
//
|
|
this.getValueAsync(this.parseParams())
|
|
.then(() => (this.IS_PARSING_PARAMS = false))
|
|
.catch(
|
|
() =>
|
|
//
|
|
(this.IS_PARSING_PARAMS = false)
|
|
);
|
|
}
|
|
|
|
private registerPageHandlers() {
|
|
//
|
|
this.registerBackHandler();
|
|
this.registerParamsHandler();
|
|
}
|
|
|
|
private handleResourcePresenting() {
|
|
//
|
|
if (!this.titleRes) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.managerService.settingsService.setTitle(
|
|
this.managerService.localizationService.getValue(this.titleRes)
|
|
);
|
|
}
|
|
|
|
private async handleCanDeactivateGuard(
|
|
component: XCanDeactivate,
|
|
route: ActivatedRouteSnapshot,
|
|
state: RouterStateSnapshot
|
|
) {
|
|
//
|
|
let result = !this.lock;
|
|
if (this.lock && this.confirmUnlock) {
|
|
//
|
|
await this.presentDeactiveGuardDialog(
|
|
() => {
|
|
result = true;
|
|
},
|
|
() => {
|
|
result = false;
|
|
}
|
|
);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private registerBackHandler() {
|
|
//
|
|
this.managerService.historyService.platformLocation.onPopState(() => {
|
|
//
|
|
if (this.PREVENT_BACK) {
|
|
this.managerService.historyService.pushEmptyState();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.historyService.backHandler.asObservable()
|
|
).subscribe(() => {
|
|
this.onBack();
|
|
});
|
|
}
|
|
|
|
private registerParamsHandler() {
|
|
//
|
|
this.applyTakeUntilWrapper(this.managerService.routeDataChanged$).subscribe(
|
|
(res) => {
|
|
this.handleParseParams();
|
|
}
|
|
);
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(this.managerService.routeParmChanged$).subscribe(
|
|
(res) => {
|
|
this.handleParseParams();
|
|
}
|
|
);
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.routeQueryParmChanged$
|
|
).subscribe((res) => {
|
|
this.handleParseParams();
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.html
|
|
|
|
<div class="x-dialog-wrapper">
|
|
<!-- Toolbar -->
|
|
<ion-header class="x-dialog-header">
|
|
<!-- Title Toolbar -->
|
|
<ion-toolbar
|
|
class="v-toolbar"
|
|
[xColor]="'primary'"
|
|
*ngIf="showToolbar | async"
|
|
>
|
|
<!-- Slots -->
|
|
<div class="toolbar-area">
|
|
<x-slotter>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'ion-float-start']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleBack()"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="backIcon"
|
|
[loading]="isLoading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<ion-title class="toolbar-item center-vertical-flex">
|
|
<h3>
|
|
{{ title | async }}
|
|
</h3>
|
|
</ion-title>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
[cssClass]="['ion-text-end', 'ion-float-end']"
|
|
>
|
|
<!-- Select -->
|
|
<div
|
|
matRipple
|
|
(click)="handleSelect()"
|
|
*ngIf="dialogCanSelect()"
|
|
class="toolbar-item toolbar-inline-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="selectIcon"
|
|
[loading]="isLoading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ion-progress-bar
|
|
*ngIf="isLoading"
|
|
type="indeterminate"
|
|
[color]="progressBarColor | async"
|
|
></ion-progress-bar>
|
|
</ion-toolbar>
|
|
</ion-header>
|
|
|
|
<!-- Component -->
|
|
<ion-content
|
|
class="x-dialog-content-wrapper"
|
|
[ngClass]="cssDialogClass | async"
|
|
[class.has-toolbar]="showToolbar | async"
|
|
>
|
|
</ion-content>
|
|
</div>
|
|
|
|
<!-- Default Item Ref -->
|
|
<ng-template #vItemRef let-item>
|
|
{{ item.data | json }}
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.scss
|
|
|
|
::ng-deep.fullscreen-dialog {
|
|
//
|
|
width: 80vw !important;
|
|
max-width: 80vw !important;
|
|
|
|
//
|
|
height: 80vh !important;
|
|
max-height: 80vh !important;
|
|
|
|
//
|
|
&.mobile {
|
|
//
|
|
width: 100vw !important;
|
|
max-width: 100vw !important;
|
|
|
|
//
|
|
height: 100vh !important;
|
|
max-height: 100vh !important;
|
|
}
|
|
|
|
//
|
|
.mat-dialog-container {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
|
|
.x-dialog-wrapper {
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
position: relative !important;
|
|
}
|
|
|
|
.x-dialog-header {
|
|
position: sticky !important;
|
|
top: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.x-dialog-content-wrapper {
|
|
height: calc(100%);
|
|
|
|
&.has-toolbar {
|
|
height: calc(100% - 56px);
|
|
}
|
|
}
|
|
|
|
x-icon {
|
|
--size: 24px;
|
|
}
|
|
|
|
.toolbar-area {
|
|
margin: 0px;
|
|
}
|
|
|
|
.toolbar-item {
|
|
width: auto;
|
|
height: 48px;
|
|
}
|
|
|
|
.toolbar-inline-item {
|
|
display: inline-flex !important;
|
|
}
|
|
|
|
.toolbar-button {
|
|
width: 32px;
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.ts
|
|
|
|
import {
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XTask,
|
|
XColor,
|
|
toArray,
|
|
isFunction,
|
|
getTaskName,
|
|
XStandardType,
|
|
XDialogResult,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XResourceIdentifier,
|
|
} from 'x-framework-core';
|
|
import { of, Subject } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { XBaseComponent } from './x-base-component';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from './x-base-action.model';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XBaseDialogAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XBaseDialogActionIdentifier = XBaseDialogAction | string;
|
|
|
|
export interface IXBaseDialogActionModel
|
|
extends XBaseActionModel<XBaseDialogActionIdentifier> {}
|
|
|
|
export interface IXBaseDialogConfig<
|
|
TActionProviderModel extends IXBaseDialogActionModel
|
|
> {
|
|
//
|
|
showToolbar?: boolean;
|
|
|
|
//
|
|
title?: XResourceIdentifier;
|
|
cssClass?: XOneOrManyType<string>;
|
|
progressBarColor?: XColorIdentifier;
|
|
|
|
//
|
|
showSearchBar?: boolean;
|
|
searchBarColor?: XColorIdentifier;
|
|
searchBarInputColor?: XColorIdentifier;
|
|
|
|
//
|
|
actionProvider?: Subject<TActionProviderModel>;
|
|
|
|
//
|
|
canMultipleSelect?: boolean;
|
|
|
|
//
|
|
onItemSelect?: (item: XOneOrManyType<any>) => XStandardType<void>;
|
|
|
|
//
|
|
onTaskStart?: (name: string) => XStandardType<void>;
|
|
onTaskFinished?: (name: string) => XStandardType<void>;
|
|
onTaskFailed?: (name: string) => XStandardType<void>;
|
|
}
|
|
|
|
export interface IXBaseDialogResult {
|
|
payload?: any;
|
|
result: XDialogResult;
|
|
}
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XBaseDialogComponent<
|
|
TItem,
|
|
TActionProviderModel extends IXBaseDialogActionModel,
|
|
TConfig extends IXBaseDialogConfig<TActionProviderModel>
|
|
> extends XBaseComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
public cancelIcon = XIconNames.close;
|
|
public selectIcon = XIconNames.checked;
|
|
public backIcon = XIconNames.arrow_back;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
|
|
//
|
|
readonly isMobile$ = this.managerService.isMobileUi$;
|
|
readonly isNotMobile$ = this.managerService.isNotMobileUi$;
|
|
|
|
//
|
|
public selectedItem: XOneOrManyType<TItem>;
|
|
|
|
//
|
|
//#region Prevent Back ...
|
|
@Output()
|
|
backPreventNotifier = new EventEmitter<{ id: string; state: boolean }>();
|
|
|
|
//
|
|
private PREVENT_BACK = false;
|
|
get isBackPreveted() {
|
|
return this.PREVENT_BACK;
|
|
}
|
|
set preventBack(v: boolean) {
|
|
//
|
|
if (v && !this.PREVENT_BACK) {
|
|
this.managerService.historyService.pushEmptyState();
|
|
} else if (v && this.PREVENT_BACK) {
|
|
this.managerService.historyService.replaceEmptyState();
|
|
}
|
|
|
|
//
|
|
this.PREVENT_BACK = v;
|
|
|
|
//
|
|
if (v) {
|
|
this.addClass('x-back-prevented');
|
|
} else {
|
|
this.addClass('x-back-prevented');
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
this.onBackPrevent(v);
|
|
this.backPreventNotifier.emit({ id: this.uuid, state: v });
|
|
}
|
|
|
|
//
|
|
onBackPrevent(state: boolean) {}
|
|
//#endregion
|
|
|
|
//
|
|
public baseActionProvider = new Subject<TActionProviderModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
public zone: NgZone,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public managerService: XManagerService,
|
|
public changeDetector: ChangeDetectorRef,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
|
public dialogRef: MatDialogRef<
|
|
XBaseDialogComponent<TItem, TActionProviderModel, TConfig>
|
|
>
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
this.preventBack = true;
|
|
}
|
|
|
|
public afterViewInit(): void {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// Register Lock Notifier for Prevent Handling ...
|
|
this.applyTakeUntilWrapper(this.lockNotifier.asObservable()).subscribe(
|
|
(event) => {
|
|
//
|
|
if (isNullOrUndefined(event)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.preventBack = event.state;
|
|
this.detectChanges();
|
|
}
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
async onTaskStart(name: string, task: XTask<any>) {
|
|
super.onTaskStart(name, task);
|
|
|
|
//
|
|
const isDialogTask = await this.isDialogTask(name);
|
|
|
|
//
|
|
if (isDialogTask) {
|
|
//
|
|
this.setLoadingState(true);
|
|
await this.notifyTaskStartEvent(name);
|
|
}
|
|
}
|
|
|
|
async onTaskFinished(name: string, task: XTask<any>) {
|
|
super.onTaskFinished(name, task);
|
|
|
|
//
|
|
const isDialogTask = await this.isDialogTask(name);
|
|
|
|
//
|
|
if (isDialogTask) {
|
|
//
|
|
this.setLoadingState(false);
|
|
await this.notifyTaskFinishedEvent(name);
|
|
}
|
|
}
|
|
|
|
async onTaskFailed(name: string, task: XTask<any>) {
|
|
super.onTaskFailed(name, task);
|
|
|
|
//
|
|
const isDialogTask = await this.isDialogTask(name);
|
|
|
|
//
|
|
if (isDialogTask) {
|
|
//
|
|
this.showError(task.error);
|
|
this.setLoadingState(false);
|
|
await this.notifyTaskFailedEvent(name);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handlers ...
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerBackHandler();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
/**
|
|
* retrieve map dialog config ...
|
|
*/
|
|
public getData() {
|
|
return this.getValue(this.data as TConfig);
|
|
}
|
|
|
|
/**
|
|
* determines map dialog config exists or not ...
|
|
*/
|
|
public hasData() {
|
|
return !isNullOrUndefined(this.getData());
|
|
}
|
|
|
|
/**
|
|
* determines dialog can select result or not ...
|
|
*/
|
|
public dialogCanSelect() {
|
|
return this.hasChild(this.selectedItem);
|
|
}
|
|
|
|
/**
|
|
* retrieve dialog title ...
|
|
*/
|
|
public get title() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config ? config.title : ''))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve dialog showTollbar ...
|
|
*/
|
|
public get showToolbar() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!config || isNullOrUndefined(config.showToolbar)
|
|
? of(true)
|
|
: this.getOptionalValue(config.showToolbar)
|
|
)
|
|
);
|
|
}
|
|
|
|
public get cssClass() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config ? config.cssClass : []))
|
|
);
|
|
}
|
|
|
|
public get progressBarColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.progressBarColor : XColor.Warning)
|
|
),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Warning))
|
|
);
|
|
}
|
|
|
|
public get actionProvider() {
|
|
return this.getData().pipe(
|
|
map((config) =>
|
|
config ? config.actionProvider : this.baseActionProvider
|
|
),
|
|
map((actionProvider) =>
|
|
!isNullOrUndefined(actionProvider)
|
|
? actionProvider
|
|
: this.baseActionProvider
|
|
)
|
|
);
|
|
}
|
|
|
|
public get canMultipleSelect() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config ? config.canMultipleSelect : false)
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
public get showSearchBar() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config ? config.showSearchBar : false)
|
|
)
|
|
);
|
|
}
|
|
|
|
public get searchBarColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.searchBarColor : XColor.Primary)
|
|
),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary))
|
|
);
|
|
}
|
|
|
|
public get searchBarInputColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.searchBarInputColor : XColor.Primary)
|
|
),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary))
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleBack() {
|
|
this.dialogRef.close();
|
|
}
|
|
|
|
async handleSelect() {
|
|
//
|
|
if (!this.dialogCanSelect()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dialogRef.close({
|
|
result: XDialogResult.Ok,
|
|
payload: this.selectedItem,
|
|
});
|
|
}
|
|
|
|
async handleDeselect() {
|
|
//
|
|
if (!this.dialogCanSelect()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const canSelectMultipleItems = await this.getValueAsync(
|
|
this.canMultipleSelect
|
|
);
|
|
if (canSelectMultipleItems) {
|
|
await this.deselectAllListItems();
|
|
} else {
|
|
//
|
|
const selectedItem = toArray(this.selectedItem)[0];
|
|
if (!isNullOrUndefined(selectedItem)) {
|
|
await this.deselectItemInList(selectedItem);
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selectedItem = undefined;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
abstract getTaskNames(): Promise<Array<string>>;
|
|
|
|
abstract deselectAllListItems(): Promise<void>;
|
|
|
|
abstract deselectItemInList(item: TItem): Promise<void>;
|
|
|
|
abstract handleSearchbarQuryChanged(query: string): Promise<void>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Protected ...
|
|
public async onBack() {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async isDialogTask(name: string) {
|
|
//
|
|
const pageTasks = await this.getTaskNames();
|
|
const mTaskKey = getTaskName(name);
|
|
const result = pageTasks.includes(mTaskKey);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private async notifyTaskStartEvent(name: string) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onTaskStart && isFunction(config.onTaskStart)) {
|
|
await this.getValueAsync(config.onTaskStart(name));
|
|
}
|
|
}
|
|
|
|
private async notifyTaskFinishedEvent(name: string) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onTaskFinished && isFunction(config.onTaskFinished)) {
|
|
await this.getValueAsync(config.onTaskFinished(name));
|
|
}
|
|
}
|
|
|
|
private async notifyTaskFailedEvent(name: string) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onTaskFailed && isFunction(config.onTaskFailed)) {
|
|
await this.getValueAsync(config.onTaskFailed(name));
|
|
}
|
|
}
|
|
|
|
private registerBackHandler() {
|
|
//
|
|
this.managerService.historyService.platformLocation.onPopState(() => {
|
|
//
|
|
if (this.PREVENT_BACK) {
|
|
this.managerService.historyService.pushEmptyState();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.managerService.historyService.backHandler.asObservable()
|
|
).subscribe(async () => {
|
|
await this.onBack();
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.observable.tools.ts
|
|
|
|
import {
|
|
toArray,
|
|
hasChild,
|
|
notValue,
|
|
toPromise,
|
|
toObservable,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
getDefaultValue,
|
|
isNullOrUndefined,
|
|
XResourceIdentifier,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Observable, forkJoin, of } from 'rxjs';
|
|
|
|
export interface IXBaseObservableTools {
|
|
//
|
|
//#region Action ...
|
|
hasChild: (items: XOneOrManyType<any>) => boolean;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Observables ...
|
|
getValue: <T>(value: XStandardType<T>) => Observable<T>;
|
|
|
|
getArrayValue: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Observable<T[]>;
|
|
|
|
hasChildValue: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Observable<boolean>;
|
|
|
|
countChildsValue: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Observable<number>;
|
|
|
|
getResourceValue: (
|
|
value: XStandardType<XResourceIdentifier>
|
|
) => Observable<string>;
|
|
|
|
notEmptyValue: (value: XStandardType<string | any>) => Observable<boolean>;
|
|
|
|
emptyValue: (value: XStandardType<string | any>) => Observable<boolean>;
|
|
|
|
notValue: (value: XStandardType<boolean>) => Observable<boolean>;
|
|
|
|
mustBeValue: (
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) => Observable<boolean>;
|
|
|
|
atLeastHasOneValue: (
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) => Observable<boolean>;
|
|
|
|
notNullOrUndefinedValue: (value: XStandardType<any>) => Observable<boolean>;
|
|
|
|
nullOrUndefinedValue: (value: XStandardType<any>) => Observable<boolean>;
|
|
|
|
getOptionalValue: <T>(value?: XStandardType<T>) => Observable<T>;
|
|
|
|
getValues: <T>(values?: XOneOrManyType<XStandardType<T>>) => Observable<T[]>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Async of Observables ...
|
|
getValueAsync: <T>(value: XStandardType<T>) => Promise<T>;
|
|
|
|
getArrayValueAsync: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Promise<T[]>;
|
|
|
|
hasChildValueAsync: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Promise<boolean>;
|
|
|
|
countChildsValueAsync: <T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) => Promise<number>;
|
|
|
|
getResourceValueAsync: (
|
|
value: XStandardType<XResourceIdentifier>
|
|
) => Promise<string>;
|
|
|
|
notEmptyValueAsync: (value: XStandardType<string | any>) => Promise<boolean>;
|
|
|
|
emptyValueAsync: (value: XStandardType<string | any>) => Promise<boolean>;
|
|
|
|
notValueAsync: (value: XStandardType<boolean>) => Promise<boolean>;
|
|
|
|
mustBeValueAsync: (
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) => Promise<boolean>;
|
|
|
|
atLeastHasOneValueAsync: (
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) => Promise<boolean>;
|
|
|
|
notNullOrUndefinedValueAsync: (value: XStandardType<any>) => Promise<boolean>;
|
|
|
|
nullOrUndefinedValueAsync: (value: XStandardType<any>) => Promise<boolean>;
|
|
|
|
getOptionalValueAsync: <T>(value?: XStandardType<T>) => Promise<T>;
|
|
|
|
getValuesAsync: <T>(
|
|
values?: XOneOrManyType<XStandardType<T>>
|
|
) => Promise<T[]>;
|
|
//#endregion
|
|
}
|
|
|
|
export abstract class XBaseObservableTools implements IXBaseObservableTools {
|
|
//
|
|
//#region Actions ...
|
|
//
|
|
//#region Observable Actions ...
|
|
/**
|
|
* Check if items has childs or not ...
|
|
*
|
|
* @param items a list item ...
|
|
*/
|
|
public hasChild(items: XOneOrManyType<any>) {
|
|
return hasChild(items);
|
|
}
|
|
|
|
/**
|
|
* convert an standard UI Value to Observable for consuming ...
|
|
*
|
|
* @param value the standard UI Value
|
|
*/
|
|
public getValue<T>(value: XStandardType<T>) {
|
|
return toObservable<T>(value);
|
|
}
|
|
|
|
/**
|
|
* retrieve an standard type var in promise
|
|
*
|
|
* @param value an standard type var
|
|
*/
|
|
public async getValueAsync<T>(value: XStandardType<T>) {
|
|
//
|
|
if (!value) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return await toPromise(this.getValue(value));
|
|
}
|
|
|
|
/**
|
|
* convert to array ...
|
|
*
|
|
* @param value an standard type one or many arg ...
|
|
*/
|
|
public getArrayValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return this.getValue(value).pipe(map((valueType) => toArray(valueType)));
|
|
}
|
|
|
|
/**
|
|
* convert to array ...
|
|
*
|
|
* @param value an standard type one or many arg ...
|
|
*/
|
|
public async getArrayValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return this.getValueAsync(value).then((valueType) => toArray(valueType));
|
|
}
|
|
|
|
/**
|
|
* check a value has child or not ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public hasChildValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
//
|
|
return this.getValue(value).pipe(
|
|
map((valueType) => hasChild(toArray(valueType)))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check a value has child or not ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async hasChildValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
//
|
|
const valueType = await this.getValueAsync(value);
|
|
if (!valueType) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return hasChild(toArray(valueType));
|
|
}
|
|
|
|
/**
|
|
* count a value's child ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public countChildsValue<T>(value: XStandardType<XOneOrManyType<T>>) {
|
|
return this.getValue(value).pipe(
|
|
map((valueType) => toArray(valueType).length)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* count a value's child ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async countChildsValueAsync<T>(
|
|
value: XStandardType<XOneOrManyType<T>>
|
|
) {
|
|
//
|
|
const valueType = await this.getValueAsync(value);
|
|
if (!valueType) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
return toArray(valueType).length;
|
|
}
|
|
|
|
/**
|
|
* providing string resources ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public getResourceValue(value: XStandardType<XResourceIdentifier>) {
|
|
//
|
|
return !value
|
|
? of('')
|
|
: this.getValue(value).pipe(
|
|
map((val) => {
|
|
return val.toString();
|
|
// return this.resourceProvider(val) || (value as string);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* providing string resources ...
|
|
*
|
|
* @param value an standard one or many of type
|
|
*/
|
|
public async getResourceValueAsync(
|
|
value: XStandardType<XResourceIdentifier>
|
|
) {
|
|
//
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const val = await this.getValueAsync(value);
|
|
return val.toString();
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public notEmptyValue(value: XStandardType<string | any>) {
|
|
return this.getValue(value).pipe(map((val) => !isNullOrEmptyString(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public async notEmptyValueAsync(value: any) {
|
|
return await toPromise(this.notEmptyValue(value));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has not content and empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public emptyValue(value: XStandardType<string | any>) {
|
|
return this.getValue(value).pipe(map((val) => isNullOrEmptyString(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has not content and empty
|
|
*
|
|
* @param value an Standard type of string
|
|
*/
|
|
public async emptyValueAsync(value: XStandardType<string | any>) {
|
|
return await toPromise(this.emptyValue(value));
|
|
}
|
|
|
|
/**
|
|
* apply not operator to a boolean ...
|
|
*/
|
|
public notValue(value: XStandardType<boolean>) {
|
|
return notValue(this.getValue(value));
|
|
}
|
|
|
|
/**
|
|
* apply not operator to a boolean ...
|
|
*/
|
|
public async notValueAsync(value: XStandardType<boolean>) {
|
|
return await this.getValueAsync(this.notValue(value));
|
|
}
|
|
|
|
/**
|
|
* check all input args be same as value ...
|
|
*
|
|
* @param value any value which going to check with all args to be same as them ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public mustBeValue(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return forkJoin(values.map((v) => toObservable(v))).pipe(
|
|
map((res) => {
|
|
return res.every((i) => i === value);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check all input args be same as value ...
|
|
*
|
|
* @param value any value which going to check with all args to be same as them ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public async mustBeValueAsync(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return (
|
|
await Promise.all(values.map(async (v) => await this.getValueAsync(v)))
|
|
).every((v) => v === value);
|
|
}
|
|
|
|
/**
|
|
* check all input args contains at least one value ...
|
|
*
|
|
* @param value any value which going to check with all args to find one same ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public atLeastHasOneValue(value: any, ...values: XStandardType<any>[]) {
|
|
//
|
|
return forkJoin(values.map((v) => toObservable(v))).pipe(
|
|
map((res) => {
|
|
return res.includes(value);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check all input args contains at least one value ...
|
|
*
|
|
* @param value any value which going to check with all args to find one same ...
|
|
* @param values the input args which be checked by value ...
|
|
*/
|
|
public async atLeastHasOneValueAsync(
|
|
value: any,
|
|
...values: XStandardType<any>[]
|
|
) {
|
|
//
|
|
return (
|
|
await Promise.all(values.map(async (v) => await this.getValueAsync(v)))
|
|
).includes(value);
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public notNullOrUndefinedValue(value: XStandardType<any>) {
|
|
return this.getValue(value).pipe(map((val) => !isNullOrUndefined(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value has content and not empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public async notNullOrUndefinedValueAsync(value: XStandardType<any>) {
|
|
return await toPromise(this.notNullOrUndefinedValue(value));
|
|
}
|
|
|
|
/**
|
|
* determines a given value content must empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public nullOrUndefinedValue(value: XStandardType<any>) {
|
|
return this.getValue(value).pipe(map((val) => isNullOrUndefined(val)));
|
|
}
|
|
|
|
/**
|
|
* determines a given value content must empty
|
|
*
|
|
* @param value an Standard type of any
|
|
*/
|
|
public async nullOrUndefinedValueAsync(value: XStandardType<any>) {
|
|
return await toPromise(this.nullOrUndefinedValue(value));
|
|
}
|
|
|
|
/**
|
|
* retrieve an optional value ...
|
|
*
|
|
* @param value the optional standard value ...
|
|
*/
|
|
public getOptionalValue<T>(value?: XStandardType<T>): Observable<T> {
|
|
//
|
|
if (value) {
|
|
return this.getValue(value);
|
|
}
|
|
|
|
//
|
|
return this.getValue(getDefaultValue(value));
|
|
}
|
|
|
|
/**
|
|
* retrieve an optional value ...
|
|
*
|
|
* @param value the optional standard value ...
|
|
*/
|
|
public async getOptionalValueAsync<T>(value?: XStandardType<T>) {
|
|
return await toPromise(this.getOptionalValue(value));
|
|
}
|
|
|
|
/**
|
|
* convert all values as observable of them ...
|
|
*
|
|
* @param values the standard list of specific type ...
|
|
* @returns observable of values array of specific type ...
|
|
*/
|
|
public getValues<T>(values?: XOneOrManyType<XStandardType<T>>) {
|
|
//
|
|
interface ForkSourceType<T> {
|
|
[index: number]: XStandardType<T>;
|
|
}
|
|
|
|
//
|
|
return this.getArrayValue(values).pipe(
|
|
concatMap((values) => {
|
|
//
|
|
if (!hasChild(values)) {
|
|
return this.getValue([] as T[]);
|
|
} else {
|
|
//
|
|
const forkSource: ForkSourceType<T> = {};
|
|
values.forEach((value, index) => {
|
|
forkSource[index] = this.getValue(value);
|
|
});
|
|
|
|
//
|
|
return forkJoin(forkSource).pipe(
|
|
map((forkResult) => {
|
|
//
|
|
const respObj = forkResult as any;
|
|
const mKeys = Object.keys(forkResult)
|
|
.map((key) => key)
|
|
.sort((a, b) => +a - +b);
|
|
const result = mKeys.map((mKey: any) => respObj[mKey] as T);
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* convert all values as observable of them ...
|
|
*
|
|
* @param values the standard list of specific type ...
|
|
* @returns observable of values array of specific type ...
|
|
*/
|
|
public async getValuesAsync<T>(values?: XOneOrManyType<XStandardType<T>>) {
|
|
return await toPromise(this.getValues(values));
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\component-templates.module.ts
|
|
|
|
import {
|
|
XCardTestComponent,
|
|
XComponentCardTestComponent,
|
|
} from './x-card.component.templates';
|
|
import {
|
|
XListTestComponent,
|
|
XComponentListTestComponent,
|
|
} from './x-list.component.templates';
|
|
import {
|
|
XTabTestComponent,
|
|
XTabsTestComponent,
|
|
} from './x-tabs.component.templates';
|
|
import {
|
|
XEmptyTestComponent,
|
|
XComponentEmptyTestComponent,
|
|
} from './x-empty.component.templates';
|
|
import {
|
|
XSlideTestComponent,
|
|
XSliderTestComponent,
|
|
} from './x-slider.component.templates';
|
|
import {
|
|
XSlotTestComponent,
|
|
XSlotterTestComponent,
|
|
} from './x-slotter.component.templates';
|
|
import {
|
|
XStepTestComponent,
|
|
XStepperTestComponent,
|
|
} from './x-stepper.component.templates';
|
|
import { NgModule } from '@angular/core';
|
|
import {
|
|
XActionBarTestComponent,
|
|
XComponentActionBarTestComponent,
|
|
} from './x-action-bar.component.templates';
|
|
import {
|
|
XSearchBarTestComponent,
|
|
XComponentSearchBarTestComponent,
|
|
} from './x-search-bar.component.templates';
|
|
import { CommonModule } from '@angular/common';
|
|
import {
|
|
XDescriptionListTestComponent,
|
|
XDescriptionListItemTestComponent,
|
|
} from './x-description-list.component.templates';
|
|
import { XMapModule } from '../x-map/x-map.module';
|
|
import { XFabModule } from '../x-fab/x-fab.module';
|
|
import { XFormModule } from '../x-form/x-form.module';
|
|
import { XGridModule } from '../x-grid/x-grid.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XPageModule } from '../x-page/x-page.module';
|
|
import { XTabsModule } from '../x-tabs/x-tabs.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XTableModule } from '../x-table/x-table.module';
|
|
import { XThemeModule } from '../x-theme/x-theme.module';
|
|
import { XColorModule } from '../x-color/x-color.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XSliderModule } from '../x-slider/x-slider.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XCounterModule } from '../x-counter/x-counter.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XSpinnerModule } from '../x-spinner/x-spinner.module';
|
|
import { XStepperModule } from '../x-stepper/x-stepper.module';
|
|
import { XMapTestComponent } from './x-map.component.templates';
|
|
import { XFabTestComponent } from './x-fab.component.templates';
|
|
import { XPageTestComponent } from './x-page.component.templates';
|
|
import { XMarkdownModule } from '../x-markdown/x-markdown.module';
|
|
import { XFormTestComponent } from './x-form.component.templates';
|
|
import { XGridTestComponent } from './x-grid.component.templates';
|
|
import { XIconTestComponent } from './x-icon.component.templates';
|
|
import { XTableTestComponent } from './x-table.component.templates';
|
|
import { XColorTestComponent } from './x-color.component.templates';
|
|
import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module';
|
|
import { XFooterTestComponent } from './x-footer.component.templates';
|
|
import { XButtonTestComponent } from './x-button.component.templates';
|
|
import { XSearchBarModule } from '../x-search-bar/x-search-bar.module';
|
|
import { XActionBarModule } from '../x-action-bar/x-action-bar.module';
|
|
import { XToolbarTestComponent } from './x-toolbar.component.templates';
|
|
import { XSpinnerTestComponent } from './x-spinner.component.templates';
|
|
import { XCounterTestComponent } from './x-counter.component.templates';
|
|
import { XDataPagerModule } from './../x-data-pager/x-data-pager.module';
|
|
import { XMarkdownTestComponent } from './x-markdown.component.templates';
|
|
import { XFileUploadModule } from '../x-file-upload/x-file-upload.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XThumbnailTestComponent } from './x-thumbnail.component.templates';
|
|
import { XNavigatorTestComponent } from './x-navigator.component.templates';
|
|
import { XDataPagerTestComponent } from './x-data-pager.component.templates';
|
|
import { XColorPickerModule } from '../x-color-picker/x-color-picker.module';
|
|
import { XFileUploadTestComponent } from './x-file-upload.component.templates';
|
|
import { XImageCropperModule } from '../x-image-cropper/x-image-cropper.module';
|
|
import { XAvatarUploadModule } from '../x-avatar-upload/x-avatar-upload.module';
|
|
import { XTabNavigatorModule } from '../x-tab-navigator/x-tab-navigator.module';
|
|
import { XDataScrollerModule } from '../x-data-scroller/x-data-scroller.module';
|
|
import { XColorPickerTestComponent } from './x-color-picker.component.templates';
|
|
import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module';
|
|
import { XTabNavigatorTestComponent } from './x-tab-navigator.component.templates';
|
|
import { XThemeManagerTestComponent } from './x-theme-manager.component.templates';
|
|
import { XAvatarUploadTestComponent } from './x-avatar-upload.component.templates';
|
|
import { XImageCropperTestComponent } from './x-image-cropper.component.templates';
|
|
import { XDataScrollerTestComponent } from './x-data-scroller.component.templates';
|
|
import { XFileDropAreaTestComponent } from './x-file-drop-area.component.templates';
|
|
import { XScreenCaptureTestComponent } from './x-screen-capture.component.templates';
|
|
import { XModelPresenterModule } from '../x-model-presenter/x-model-presenter.module';
|
|
import { XExpandableListModule } from '../x-expandable-list/x-expandable-list.module';
|
|
import { XExpandableListTestComponent } from './x-expandable-list.component.templates';
|
|
import { XModelPresenterTestComponent } from './x-model-presenter.component.templates';
|
|
import { XDescriptionListModule } from '../x-description-list/x-description-list.module';
|
|
import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module';
|
|
import { XExpandablePandelTestComponent } from './x-expandable-panel.component.templates';
|
|
|
|
@NgModule({
|
|
declarations: [
|
|
//
|
|
// x-action-bar ...
|
|
XActionBarTestComponent,
|
|
XComponentActionBarTestComponent,
|
|
//
|
|
// x-avatar-upload ...
|
|
XAvatarUploadTestComponent,
|
|
//
|
|
// x-button ...
|
|
XButtonTestComponent,
|
|
//
|
|
// x-card ...
|
|
XCardTestComponent,
|
|
XComponentCardTestComponent,
|
|
//
|
|
// x-color ...
|
|
XColorTestComponent,
|
|
//
|
|
// x-color-picker ...
|
|
XColorPickerTestComponent,
|
|
//
|
|
// x-counter ...
|
|
XCounterTestComponent,
|
|
//
|
|
// x-data-pager ...
|
|
XDataPagerTestComponent,
|
|
//
|
|
// x-data-scroller ...
|
|
XDataScrollerTestComponent,
|
|
//
|
|
// x-description-list ...
|
|
XDescriptionListTestComponent,
|
|
XDescriptionListItemTestComponent,
|
|
//
|
|
// x-empty ...
|
|
XEmptyTestComponent,
|
|
XComponentEmptyTestComponent,
|
|
//
|
|
// x-expandable-list ...
|
|
XExpandableListTestComponent,
|
|
//
|
|
// x-expandable-panel ...
|
|
XExpandablePandelTestComponent,
|
|
//
|
|
// x-fab ...
|
|
XFabTestComponent,
|
|
//
|
|
// x-file-drop-area ...
|
|
XFileDropAreaTestComponent,
|
|
//
|
|
// x-file-upload ...
|
|
XFileUploadTestComponent,
|
|
//
|
|
// x-form ...
|
|
XFormTestComponent,
|
|
//
|
|
// x-grid ...
|
|
XGridTestComponent,
|
|
//
|
|
// x-icon ...
|
|
XIconTestComponent,
|
|
//
|
|
// x-image-cropper ...
|
|
XImageCropperTestComponent,
|
|
//
|
|
// x-list ...
|
|
XListTestComponent,
|
|
XComponentListTestComponent,
|
|
//
|
|
// x-map ...
|
|
XMapTestComponent,
|
|
//
|
|
// x-markdown ...
|
|
XMarkdownTestComponent,
|
|
//
|
|
// x-model-presenter ...
|
|
XModelPresenterTestComponent,
|
|
//
|
|
// x-page ...
|
|
XPageTestComponent,
|
|
//
|
|
// x-footer ...
|
|
XFooterTestComponent,
|
|
//
|
|
// x-navigator ...
|
|
XNavigatorTestComponent,
|
|
//
|
|
// x-toolbar ...
|
|
XToolbarTestComponent,
|
|
//
|
|
// x-screen-capture ...
|
|
XScreenCaptureTestComponent,
|
|
//
|
|
// x-search-bar ...
|
|
XSearchBarTestComponent,
|
|
XComponentSearchBarTestComponent,
|
|
//
|
|
// x-slider ...
|
|
XSlideTestComponent,
|
|
XSliderTestComponent,
|
|
//
|
|
// x-slotter ...
|
|
XSlotTestComponent,
|
|
XSlotterTestComponent,
|
|
//
|
|
// x-spinner ...
|
|
XSpinnerTestComponent,
|
|
//
|
|
// x-stepper ...
|
|
XStepTestComponent,
|
|
XStepperTestComponent,
|
|
//
|
|
// x-tab-navigator ...
|
|
XTabNavigatorTestComponent,
|
|
//
|
|
// x-table ...
|
|
XTableTestComponent,
|
|
//
|
|
// x-tabs ...
|
|
XTabTestComponent,
|
|
XTabsTestComponent,
|
|
//
|
|
// x-theme-manager ...
|
|
XThemeManagerTestComponent,
|
|
//
|
|
// x-thumbnail ...
|
|
XThumbnailTestComponent,
|
|
],
|
|
imports: [
|
|
//
|
|
CommonModule,
|
|
|
|
//
|
|
XEmptyModule,
|
|
XBaseComponentModule,
|
|
|
|
//
|
|
XFabModule,
|
|
XMapModule,
|
|
XPageModule,
|
|
XCardModule,
|
|
XIconModule,
|
|
XFormModule,
|
|
XTabsModule,
|
|
XTabsModule,
|
|
XListModule,
|
|
XGridModule,
|
|
XColorModule,
|
|
XTableModule,
|
|
XThemeModule,
|
|
XButtonModule,
|
|
XSliderModule,
|
|
XSpinnerModule,
|
|
XStepperModule,
|
|
XSlotterModule,
|
|
XCounterModule,
|
|
XMarkdownModule,
|
|
XDataPagerModule,
|
|
XSearchBarModule,
|
|
XThumbnailModule,
|
|
XActionBarModule,
|
|
XFileUploadModule,
|
|
XColorPickerModule,
|
|
XImageCropperModule,
|
|
XFileDropAreaModule,
|
|
XDataScrollerModule,
|
|
XTabNavigatorModule,
|
|
XAvatarUploadModule,
|
|
XExpandableListModule,
|
|
XModelPresenterModule,
|
|
XExpandablePanelModule,
|
|
XDescriptionListModule,
|
|
],
|
|
exports: [],
|
|
})
|
|
export class XComponentTemplatesModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-action-bar.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import {
|
|
XActionBarContainerComponent,
|
|
XComponentActionBarContainerComponent,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-action-bar
|
|
[color]="props.color"
|
|
[actions]="props.actions"
|
|
[cssClass]="props.cssClass"
|
|
(actionFired)="(props.actionFired)"
|
|
[actionProvider]="props.actionProvider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
>
|
|
</x-action-bar>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XActionBarTestComponent extends XActionBarContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showActionBar">
|
|
<x-action-bar
|
|
[color]="props.actionBarColor"
|
|
[actions]="props.actionBarActions"
|
|
[cssClass]="props.actionBarCssClass"
|
|
(actionFired)="(props.actionBarActionFired)"
|
|
[actionProvider]="props.actionBarActionProvider"
|
|
[foregroundColor]="props.actionBarForegroundColor"
|
|
></x-action-bar>
|
|
</ng-container>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XComponentActionBarTestComponent extends XComponentActionBarContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-avatar-upload.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XAvatarUploadContainerComponent } from '../x-avatar-upload/x-avatar-upload.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-avatar-upload
|
|
[color]="props.color"
|
|
[actions]="props.actions"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
(avatarChange)="(props.avatarChange)"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
[maxAllowedSize]="props.maxAllowedSize"
|
|
[fileDropAreaCardForegroundColor]="
|
|
props.fileDropAreaCardForegroundColor
|
|
"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[maxAllowedFiles]="props.maxAllowedFiles"
|
|
[fileDropAreaSupportsMultipleFiles]="
|
|
props.fileDropAreaSupportsMultipleFiles
|
|
"
|
|
[showFileDropArea]="props.showFileDropArea"
|
|
[fileDropAreaIcon]="props.fileDropAreaIcon"
|
|
[fileDropAreaColor]="props.fileDropAreaColor"
|
|
[placeHolderAvatar]="props.placeHolderAvatar"
|
|
[allowedExtensions]="props.allowedExtensions"
|
|
[minAllowedFileSize]="props.minAllowedFileSize"
|
|
[maxAllowedFileSize]="props.maxAllowedFileSize"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[emptyFileException]="props.emptyFileException"
|
|
[fileDropAreaMessage]="props.fileDropAreaMessage"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[fileDropAreaIsInPage]="props.fileDropAreaIsInPage"
|
|
[fileDropAreaCssClass]="props.fileDropAreaCssClass"
|
|
[fileDropAreaCardColor]="props.fileDropAreaCardColor"
|
|
[fileDropAreaCardTitle]="props.fileDropAreaCardTitle"
|
|
[fileDropAreaErrorColor]="props.fileDropAreaErrorColor"
|
|
[fileDropAreaAccentColor]="props.fileDropAreaAccentColor"
|
|
[maxAllowedSizeException]="props.maxAllowedSizeException"
|
|
[notAllowedFileException]="props.notAllowedFileException"
|
|
[fileDropAreaSuccessColor]="props.fileDropAreaSuccessColor"
|
|
[fileDropAreaWrapWithCard]="props.fileDropAreaWrapWithCard"
|
|
[maxAllowedFilesException]="props.maxAllowedFilesException"
|
|
[fileDropAreaDragDisabled]="props.fileDropAreaDragDisabled"
|
|
[fileDropAreaCardSubTitle]="props.fileDropAreaCardSubTitle"
|
|
[fileDropAreaCardCssClass]="props.fileDropAreaCardCssClass"
|
|
[fileDropAreaCardShowFooter]="props.fileDropAreaCardShowFooter"
|
|
[fileDropAreaActionProvider]="props.fileDropAreaActionProvider"
|
|
[fileDropAreaContentTemplate]="props.fileDropAreaContentTemplate"
|
|
[minAllowedFileSizeException]="props.minAllowedFileSizeException"
|
|
[maxAllowedFileSizeException]="props.maxAllowedFileSizeException"
|
|
[fileDropAreaForegroundColor]="props.fileDropAreaForegroundColor"
|
|
[fileDropAreaDisableFileCheck]="props.fileDropAreaDisableFileCheck"
|
|
[fileDropAreaAllowedExtensions]="props.fileDropAreaAllowedExtensions"
|
|
(fileDropAreaFilesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
|
|
[fileDropAreaCardActionProvider]="props.fileDropAreaCardActionProvider"
|
|
>
|
|
</x-avatar-upload>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XAvatarUploadTestComponent extends XAvatarUploadContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-button.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XButtonContainerComponent } from '../x-button/x-button.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-button
|
|
[type]="props.type"
|
|
[icon]="props.icon"
|
|
[title]="props.title"
|
|
[color]="props.color"
|
|
(clicked)="(props.clicked)"
|
|
[cssClass]="props.cssClass"
|
|
[iconColor]="props.iconColor"
|
|
[iconPosition]="props.iconPosition"
|
|
[actionProvider]="props.actionProvider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
>
|
|
</x-button>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XButtonTestComponent extends XButtonContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-card.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import {
|
|
XCardContainerComponent,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-card
|
|
[title]="props.title"
|
|
[color]="props.color"
|
|
[isInPage]="props.isInPage"
|
|
[cssClass]="props.cssClass"
|
|
[imageUrl]="props.imageUrl"
|
|
[subTitle]="props.subTitle"
|
|
[avatarUrl]="props.avatarUrl"
|
|
[showHeader]="props.showHeader"
|
|
[showFooter]="props.showFooter"
|
|
[showContent]="props.showContent"
|
|
[showActions]="props.showActions"
|
|
[actionProvider]="props.actionProvider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[imageDescription]="props.imageDescription"
|
|
>
|
|
</x-card>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XCardTestComponent extends XCardContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<!-- Standalone Template -->
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.wrapWithCard">
|
|
<x-card
|
|
[title]="props.cardTitle"
|
|
[color]="props.cardColor"
|
|
[isInPage]="props.isInPage"
|
|
[cssClass]="props.cardCssClass"
|
|
[subTitle]="props.cardSubTitle"
|
|
[showFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.cardActionProvider"
|
|
[foregroundColor]="props.cardForegroundColor"
|
|
>
|
|
</x-card>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Component Present Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="props.cardColor"
|
|
[ngClass]="props.cardCssClass"
|
|
[isInPage]="props.isInPage"
|
|
[showHeader]="
|
|
(notEmptyValue(props.cardTitle) | async) ||
|
|
(notEmptyValue(props.cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(props.cardSubTitle)"
|
|
[title]="getResourceValue(props.cardTitle) | async"
|
|
[showFooter]="getValue(props.cardShowFooter) | async"
|
|
[foregroundColor]="getValue(props.cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="props.cardCssClass" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="props.cardShowFooter">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef> </ng-template>
|
|
`,
|
|
})
|
|
export class XComponentCardTestComponent extends XComponentCardContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-color-picker.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XColorPickerContainerComponent } from '../x-color-picker/x-color-picker.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-color-picker
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardColor]="props.cardColor"
|
|
[cursorColor]="props.cursorColor"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[presetColors]="props.presetColors"
|
|
[outputFormat]="props.outputFormat"
|
|
[selectedColor]="props.selectedColor"
|
|
[colorTextColor]="props.colorTextColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
(colorSelected)="(props.colorSelected)"
|
|
[showColorInput]="props.showColorInput"
|
|
[showHueChannel]="props.showHueChannel"
|
|
[showColorValue]="props.showColorValue"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[showAlphaChannel]="props.showAlphaChannel"
|
|
[showPresetColors]="props.showPresetColors"
|
|
[presetColorsLable]="props.presetColorsLable"
|
|
[showPaletteChannel]="props.showPaletteChannel"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[colorInputIconColor]="props.colorInputIconColor"
|
|
[clearColorIconColor]="props.clearColorIconColor"
|
|
[colorInputIconLabel]="props.colorInputIconLabel"
|
|
[clearColorIconLabel]="props.clearColorIconLabel"
|
|
[showCopyToClipboard]="props.showCopyToClipboard"
|
|
[representColorFormats]="props.representColorFormats"
|
|
[presetColorsLableColor]="props.presetColorsLableColor"
|
|
[copyToClipboardIconLabel]="props.copyToClipboardIconLabel"
|
|
[showSelectedColorPreview]="props.showSelectedColorPreview"
|
|
[copyToClipboardIconColor]="props.copyToClipboardIconColor"
|
|
>
|
|
</x-color-picker>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XColorPickerTestComponent extends XColorPickerContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-color.component.templates.ts
|
|
|
|
import { Component } from "@angular/core";
|
|
import { XColorContainerComponent } from "../x-color/x-color.typings";
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-color
|
|
[size]="props.size"
|
|
[value]="props.value"
|
|
[cssClass]="props.cssClass"
|
|
[showLabel]="props.showLabel"
|
|
[labelColor]="props.labelColor"
|
|
[borderWidth]="props.borderWidth"
|
|
[borderStyle]="props.borderStyle"
|
|
[borderColor]="props.borderColor"
|
|
[actionProvider]="props.actionProvider"
|
|
>
|
|
</x-color>
|
|
</ng-container>
|
|
`
|
|
})
|
|
export class XColorTestComponent extends XColorContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-counter.component.templates.ts
|
|
|
|
|
|
import { Component } from "@angular/core";
|
|
import { XCounterContainerComponent } from "../x-counter/x-counter.typings";
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-counter
|
|
[type]="props.type"
|
|
[delay]="props.delay"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardTitle]="props.cardTitle"
|
|
[stopValue]="props.stopValue"
|
|
[cardColor]="props.cardColor"
|
|
[startValue]="props.startValue"
|
|
[currentValue]="props.currentValue"
|
|
(counterStop)="(props.counterStop)"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
(counterStart)="(props.counterStart)"
|
|
(counterTtick)="(props.counterTtick)"
|
|
[displayPattern]="props.displayPattern"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
>
|
|
</x-counter>
|
|
</ng-container>
|
|
`
|
|
})
|
|
export class XCounterTestComponent extends XCounterContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-data-pager.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XDataPagerContainerComponent } from '../x-data-pager/x-data-pager.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-data-pager
|
|
[type]="props.type"
|
|
[task]="props.task"
|
|
[query]="props.query"
|
|
[result]="props.result"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardColor]="props.cardColor"
|
|
[emptyColor]="props.emptyColor"
|
|
(taskReady)="(props.taskReady)"
|
|
(pageChanged)="(props.pageChanged)"
|
|
(queryChange)="(props.queryChange)"
|
|
[itemTemplate]="props.itemTemplate"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[emptyMessage]="props.emptyMessage"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
[showPaginator]="props.showPaginator"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[paginatorColor]="props.paginatorColor"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[paginatorOptions]="props.paginatorOptions"
|
|
[emptyListTemplate]="props.emptyListTemplate"
|
|
[paginatorPosition]="props.paginatorPosition"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
>
|
|
</x-data-pager>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XDataPagerTestComponent extends XDataPagerContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-data-scroller.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XDataScrollerContainerComponent } from '../x-data-scroller/x-data-scroller.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-data-scroller
|
|
[task]="props.task"
|
|
[query]="props.query"
|
|
[result]="props.result"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardColor]="props.cardColor"
|
|
[emptyColor]="props.emptyColor"
|
|
(taskReady)="(props.taskReady)"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[emptyMessage]="props.emptyMessage"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
(queryChange)="(props.queryChange)"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[emptyListTemplate]="props.emptyListTemplate"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
>
|
|
</x-data-scroller>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XDataScrollerTestComponent extends XDataScrollerContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-description-list.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XDescriptionListContainerComponent } from '../x-description-list/x-description-list.typings';
|
|
import { XDescriptionListItemContainerComponent } from '../x-description-list/x-description-list-item/x-description-list-item.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-description-list
|
|
[color]="props.color"
|
|
[model]="props.model"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[isLegacy]="props.isLegacy"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardColor]="props.cardColor"
|
|
[showLabels]="props.showLabels"
|
|
[labelColor]="props.labelColor"
|
|
[valueColor]="props.valueColor"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
(onModelChanged)="(props.onModelChanged)"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[hiddenModelKeys]="props.hiddenModelKeys"
|
|
[modelKeyProvider]="props.modelKeyProvider"
|
|
[modelValueProvider]="props.modelValueProvider"
|
|
[hideOptionalValues]="props.hideOptionalValues"
|
|
[availableModelKeys]="props.availableModelKeys"
|
|
[sortOrderModelKeys]="props.sortOrderModelKeys"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[hiddenLabelModelKeys]="props.hiddenLabelModelKeys"
|
|
[propertyActionTemplate]="props.propertyActionTemplate"
|
|
>
|
|
</x-description-list>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XDescriptionListTestComponent extends XDescriptionListContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-description-list-item
|
|
[name]="props.name"
|
|
[value]="props.value"
|
|
[cssClass]="props.cssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
>
|
|
</x-description-list-item>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XDescriptionListItemTestComponent extends XDescriptionListItemContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-empty.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import {
|
|
XComponentEmptyContainerComponent,
|
|
XEmptyContainerComponent,
|
|
} from '../x-empty/x-empty.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-empty
|
|
[color]="props.color"
|
|
[message]="props.message"
|
|
(refresh)="(props.refresh)"
|
|
[cssClass]="props.cssClass"
|
|
[hasRefresh]="props.hasRefresh"
|
|
[refreshIcon]="props.refreshIcon"
|
|
[messageColor]="props.messageColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[refreshButtonColor]="props.refreshButtonColor"
|
|
[foregroundMessageColor]="props.foregroundMessageColor"
|
|
[foregroundRefreshButtonColor]="props.foregroundRefreshButtonColor"
|
|
>
|
|
</x-empty>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XEmptyTestComponent extends XEmptyContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showEmpty">
|
|
<x-empty
|
|
[color]="props.emptyColor"
|
|
[message]="props.emptyMessage"
|
|
(refresh)="(props.emptyRefresh)"
|
|
[cssClass]="props.emptyCssClass"
|
|
[hasRefresh]="props.emptyHasRefresh"
|
|
[refreshIcon]="props.emptyRefreshIcon"
|
|
[messageColor]="props.emptyMessageColor"
|
|
[actionProvider]="props.emptyActionProvider"
|
|
[foregroundColor]="props.emptyForegroundColor"
|
|
[refreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[foregroundMessageColor]="props.emptyForegroundMessageColor"
|
|
[foregroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
>
|
|
</x-empty>
|
|
</ng-container>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XComponentEmptyTestComponent extends XComponentEmptyContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-expandable-list.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XExpandableListContainerComponent } from '../x-expandable-list/x-expandable-list.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-expandable-list
|
|
[items]="props.items"
|
|
[isInPage]="props.isInPage"
|
|
[cssClass]="props.cssClass"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[childColor]="props.childColor"
|
|
[parentColor]="props.parentColor"
|
|
[dividerColor]="props.dividerColor"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[itemCssClass]="props.itemCssClass"
|
|
[startupState]="props.startupState"
|
|
(itemSelected)="(props.itemSelected)"
|
|
[closeSiblings]="props.closeSiblings"
|
|
[childTemplate]="props.childTemplate"
|
|
[highlightColor]="props.highlightColor"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
[supportRouting]="props.supportRouting"
|
|
[parentTemplate]="props.parentTemplate"
|
|
[childActiveColor]="props.childActiveColor"
|
|
[parentActiveColor]="props.parentActiveColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[showChildDetailIcon]="props.showChildDetailIcon"
|
|
[disableParentRouting]="props.disableParentRouting"
|
|
[showParentDetailIcon]="props.showParentDetailIcon"
|
|
>
|
|
</x-expandable-list>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XExpandableListTestComponent extends XExpandableListContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-expandable-panel.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XExpandablePandelContainerComponent } from '../x-expandable-panel/x-expandable-panel.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-expandable-panel
|
|
[canNext]="props.canNext"
|
|
(onNext)="(props.onNext)"
|
|
[canPrev]="props.canPrev"
|
|
(onPrev)="(props.onPrev)"
|
|
[cssClass]="props.cssClass"
|
|
[selected]="props.selected"
|
|
[isInPage]="props.isInPage"
|
|
[canReset]="props.canReset"
|
|
(onReset)="(props.onReset)"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[isAccordion]="props.isAccordion"
|
|
[applyColors]="props.applyColors"
|
|
[headerColor]="props.headerColor"
|
|
[startupState]="props.startupState"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[multiExpanded]="props.multiExpanded"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[resetConfirmer]="props.resetConfirmer"
|
|
(selectedChange)="(props.selectedChange)"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[headerHighlightColor]="props.headerHighlightColor"
|
|
[hideDescriptionOnSmallScreens]="props.hideDescriptionOnSmallScreens"
|
|
>
|
|
</x-expandable-panel>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XExpandablePandelTestComponent extends XExpandablePandelContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-fab.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XFabContainerComponent } from '../x-fab/x-fab.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-fab
|
|
[item]="props.item"
|
|
[cssClass]="props.cssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
[childsCssClass]="props.childsCssClass"
|
|
>
|
|
</x-fab>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XFabTestComponent extends XFabContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-file-drop-area.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XFileDropAreaContainerComponent } from '../x-file-drop-area/x-file-drop-area.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-file-drop-area
|
|
[icon]="props.icon"
|
|
[color]="props.color"
|
|
[message]="props.message"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardColor]="props.cardColor"
|
|
[errorColor]="props.errorColor"
|
|
[accentColor]="props.accentColor"
|
|
[dragDisabled]="props.dragDisabled"
|
|
[successColor]="props.successColor"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[contentTemplate]="props.contentTemplate"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[disableFileCheck]="props.disableFileCheck"
|
|
[allowedExtensions]="props.allowedExtensions"
|
|
(filesChangeEmiter)="(props.filesChangeEmiter)"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[supportsMultipleFiles]="props.supportsMultipleFiles"
|
|
></x-file-drop-area>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XFileDropAreaTestComponent extends XFileDropAreaContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-file-upload.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XFileUploadContainerComponent } from '../x-file-upload/x-file-upload.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-file-upload
|
|
[color]="props.color"
|
|
[isInPage]="props.isInPage"
|
|
[showList]="props.showList"
|
|
[cssClass]="props.cssClass"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[showEmpty]="props.showEmpty"
|
|
[emptyColor]="props.emptyColor"
|
|
(fileChange)="(props.fileChange)"
|
|
[emptyMessage]="props.emptyMessage"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[listCssClass]="props.listCssClass"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
[searchBarType]="props.searchBarType"
|
|
[showActionBar]="props.showActionBar"
|
|
[showSearchBar]="props.showSearchBar"
|
|
[searchBarTitle]="props.searchBarTitle"
|
|
[searchBarValue]="props.searchBarValue"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
[maxAllowedSize]="props.maxAllowedSize"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionBarColor]="props.actionBarColor"
|
|
[searchBarColor]="props.searchBarColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[maxAllowedFiles]="props.maxAllowedFiles"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[listShowToolbar]="props.listShowToolbar"
|
|
[listShowDivider]="props.listShowDivider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[fileDropAreaSupportsMultipleFiles]="
|
|
props.fileDropAreaSupportsMultipleFiles
|
|
"
|
|
[actionBarActions]="props.actionBarActions"
|
|
[showFileDropArea]="props.showFileDropArea"
|
|
[fileDropAreaIcon]="props.fileDropAreaIcon"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[searchBarForegroundSearchInputColor]="
|
|
props.searchBarForegroundSearchInputColor
|
|
"
|
|
[allowedExtensions]="props.allowedExtensions"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[searchBarDebounce]="props.searchBarDebounce"
|
|
(searchBarOnEvent)="(props.searchBarOnEvent)"
|
|
[listConfirmRemove]="props.listConfirmRemove"
|
|
[listStickyToolbar]="props.listStickyToolbar"
|
|
[actionBarCssClass]="props.actionBarCssClass"
|
|
[searchBarCssClass]="props.searchBarCssClass"
|
|
[fileDropAreaColor]="props.fileDropAreaColor"
|
|
[emptyFileException]="props.emptyFileException"
|
|
[minAllowedFileSize]="props.minAllowedFileSize"
|
|
[maxAllowedFileSize]="props.maxAllowedFileSize"
|
|
[searchBarClearIcon]="props.searchBarClearIcon"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[listActionProvider]="props.listActionProvider"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[searchBarSearchIcon]="props.searchBarSearchIcon"
|
|
[searchBarSpellcheck]="props.searchBarSpellcheck"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[fileDropAreaMessage]="props.fileDropAreaMessage"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[listEnableReordering]="props.listEnableReordering"
|
|
[listFilteringHandler]="props.listFilteringHandler"
|
|
[fileDropAreaCssClass]="props.fileDropAreaCssClass"
|
|
(searchBarQueryChange)="(props.searchBarQueryChange)"
|
|
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
|
|
[searchBarKeyboardType]="props.searchBarKeyboardType"
|
|
(actionBarActionFired)="(props.actionBarActionFired)"
|
|
[fileDropAreaErrorColor]="props.fileDropAreaErrorColor"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[notAllowedFileException]="props.notAllowedFileException"
|
|
[maxAllowedSizeException]="props.maxAllowedSizeException"
|
|
[searchBarClearIconColor]="props.searchBarClearIconColor"
|
|
[actionBarActionProvider]="props.actionBarActionProvider"
|
|
[searchBarActionProvider]="props.searchBarActionProvider"
|
|
[fileDropAreaAccentColor]="props.fileDropAreaAccentColor"
|
|
[maxAllowedFilesException]="props.maxAllowedFilesException"
|
|
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
|
|
[actionBarForegroundColor]="props.actionBarForegroundColor"
|
|
[searchBarForegroundColor]="props.searchBarForegroundColor"
|
|
[fileDropAreaDragDisabled]="props.fileDropAreaDragDisabled"
|
|
[fileDropAreaSuccessColor]="props.fileDropAreaSuccessColor"
|
|
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
|
|
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
|
|
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
|
|
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
|
|
[fileDropAreaActionProvider]="props.fileDropAreaActionProvider"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
[minAllowedFileSizeException]="props.minAllowedFileSizeException"
|
|
[maxAllowedFileSizeException]="props.maxAllowedFileSizeException"
|
|
[fileDropAreaForegroundColor]="props.fileDropAreaForegroundColor"
|
|
[fileDropAreaContentTemplate]="props.fileDropAreaContentTemplate"
|
|
[fileDropAreaDisableFileCheck]="props.fileDropAreaDisableFileCheck"
|
|
[fileDropAreaAllowedExtensions]="props.fileDropAreaAllowedExtensions"
|
|
(fileDropAreaFilesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
|
|
>
|
|
</x-file-upload>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XFileUploadTestComponent extends XFileUploadContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-footer.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XFooterContainerComponent } from '../x-page/x-footer/x-footer.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-footer
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
[contentTemplate]="props.contentTemplate"
|
|
>
|
|
</x-footer>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XFooterTestComponent extends XFooterContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-form.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XFormContainerComponent } from '../x-form/x-form.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-form
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[hintColor]="props.hintColor"
|
|
[fillColor]="props.fillColor"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[formConfig]="props.formConfig"
|
|
[validColor]="props.validColor"
|
|
[accentColor]="props.accentColor"
|
|
[activeColor]="props.activeColor"
|
|
[regularColor]="props.regularColor"
|
|
[invalidColor]="props.invalidColor"
|
|
[pendingColor]="props.pendingColor"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[disabledColor]="props.disabledColor"
|
|
(valueChanged)="(props.valueChanged)"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
(statusChanged)="(props.statusChanged)"
|
|
(controlBlured)="(props.controlBlured)"
|
|
(controlFocused)="(props.controlFocused)"
|
|
[disabledFillColor]="props.disabledFillColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
(controlValueChanged)="(props.controlValueChanged)"
|
|
[applyStatusOnControls]="props.applyStatusOnControls"
|
|
(controlStatusChanged)="(props.controlStatusChanged)"
|
|
>
|
|
</x-form>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XFormTestComponent extends XFormContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-grid.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XGridContainerComponent } from '../x-grid/x-grid.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-grid
|
|
[gap]="props.gap"
|
|
[cols]="props.cols"
|
|
[type]="props.type"
|
|
[align]="props.align"
|
|
[items]="props.items"
|
|
[layout]="props.layout"
|
|
[options]="props.options"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[showEmpty]="props.showEmpty"
|
|
[emptyColor]="props.emptyColor"
|
|
[itemTemplate]="props.itemTemplate"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[emptyMessage]="props.emptyMessage"
|
|
(itemSelected)="(props.itemSelected)"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[selectableItems]="props.selectableItems"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
></x-grid>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XGridTestComponent extends XGridContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-icon.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XIconContainerComponent } from '../x-icon/x-icon.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-icon
|
|
[slot]="props.slot"
|
|
[name]="props.name"
|
|
[color]="props.color"
|
|
(clicked)="(props.clicked)"
|
|
[cssClass]="props.cssClass"
|
|
[clickable]="props.clickable"
|
|
[selectable]="props.selectable"
|
|
[actionProvider]="props.actionProvider"
|
|
[applyDirection]="props.applyDirection"
|
|
[foregroundColor]="props.foregroundColor"
|
|
>
|
|
</x-icon>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XIconTestComponent extends XIconContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-image-cropper.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XImageCropperContainerComponent } from '../x-image-cropper/x-image-cropper.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-image-cropper
|
|
[format]="props.format"
|
|
[cropper]="props.cropper"
|
|
[autoCrop]="props.autoCrop"
|
|
[cssClass]="props.cssClass"
|
|
[alignImage]="props.alignImage"
|
|
[outputType]="props.outputType"
|
|
[imageBase64]="props.imageBase64"
|
|
[aspectRatio]="props.aspectRatio"
|
|
[imageQuality]="props.imageQuality"
|
|
[roundCropper]="props.roundCropper"
|
|
(imageLoaded)="(props.imageLoaded)"
|
|
[onlyScaleDown]="props.onlyScaleDown"
|
|
[resizeToWidth]="props.resizeToWidth"
|
|
(imageCropped)="(props.imageCropped)"
|
|
(cropperReady)="(props.cropperReady)"
|
|
[actionProvider]="props.actionProvider"
|
|
[cropperMinWidth]="props.cropperMinWidth"
|
|
(startCropImage)="(props.startCropImage)"
|
|
(loadImageFailed)="(props.loadImageFailed)"
|
|
[imageFileChanged]="props.imageFileChanged"
|
|
[cropperMinHeight]="props.cropperMinHeight"
|
|
(imageCroppedFile)="(props.imageCroppedFile)"
|
|
[imageChangedEvent]="props.imageChangedEvent"
|
|
[maintainAspectRatio]="props.maintainAspectRatio"
|
|
(imageCroppedBase64)="(props.imageCroppedBase64)"
|
|
>
|
|
</x-image-cropper>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XImageCropperTestComponent extends XImageCropperContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-list.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import {
|
|
XComponentListContainerComponent,
|
|
XListContainerComponent,
|
|
} from '../x-list/x-list.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-list
|
|
[items]="props.items"
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[showEmpty]="props.showEmpty"
|
|
[emptyColor]="props.emptyColor"
|
|
[showToolbar]="props.showToolbar"
|
|
[showDivider]="props.showDivider"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
(removeItems)="(props.removeItems)"
|
|
[itemTemplate]="props.itemTemplate"
|
|
[emptyMessage]="props.emptyMessage"
|
|
(itemsChanged)="(props.itemsChanged)"
|
|
(orderChanged)="(props.orderChanged)"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
(itemSelected)="(props.itemSelected)"
|
|
[confirmRemove]="props.confirmRemove"
|
|
[stickyToolbar]="props.stickyToolbar"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[showActionBar]="props.showActionBar"
|
|
[showSearchBar]="props.showSearchBar"
|
|
[searchBarType]="props.searchBarType"
|
|
[searchBarTitle]="props.searchBarTitle"
|
|
[searchBarValue]="props.searchBarValue"
|
|
[actionProvider]="props.actionProvider"
|
|
[clickableItems]="props.clickableItems"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionBarColor]="props.actionBarColor"
|
|
[searchBarColor]="props.searchBarColor"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
(optionSelected)="(props.optionSelected)"
|
|
[showItemOptions]="props.showItemOptions"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[selectableItems]="props.selectableItems"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[searchBarForegroundSearchInputColor]="
|
|
props.searchBarForegroundSearchInputColor
|
|
"
|
|
[filteringHandler]="props.filteringHandler"
|
|
[enableReordering]="props.enableReordering"
|
|
[actionBarActions]="props.actionBarActions"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[showOptionsAsMenuWhenSlidingAvailable]="
|
|
props.showOptionsAsMenuWhenSlidingAvailable
|
|
"
|
|
[searchBarDebounce]="props.searchBarDebounce"
|
|
(searchBarOnEvent)="(props.searchBarOnEvent)"
|
|
(selectionChanged)="(props.selectionChanged)"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[actionBarCssClass]="props.actionBarCssClass"
|
|
[searchBarCssClass]="props.searchBarCssClass"
|
|
[searchBarClearIcon]="props.searchBarClearIcon"
|
|
[showOptionsAsSlide]="props.showOptionsAsSlide"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[searchBarSearchIcon]="props.searchBarSearchIcon"
|
|
[searchBarSpellcheck]="props.searchBarSpellcheck"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
|
|
[searchBarKeyboardType]="props.searchBarKeyboardType"
|
|
(searchBarQueryChange)="(props.searchBarQueryChange)"
|
|
[slidingOptionTemplate]="props.slidingOptionTemplate"
|
|
(actionBarActionFired)="(props.actionBarActionFired)"
|
|
[searchBarClearIconColor]="props.searchBarClearIconColor"
|
|
[closeOptionsAfterSelect]="props.closeOptionsAfterSelect"
|
|
[actionBarActionProvider]="props.actionBarActionProvider"
|
|
[searchBarActionProvider]="props.searchBarActionProvider"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
|
|
[nonSlidingOptionTemplate]="props.nonSlidingOptionTemplate"
|
|
[actionBarForegroundColor]="props.actionBarForegroundColor"
|
|
[searchBarForegroundColor]="props.searchBarForegroundColor"
|
|
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
|
|
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
|
|
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
|
|
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
>
|
|
</x-list>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XListTestComponent extends XListContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showList">
|
|
<x-list
|
|
[items]="props.listItems"
|
|
[color]="props.listColor"
|
|
[cssClass]="props.listCssClass"
|
|
[isInPage]="props.listIsInPage"
|
|
[cardColor]="props.listCardColor"
|
|
[cardTitle]="props.listCardTitle"
|
|
[showEmpty]="props.listShowEmpty"
|
|
[emptyColor]="props.listEmptyColor"
|
|
[showToolbar]="props.listShowToolbar"
|
|
[showDivider]="props.listShowDivider"
|
|
[cardCssClass]="props.listCardCssClass"
|
|
[cardSubTitle]="props.listCardSubTitle"
|
|
[wrapWithCard]="props.listWrapWithCard"
|
|
(removeItems)="(props.listRemoveItems)"
|
|
[itemTemplate]="props.listItemTemplate"
|
|
[emptyMessage]="props.listEmptyMessage"
|
|
(itemsChanged)="(props.listItemsChanged)"
|
|
(orderChanged)="(props.listOrderChanged)"
|
|
[emptyCssClass]="props.listEmptyCssClass"
|
|
(itemSelected)="(props.listItemSelected)"
|
|
[confirmRemove]="props.listConfirmRemove"
|
|
[stickyToolbar]="props.listStickyToolbar"
|
|
(emptyRefresh)="(props.listEmptyRefresh)"
|
|
[showActionBar]="props.listShowActionBar"
|
|
[showSearchBar]="props.listShowSearchBar"
|
|
[searchBarType]="props.listSearchBarType"
|
|
[searchBarTitle]="props.listSearchBarTitle"
|
|
[searchBarValue]="props.listSearchBarValue"
|
|
[actionProvider]="props.listActionProvider"
|
|
[clickableItems]="props.listClickableItems"
|
|
[cardShowFooter]="props.listCardShowFooter"
|
|
[actionBarColor]="props.listActionBarColor"
|
|
[searchBarColor]="props.listSearchBarColor"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.listEmptyForegroundRefreshButtonColor
|
|
"
|
|
(optionSelected)="(props.listOptionSelected)"
|
|
[showItemOptions]="props.listShowItemOptions"
|
|
[emptyHasRefresh]="props.listEmptyHasRefresh"
|
|
[selectableItems]="props.listSelectableItems"
|
|
[foregroundColor]="props.listForegroundColor"
|
|
[searchBarForegroundSearchInputColor]="
|
|
props.listSearchBarForegroundSearchInputColor
|
|
"
|
|
[filteringHandler]="props.listFilteringHandler"
|
|
[enableReordering]="props.listEnableReordering"
|
|
[actionBarActions]="props.listActionBarActions"
|
|
[emptyRefreshIcon]="props.listEmptyRefreshIcon"
|
|
[showOptionsAsMenuWhenSlidingAvailable]="
|
|
props.listShowOptionsAsMenuWhenSlidingAvailable
|
|
"
|
|
[searchBarDebounce]="props.listSearchBarDebounce"
|
|
(searchBarOnEvent)="(props.listSearchBarOnEvent)"
|
|
(selectionChanged)="(props.listSelectionChanged)"
|
|
[emptyMessageColor]="props.listEmptyMessageColor"
|
|
[actionBarCssClass]="props.listActionBarCssClass"
|
|
[searchBarCssClass]="props.listSearchBarCssClass"
|
|
[searchBarClearIcon]="props.listSearchBarClearIcon"
|
|
[showOptionsAsSlide]="props.listShowOptionsAsSlide"
|
|
[cardActionProvider]="props.listCardActionProvider"
|
|
[searchBarSearchIcon]="props.listSearchBarSearchIcon"
|
|
[searchBarSpellcheck]="props.listSearchBarSpellcheck"
|
|
[cardForegroundColor]="props.listCardForegroundColor"
|
|
[emptyActionProvider]="props.listEmptyActionProvider"
|
|
[emptyForegroundColor]="props.listEmptyForegroundColor"
|
|
[searchBarEnterKeyHint]="props.listSearchBarEnterKeyHint"
|
|
[searchBarKeyboardType]="props.listSearchBarKeyboardType"
|
|
(searchBarQueryChange)="(props.listSearchBarQueryChange)"
|
|
[slidingOptionTemplate]="props.listSlidingOptionTemplate"
|
|
(actionBarActionFired)="(props.listActionBarActionFired)"
|
|
[searchBarClearIconColor]="props.listSearchBarClearIconColor"
|
|
[closeOptionsAfterSelect]="props.listCloseOptionsAfterSelect"
|
|
[actionBarActionProvider]="props.listActionBarActionProvider"
|
|
[searchBarActionProvider]="props.listSearchBarActionProvider"
|
|
[emptyRefreshButtonColor]="props.listEmptyRefreshButtonColor"
|
|
[searchBarSearchIconColor]="props.listSearchBarSearchIconColor"
|
|
[nonSlidingOptionTemplate]="props.listNonSlidingOptionTemplate"
|
|
[actionBarForegroundColor]="props.listActionBarForegroundColor"
|
|
[searchBarForegroundColor]="props.listSearchBarForegroundColor"
|
|
[searchBarShowCancelButton]="props.listSearchBarShowCancelButton"
|
|
[searchBarCancelButtonIcon]="props.listSearchBarCancelButtonIcon"
|
|
[searchBarSearchInputColor]="props.listSearchBarSearchInputColor"
|
|
[searchBarCancelButtonTitle]="props.listSearchBarCancelButtonTitle"
|
|
[emptyForegroundMessageColor]="props.listEmptyForegroundMessageColor"
|
|
>
|
|
</x-list>
|
|
</ng-container>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XComponentListTestComponent extends XComponentListContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-map.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XMapContainerComponent } from '../x-map/x-map.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-map
|
|
[zoom]="props.zoom"
|
|
[cssClass]="props.cssClass"
|
|
(isReady)="(props.isReady)"
|
|
[latitude]="props.latitude"
|
|
[showZoom]="props.showZoom"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[longitude]="props.longitude"
|
|
[canSelect]="props.canSelect"
|
|
[showRotate]="props.showRotate"
|
|
[showLocator]="props.showLocator"
|
|
[markerStyle]="props.markerStyle"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[cardCssClass]="props.cardCssClass"
|
|
(viewChanged)="(props.viewChanged)"
|
|
[searchBarType]="props.searchBarType"
|
|
[showSearchBar]="props.showSearchBar"
|
|
[searchBarTitle]="props.searchBarTitle"
|
|
[searchBarValue]="props.searchBarValue"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[showZoomSlider]="props.showZoomSlider"
|
|
[searchBarColor]="props.searchBarColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[showProgressBar]="props.showProgressBar"
|
|
[showClearMarker]="props.showClearMarker"
|
|
[locatorPosition]="props.locatorPosition"
|
|
[progressBarColor]="props.progressBarColor"
|
|
[searchBarPosition]="props.searchBarPosition"
|
|
[searchBarCssClass]="props.searchBarCssClass"
|
|
[searchBarDebounce]="props.searchBarDebounce"
|
|
(searchBarOnEvent)="(props.searchBarOnEvent)"
|
|
(locationSelected)="(props.locationSelected)"
|
|
[showGoMarkedPlace]="props.showGoMarkedPlace"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[searchBarClearIcon]="props.searchBarClearIcon"
|
|
[searchPlaceProvider]="props.searchPlaceProvider"
|
|
[searchBarSearchIcon]="props.searchBarSearchIcon"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[searchBarSpellcheck]="props.searchBarSpellcheck"
|
|
[clearMarkerPosition]="props.clearMarkerPosition"
|
|
[progressBarPosition]="props.progressBarPosition"
|
|
[showSelectedLocation]="props.showSelectedLocation"
|
|
[searchResultListColor]="props.searchResultListColor"
|
|
(searchBarQueryChange)="(props.searchBarQueryChange)"
|
|
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
|
|
[searchBarKeyboardType]="props.searchBarKeyboardType"
|
|
[goMarkedPlacePosition]="props.goMarkedPlacePosition"
|
|
[searchBarActionProvider]="props.searchBarActionProvider"
|
|
[searchBarClearIconColor]="props.searchBarClearIconColor"
|
|
[searchBarForegroundColor]="props.searchBarForegroundColor"
|
|
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
|
|
[selectedLocationPosition]="props.selectedLocationPosition"
|
|
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
|
|
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
|
|
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
|
|
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
|
|
[addMarkerOnSelectedLocation]="props.addMarkerOnSelectedLocation"
|
|
[searchBarForegroundSearchInputColor]="
|
|
props.searchBarForegroundSearchInputColor
|
|
"
|
|
>
|
|
</x-map>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XMapTestComponent extends XMapContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-markdown.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XMarkdownContainerComponent } from '../x-markdown/x-markdown.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-markdown
|
|
[mode]="props.mode"
|
|
[content]="props.content"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[hasToolbar]="props.hasToolbar"
|
|
[toolbarColor]="props.toolbarColor"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[toolbarConfig]="props.toolbarConfig"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
(contentChange)="(props.contentChange)"
|
|
[editorBoxColor]="props.editorBoxColor"
|
|
[toolbarCssClass]="props.toolbarCssClass"
|
|
[previewBoxColor]="props.previewBoxColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[toolbarForegroundColor]="props.toolbarForegroundColor"
|
|
></x-markdown>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XMarkdownTestComponent extends XMarkdownContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-model-presenter.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XModelPresenterContainerComponent } from '../x-model-presenter/x-model-presenter.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-model-presenter
|
|
[color]="props.color"
|
|
[model]="props.model"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[labelColor]="props.labelColor"
|
|
[valueColor]="props.valueColor"
|
|
[showLabels]="props.showLabels"
|
|
[headerColor]="props.headerColor"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[contentColor]="props.contentColor"
|
|
[startupState]="props.startupState"
|
|
[panelCssClass]="props.panelCssClass"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[hiddenModelKeys]="props.hiddenModelKeys"
|
|
(onModelChanged)="(props.onModelChanged)"
|
|
[modelKeyProvider]="props.modelKeyProvider"
|
|
[sortOrderModelKeys]="props.sortOrderModelKeys"
|
|
[modelValueProvider]="props.modelValueProvider"
|
|
[hideOptionalValues]="props.hideOptionalValues"
|
|
[availableModelKeys]="props.availableModelKeys"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[panelActionProvider]="props.panelActionProvider"
|
|
[hiddenLabelModelKeys]="props.hiddenLabelModelKeys"
|
|
[headerHighlightColor]="props.headerHighlightColor"
|
|
[propertyActionTemplate]="props.propertyActionTemplate"
|
|
>
|
|
</x-model-presenter>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XModelPresenterTestComponent extends XModelPresenterContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-navigator.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XNavigatorContainerComponent } from '../x-page/x-navigator/x-navigator.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-navigator
|
|
[items]="props.items"
|
|
[cssClass]="props.cssClass"
|
|
[iconSlot]="props.iconSlot"
|
|
[childColor]="props.childColor"
|
|
[parentColor]="props.parentColor"
|
|
[dividerColor]="props.dividerColor"
|
|
[startupState]="props.startupState"
|
|
[itemCssClass]="props.itemCssClass"
|
|
(itemSelected)="(props.itemSelected)"
|
|
[closeSiblings]="props.closeSiblings"
|
|
[showChildIcon]="props.showChildIcon"
|
|
[actionProvider]="props.actionProvider"
|
|
[showParentIcon]="props.showParentIcon"
|
|
[highlightColor]="props.highlightColor"
|
|
[childActiveColor]="props.childActiveColor"
|
|
[parentActiveColor]="props.parentActiveColor"
|
|
[showChildDetailIcon]="props.showChildDetailIcon"
|
|
[disableParentRouting]="props.disableParentRouting"
|
|
[showParentDetailIcon]="props.showParentDetailIcon"
|
|
>
|
|
</x-navigator>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XNavigatorTestComponent extends XNavigatorContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-page.component.templates.ts
|
|
|
|
|
|
import { Component } from "@angular/core";
|
|
import { XPageContainerComponent } from "../x-page/x-page.container";
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-page
|
|
[color]="props.color"
|
|
[hasSide]="props.hasSide"
|
|
[actions]="props.actions"
|
|
[cssClass]="props.cssClass"
|
|
[sideSlot]="props.sideSlot"
|
|
[sideType]="props.sideType"
|
|
[sideColor]="props.sideColor"
|
|
(loadMore)="(props.loadMore)"
|
|
[showFooter]="props.showFooter"
|
|
[showToolbar]="props.showToolbar"
|
|
[footerColor]="props.footerColor"
|
|
[toolbarTitle]="props.toolbarTitle"
|
|
(refreshPage)="(props.refreshPage)"
|
|
[toolbarColor]="props.toolbarColor"
|
|
[sideMenuWidth]="props.sideMenuWidth"
|
|
[toolbarLogoUrl]="props.toolbarLogoUrl"
|
|
[toolbarHasBack]="props.toolbarHasBack"
|
|
[toolbarHasMenu]="props.toolbarHasMenu"
|
|
[footerCssClass]="props.footerCssClass"
|
|
[refreshingText]="props.refreshingText"
|
|
(scrolledEvent)="(props.scrolledEvent)"
|
|
[toggleMenuWhen]="props.toggleMenuWhen"
|
|
(imageCaptured)="(props.imageCaptured)"
|
|
[toolbarStartSlotButtonsTemplate]="
|
|
props.toolbarStartSlotButtonsTemplate
|
|
"
|
|
[toolbarShowBack]="props.toolbarShowBack"
|
|
[toolbarBackSlot]="props.toolbarBackSlot"
|
|
[toolbarSubTitle]="props.toolbarSubTitle"
|
|
[toolbarShowLogo]="props.toolbarShowLogo"
|
|
[toolbarLogoSlot]="props.toolbarLogoSlot"
|
|
[toolbarShowTitle]="props.toolbarShowTitle"
|
|
[toolbarTitleSlot]="props.toolbarTitleSlot"
|
|
[toolbarShowMenu]="props.toolbarShowMenu"
|
|
[toolbarMenuSlot]="props.toolbarMenuSlot"
|
|
[toolbarCssClass]="props.toolbarCssClass"
|
|
[scrollBehaviour]="props.scrollBehaviour"
|
|
[sideMenuMaxWidth]="props.sideMenuMaxWidth"
|
|
[scrollingClasses]="props.scrollingClasses"
|
|
[sideMenuMinWidth]="props.sideMenuMinWidth"
|
|
[scrollEndClasses]="props.scrollEndClasses"
|
|
[captureTopOffset]="props.captureTopOffset"
|
|
[showPageRefresher]="props.showPageRefresher"
|
|
[refreshingSpinner]="props.refreshingSpinner"
|
|
[enableCaptureMode]="props.enableCaptureMode"
|
|
[toolbarBackHandler]="props.toolbarBackHandler"
|
|
[toolbarDefaultHref]="props.toolbarDefaultHref"
|
|
[refreshPullingText]="props.refreshPullingText"
|
|
[refreshPullingIcon]="props.refreshPullingIcon"
|
|
[toolbarContentSlot]="props.toolbarContentSlot"
|
|
[scrollStartClasses]="props.scrollStartClasses"
|
|
[toolbarShowSubTitle]="props.toolbarShowSubTitle"
|
|
[captureBottomOffset]="props.captureBottomOffset"
|
|
[provideScrollEvents]="props.provideScrollEvents"
|
|
[footerActionProvider]="props.footerActionProvider"
|
|
[footerContentTemplate]="props.footerContentTemplate"
|
|
[downloadCapturedImage]="props.downloadCapturedImage"
|
|
[actionsActionProvider]="props.actionsActionProvider"
|
|
[toolbarActionProvider]="props.toolbarActionProvider"
|
|
[toolbarContentTemplate]="props.toolbarContentTemplate"
|
|
[infinityScrollDisabled]="props.infinityScrollDisabled"
|
|
[toolbarShowProgressBar]="props.toolbarShowProgressBar"
|
|
[toolbarProgressBarColor]="props.toolbarProgressBarColor"
|
|
[infinityScrollThreshold]="props.infinityScrollThreshold"
|
|
[showPageInfinityScroller]="props.showPageInfinityScroller"
|
|
[scrollEventActionProvider]="props.scrollEventActionProvider"
|
|
[infinityScrollerLoadingText]="props.infinityScrollerLoadingText"
|
|
[toolbarEndSlotButtonsTemplate]="props.toolbarEndSlotButtonsTemplate"
|
|
[infinityScrollerLoadingSpinner]="props.infinityScrollerLoadingSpinner"
|
|
>
|
|
</x-page>
|
|
</ng-container>
|
|
`
|
|
})
|
|
export class XPageTestComponent extends XPageContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-screen-capture.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XScreenCaptureContainerComponent } from '../x-screen-capture/x-screen-capture.container';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-screen-capture
|
|
[enable]="props.enable"
|
|
[topOffset]="props.topOffset"
|
|
[bottomOffset]="props.bottomOffset"
|
|
(imageCaptured)="(props.imageCaptured)"
|
|
[downloadCapturedImage]="props.downloadCapturedImage"
|
|
>
|
|
</x-screen-capture>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XScreenCaptureTestComponent extends XScreenCaptureContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-search-bar.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import {
|
|
XComponentSearchBarContainerComponent,
|
|
XSearchBarContainerComponent,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-search-bar
|
|
[type]="props.type"
|
|
[color]="props.color"
|
|
[title]="props.title"
|
|
[value]="props.value"
|
|
[cssClass]="props.cssClass"
|
|
(onEvent)="(props.onEvent)"
|
|
[debounce]="props.debounce"
|
|
[clearIcon]="props.clearIcon"
|
|
[spellcheck]="props.spellcheck"
|
|
[searchIcon]="props.searchIcon"
|
|
[enterKeyHint]="props.enterKeyHint"
|
|
[keyboardType]="props.keyboardType"
|
|
(queryChange)="(props.queryChange)"
|
|
[clearIconColor]="props.clearIconColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[searchIconColor]="props.searchIconColor"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[showCancelButton]="props.showCancelButton"
|
|
[cancelButtonIcon]="props.cancelButtonIcon"
|
|
[searchInputColor]="props.searchInputColor"
|
|
[cancelButtonTitle]="props.cancelButtonTitle"
|
|
[foregroundSearchInputColor]="props.foregroundSearchInputColor"
|
|
>
|
|
</x-search-bar>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSearchBarTestComponent extends XSearchBarContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showSearchBar">
|
|
<x-search-bar
|
|
[color]="props.searchBarColor"
|
|
[title]="props.searchBarTitle"
|
|
[value]="props.searchBarValue"
|
|
[cssClass]="props.searchBarCssClass"
|
|
[debounce]="props.searchBarDebounce"
|
|
(onEvent)="(props.searchBarOnEvent)"
|
|
[clearIcon]="props.searchBarClearIcon"
|
|
[spellcheck]="props.searchBarSpellcheck"
|
|
[searchIcon]="props.searchBarSearchIcon"
|
|
[foregroundSearchInputColor]="
|
|
props.searchBarForegroundSearchInputColor
|
|
"
|
|
[type]="props.searchBarType"
|
|
[enterKeyHint]="props.searchBarEnterKeyHint"
|
|
[keyboardType]="props.searchBarKeyboardType"
|
|
(queryChange)="(props.searchBarQueryChange)"
|
|
[actionProvider]="props.searchBarActionProvider"
|
|
[clearIconColor]="props.searchBarClearIconColor"
|
|
[searchIconColor]="props.searchBarSearchIconColor"
|
|
[foregroundColor]="props.searchBarForegroundColor"
|
|
[searchInputColor]="props.searchBarSearchInputColor"
|
|
[showCancelButton]="props.searchBarShowCancelButton"
|
|
[cancelButtonIcon]="props.searchBarCancelButtonIcon"
|
|
[cancelButtonTitle]="props.searchBarCancelButtonTitle"
|
|
>
|
|
</x-search-bar>
|
|
</ng-container>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XComponentSearchBarTestComponent extends XComponentSearchBarContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-slider.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XSliderContainerComponent } from '../x-slider/x-slider.typings';
|
|
import { XSlideContainerComponent } from '../x-slider/x-slide/x-slide.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-slider
|
|
[options]="props.options"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[animation]="props.animation"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
>
|
|
</x-slider>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSliderTestComponent extends XSliderContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-slide [actionProvider]="props.actionProvider"></x-slide>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSlideTestComponent extends XSlideContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-slotter.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XSlotterContainerComponent } from '../x-slotter/x-slotter.typings';
|
|
import { XSlotContainerComponent } from '../x-slotter/x-slot/x-slot.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-slotter
|
|
[layout]="props.layout"
|
|
[cssClass]="props.cssClass"
|
|
[hasCenterSlot]="props.hasCenterSlot"
|
|
[actionProvider]="props.actionProvider"
|
|
[hasStartOrTopSlot]="props.hasStartOrTopSlot"
|
|
[centerSlotCssClass]="props.centerSlotCssClass"
|
|
[hasEndOrBottomSlot]="props.hasEndOrBottomSlot"
|
|
[startTopSlotCssClass]="props.startTopSlotCssClass"
|
|
[endBottomSlotCssClass]="props.endBottomSlotCssClass"
|
|
>
|
|
</x-slotter>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSlotterTestComponent extends XSlotterContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-slot
|
|
[name]="props.name"
|
|
[cssClass]="props.cssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
>
|
|
</x-slot>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSlotTestComponent extends XSlotContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-spinner.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XSpinnerContainerComponent } from '../x-spinner/x-spinner.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-spinner
|
|
[name]="props.name"
|
|
[color]="props.color"
|
|
[paused]="props.paused"
|
|
[cssClass]="props.cssClass"
|
|
[duration]="props.duration"
|
|
[actionProvider]="props.actionProvider"
|
|
>
|
|
</x-spinner>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XSpinnerTestComponent extends XSpinnerContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-stepper.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XStepperContainerComponent } from '../x-stepper/x-stepper.typings';
|
|
import { XStepContainerComponent } from '../x-stepper/x-step/x-step.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-stepper
|
|
[type]="props.type"
|
|
[hasNext]="props.hasNext"
|
|
[hasPrev]="props.hasPrev"
|
|
[canNext]="props.canNext"
|
|
(onNext)="(props.onNext)"
|
|
[canPrev]="props.canPrev"
|
|
(onPrev)="(props.onPrev)"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[canReset]="props.canReset"
|
|
(onReset)="(props.onReset)"
|
|
[hasReset]="props.hasReset"
|
|
[cardColor]="props.cardColor"
|
|
[showLabel]="props.showLabel"
|
|
[cardTitle]="props.cardTitle"
|
|
[nextButton]="props.nextButton"
|
|
[prevButton]="props.prevButton"
|
|
[disablePrev]="props.disablePrev"
|
|
[resetButton]="props.resetButton"
|
|
[disableNext]="props.disableNext"
|
|
[prevPosition]="props.prevPosition"
|
|
[prevCssClass]="props.prevCssClass"
|
|
[disableReset]="props.disableReset"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[nextPosition]="props.nextPosition"
|
|
[nextCssClass]="props.nextCssClass"
|
|
[nextConfirmer]="props.nextConfirmer"
|
|
[labelPosition]="props.labelPosition"
|
|
[selectedIndex]="props.selectedIndex"
|
|
[prevConfirmer]="props.prevConfirmer"
|
|
[resetPosition]="props.resetPosition"
|
|
[resetCssClass]="props.resetCssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[resetConfirmer]="props.resetConfirmer"
|
|
(selectedChange)="(props.selectedChange)"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
>
|
|
</x-stepper>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XStepperTestComponent extends XStepperContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-step
|
|
[id]="props.id"
|
|
[hasNext]="props.hasNext"
|
|
[hasPrev]="props.hasPrev"
|
|
[hasReset]="props.hasReset"
|
|
[nextButton]="props.nextButton"
|
|
[prevButton]="props.prevButton"
|
|
[disableNext]="props.disableNext"
|
|
[disablePrev]="props.disablePrev"
|
|
[resetButton]="props.resetButton"
|
|
[nextCssClass]="props.nextCssClass"
|
|
[prevPosition]="props.prevPosition"
|
|
[prevCssClass]="props.prevCssClass"
|
|
[disableReset]="props.disableReset"
|
|
[nextPosition]="props.nextPosition"
|
|
[prevConfirmer]="props.prevConfirmer"
|
|
[resetPosition]="props.resetPosition"
|
|
[nextConfirmer]="props.nextConfirmer"
|
|
[resetCssClass]="props.resetCssClass"
|
|
[resetConfirmer]="props.resetConfirmer"
|
|
[actionProvider]="props.actionProvider"
|
|
[hasCustomActions]="props.hasCustomActions"
|
|
>
|
|
</x-step>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XStepTestComponent extends XStepContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-tab-navigator.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XTabNavigatorContainerComponent } from '../x-tab-navigator/x-tab-navigator.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-tab-navigator
|
|
[items]="props.items"
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[iconColor]="props.iconColor"
|
|
[badgeColor]="props.badgeColor"
|
|
[navigatorSlot]="props.navigatorSlot"
|
|
[selectedColor]="props.selectedColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[highlightColor]="props.highlightColor"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[hideTabLabelsOnSmallScreens]="props.hideTabLabelsOnSmallScreens"
|
|
>
|
|
</x-tab-navigator>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XTabNavigatorTestComponent extends XTabNavigatorContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-table.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XTableContainerComponent } from '../x-table/x-table.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-table
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[showEmpty]="props.showEmpty"
|
|
[emptyColor]="props.emptyColor"
|
|
[properties]="props.properties"
|
|
[showHeader]="props.showHeader"
|
|
(rowClicked)="(props.rowClicked)"
|
|
[headerColor]="props.headerColor"
|
|
[searchTitle]="props.searchTitle"
|
|
(rowSelected)="(props.rowSelected)"
|
|
[canClearSort]="props.canClearSort"
|
|
[cellCssClass]="props.cellCssClass"
|
|
[stickyHeader]="props.stickyHeader"
|
|
[cellTemplate]="props.cellTemplate"
|
|
(pageChanged)="(props.pageChanged)"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
(removeItems)="(props.removeItems)"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
[emptyMessage]="props.emptyMessage"
|
|
(emptyRefresh)="(props.emptyRefresh)"
|
|
[clickableRows]="props.clickableRows"
|
|
[showSearchBar]="props.showSearchBar"
|
|
[showActionBar]="props.showActionBar"
|
|
[showPaginator]="props.showPaginator"
|
|
[actionOptions]="props.actionOptions"
|
|
[emptyCssClass]="props.emptyCssClass"
|
|
[searchBarColor]="props.searchBarColor"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[paginatorColor]="props.paginatorColor"
|
|
[actionBarColor]="props.actionBarColor"
|
|
[selectableRows]="props.selectableRows"
|
|
[actionProvider]="props.actionProvider"
|
|
[emptyHasRefresh]="props.emptyHasRefresh"
|
|
[foregroundColor]="props.foregroundColor"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
props.emptyForegroundRefreshButtonColor
|
|
"
|
|
[emptyRefreshIcon]="props.emptyRefreshIcon"
|
|
[paginatorOptions]="props.paginatorOptions"
|
|
[allowMultiSelect]="props.allowMultiSelect"
|
|
[searchBarPosition]="props.searchBarPosition"
|
|
[paginatorPosition]="props.paginatorPosition"
|
|
[actionBarPosition]="props.actionBarPosition"
|
|
[emptyMessageColor]="props.emptyMessageColor"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[headerCellCssClass]="props.headerCellCssClass"
|
|
[customCellTemplate]="props.customCellTemplate"
|
|
[emptyActionProvider]="props.emptyActionProvider"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
(rowSelectionChanged)="(props.rowSelectionChanged)"
|
|
[emptyForegroundColor]="props.emptyForegroundColor"
|
|
[headerForegroundColor]="props.headerForegroundColor"
|
|
[initialSelectedValues]="props.initialSelectedValues"
|
|
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
|
|
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
|
|
>
|
|
</x-table>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XTableTestComponent extends XTableContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-tabs.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XTabsContainerComponent } from '../x-tabs/x-tabs.typings';
|
|
import { XTabContainerComponent } from '../x-tabs/x-tab/x-tab.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-tabs
|
|
[lock]="props.lock"
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[loopTabs]="props.loopTabs"
|
|
[swipable]="props.swipable"
|
|
[alignTabs]="props.alignTabs"
|
|
[showHeader]="props.showHeader"
|
|
[headerColor]="props.headerColor"
|
|
[selectedIndex]="props.selectedIndex"
|
|
[dynamicHeight]="props.dynamicHeight"
|
|
[disableRipple]="props.disableRipple"
|
|
[activeTabColor]="props.activeTabColor"
|
|
[headerPosition]="props.headerPosition"
|
|
[actionProvider]="props.actionProvider"
|
|
(animationDone)="(props.animationDone)"
|
|
[disablePagination]="props.disablePagination"
|
|
[animationDuration]="props.animationDuration"
|
|
[tabIndicatorColor]="props.tabIndicatorColor"
|
|
[tabPaginatorColor]="props.tabPaginatorColor"
|
|
(selectedTabChange)="(props.selectedTabChange)"
|
|
(selectedIndexChange)="(props.selectedIndexChange)"
|
|
>
|
|
</x-tabs>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XTabsTestComponent extends XTabsContainerComponent {}
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-tab [actionProvider]="props.actionProvider"></x-tab>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XTabTestComponent extends XTabContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-theme-manager.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XThemeManagerContainerComponent } from '../x-theme/x-theme-manager/x-theme-manager.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-theme-manager
|
|
[color]="props.color"
|
|
[cssClass]="props.cssClass"
|
|
[isInPage]="props.isInPage"
|
|
[cardColor]="props.cardColor"
|
|
[cardTitle]="props.cardTitle"
|
|
[saveColor]="props.saveColor"
|
|
[saveLabel]="props.saveLabel"
|
|
[resetColor]="props.resetColor"
|
|
[resetLabel]="props.resetLabel"
|
|
(tabChange)="(props.tabChange)"
|
|
[cardSubTitle]="props.cardSubTitle"
|
|
[wrapWithCard]="props.wrapWithCard"
|
|
[cardCssClass]="props.cardCssClass"
|
|
(themeChange)="(props.themeChange)"
|
|
[listCssClass]="props.listCssClass"
|
|
[listShowEmpty]="props.listShowEmpty"
|
|
[showActionBar]="props.showActionBar"
|
|
[themeUploadFileDropAreaCssClass]="
|
|
props.themeUploadFileDropAreaCssClass
|
|
"
|
|
[listEmptyForegroundMessageColor]="
|
|
props.listEmptyForegroundMessageColor
|
|
"
|
|
[cardShowFooter]="props.cardShowFooter"
|
|
[maxAllowedSize]="props.maxAllowedSize"
|
|
[listEmptyColor]="props.listEmptyColor"
|
|
[actionBarColor]="props.actionBarColor"
|
|
[actionProvider]="props.actionProvider"
|
|
[themeUploadFileDropAreaErrorColor]="
|
|
props.themeUploadFileDropAreaErrorColor
|
|
"
|
|
[maxAllowedFiles]="props.maxAllowedFiles"
|
|
[listShowDivider]="props.listShowDivider"
|
|
[themeUploadFileDropAreaAccentColor]="
|
|
props.themeUploadFileDropAreaAccentColor
|
|
"
|
|
[themeUploadFileDropAreaSuccessColor]="
|
|
props.themeUploadFileDropAreaSuccessColor
|
|
"
|
|
[propertyEditIcon]="props.propertyEditIcon"
|
|
[listEmptyMessage]="props.listEmptyMessage"
|
|
[themeUploadColor]="props.themeUploadColor"
|
|
[listEmptyForegroundRefreshButtonColor]="
|
|
props.listEmptyForegroundRefreshButtonColor
|
|
"
|
|
[listShowSearchBar]="props.listShowSearchBar"
|
|
(listEmptyRefresh)="(props.listEmptyRefresh)"
|
|
[listEmptyCssClass]="props.listEmptyCssClass"
|
|
[actionBarCssClass]="props.actionBarCssClass"
|
|
[propertyClearIcon]="props.propertyClearIcon"
|
|
[themeUploadFileDropAreaForegroundColor]="
|
|
props.themeUploadFileDropAreaForegroundColor
|
|
"
|
|
[themeUploadEmptyForegroundMessageColor]="
|
|
props.themeUploadEmptyForegroundMessageColor
|
|
"
|
|
[listSearchBarForegroundSearchInputColor]="
|
|
props.listSearchBarForegroundSearchInputColor
|
|
"
|
|
[minAllowedFileSize]="props.minAllowedFileSize"
|
|
[maxAllowedFileSize]="props.maxAllowedFileSize"
|
|
[cardActionProvider]="props.cardActionProvider"
|
|
[listSearchBarTitle]="props.listSearchBarTitle"
|
|
[listSearchBarValue]="props.listSearchBarValue"
|
|
[listSearchBarColor]="props.listSearchBarColor"
|
|
[propertyLabelColor]="props.propertyLabelColor"
|
|
[propertyValueColor]="props.propertyValueColor"
|
|
[cardForegroundColor]="props.cardForegroundColor"
|
|
[listEmptyHasRefresh]="props.listEmptyHasRefresh"
|
|
[themeUploadCssClass]="props.themeUploadCssClass"
|
|
[listEmptyRefreshIcon]="props.listEmptyRefreshIcon"
|
|
[colorViewBorderColor]="props.colorViewBorderColor"
|
|
[restartAfterSetTheme]="props.restartAfterSetTheme"
|
|
[colorViewBorderWidth]="props.colorViewBorderWidth"
|
|
[colorViewBorderStyle]="props.colorViewBorderStyle"
|
|
[presenterHeaderColor]="props.presenterHeaderColor"
|
|
[themeUploadFileDropAreaSupportsMultipleFiles]="
|
|
props.themeUploadFileDropAreaSupportsMultipleFiles
|
|
"
|
|
[listSearchBarCssClass]="props.listSearchBarCssClass"
|
|
(listSearchBarOnEvent)="(props.listSearchBarOnEvent)"
|
|
[listEmptyMessageColor]="props.listEmptyMessageColor"
|
|
[listSearchBarDebounce]="props.listSearchBarDebounce"
|
|
[presenterContentColor]="props.presenterContentColor"
|
|
[propertyEditIconColor]="props.propertyEditIconColor"
|
|
[listSearchBarClearIcon]="props.listSearchBarClearIcon"
|
|
[propertyActionMenuIcon]="props.propertyActionMenuIcon"
|
|
[propertyClearIconColor]="props.propertyClearIconColor"
|
|
[themeUploadEmptyMessage]="props.themeUploadEmptyMessage"
|
|
[listSearchBarSpellcheck]="props.listSearchBarSpellcheck"
|
|
[listSearchBarSearchIcon]="props.listSearchBarSearchIcon"
|
|
[listEmptyActionProvider]="props.listEmptyActionProvider"
|
|
[listEmptyForegroundColor]="props.listEmptyForegroundColor"
|
|
[actionBarForegroundColor]="props.actionBarForegroundColor"
|
|
[listSearchBarEnterKeyHint]="props.listSearchBarEnterKeyHint"
|
|
[listSearchBarKeyboardType]="props.listSearchBarKeyboardType"
|
|
(listActionBarActionFired)="(props.listActionBarActionFired)"
|
|
(listSearchBarQueryChange)="(props.listSearchBarQueryChange)"
|
|
[themeUploadForegroundColor]="props.themeUploadForegroundColor"
|
|
[emptyPropertyEditIconColor]="props.emptyPropertyEditIconColor"
|
|
[themeUploadFileDropAreaIcon]="props.themeUploadFileDropAreaIcon"
|
|
[themeUploadShowFileDropArea]="props.themeUploadShowFileDropArea"
|
|
[listSearchBarClearIconColor]="props.listSearchBarClearIconColor"
|
|
[listEmptyRefreshButtonColor]="props.listEmptyRefreshButtonColor"
|
|
[propertyActionMenuIconColor]="props.propertyActionMenuIconColor"
|
|
[themeUploadFileDropAreaColor]="props.themeUploadFileDropAreaColor"
|
|
[listSearchBarSearchIconColor]="props.listSearchBarSearchIconColor"
|
|
[listSearchBarForegroundColor]="props.listSearchBarForegroundColor"
|
|
[listSearchBarShowCancelButton]="props.listSearchBarShowCancelButton"
|
|
[listSearchBarCancelButtonIcon]="props.listSearchBarCancelButtonIcon"
|
|
[listSearchBarSearchInputColor]="props.listSearchBarSearchInputColor"
|
|
[presenterHeaderHighlightColor]="props.presenterHeaderHighlightColor"
|
|
[themeUploadFileDropAreaMessage]="props.themeUploadFileDropAreaMessage"
|
|
[listSearchBarCancelButtonTitle]="props.listSearchBarCancelButtonTitle"
|
|
></x-theme-manager>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XThemeManagerTestComponent extends XThemeManagerContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-thumbnail.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XThumbnailContainerComponent } from '../x-thumbnail/x-thumbnail.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-thumbnail
|
|
[type]="props.type"
|
|
(clicked)="(props.clicked)"
|
|
[cssClass]="props.cssClass"
|
|
[circular]="props.circular"
|
|
[clickable]="props.clickable"
|
|
[selectable]="props.selectable"
|
|
[identifier]="props.identifier"
|
|
[actionProvider]="props.actionProvider"
|
|
>
|
|
</x-thumbnail>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XThumbnailTestComponent extends XThumbnailContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-toolbar.component.templates.ts
|
|
|
|
import { Component } from '@angular/core';
|
|
import { XToolbarContainerComponent } from '../x-page/x-toolbar/x-toolbar.typings';
|
|
|
|
@Component({
|
|
template: `
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-toolbar
|
|
[color]="props.color"
|
|
[title]="props.title"
|
|
[logoUrl]="props.logoUrl"
|
|
[hasBack]="props.hasBack"
|
|
[hasMenu]="props.hasMenu"
|
|
[subTitle]="props.subTitle"
|
|
[showLogo]="props.showLogo"
|
|
[logoSlot]="props.logoSlot"
|
|
[showBack]="props.showBack"
|
|
[backSlot]="props.backSlot"
|
|
[showMenu]="props.showMenu"
|
|
[menuSlot]="props.menuSlot"
|
|
[cssClass]="props.cssClass"
|
|
[showTitle]="props.showTitle"
|
|
[titleSlot]="props.titleSlot"
|
|
[backHandler]="props.backHandler"
|
|
[defaultHref]="props.defaultHref"
|
|
[contentSlot]="props.contentSlot"
|
|
[showSubTitle]="props.showSubTitle"
|
|
[actionProvider]="props.actionProvider"
|
|
[contentTemplate]="props.contentTemplate"
|
|
[showProgressBar]="props.showProgressBar"
|
|
[progressBarColor]="props.progressBarColor"
|
|
[endSlotButtonsTemplate]="props.endSlotButtonsTemplate"
|
|
[startSlotButtonsTemplate]="props.startSlotButtonsTemplate"
|
|
>
|
|
</x-toolbar>
|
|
</ng-container>
|
|
`,
|
|
})
|
|
export class XToolbarTestComponent extends XToolbarContainerComponent {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\config\x-framework-components.config.ts
|
|
|
|
import { XFrameworkCoreConfig } from 'x-framework-core';
|
|
import { XFrameworkServicesConfig } from 'x-framework-services';
|
|
|
|
export type XSharedConfig = XFrameworkCoreConfig & XFrameworkServicesConfig;
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XFrameworkComponentsConfig extends XSharedConfig {
|
|
//
|
|
// File Config ...
|
|
maxAllowedSize: number;
|
|
maxUploadFiles: number;
|
|
minAllowedFileSize: number;
|
|
maxAllowedFileSize: number;
|
|
|
|
//
|
|
defaultSearchDebounceTime: number;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XPopoverService } from './x-popover/x-popover.service';
|
|
import { XSlotterModule } from './../x-slotter/x-slotter.module';
|
|
import { XPopoverComponent } from './x-popover/x-popover.component';
|
|
import { XSearchBarModule } from '../x-search-bar/x-search-bar.module';
|
|
import { XDataPagerModule } from '../x-data-pager/x-data-pager.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XSelectorDialogService } from './x-selector-dialog/x-selector-dialog.service';
|
|
import { XSelectorDialogComponent } from './x-selector-dialog/x-selector-dialog.component';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
XListModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XSearchBarModule,
|
|
XDataPagerModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XListModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XSearchBarModule,
|
|
XDataPagerModule,
|
|
XBaseComponentModule,
|
|
],
|
|
providers: [XPopoverService, XSelectorDialogService],
|
|
declarations: [XPopoverComponent, XSelectorDialogComponent],
|
|
entryComponents: [XPopoverComponent, XSelectorDialogComponent],
|
|
})
|
|
export class XDialogsModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.html
|
|
|
|
<section
|
|
#xBaseDialogContainer
|
|
class="x-base-dialog"
|
|
[isForeground]="false"
|
|
[xColor]="getBackgroundColor() | async"
|
|
[ngClass]="getDialogContainerClasses() | async"
|
|
>
|
|
<!-- Title Toolbar -->
|
|
<section #xBaseDialogToolbar>
|
|
<!-- Toolbar -->
|
|
<ion-toolbar
|
|
[xColor]="getToolbarColor() | async"
|
|
[ngClass]="getDialogToolbarClasses() | async"
|
|
>
|
|
<!-- Slots -->
|
|
<div class="x-base-dialog-toolbar-area">
|
|
<x-slotter>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'ion-float-start']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleClosePopup()"
|
|
class="x-base-dialog-toolbar-item x-base-dialog-toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="backIcon"
|
|
[loading]="isLoading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<ion-title class="x-base-dialog-toolbar-item center-vertical-flex">
|
|
<h3>
|
|
{{ getTitle() | async }}
|
|
</h3>
|
|
</ion-title>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
[cssClass]="['ion-text-end', 'ion-float-end']"
|
|
>
|
|
<div
|
|
matRipple
|
|
*ngIf="canSelect() | async"
|
|
(click)="handleSelect(selectedValue)"
|
|
[matRippleDisabled]="!(hasSelectedValue() | async)"
|
|
class="x-base-dialog-toolbar-item x-base-dialog-toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="selectIcon"
|
|
[loading]="isLoading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</ion-toolbar>
|
|
|
|
<!-- Progressbar -->
|
|
<ion-progress-bar
|
|
type="indeterminate"
|
|
*ngIf="canShowProgressBar() | async"
|
|
[color]="getProgressBarColor() | async"
|
|
></ion-progress-bar>
|
|
</section>
|
|
|
|
<!-- Components -->
|
|
<section class="x-base-dialog-content">
|
|
<!-- Content -->
|
|
</section>
|
|
</section>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.scss
|
|
|
|
x-icon {
|
|
--size: 24px;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.x-base-dialog-container {
|
|
height: 100%;
|
|
}
|
|
|
|
.x-base-dialog-content {
|
|
height: 100%;
|
|
overflow-y: scroll;
|
|
}
|
|
|
|
.x-base-dialog-toolbar-area {
|
|
margin: 8px;
|
|
}
|
|
|
|
.x-base-dialog-toolbar-item {
|
|
width: auto;
|
|
height: 48px;
|
|
}
|
|
|
|
.x-base-dialog-toolbar-button {
|
|
width: 32px;
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.ts
|
|
|
|
import {
|
|
XDialogConfig,
|
|
XDialogContext,
|
|
defaultBaseDialogConfig,
|
|
} from './x-dialog.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Input, Component, ViewChild, ElementRef } from '@angular/core';
|
|
import { XIconNames } from '../../x-icon/x-icon.typings';
|
|
import { XSlotName } from '../../x-slotter/x-slotter.typings';
|
|
import { XBaseComponent } from '../../classes/x-base-component';
|
|
import { XStandardType, isNullOrUndefined } from 'x-framework-core';
|
|
|
|
@Component({
|
|
template: '',
|
|
})
|
|
export abstract class XDialogComponent extends XBaseComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Private/Readonly ...
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
//#endregion
|
|
|
|
//
|
|
//#region Self Props ...
|
|
//
|
|
@Input()
|
|
context: XStandardType<XDialogConfig>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ViewChilds ...
|
|
@ViewChild('xBaseDialogToolbar')
|
|
dialogToolbar: ElementRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
selectedValue: any;
|
|
applyThemeColors = true;
|
|
selectIcon = XIconNames.checked;
|
|
backIcon = XIconNames.arrow_back;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
//#region Context Options UI Providers ...
|
|
/**
|
|
* retrieve id of dialog ...
|
|
*
|
|
* @returns Observable of Id ...
|
|
*/
|
|
getId() {
|
|
return this.getData().pipe(map((config) => config.id));
|
|
}
|
|
|
|
/**
|
|
* retrieve map dialog config ...
|
|
*/
|
|
getData() {
|
|
return this.getValue(this.context);
|
|
}
|
|
|
|
/**
|
|
* retrieve dialog title ...
|
|
*/
|
|
getTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.title))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve dialog can Select values or not ...
|
|
*
|
|
* @returns observable of boolean ...
|
|
*/
|
|
canSelect() {
|
|
return this.getData().pipe(map((config) => !!config.canSelect));
|
|
}
|
|
|
|
/**
|
|
* retrieve payload of data for dialog ...
|
|
*
|
|
* @returns observable of any ...
|
|
*/
|
|
getPayload() {
|
|
return this.getData().pipe(map((config) => config.payload));
|
|
}
|
|
|
|
/**
|
|
* retrieve toolbar color ...
|
|
*
|
|
* @returns observable of XColorIdentifier ...
|
|
*/
|
|
getToolbarColor() {
|
|
return this.getData().pipe(
|
|
map(
|
|
(config) => config.toolbarColor || defaultBaseDialogConfig.toolbarColor
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve background color ...
|
|
*
|
|
* @returns observable of XColorIdentifier ...
|
|
*/
|
|
getBackgroundColor() {
|
|
return this.getData().pipe(
|
|
map(
|
|
(config) =>
|
|
config.backgroundColor || defaultBaseDialogConfig.backgroundColor
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve progressBar color ...
|
|
*
|
|
* @returns observable of XColorIdentifier ...
|
|
*/
|
|
getProgressBarColor() {
|
|
return this.getData().pipe(
|
|
map(
|
|
(config) =>
|
|
config.progressBarColor || defaultBaseDialogConfig.progressBarColor
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Class Providers ...
|
|
getDialogToolbarClasses() {
|
|
return this.getValue(this.getId()).pipe(
|
|
map((id) => {
|
|
return ['x-base-dialog-toolbar', `x-base-dialog-${id}-toolbar`];
|
|
})
|
|
);
|
|
}
|
|
|
|
getDialogContainerClasses() {
|
|
return this.getValue(this.getId()).pipe(
|
|
map((id) => {
|
|
return ['x-base-dialog-container', `x-base-dialog-${id}-container`];
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
hasSelectedValue() {
|
|
return this.notNullOrUndefinedValue(this.selectedValue);
|
|
}
|
|
|
|
canShowProgressBar() {
|
|
return this.getValue(this.loading || this.uiDisabled);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleClosePopup(payload: any = undefined) {
|
|
//
|
|
const id = await this.getValueAsync(this.getId());
|
|
const context = await this.getValueAsync(this.context);
|
|
if (isNullOrUndefined(context)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (context.type) {
|
|
//
|
|
case XDialogContext.Modal:
|
|
await this.managerService.dialogService.modalController.dismiss(
|
|
payload,
|
|
undefined,
|
|
id
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XDialogContext.PopOver:
|
|
await this.managerService.dialogService.popoverController.dismiss(
|
|
payload,
|
|
undefined,
|
|
id
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleSelect(payload: any) {
|
|
//
|
|
if (isNullOrUndefined(payload)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasSelectedValue = await this.getValueAsync(this.hasSelectedValue());
|
|
if (!hasSelectedValue) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleClosePopup(payload);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.typings.ts
|
|
|
|
import { XColorIdentifier, XColorWithBrightness } from 'x-framework-core';
|
|
|
|
export type XDialogConfigKeys = 'title' | string;
|
|
|
|
export type XDialogConfigType = {
|
|
[key in XDialogConfigKeys]: any;
|
|
};
|
|
|
|
export enum XDialogContext {
|
|
Modal = 'modal',
|
|
PopOver = 'pop_over',
|
|
}
|
|
|
|
export interface XDialogConfig extends XDialogConfigType {
|
|
id: string;
|
|
title: string;
|
|
payload?: any;
|
|
canSelect?: boolean;
|
|
type: XDialogContext;
|
|
toolbarColor?: XColorIdentifier;
|
|
backgroundColor?: XColorIdentifier;
|
|
progressBarColor?: XColorIdentifier;
|
|
}
|
|
|
|
export const defaultBaseDialogConfig: Partial<XDialogConfig> = {
|
|
//
|
|
toolbarColor: XColorWithBrightness.Primary,
|
|
backgroundColor: XColorWithBrightness.Light,
|
|
progressBarColor: XColorWithBrightness.Warning,
|
|
};
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.html
|
|
|
|
<mat-card class="x-card mobile x-popover-wrapper">
|
|
<ion-list #list class="ion-no-padding">
|
|
<!-- Options -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasChildValue(options) | async) && !(hasChildValue(items) | async)
|
|
"
|
|
>
|
|
<ng-container *ngFor="let item of getArrayValue(options) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
listItemRef;
|
|
context: { $implicit: item, isItem: false }
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Items -->
|
|
<ng-container
|
|
*ngIf="
|
|
!(hasChildValue(options) | async) && (hasChildValue(items) | async)
|
|
"
|
|
>
|
|
<ng-container *ngFor="let item of getArrayValue(items) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
listItemRef;
|
|
context: { $implicit: item, isItem: true }
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-list>
|
|
</mat-card>
|
|
|
|
<!-- -->
|
|
<!-- Templates -->
|
|
<!-- -->
|
|
|
|
<!-- List Item Template -->
|
|
<ng-template #listItemRef let-item let-isItem="isItem">
|
|
<ion-item
|
|
button
|
|
lines="full"
|
|
[isForeground]="true"
|
|
[xColor]="getValue(item.color) | async"
|
|
(click)="handleMenuSelected(isItem, item, $event)"
|
|
[matTooltip]="getResourceValue(item.title) | async"
|
|
[matTooltipDisabled]="!(getValue(item.onlyIcon) | async)"
|
|
[detail]="
|
|
(getValue(item.showDetailedIcon) | async) &&
|
|
(hasChildValue(item.options) | async)
|
|
"
|
|
[disabled]="!(getValue(item) | async) || (getValue(item.disabled) | async)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
listItemContentRef;
|
|
context: {
|
|
icon: item.icon,
|
|
title: item.title,
|
|
onlyIcon: item.onlyIcon,
|
|
iconSlot: item.slot || item.iconSlot,
|
|
iconColor: item.color || item.iconColor
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-item>
|
|
</ng-template>
|
|
|
|
<!-- List Item Content Template -->
|
|
<ng-template
|
|
#listItemContentRef
|
|
let-icon="icon"
|
|
let-title="title"
|
|
let-iconSlot="iconSlot"
|
|
let-onlyIcon="onlyIcon"
|
|
let-iconColor="iconColor"
|
|
>
|
|
<x-slotter
|
|
class="full-with"
|
|
[cssClass]="'full-with'"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[startTopSlotCssClass]="'dynamic-slot'"
|
|
[endBottomSlotCssClass]="'dynamic-slot'"
|
|
[centerSlotCssClass]="
|
|
'align-self-center ion-text-start ion-margin-horizontal'
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
(notEmptyValue(icon) | async) && (getValue(iconSlot) | async) === 'end'
|
|
"
|
|
[hasStartOrTopSlot]="
|
|
(notEmptyValue(icon) | async) && (getValue(iconSlot) | async) === 'start'
|
|
"
|
|
[hasCenterSlot]="notEmptyValue(title) && !(getValue(onlyIcon) | async)"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { icon: icon, color: iconColor }"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<ng-container
|
|
*ngTemplateOutlet="labelRef; context: { $implicit: title }"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { icon: icon, color: iconColor }"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</ng-template>
|
|
|
|
<!-- Icon Template -->
|
|
<ng-template #iconRef let-icon="icon" let-color="color">
|
|
<x-icon
|
|
[foregroundColor]="true"
|
|
*ngIf="notEmptyValue(icon)"
|
|
[name]="getValue(icon) | async"
|
|
[color]="
|
|
(notEmptyValue(color) | async)
|
|
? (getValue(color) | async)
|
|
: ColorNames.Tertiary
|
|
"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Label Template -->
|
|
<ng-template #labelRef let-title>
|
|
<ion-label *ngIf="notEmptyValue(title)">{{
|
|
getResourceValue(title) | async
|
|
}}</ion-label>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.scss
|
|
|
|
:host {
|
|
--max-popover-height: 260px;
|
|
--background-color: var(--x-color-light);
|
|
--divider-color: var(--x-color-dark-shade);
|
|
}
|
|
|
|
:host::ng-deep {
|
|
mat-card {
|
|
background-color: var(--background-color) !important;
|
|
}
|
|
}
|
|
|
|
:host::ng-deep.align-self-center {
|
|
align-self: center !important;
|
|
}
|
|
|
|
ion-list,
|
|
ion-item.item,
|
|
ion-item-divider,
|
|
ion-list-header {
|
|
--background: var(--background-color);
|
|
}
|
|
|
|
ion-item-divider {
|
|
--color: var(--divider-color);
|
|
}
|
|
|
|
ion-list-header.x-list-header {
|
|
text-align: center !important;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0;
|
|
}
|
|
|
|
.x-popover-wrapper {
|
|
max-height: var(--max-popover-height);
|
|
overflow-y: scroll;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.ts
|
|
|
|
import {
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
isFunction,
|
|
parseXColor,
|
|
XExceptionIDs,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
isNullOrUndefined,
|
|
XColorWithBrightness,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XPopoverItem,
|
|
XPopoverCssVar,
|
|
XPopoverOption,
|
|
XPopoverResult,
|
|
} from './x-popover.typings';
|
|
import { NavParams } from '@ionic/angular';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XPopoverService } from './x-popover.service';
|
|
import { generatePopoverId } from './x-popover.tools';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseComponent } from '../../classes/x-base-component';
|
|
import { XSlotLayout, XSlotName } from '../../x-slotter/x-slotter.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-popover',
|
|
templateUrl: './x-popover.component.html',
|
|
styleUrls: ['./x-popover.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XPopoverComponent extends XBaseComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
readonly ColorNames = Object.assign({}, XColorWithBrightness);
|
|
|
|
//
|
|
items: XOneOrManyType<XPopoverItem>;
|
|
options: XOneOrManyType<XPopoverOption>;
|
|
|
|
//
|
|
height: string;
|
|
dividerColor: XColorIdentifier;
|
|
backgroundColor: XColorIdentifier;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
public zone: NgZone,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public navParams: NavParams,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected popOverService: XPopoverService
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
|
|
//
|
|
// Options ...
|
|
const options = this.navParams.get(
|
|
nameof<XPopoverComponent>('options')
|
|
) as XPopoverOption[];
|
|
this.options = options;
|
|
|
|
//
|
|
// Items ...
|
|
const items = this.navParams.get(
|
|
nameof<XPopoverComponent>('items')
|
|
) as XPopoverItem[];
|
|
this.items = items;
|
|
|
|
//
|
|
// Error if not Options or Items ...
|
|
if (!this.hasChild(options) && !this.hasChild(items)) {
|
|
this.showError(XExceptionIDs.InvalidArgs, () => {
|
|
this.managerService.dialogService.popoverController.dismiss();
|
|
});
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
public afterViewInit(): void {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// Height ...
|
|
this.height = this.navParams.get(nameof<XPopoverComponent>('height'));
|
|
if (!isNullOrEmptyString(this.height)) {
|
|
this.applyHeight();
|
|
}
|
|
|
|
//
|
|
// DividerColor ...
|
|
this.dividerColor = this.navParams.get(
|
|
nameof<XPopoverComponent>('dividerColor')
|
|
);
|
|
if (!isNullOrEmptyString(this.dividerColor)) {
|
|
this.applyDividerColor();
|
|
}
|
|
|
|
//
|
|
// BackgroundColor ...
|
|
this.backgroundColor = this.navParams.get(
|
|
nameof<XPopoverComponent>('backgroundColor')
|
|
);
|
|
if (!isNullOrEmptyString(this.backgroundColor)) {
|
|
this.applyBackgroundColor();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
handleMenuSelected(
|
|
isItem: boolean,
|
|
item: XPopoverItem | XPopoverOption,
|
|
event: Event
|
|
) {
|
|
//
|
|
if (!!isItem) {
|
|
this.handleItemSelected(item as XPopoverItem, event);
|
|
} else {
|
|
this.handleOptionSelected(item as XPopoverOption);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Privates ...
|
|
private async handleItemSelected(item: XPopoverItem, event: Event) {
|
|
//
|
|
const itemResult =
|
|
!isNullOrUndefined(item) &&
|
|
!isNullOrUndefined(item.handler) &&
|
|
isFunction(item.handler)
|
|
? await this.getValueAsync(item.handler())
|
|
: undefined;
|
|
|
|
//
|
|
const optionsResultObj = !this.hasChild(item.options)
|
|
? undefined
|
|
: await this.popOverService.presentContextMenu(item.options, event);
|
|
|
|
//
|
|
if (
|
|
isNullOrUndefined(
|
|
optionsResultObj || isNullOrUndefined(optionsResultObj.option)
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const popoverId = generatePopoverId(this.items);
|
|
|
|
//
|
|
await this.managerService.dialogService.popoverController.dismiss(
|
|
{
|
|
item,
|
|
itemResult,
|
|
...optionsResultObj,
|
|
} as XPopoverResult,
|
|
undefined,
|
|
popoverId
|
|
);
|
|
}
|
|
|
|
private async handleOptionSelected(option: XPopoverOption) {
|
|
//
|
|
const optionResult =
|
|
!isNullOrUndefined(option) &&
|
|
!isNullOrUndefined(option.handler) &&
|
|
isFunction(option.handler)
|
|
? await this.getValueAsync(option.handler())
|
|
: undefined;
|
|
|
|
//
|
|
await this.managerService.dialogService.popoverController.dismiss({
|
|
option,
|
|
optionResult,
|
|
} as XPopoverResult);
|
|
}
|
|
|
|
private applyHeight() {
|
|
//
|
|
if (isNullOrEmptyString(this.height)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XPopoverCssVar.MaxPopoverHeight, this.height);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private applyDividerColor() {
|
|
//
|
|
if (isNullOrEmptyString(this.dividerColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const color = this.dividerColor;
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XPopoverCssVar.DividerColor, `var(${bgColor})`);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private applyBackgroundColor() {
|
|
//
|
|
if (isNullOrEmptyString(this.backgroundColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const color = this.backgroundColor;
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XPopoverCssVar.BackgroundColor, `var(${bgColor})`);
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.service.ts
|
|
|
|
import {
|
|
toArray,
|
|
hasChild,
|
|
XBaseService,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XPopoverItem,
|
|
XPopoverOption,
|
|
XPopoverResult,
|
|
XPopoverComponentProps,
|
|
XPopoverPresentOptions,
|
|
XPopoverPresenterOptions,
|
|
} from './x-popover.typings';
|
|
import { Inject, Injectable } from '@angular/core';
|
|
import { generatePopoverId } from './x-popover.tools';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XPopoverComponent } from './x-popover.component';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XPopoverService extends XBaseService {
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService
|
|
) {
|
|
super(config);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* Present Context Menu by Providinf XPopOverOption instance array ...
|
|
*
|
|
* @param options menu options which going to show to user ...
|
|
* @param event click event for positioning ...
|
|
*/
|
|
public async presentContextMenu(
|
|
options: XOneOrManyType<XPopoverOption>,
|
|
event: Event,
|
|
props?: XPopoverPresentOptions,
|
|
presentProps?: XPopoverPresenterOptions
|
|
) {
|
|
//
|
|
if (!hasChild(options)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const overrideWidth = toArray(options).every((option) => !!option.onlyIcon);
|
|
if (overrideWidth) {
|
|
//
|
|
let currentCssClass = !isNullOrUndefined(presentProps)
|
|
? toArray(presentProps.cssClass).join(' ')
|
|
: '';
|
|
currentCssClass += `${
|
|
currentCssClass.length > 0 ? ' ' : ''
|
|
}x-minimal-popover`;
|
|
|
|
//
|
|
presentProps = {
|
|
...presentProps,
|
|
cssClass: currentCssClass,
|
|
};
|
|
}
|
|
|
|
//
|
|
const mProps: XPopoverComponentProps = {
|
|
options,
|
|
...props,
|
|
};
|
|
|
|
//
|
|
// Present Popover as Context Menu ...
|
|
const popOver = await this.managerService.dialogService.presentPopover({
|
|
//
|
|
...presentProps,
|
|
//
|
|
event,
|
|
translucent: true,
|
|
showBackdrop: true,
|
|
componentProps: mProps,
|
|
component: XPopoverComponent,
|
|
});
|
|
|
|
//
|
|
// Extract Data from PopOver ...
|
|
const { data } = await popOver.onWillDismiss();
|
|
if (!data) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
const result = data as XPopoverResult;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Present Context Menu by Providinf XPopoverItem instance array ...
|
|
*
|
|
* @param items
|
|
* @param event
|
|
*/
|
|
public async presentContextMenuItems(
|
|
items: XOneOrManyType<XPopoverItem>,
|
|
event: Event,
|
|
props?: XPopoverPresentOptions,
|
|
presentProps?: XPopoverPresenterOptions
|
|
) {
|
|
//
|
|
if (!hasChild(items)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const overrideWidth = toArray(items).every((i) => !!i.onlyIcon);
|
|
if (overrideWidth) {
|
|
//
|
|
let currentCssClass = !isNullOrUndefined(presentProps)
|
|
? toArray(presentProps.cssClass).join(' ')
|
|
: '';
|
|
currentCssClass += `${
|
|
currentCssClass.length > 0 ? ' ' : ''
|
|
}x-minimal-popover`;
|
|
|
|
//
|
|
presentProps = {
|
|
...presentProps,
|
|
cssClass: currentCssClass,
|
|
};
|
|
}
|
|
|
|
//
|
|
// Generate unique id from items ...
|
|
const popoverId = generatePopoverId(items);
|
|
|
|
//
|
|
const mProps: XPopoverComponentProps = {
|
|
items,
|
|
...props,
|
|
};
|
|
|
|
//
|
|
// Present Popover as Context Menu ...
|
|
const popOver = await this.managerService.dialogService.presentPopover({
|
|
//
|
|
...presentProps,
|
|
//
|
|
event,
|
|
id: popoverId,
|
|
translucent: true,
|
|
showBackdrop: true,
|
|
componentProps: mProps,
|
|
component: XPopoverComponent,
|
|
});
|
|
|
|
//
|
|
// Extract Data from PopOver ...
|
|
const { data } = await popOver.onWillDismiss();
|
|
if (!data) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = data as XPopoverResult;
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.tools.ts
|
|
|
|
import { XListItem } from '../../x-list/x-list.typings';
|
|
import {
|
|
toMd5,
|
|
toArray,
|
|
hasChild,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import { XPopoverItem, XPopoverOption } from './x-popover.typings';
|
|
|
|
export const generatePopoverId: (
|
|
items: XOneOrManyType<XPopoverItem>
|
|
) => string = (items) => {
|
|
//
|
|
const itemIds = toArray(items)
|
|
.map((i) => i.id)
|
|
.join('|');
|
|
const result = toMd5(itemIds);
|
|
|
|
//
|
|
return result;
|
|
};
|
|
|
|
export const toPopoverOptions: (
|
|
item: XListItem<any>
|
|
) => XOneOrManyType<XPopoverOption> = (item) => {
|
|
//
|
|
let result: XPopoverOption[] = [];
|
|
|
|
//
|
|
if (isNullOrUndefined(item) || !hasChild(item.slideOptions)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = item.slideOptions.map((so) => {
|
|
return {
|
|
id: so.id,
|
|
onlyIcon: so.onlyIcon,
|
|
disabled: so.disabled,
|
|
icon: so.icon,
|
|
color: so.color,
|
|
title: so.title,
|
|
slot: so.slot,
|
|
handler: so.handler,
|
|
} as XPopoverOption;
|
|
});
|
|
|
|
//
|
|
return result;
|
|
};
|
|
|
|
export const defaultPopoverItem: XPopoverItem = {
|
|
id: '',
|
|
icon: '',
|
|
color: '',
|
|
title: '',
|
|
options: [],
|
|
iconColor: '',
|
|
iconSlot: 'end',
|
|
onlyIcon: false,
|
|
disabled: false,
|
|
handler: () => {},
|
|
showDetailedIcon: false,
|
|
};
|
|
|
|
export const defaultPopoverOption: XPopoverOption = {
|
|
id: '',
|
|
icon: '',
|
|
color: '',
|
|
title: '',
|
|
slot: 'end',
|
|
onlyIcon: false,
|
|
disabled: false,
|
|
handler: () => {},
|
|
};
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.typings.ts
|
|
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XPopoverOptions,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
} from 'x-framework-core';
|
|
import { XPopoverComponent } from './x-popover.component';
|
|
import { XIconIdentifier } from '../../x-icon/x-icon.typings';
|
|
|
|
export type XPopoverItemOptionSlot = 'end' | 'start';
|
|
|
|
export enum XPopoverCssVar {
|
|
DividerColor = 'divider-color',
|
|
BackgroundColor = 'background-color',
|
|
MaxPopoverHeight = 'max-popover-height',
|
|
}
|
|
|
|
export type XPopoverCssVarIdentifier = XPopoverCssVar | string;
|
|
|
|
export interface XPopoverOption {
|
|
id: string;
|
|
onlyIcon?: boolean;
|
|
disabled?: boolean;
|
|
icon?: XIconIdentifier;
|
|
color?: XColorIdentifier;
|
|
title?: XResourceIdentifier;
|
|
slot?: XPopoverItemOptionSlot;
|
|
handler?: () => XStandardType<any>;
|
|
}
|
|
|
|
export interface XPopoverItem {
|
|
id: string;
|
|
disabled?: boolean;
|
|
onlyIcon?: boolean;
|
|
icon?: XIconIdentifier;
|
|
color: XColorIdentifier;
|
|
title: XResourceIdentifier;
|
|
showDetailedIcon?: boolean;
|
|
iconColor?: XColorIdentifier;
|
|
options?: XPopoverOption[];
|
|
iconSlot?: XPopoverItemOptionSlot;
|
|
handler?: () => XStandardType<any>;
|
|
}
|
|
|
|
export interface XPopoverResult {
|
|
//
|
|
item?: XPopoverItem;
|
|
itemResult?: any;
|
|
//
|
|
option?: XPopoverOption;
|
|
optionResult?: any;
|
|
}
|
|
|
|
type SelectedKeysOfXpopoverComponent = Pick<
|
|
Partial<XPopoverComponent>,
|
|
'items' | 'options' | 'height' | 'dividerColor' | 'backgroundColor'
|
|
>;
|
|
export type XPopoverComponentPropsType = {
|
|
[key in keyof SelectedKeysOfXpopoverComponent]: any;
|
|
};
|
|
|
|
export interface XPopoverComponentProps extends XPopoverComponentPropsType {
|
|
height?: string;
|
|
dividerColor?: XColorIdentifier;
|
|
backgroundColor?: XColorIdentifier;
|
|
items?: XOneOrManyType<XPopoverItem>;
|
|
options?: XOneOrManyType<XPopoverOption>;
|
|
}
|
|
|
|
export type XPopoverPresentOptions = Pick<
|
|
Partial<XPopoverComponentProps>,
|
|
'height' | 'dividerColor' | 'backgroundColor'
|
|
>;
|
|
|
|
export type XPopoverPresenterOptions = Partial<
|
|
Omit<
|
|
XPopoverOptions,
|
|
| 'backdropDismiss'
|
|
| 'componentProps'
|
|
| 'component'
|
|
| 'id'
|
|
| 'translucent'
|
|
| 'showBackdrop'
|
|
| 'event'
|
|
>
|
|
>;
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.html
|
|
|
|
<div class="x-dialog-wrapper">
|
|
<!-- Toolbar -->
|
|
<ion-header class="x-dialog-header">
|
|
<!-- Title Toolbar -->
|
|
<ion-toolbar
|
|
class="v-toolbar"
|
|
[xColor]="'primary'"
|
|
*ngIf="showToolbar | async"
|
|
>
|
|
<!-- Slots -->
|
|
<div class="toolbar-area">
|
|
<x-slotter>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'ion-float-start']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleBack()"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="backIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<ion-title class="toolbar-item center-vertical-flex">
|
|
<h3>
|
|
{{ title | async }}
|
|
</h3>
|
|
</ion-title>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
[cssClass]="['ion-text-end', 'ion-float-end']"
|
|
>
|
|
<!-- De Select -->
|
|
<div
|
|
matRipple
|
|
(click)="handleDeselect()"
|
|
*ngIf="dialogCanSelect()"
|
|
class="
|
|
toolbar-item toolbar-inline-item toolbar-button
|
|
center-vertical-flex
|
|
"
|
|
>
|
|
<x-icon
|
|
[name]="cancelIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
|
|
<!-- Select -->
|
|
<div
|
|
matRipple
|
|
(click)="handleSelect()"
|
|
*ngIf="dialogCanSelect()"
|
|
class="
|
|
toolbar-item toolbar-inline-item toolbar-button
|
|
center-vertical-flex
|
|
"
|
|
>
|
|
<x-icon
|
|
[name]="selectIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ion-progress-bar
|
|
*ngIf="loading"
|
|
type="indeterminate"
|
|
[color]="progressBarColor | async"
|
|
></ion-progress-bar>
|
|
</ion-toolbar>
|
|
</ion-header>
|
|
|
|
<!-- Component -->
|
|
<ion-content
|
|
[ngClass]="cssClass | async"
|
|
class="x-dialog-content-wrapper"
|
|
[class.has-toolbar]="showToolbar | async"
|
|
>
|
|
<!-- Search -->
|
|
<x-search-bar
|
|
class="x-selector-search"
|
|
[color]="searchBarColor | async"
|
|
[value]="dataPagerQuery.filter"
|
|
[searchInputColor]="searchBarInputColor | async"
|
|
(queryChange)="handleSearchbarQuryChanged($event)"
|
|
*ngIf="(showSearchBar | async) && (getValue(canSearch) | async)"
|
|
></x-search-bar>
|
|
|
|
<!-- Data Pager -->
|
|
<x-data-pager
|
|
[loading]="loading"
|
|
[itemTemplate]="listRef"
|
|
[query]="dataPagerQuery"
|
|
[uiDisabled]="uiDisabled"
|
|
[result]="dataPagerResult"
|
|
[task]="queryFetcher | async"
|
|
clas="x-selector-data-pager"
|
|
[type]="DataPagerPresentTypes.Page"
|
|
[paginatorColor]="paginatorColor | async"
|
|
[actionProvider]="actionProvider | async"
|
|
(emptyRefresh)="handleResetDataPagerQuery()"
|
|
(taskReady)="handleDataPagerTaskReady($event)"
|
|
[paginatorPosition]="paginatorPosition | async"
|
|
(queryChange)="handleDataPagerQueryChanged($event)"
|
|
[showPaginator]="(showPaginator | async) && showDataPagerPaginator"
|
|
></x-data-pager>
|
|
</ion-content>
|
|
</div>
|
|
|
|
<!-- List Template -->
|
|
<ng-template #listRef>
|
|
<ng-container *ngIf="hasChildValue(dataPagerResultListItems) | async">
|
|
<x-list
|
|
[showEmpty]="true"
|
|
[showDivider]="true"
|
|
class="x-selector-list"
|
|
[emptyHasRefresh]="true"
|
|
[items]="dataPagerResultListItems"
|
|
[actionProvider]="pageListActionProvider"
|
|
(emptyRefresh)="handleResetDataPagerQuery()"
|
|
[selectableItems]="canMultipleSelect | async"
|
|
[clickableItems]="!(canMultipleSelect | async)"
|
|
(itemSelected)="handleListItemSelected($event)"
|
|
[itemTemplate]="
|
|
(notNullOrUndefinedValue(itemTemplate) | async)
|
|
? (itemTemplate | async)
|
|
: vItemRef
|
|
"
|
|
(selectionChanged)="handleListItemsSelected($event)"
|
|
>
|
|
</x-list>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<ng-template #vItemRef let-item>
|
|
{{ item.data | json }}
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.scss
|
|
|
|
::ng-deep.fullscreen-dialog {
|
|
//
|
|
width: 80vw !important;
|
|
max-width: 80vw !important;
|
|
|
|
//
|
|
height: 80vh !important;
|
|
max-height: 80vh !important;
|
|
|
|
//
|
|
&.mobile {
|
|
//
|
|
width: 100vw !important;
|
|
max-width: 100vw !important;
|
|
|
|
//
|
|
height: 100vh !important;
|
|
max-height: 100vh !important;
|
|
}
|
|
|
|
//
|
|
.mat-dialog-container {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
|
|
.x-dialog-wrapper {
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
position: relative !important;
|
|
}
|
|
|
|
.x-dialog-header {
|
|
position: sticky !important;
|
|
top: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.x-dialog-content-wrapper {
|
|
height: calc(100%);
|
|
|
|
&.has-toolbar {
|
|
height: calc(100% - 56px);
|
|
}
|
|
}
|
|
|
|
x-icon {
|
|
--size: 24px;
|
|
}
|
|
|
|
.toolbar-area {
|
|
margin: 0px;
|
|
}
|
|
|
|
.toolbar-item {
|
|
width: auto;
|
|
height: 48px;
|
|
}
|
|
|
|
.toolbar-inline-item {
|
|
display: inline-flex !important;
|
|
}
|
|
|
|
.toolbar-button {
|
|
width: 32px;
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.ts
|
|
|
|
import {
|
|
Inject,
|
|
NgZone,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XTask,
|
|
XColor,
|
|
toArray,
|
|
isFunction,
|
|
generateUuid,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XBaseDataPagerQuery,
|
|
XBaseDataPagerQueryResult,
|
|
} from 'x-framework-core';
|
|
import { Observable, Subject } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XDataPagerActionModel,
|
|
XDataPagerPresentType,
|
|
XDataPagerPaginatorPosition,
|
|
} from '../../x-data-pager/x-data-pager.typings';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XSelectorDialogConfig } from './x-selector-dialog.typings';
|
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
import { XListItem, XListActionModel } from '../../x-list/x-list.typings';
|
|
import { XBaseDialogComponent } from '../../classes/x-base.dialog.component';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-selector-dialog',
|
|
templateUrl: './x-selector-dialog.component.html',
|
|
styleUrls: ['./x-selector-dialog.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSelectorDialogComponent extends XBaseDialogComponent<
|
|
any,
|
|
XDataPagerActionModel,
|
|
XSelectorDialogConfig
|
|
> {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
uuid = generateUuid('XFormSelector');
|
|
|
|
//
|
|
canSearch: boolean;
|
|
dataPagerQuery: XBaseDataPagerQuery = {
|
|
...this.getDataPagerQuery(),
|
|
};
|
|
showDataPagerPaginator: boolean = true;
|
|
dataPagerResultListItems: XListItem<any>[] = [];
|
|
dataPagerResult: XBaseDataPagerQueryResult<any>;
|
|
dataPagerActionProvider = new Subject<XDataPagerActionModel>();
|
|
|
|
//
|
|
pageListActionProvider = new Subject<XListActionModel>();
|
|
|
|
//
|
|
readonly DataPagerPresentTypes = Object.assign({}, XDataPagerPresentType);
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
public zone: NgZone,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public managerService: XManagerService,
|
|
public changeDetector: ChangeDetectorRef,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
|
public dialogRef: MatDialogRef<XSelectorDialogComponent>
|
|
) {
|
|
super(
|
|
zone,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
managerService,
|
|
changeDetector,
|
|
config,
|
|
data,
|
|
dialogRef
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
async onTaskFinished(name: string, task: XTask<any>) {
|
|
await super.onTaskFinished(name, task);
|
|
|
|
//
|
|
const tName = await this.getValueAsync(this.taskName);
|
|
if (name === tName) {
|
|
//
|
|
this.setLoadingState(false);
|
|
await this.handleDataPagerTaskFinished(task.result);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
get taskName() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.taskName : this.uuid)
|
|
),
|
|
map((name) => (!isNullOrEmptyString(name) ? name : this.uuid))
|
|
);
|
|
}
|
|
|
|
get queryFetcher() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.queryFetcher : undefined)
|
|
)
|
|
);
|
|
}
|
|
|
|
get itemTemplate() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.itemTemplate : undefined)
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Data Pager Paginator ...
|
|
get showPaginator() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config ? config.showPaginator : false)
|
|
)
|
|
);
|
|
}
|
|
|
|
get paginatorColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config ? config.paginatorColor : XColor.Primary)
|
|
),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary))
|
|
);
|
|
}
|
|
|
|
get paginatorPosition() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(
|
|
config ? config.paginatorPosition : XDataPagerPaginatorPosition.Above
|
|
)
|
|
),
|
|
map((position) =>
|
|
!isNullOrEmptyString(position)
|
|
? position
|
|
: XDataPagerPaginatorPosition.Above
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleResetDataPagerQuery() {
|
|
//
|
|
this.dataPagerQuery = {
|
|
...this.getDataPagerQuery(),
|
|
};
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleDataPagerTaskReady(
|
|
task: Observable<XBaseDataPagerQueryResult<any>>
|
|
) {
|
|
//
|
|
// XBaseDataPagerQueryResult<any> ...
|
|
if (!task || this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.issueDataPagerTask(task);
|
|
}
|
|
|
|
async handleDataPagerQueryChanged(query: XBaseDataPagerQuery) {
|
|
//
|
|
if (!query) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onQueryChanged && isFunction(config.onQueryChanged)) {
|
|
await this.getValueAsync(config.onQueryChanged(query));
|
|
}
|
|
}
|
|
|
|
async handleListItemSelected(event: XListItem<any>) {
|
|
//
|
|
const canSelectMultipleItems = await this.getValueAsync(
|
|
this.canMultipleSelect
|
|
);
|
|
|
|
//
|
|
if (!event || !event.data || canSelectMultipleItems) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const index = this.dataPagerResultListItems.findIndex((i) =>
|
|
Object.is(i, event)
|
|
);
|
|
if (index > -1) {
|
|
//
|
|
// Cancel Previous Selected Item(s) ...
|
|
this.dataPagerResultListItems.forEach((i) => {
|
|
i.disabled = false;
|
|
});
|
|
|
|
//
|
|
// Disable Current Selected Item ...
|
|
this.dataPagerResultListItems[index].disabled = true;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
await this.handleSelectedItems(event);
|
|
}
|
|
|
|
async handleSelectedItems(event: XOneOrManyType<XListItem<any>>) {
|
|
//
|
|
this.selectedItem = toArray(event).map((i) => i.data);
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onItemSelect && isFunction(config.onItemSelect)) {
|
|
await this.getValueAsync(config.onItemSelect(event));
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleListItemsSelected(event: XListItem<any>[]) {
|
|
//
|
|
const canSelectMultipleItems = await this.getValueAsync(
|
|
this.canMultipleSelect
|
|
);
|
|
|
|
//
|
|
if (!this.hasChild(event) || !canSelectMultipleItems) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleSelectedItems(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
async getTaskNames(): Promise<string[]> {
|
|
return [await this.getValueAsync(this.taskName)];
|
|
}
|
|
|
|
async deselectAllListItems(): Promise<void> {
|
|
//
|
|
if (!this.hasChild(this.dataPagerResultListItems)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataPagerResultListItems.forEach((i) => {
|
|
i.disabled = false;
|
|
});
|
|
|
|
//
|
|
this.dataPagerResultListItems = [...this.dataPagerResultListItems];
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async deselectItemInList(item: any): Promise<void> {
|
|
//
|
|
if (
|
|
isNullOrUndefined(item) ||
|
|
!this.hasChild(this.dataPagerResultListItems)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const index = this.dataPagerResultListItems.findIndex((i) =>
|
|
Object.is(i.data, item)
|
|
);
|
|
if (index > -1) {
|
|
//
|
|
this.dataPagerResultListItems[index].disabled = false;
|
|
|
|
//
|
|
this.dataPagerResultListItems = [...this.dataPagerResultListItems];
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
}
|
|
|
|
async handleSearchbarQuryChanged(query: string): Promise<void> {
|
|
//
|
|
this.dataPagerQuery = {
|
|
...this.dataPagerQuery,
|
|
filter: query,
|
|
};
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private getDataPagerQuery(): XBaseDataPagerQuery {
|
|
return {
|
|
filter: '',
|
|
pageNumber: 1,
|
|
rowsInPage: this.config.defaultPageSize,
|
|
} as XBaseDataPagerQuery;
|
|
}
|
|
|
|
private async issueDataPagerTask(
|
|
task: Observable<XBaseDataPagerQueryResult<any>>
|
|
) {
|
|
//
|
|
if (!task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const mTaskName = await this.getValueAsync(this.taskName);
|
|
const mTask = task;
|
|
|
|
//
|
|
await this.addOrUpdateTask({
|
|
priority: 0,
|
|
affectLoading: true,
|
|
name: mTaskName,
|
|
task: mTask,
|
|
});
|
|
|
|
//
|
|
await this.dispatchTask(mTaskName);
|
|
}
|
|
|
|
private async handleDataPagerTaskFinished(
|
|
result: XBaseDataPagerQueryResult<any>
|
|
) {
|
|
//
|
|
this.dataPagerResult = null;
|
|
this.dataPagerResultListItems = [];
|
|
this.detectChanges();
|
|
|
|
//
|
|
if (!result) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataPagerResult = {
|
|
...result,
|
|
};
|
|
|
|
//
|
|
this.canSearch =
|
|
(this.hasChild(this.dataPagerResult.items) &&
|
|
this.dataPagerResult.items.length > 1) ||
|
|
!isNullOrEmptyString(this.dataPagerQuery.filter);
|
|
|
|
//
|
|
this.showDataPagerPaginator =
|
|
this.hasChild(this.dataPagerResult.items) &&
|
|
this.dataPagerResult.items.length > 1;
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (config && config.onPageLoad && isFunction(config.onPageLoad)) {
|
|
await this.getValueAsync(config.onPageLoad(this.dataPagerResult));
|
|
}
|
|
|
|
//
|
|
this.dataPagerResultListItems = await this.prepareListItems();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async prepareListItems() {
|
|
//
|
|
if (!this.dataPagerResult || !this.hasChild(this.dataPagerResult.items)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return this.dataPagerResult.items.map((sr) => {
|
|
return {
|
|
data: sr,
|
|
} as XListItem<any>;
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.service.ts
|
|
|
|
import {
|
|
MatDialog,
|
|
MatDialogRef,
|
|
MatDialogConfig,
|
|
} from '@angular/material/dialog';
|
|
import { Inject, Injectable } from '@angular/core';
|
|
import { XResourceIdentifier } from 'x-framework-core';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XSelectorDialogConfig } from './x-selector-dialog.typings';
|
|
import { XSelectorDialogComponent } from './x-selector-dialog.component';
|
|
import { XBaseDialogService } from '../../classes/x-base-dialog.service';
|
|
import { XDataPagerActionModel } from '../../x-data-pager/x-data-pager.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XSelectorDialogService extends XBaseDialogService<
|
|
any,
|
|
XDataPagerActionModel,
|
|
XSelectorDialogConfig,
|
|
XSelectorDialogComponent
|
|
> {
|
|
//
|
|
defaultTitleResourceIdentifier: XResourceIdentifier;
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected dialog: MatDialog,
|
|
protected managerService: XManagerService,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig
|
|
) {
|
|
super(dialog, managerService, config);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
openDialogAndReturnRef(
|
|
config: MatDialogConfig<any>
|
|
): MatDialogRef<XSelectorDialogComponent, any> {
|
|
return this.dialog.open(XSelectorDialogComponent, config);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.typings.ts
|
|
|
|
import {
|
|
XStandardType,
|
|
XColorIdentifier,
|
|
XBaseDataPagerQuery,
|
|
XBaseDataPagerQueryResult,
|
|
} from 'x-framework-core';
|
|
import { Observable } from 'rxjs';
|
|
import { TemplateRef } from '@angular/core';
|
|
import {
|
|
IXBaseDialogConfig,
|
|
IXBaseDialogResult,
|
|
} from '../../classes/x-base.dialog.component';
|
|
import {
|
|
XDataPagerActionModel,
|
|
XDataPagerPaginatorPositionIdentifier,
|
|
} from '../../x-data-pager/x-data-pager.typings';
|
|
|
|
export interface XSelectorDialogResult extends IXBaseDialogResult {}
|
|
|
|
export interface XSelectorDialogConfig
|
|
extends IXBaseDialogConfig<XDataPagerActionModel> {
|
|
//
|
|
showPaginator?: XStandardType<boolean>;
|
|
paginatorColor?: XStandardType<XColorIdentifier>;
|
|
paginatorPosition?: XStandardType<XDataPagerPaginatorPositionIdentifier>;
|
|
|
|
//
|
|
queryFetcher?: (
|
|
query: XBaseDataPagerQuery
|
|
) => Observable<XBaseDataPagerQueryResult<any>>;
|
|
onQueryChanged?: (query: XBaseDataPagerQuery) => XStandardType<void>;
|
|
onPageLoad?: (result: XBaseDataPagerQueryResult<any>) => XStandardType<void>;
|
|
itemTemplate?: XStandardType<TemplateRef<any>>;
|
|
|
|
//
|
|
taskName?: XStandardType<string>;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\modules\x-base-component.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { IonicModule } from '@ionic/angular';
|
|
import { CommonModule } from '@angular/common';
|
|
import { RouterModule } from '@angular/router';
|
|
import { XMaterialModule } from './x-material.module';
|
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
import { XDirectivesModule as XFrameworkCoreDirectivesModule } from 'x-framework-core';
|
|
import { XDirectivesModule as XFrameworkServicesDirectivesModule } from 'x-framework-services';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
IonicModule,
|
|
FormsModule,
|
|
CommonModule,
|
|
RouterModule,
|
|
XMaterialModule,
|
|
ReactiveFormsModule,
|
|
XFrameworkCoreDirectivesModule,
|
|
XFrameworkServicesDirectivesModule,
|
|
],
|
|
exports: [
|
|
FormsModule,
|
|
IonicModule,
|
|
RouterModule,
|
|
CommonModule,
|
|
XMaterialModule,
|
|
ReactiveFormsModule,
|
|
XFrameworkCoreDirectivesModule,
|
|
XFrameworkServicesDirectivesModule,
|
|
],
|
|
})
|
|
export class XBaseComponentModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\modules\x-material.module.ts
|
|
|
|
//
|
|
import { NgModule } from '@angular/core';
|
|
|
|
//
|
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
|
import { CdkTableModule } from '@angular/cdk/table';
|
|
import { CdkTreeModule } from '@angular/cdk/tree';
|
|
|
|
//
|
|
// Form Controls ...
|
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
import { MatInputModule } from '@angular/material/input';
|
|
import { MatRadioModule } from '@angular/material/radio';
|
|
import { MatSelectModule } from '@angular/material/select';
|
|
import { MatSliderModule } from '@angular/material/slider';
|
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
|
|
//
|
|
// Navigations / Menus ...
|
|
import { MatMenuModule } from '@angular/material/menu';
|
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
|
|
//
|
|
// Layout ...
|
|
import { MatCardModule } from '@angular/material/card';
|
|
import { MatDividerModule } from '@angular/material/divider';
|
|
import { MatExpansionModule } from '@angular/material/expansion';
|
|
import { MatGridListModule } from '@angular/material/grid-list';
|
|
import { MatListModule } from '@angular/material/list';
|
|
import { MatStepperModule } from '@angular/material/stepper';
|
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
import { MatTreeModule } from '@angular/material/tree';
|
|
|
|
//
|
|
// Buttons and Indicators ...
|
|
import { MatButtonModule } from '@angular/material/button';
|
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
import { MatBadgeModule } from '@angular/material/badge';
|
|
import { MatChipsModule } from '@angular/material/chips';
|
|
import { MatIconModule } from '@angular/material/icon';
|
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
import { MatRippleModule } from '@angular/material/core';
|
|
import { MatNativeDateModule } from '@angular/material/core';
|
|
|
|
//
|
|
// Popups and Dialogs ...
|
|
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
|
import { MatDialogModule } from '@angular/material/dialog';
|
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
|
|
//
|
|
// Data Table ...
|
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
import { MatSortModule } from '@angular/material/sort';
|
|
import { MatTableModule } from '@angular/material/table';
|
|
|
|
//
|
|
import {
|
|
MomentDateModule,
|
|
MatMomentDateModule,
|
|
} from '@angular/material-moment-adapter';
|
|
import { LayoutModule } from '@angular/cdk/layout';
|
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
|
import { CommonModule } from '@angular/common';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
CommonModule,
|
|
|
|
//
|
|
CdkTableModule,
|
|
CdkTreeModule,
|
|
|
|
//
|
|
DragDropModule,
|
|
ScrollingModule,
|
|
|
|
//
|
|
LayoutModule,
|
|
FlexLayoutModule,
|
|
|
|
//
|
|
MatAutocompleteModule,
|
|
MatBadgeModule,
|
|
MatBottomSheetModule,
|
|
MatButtonModule,
|
|
MatButtonToggleModule,
|
|
MatCardModule,
|
|
MatCheckboxModule,
|
|
MatChipsModule,
|
|
MatStepperModule,
|
|
MatDatepickerModule,
|
|
MatDialogModule,
|
|
MatDividerModule,
|
|
MatExpansionModule,
|
|
MatGridListModule,
|
|
MatIconModule,
|
|
MatInputModule,
|
|
MatListModule,
|
|
MatNativeDateModule,
|
|
MatPaginatorModule,
|
|
MatProgressBarModule,
|
|
MatProgressSpinnerModule,
|
|
MatRadioModule,
|
|
MatRippleModule,
|
|
MatSelectModule,
|
|
MatSidenavModule,
|
|
MatSliderModule,
|
|
MatSlideToggleModule,
|
|
MatSnackBarModule,
|
|
MatSortModule,
|
|
MatTableModule,
|
|
MatTabsModule,
|
|
MatToolbarModule,
|
|
MatTooltipModule,
|
|
MatTreeModule,
|
|
MatFormFieldModule,
|
|
MatMenuModule,
|
|
|
|
//
|
|
MomentDateModule,
|
|
MatMomentDateModule,
|
|
],
|
|
exports: [
|
|
//
|
|
CdkTableModule,
|
|
CdkTreeModule,
|
|
|
|
//
|
|
DragDropModule,
|
|
ScrollingModule,
|
|
|
|
//
|
|
LayoutModule,
|
|
FlexLayoutModule,
|
|
|
|
//
|
|
MatAutocompleteModule,
|
|
MatBadgeModule,
|
|
MatBottomSheetModule,
|
|
MatButtonModule,
|
|
MatButtonToggleModule,
|
|
MatCardModule,
|
|
MatCheckboxModule,
|
|
MatChipsModule,
|
|
MatStepperModule,
|
|
MatDatepickerModule,
|
|
MatDialogModule,
|
|
MatDividerModule,
|
|
MatExpansionModule,
|
|
MatGridListModule,
|
|
MatIconModule,
|
|
MatInputModule,
|
|
MatListModule,
|
|
MatNativeDateModule,
|
|
MatPaginatorModule,
|
|
MatProgressBarModule,
|
|
MatProgressSpinnerModule,
|
|
MatRadioModule,
|
|
MatRippleModule,
|
|
MatSelectModule,
|
|
MatSidenavModule,
|
|
MatSliderModule,
|
|
MatSlideToggleModule,
|
|
MatSnackBarModule,
|
|
MatSortModule,
|
|
MatTableModule,
|
|
MatTabsModule,
|
|
MatToolbarModule,
|
|
MatTooltipModule,
|
|
MatTreeModule,
|
|
MatFormFieldModule,
|
|
MatMenuModule,
|
|
|
|
//
|
|
MomentDateModule,
|
|
MatMomentDateModule,
|
|
],
|
|
})
|
|
export class XMaterialModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\_tools.scss
|
|
|
|
@import "./animate.scss";
|
|
|
|
//
|
|
//#region Tools ...
|
|
|
|
//
|
|
//#region Dimensions ...
|
|
//
|
|
// These are default values which can be used for margins and
|
|
// paddings ...
|
|
$d-xsm: 2px;
|
|
$d-sm: 4px;
|
|
$d-md: 8px;
|
|
$d-l: 16px;
|
|
$d-el: 32px;
|
|
$d-exl: 48px;
|
|
|
|
//
|
|
// Box Sizing ...
|
|
$d-min: 300px;
|
|
$d-medium: 500px;
|
|
$d-max: 800px;
|
|
|
|
//
|
|
// Percentages ...
|
|
$d-25p: 25%;
|
|
$d-50p: 50%;
|
|
$d-75p: 75%;
|
|
$d-100p: 100%;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Margin adnd Padding mixins ...
|
|
.m-0 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.p-0 {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
@mixin m-rl($size: $d-sm) {
|
|
margin-left: $size;
|
|
margin-right: $size;
|
|
}
|
|
|
|
@mixin p-rl($size: $d-sm) {
|
|
padding-left: $size;
|
|
padding-right: $size;
|
|
}
|
|
|
|
@mixin m-tb($size: $d-sm) {
|
|
margin-top: $size;
|
|
margin-bottom: $size;
|
|
}
|
|
|
|
@mixin p-tb($size: $d-sm) {
|
|
padding-top: $size;
|
|
padding-bottom: $size;
|
|
}
|
|
|
|
@mixin m($size: $d-sm) {
|
|
margin: $size !important;
|
|
}
|
|
|
|
@mixin p($size: $d-sm) {
|
|
padding: $size !important;
|
|
}
|
|
|
|
@mixin m-full($top: 0px, $left: 0px, $bottom: 0px, $right: 0px) {
|
|
margin: {
|
|
top: $top;
|
|
left: $left;
|
|
bottom: $bottom;
|
|
right: $right;
|
|
}
|
|
}
|
|
|
|
@mixin p-full($top: 0px, $left: 0px, $bottom: 0px, $right: 0px) {
|
|
padding: {
|
|
top: $top;
|
|
left: $left;
|
|
bottom: $bottom;
|
|
right: $right;
|
|
}
|
|
}
|
|
|
|
@mixin push-auto {
|
|
margin: {
|
|
left: auto;
|
|
right: auto;
|
|
}
|
|
}
|
|
|
|
.push-auto {
|
|
margin: {
|
|
left: auto;
|
|
right: auto;
|
|
}
|
|
}
|
|
|
|
// #endregion
|
|
|
|
//
|
|
//#region Animation mixins and classes ...
|
|
@mixin animation(
|
|
$animation-name: ".fadeIn",
|
|
$animation-duration: 500ms,
|
|
$animation-delay: "",
|
|
$animation-repeat: 1
|
|
) {
|
|
@extend .animated;
|
|
@extend .#{$animation-name};
|
|
animation-delay: $animation-delay;
|
|
animation-duration: $animation-duration;
|
|
animation-iteration-count: $animation-repeat;
|
|
}
|
|
|
|
@mixin transition-duration($duration: 500ms, $delay: 0ms) {
|
|
//
|
|
transition-delay: $delay;
|
|
-webkit-transition-delay: $delay;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
|
|
@mixin transformer($transform, $duration: 500ms, $delay: 0ms) {
|
|
//
|
|
transform: $transform;
|
|
-ms-transform: $transform;
|
|
-webkit-transform: $transform;
|
|
|
|
//
|
|
@include transition(transform, $duration, $delay);
|
|
}
|
|
|
|
@mixin transition($transition, $duration: 500ms, $delay: 0ms) {
|
|
//
|
|
transition: $transition;
|
|
-webkit-transition: $transition;
|
|
|
|
@include transition-duration($duration, $delay);
|
|
}
|
|
|
|
@mixin show {
|
|
@include animation("fadeIn", "250ms");
|
|
@include transition("height", "250ms");
|
|
}
|
|
|
|
@mixin hide {
|
|
@include animation("fadeOut", "250ms");
|
|
|
|
height: 0;
|
|
@include transition("height", "250ms", "250ms");
|
|
}
|
|
|
|
.show {
|
|
@include show();
|
|
}
|
|
|
|
.hide {
|
|
@include hide();
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Width Height and Alignment ...
|
|
@mixin applyWidthHeight($size: $d-75p, $min-width: $d-min, $max-width: $d-max) {
|
|
width: calc(#{$size});
|
|
max-width: $max-width;
|
|
min-width: $min-width;
|
|
}
|
|
|
|
@mixin horizontal-spacer {
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.horizontal-spacer {
|
|
@include horizontal-spacer();
|
|
}
|
|
|
|
@mixin center-vertical-flex {
|
|
//
|
|
display: flex !important;
|
|
flex-direction: column !important;
|
|
justify-content: center !important;
|
|
}
|
|
|
|
.center-vertical-flex {
|
|
@include center-vertical-flex();
|
|
}
|
|
|
|
@mixin center-vertical {
|
|
position: relative;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.center-vertical {
|
|
@include center-vertical();
|
|
}
|
|
|
|
@mixin center {
|
|
@extend .center;
|
|
}
|
|
|
|
.center {
|
|
text-align: center;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
@mixin text-truncate {
|
|
@extend .text-truncate;
|
|
}
|
|
|
|
.text-truncate {
|
|
display: inline-block;
|
|
overflow-x: hidden !important;
|
|
text-overflow: ellipsis !important;
|
|
white-space: nowrap;
|
|
min-width: 0;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Shadows Tools ...
|
|
@mixin add-shadow-box($vert, $horz, $blur, $size, $color: $shadow-color) {
|
|
//
|
|
$box-shadow-data: $vert $horz $blur $size $shadow-color !important;
|
|
|
|
//
|
|
box-shadow: $box-shadow-data;
|
|
-moz-box-shadow: $box-shadow-data;
|
|
-webkit-box-shadow: $box-shadow-data;
|
|
}
|
|
|
|
@mixin remove-shadow-box() {
|
|
//
|
|
$box-shadow-data: none !important;
|
|
|
|
//
|
|
box-shadow: $box-shadow-data;
|
|
-moz-box-shadow: $box-shadow-data;
|
|
-webkit-box-shadow: $box-shadow-data;
|
|
}
|
|
|
|
@mixin filterBlur($level: 4px) {
|
|
-webkit-filter: blur($level);
|
|
filter: blur($level);
|
|
}
|
|
|
|
@mixin filterBrightness($level: 0.3) {
|
|
-webkit-filter: brightness($level);
|
|
filter: brightness($level);
|
|
}
|
|
|
|
@mixin filterContrast($level: 180%) {
|
|
-webkit-filter: contrast($level);
|
|
filter: contrast($level);
|
|
}
|
|
|
|
@mixin filterGrayscale($level: 100%) {
|
|
-webkit-filter: grayscale($level);
|
|
filter: grayscale($level);
|
|
}
|
|
|
|
@mixin filterHuerotate($level: 180deg) {
|
|
-webkit-filter: hue-rotate($level);
|
|
filter: hue-rotate($level);
|
|
}
|
|
|
|
@mixin filterInvert($level: 100%) {
|
|
-webkit-filter: invert($level);
|
|
filter: invert($level);
|
|
}
|
|
|
|
@mixin filterOpacity($level: 50%) {
|
|
-webkit-filter: opacity($level);
|
|
filter: opacity($level);
|
|
}
|
|
|
|
@mixin filterSaturate($level: 7) {
|
|
-webkit-filter: saturate($level);
|
|
filter: saturate($level);
|
|
}
|
|
|
|
@mixin filterSepia($level: 100%) {
|
|
-webkit-filter: sepia($level);
|
|
filter: sepia(100%);
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Other ...
|
|
@mixin disableLink {
|
|
pointer-events: none;
|
|
|
|
* {
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\animate.scss
|
|
|
|
@charset "UTF-8";
|
|
|
|
/*!
|
|
* animate.css -http://daneden.me/animate
|
|
* Version - 3.7.0
|
|
* Licensed under the MIT license - http://opensource.org/licenses/MIT
|
|
*
|
|
* Copyright (c) 2018 Daniel Eden
|
|
*/
|
|
|
|
@-webkit-keyframes bounce {
|
|
from,
|
|
20%,
|
|
53%,
|
|
80%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
40%,
|
|
43% {
|
|
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
-webkit-transform: translate3d(0, -30px, 0);
|
|
transform: translate3d(0, -30px, 0);
|
|
}
|
|
|
|
70% {
|
|
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
-webkit-transform: translate3d(0, -15px, 0);
|
|
transform: translate3d(0, -15px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, -4px, 0);
|
|
transform: translate3d(0, -4px, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounce {
|
|
from,
|
|
20%,
|
|
53%,
|
|
80%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
40%,
|
|
43% {
|
|
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
-webkit-transform: translate3d(0, -30px, 0);
|
|
transform: translate3d(0, -30px, 0);
|
|
}
|
|
|
|
70% {
|
|
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
-webkit-transform: translate3d(0, -15px, 0);
|
|
transform: translate3d(0, -15px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, -4px, 0);
|
|
transform: translate3d(0, -4px, 0);
|
|
}
|
|
}
|
|
|
|
.bounce {
|
|
-webkit-animation-name: bounce;
|
|
animation-name: bounce;
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
}
|
|
|
|
@-webkit-keyframes flash {
|
|
from,
|
|
50%,
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
|
|
25%,
|
|
75% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes flash {
|
|
from,
|
|
50%,
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
|
|
25%,
|
|
75% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.flash {
|
|
-webkit-animation-name: flash;
|
|
animation-name: flash;
|
|
}
|
|
|
|
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
|
|
|
@-webkit-keyframes pulse {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
|
transform: scale3d(1.05, 1.05, 1.05);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes pulse {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
|
transform: scale3d(1.05, 1.05, 1.05);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
.pulse {
|
|
-webkit-animation-name: pulse;
|
|
animation-name: pulse;
|
|
}
|
|
|
|
@-webkit-keyframes rubberBand {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: scale3d(1.25, 0.75, 1);
|
|
transform: scale3d(1.25, 0.75, 1);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: scale3d(0.75, 1.25, 1);
|
|
transform: scale3d(0.75, 1.25, 1);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: scale3d(1.15, 0.85, 1);
|
|
transform: scale3d(1.15, 0.85, 1);
|
|
}
|
|
|
|
65% {
|
|
-webkit-transform: scale3d(0.95, 1.05, 1);
|
|
transform: scale3d(0.95, 1.05, 1);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: scale3d(1.05, 0.95, 1);
|
|
transform: scale3d(1.05, 0.95, 1);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes rubberBand {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: scale3d(1.25, 0.75, 1);
|
|
transform: scale3d(1.25, 0.75, 1);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: scale3d(0.75, 1.25, 1);
|
|
transform: scale3d(0.75, 1.25, 1);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: scale3d(1.15, 0.85, 1);
|
|
transform: scale3d(1.15, 0.85, 1);
|
|
}
|
|
|
|
65% {
|
|
-webkit-transform: scale3d(0.95, 1.05, 1);
|
|
transform: scale3d(0.95, 1.05, 1);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: scale3d(1.05, 0.95, 1);
|
|
transform: scale3d(1.05, 0.95, 1);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
.rubberBand {
|
|
-webkit-animation-name: rubberBand;
|
|
animation-name: rubberBand;
|
|
}
|
|
|
|
@-webkit-keyframes shake {
|
|
from,
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
10%,
|
|
30%,
|
|
50%,
|
|
70%,
|
|
90% {
|
|
-webkit-transform: translate3d(-10px, 0, 0);
|
|
transform: translate3d(-10px, 0, 0);
|
|
}
|
|
|
|
20%,
|
|
40%,
|
|
60%,
|
|
80% {
|
|
-webkit-transform: translate3d(10px, 0, 0);
|
|
transform: translate3d(10px, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes shake {
|
|
from,
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
10%,
|
|
30%,
|
|
50%,
|
|
70%,
|
|
90% {
|
|
-webkit-transform: translate3d(-10px, 0, 0);
|
|
transform: translate3d(-10px, 0, 0);
|
|
}
|
|
|
|
20%,
|
|
40%,
|
|
60%,
|
|
80% {
|
|
-webkit-transform: translate3d(10px, 0, 0);
|
|
transform: translate3d(10px, 0, 0);
|
|
}
|
|
}
|
|
|
|
.shake {
|
|
-webkit-animation-name: shake;
|
|
animation-name: shake;
|
|
}
|
|
|
|
@-webkit-keyframes headShake {
|
|
0% {
|
|
-webkit-transform: translateX(0);
|
|
transform: translateX(0);
|
|
}
|
|
|
|
6.5% {
|
|
-webkit-transform: translateX(-6px) rotateY(-9deg);
|
|
transform: translateX(-6px) rotateY(-9deg);
|
|
}
|
|
|
|
18.5% {
|
|
-webkit-transform: translateX(5px) rotateY(7deg);
|
|
transform: translateX(5px) rotateY(7deg);
|
|
}
|
|
|
|
31.5% {
|
|
-webkit-transform: translateX(-3px) rotateY(-5deg);
|
|
transform: translateX(-3px) rotateY(-5deg);
|
|
}
|
|
|
|
43.5% {
|
|
-webkit-transform: translateX(2px) rotateY(3deg);
|
|
transform: translateX(2px) rotateY(3deg);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: translateX(0);
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
@keyframes headShake {
|
|
0% {
|
|
-webkit-transform: translateX(0);
|
|
transform: translateX(0);
|
|
}
|
|
|
|
6.5% {
|
|
-webkit-transform: translateX(-6px) rotateY(-9deg);
|
|
transform: translateX(-6px) rotateY(-9deg);
|
|
}
|
|
|
|
18.5% {
|
|
-webkit-transform: translateX(5px) rotateY(7deg);
|
|
transform: translateX(5px) rotateY(7deg);
|
|
}
|
|
|
|
31.5% {
|
|
-webkit-transform: translateX(-3px) rotateY(-5deg);
|
|
transform: translateX(-3px) rotateY(-5deg);
|
|
}
|
|
|
|
43.5% {
|
|
-webkit-transform: translateX(2px) rotateY(3deg);
|
|
transform: translateX(2px) rotateY(3deg);
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: translateX(0);
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
.headShake {
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
-webkit-animation-name: headShake;
|
|
animation-name: headShake;
|
|
}
|
|
|
|
@-webkit-keyframes swing {
|
|
20% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 15deg);
|
|
transform: rotate3d(0, 0, 1, 15deg);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: rotate3d(0, 0, 1, -10deg);
|
|
transform: rotate3d(0, 0, 1, -10deg);
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 5deg);
|
|
transform: rotate3d(0, 0, 1, 5deg);
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: rotate3d(0, 0, 1, -5deg);
|
|
transform: rotate3d(0, 0, 1, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: rotate3d(0, 0, 1, 0deg);
|
|
transform: rotate3d(0, 0, 1, 0deg);
|
|
}
|
|
}
|
|
|
|
@keyframes swing {
|
|
20% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 15deg);
|
|
transform: rotate3d(0, 0, 1, 15deg);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: rotate3d(0, 0, 1, -10deg);
|
|
transform: rotate3d(0, 0, 1, -10deg);
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 5deg);
|
|
transform: rotate3d(0, 0, 1, 5deg);
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: rotate3d(0, 0, 1, -5deg);
|
|
transform: rotate3d(0, 0, 1, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: rotate3d(0, 0, 1, 0deg);
|
|
transform: rotate3d(0, 0, 1, 0deg);
|
|
}
|
|
}
|
|
|
|
.swing {
|
|
-webkit-transform-origin: top center;
|
|
transform-origin: top center;
|
|
-webkit-animation-name: swing;
|
|
animation-name: swing;
|
|
}
|
|
|
|
@-webkit-keyframes tada {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
10%,
|
|
20% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
|
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
30%,
|
|
50%,
|
|
70%,
|
|
90% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
|
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
|
}
|
|
|
|
40%,
|
|
60%,
|
|
80% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
|
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes tada {
|
|
from {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
|
|
10%,
|
|
20% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
|
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
30%,
|
|
50%,
|
|
70%,
|
|
90% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
|
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
|
}
|
|
|
|
40%,
|
|
60%,
|
|
80% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
|
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
.tada {
|
|
-webkit-animation-name: tada;
|
|
animation-name: tada;
|
|
}
|
|
|
|
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
|
|
|
@-webkit-keyframes wobble {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
15% {
|
|
-webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
|
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
|
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
|
}
|
|
|
|
45% {
|
|
-webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
|
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
|
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
|
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes wobble {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
15% {
|
|
-webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
|
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
|
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
|
}
|
|
|
|
45% {
|
|
-webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
|
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
|
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
|
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.wobble {
|
|
-webkit-animation-name: wobble;
|
|
animation-name: wobble;
|
|
}
|
|
|
|
@-webkit-keyframes jello {
|
|
from,
|
|
11.1%,
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
22.2% {
|
|
-webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
|
|
transform: skewX(-12.5deg) skewY(-12.5deg);
|
|
}
|
|
|
|
33.3% {
|
|
-webkit-transform: skewX(6.25deg) skewY(6.25deg);
|
|
transform: skewX(6.25deg) skewY(6.25deg);
|
|
}
|
|
|
|
44.4% {
|
|
-webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
|
|
transform: skewX(-3.125deg) skewY(-3.125deg);
|
|
}
|
|
|
|
55.5% {
|
|
-webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
|
|
transform: skewX(1.5625deg) skewY(1.5625deg);
|
|
}
|
|
|
|
66.6% {
|
|
-webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
|
transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
|
}
|
|
|
|
77.7% {
|
|
-webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
|
|
transform: skewX(0.390625deg) skewY(0.390625deg);
|
|
}
|
|
|
|
88.8% {
|
|
-webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
|
transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
|
}
|
|
}
|
|
|
|
@keyframes jello {
|
|
from,
|
|
11.1%,
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
22.2% {
|
|
-webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
|
|
transform: skewX(-12.5deg) skewY(-12.5deg);
|
|
}
|
|
|
|
33.3% {
|
|
-webkit-transform: skewX(6.25deg) skewY(6.25deg);
|
|
transform: skewX(6.25deg) skewY(6.25deg);
|
|
}
|
|
|
|
44.4% {
|
|
-webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
|
|
transform: skewX(-3.125deg) skewY(-3.125deg);
|
|
}
|
|
|
|
55.5% {
|
|
-webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
|
|
transform: skewX(1.5625deg) skewY(1.5625deg);
|
|
}
|
|
|
|
66.6% {
|
|
-webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
|
transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
|
}
|
|
|
|
77.7% {
|
|
-webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
|
|
transform: skewX(0.390625deg) skewY(0.390625deg);
|
|
}
|
|
|
|
88.8% {
|
|
-webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
|
transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
|
}
|
|
}
|
|
|
|
.jello {
|
|
-webkit-animation-name: jello;
|
|
animation-name: jello;
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
}
|
|
|
|
@-webkit-keyframes heartBeat {
|
|
0% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
|
|
14% {
|
|
-webkit-transform: scale(1.3);
|
|
transform: scale(1.3);
|
|
}
|
|
|
|
28% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
|
|
42% {
|
|
-webkit-transform: scale(1.3);
|
|
transform: scale(1.3);
|
|
}
|
|
|
|
70% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes heartBeat {
|
|
0% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
|
|
14% {
|
|
-webkit-transform: scale(1.3);
|
|
transform: scale(1.3);
|
|
}
|
|
|
|
28% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
|
|
42% {
|
|
-webkit-transform: scale(1.3);
|
|
transform: scale(1.3);
|
|
}
|
|
|
|
70% {
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.heartBeat {
|
|
-webkit-animation-name: heartBeat;
|
|
animation-name: heartBeat;
|
|
-webkit-animation-duration: 1.3s;
|
|
animation-duration: 1.3s;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
}
|
|
|
|
@-webkit-keyframes bounceIn {
|
|
from,
|
|
20%,
|
|
40%,
|
|
60%,
|
|
80%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
20% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1);
|
|
transform: scale3d(1.1, 1.1, 1.1);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9);
|
|
transform: scale3d(0.9, 0.9, 0.9);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1.03, 1.03, 1.03);
|
|
transform: scale3d(1.03, 1.03, 1.03);
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: scale3d(0.97, 0.97, 0.97);
|
|
transform: scale3d(0.97, 0.97, 0.97);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceIn {
|
|
from,
|
|
20%,
|
|
40%,
|
|
60%,
|
|
80%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
20% {
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1);
|
|
transform: scale3d(1.1, 1.1, 1.1);
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9);
|
|
transform: scale3d(0.9, 0.9, 0.9);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1.03, 1.03, 1.03);
|
|
transform: scale3d(1.03, 1.03, 1.03);
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: scale3d(0.97, 0.97, 0.97);
|
|
transform: scale3d(0.97, 0.97, 0.97);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1, 1, 1);
|
|
transform: scale3d(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
.bounceIn {
|
|
-webkit-animation-duration: 0.75s;
|
|
animation-duration: 0.75s;
|
|
-webkit-animation-name: bounceIn;
|
|
animation-name: bounceIn;
|
|
}
|
|
|
|
@-webkit-keyframes bounceInDown {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -3000px, 0);
|
|
transform: translate3d(0, -3000px, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 25px, 0);
|
|
transform: translate3d(0, 25px, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(0, -10px, 0);
|
|
transform: translate3d(0, -10px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, 5px, 0);
|
|
transform: translate3d(0, 5px, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceInDown {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -3000px, 0);
|
|
transform: translate3d(0, -3000px, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 25px, 0);
|
|
transform: translate3d(0, 25px, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(0, -10px, 0);
|
|
transform: translate3d(0, -10px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, 5px, 0);
|
|
transform: translate3d(0, 5px, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceInDown {
|
|
-webkit-animation-name: bounceInDown;
|
|
animation-name: bounceInDown;
|
|
}
|
|
|
|
@-webkit-keyframes bounceInLeft {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-3000px, 0, 0);
|
|
transform: translate3d(-3000px, 0, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(25px, 0, 0);
|
|
transform: translate3d(25px, 0, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(-10px, 0, 0);
|
|
transform: translate3d(-10px, 0, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(5px, 0, 0);
|
|
transform: translate3d(5px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceInLeft {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
0% {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-3000px, 0, 0);
|
|
transform: translate3d(-3000px, 0, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(25px, 0, 0);
|
|
transform: translate3d(25px, 0, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(-10px, 0, 0);
|
|
transform: translate3d(-10px, 0, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(5px, 0, 0);
|
|
transform: translate3d(5px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceInLeft {
|
|
-webkit-animation-name: bounceInLeft;
|
|
animation-name: bounceInLeft;
|
|
}
|
|
|
|
@-webkit-keyframes bounceInRight {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(3000px, 0, 0);
|
|
transform: translate3d(3000px, 0, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(-25px, 0, 0);
|
|
transform: translate3d(-25px, 0, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(10px, 0, 0);
|
|
transform: translate3d(10px, 0, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(-5px, 0, 0);
|
|
transform: translate3d(-5px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceInRight {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(3000px, 0, 0);
|
|
transform: translate3d(3000px, 0, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(-25px, 0, 0);
|
|
transform: translate3d(-25px, 0, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(10px, 0, 0);
|
|
transform: translate3d(10px, 0, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(-5px, 0, 0);
|
|
transform: translate3d(-5px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceInRight {
|
|
-webkit-animation-name: bounceInRight;
|
|
animation-name: bounceInRight;
|
|
}
|
|
|
|
@-webkit-keyframes bounceInUp {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 3000px, 0);
|
|
transform: translate3d(0, 3000px, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, -20px, 0);
|
|
transform: translate3d(0, -20px, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(0, 10px, 0);
|
|
transform: translate3d(0, 10px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, -5px, 0);
|
|
transform: translate3d(0, -5px, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceInUp {
|
|
from,
|
|
60%,
|
|
75%,
|
|
90%,
|
|
to {
|
|
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
}
|
|
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 3000px, 0);
|
|
transform: translate3d(0, 3000px, 0);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, -20px, 0);
|
|
transform: translate3d(0, -20px, 0);
|
|
}
|
|
|
|
75% {
|
|
-webkit-transform: translate3d(0, 10px, 0);
|
|
transform: translate3d(0, 10px, 0);
|
|
}
|
|
|
|
90% {
|
|
-webkit-transform: translate3d(0, -5px, 0);
|
|
transform: translate3d(0, -5px, 0);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceInUp {
|
|
-webkit-animation-name: bounceInUp;
|
|
animation-name: bounceInUp;
|
|
}
|
|
|
|
@-webkit-keyframes bounceOut {
|
|
20% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9);
|
|
transform: scale3d(0.9, 0.9, 0.9);
|
|
}
|
|
|
|
50%,
|
|
55% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1);
|
|
transform: scale3d(1.1, 1.1, 1.1);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceOut {
|
|
20% {
|
|
-webkit-transform: scale3d(0.9, 0.9, 0.9);
|
|
transform: scale3d(0.9, 0.9, 0.9);
|
|
}
|
|
|
|
50%,
|
|
55% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(1.1, 1.1, 1.1);
|
|
transform: scale3d(1.1, 1.1, 1.1);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
}
|
|
|
|
.bounceOut {
|
|
-webkit-animation-duration: 0.75s;
|
|
animation-duration: 0.75s;
|
|
-webkit-animation-name: bounceOut;
|
|
animation-name: bounceOut;
|
|
}
|
|
|
|
@-webkit-keyframes bounceOutDown {
|
|
20% {
|
|
-webkit-transform: translate3d(0, 10px, 0);
|
|
transform: translate3d(0, 10px, 0);
|
|
}
|
|
|
|
40%,
|
|
45% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, -20px, 0);
|
|
transform: translate3d(0, -20px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceOutDown {
|
|
20% {
|
|
-webkit-transform: translate3d(0, 10px, 0);
|
|
transform: translate3d(0, 10px, 0);
|
|
}
|
|
|
|
40%,
|
|
45% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, -20px, 0);
|
|
transform: translate3d(0, -20px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
}
|
|
|
|
.bounceOutDown {
|
|
-webkit-animation-name: bounceOutDown;
|
|
animation-name: bounceOutDown;
|
|
}
|
|
|
|
@-webkit-keyframes bounceOutLeft {
|
|
20% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(20px, 0, 0);
|
|
transform: translate3d(20px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceOutLeft {
|
|
20% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(20px, 0, 0);
|
|
transform: translate3d(20px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceOutLeft {
|
|
-webkit-animation-name: bounceOutLeft;
|
|
animation-name: bounceOutLeft;
|
|
}
|
|
|
|
@-webkit-keyframes bounceOutRight {
|
|
20% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(-20px, 0, 0);
|
|
transform: translate3d(-20px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceOutRight {
|
|
20% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(-20px, 0, 0);
|
|
transform: translate3d(-20px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
.bounceOutRight {
|
|
-webkit-animation-name: bounceOutRight;
|
|
animation-name: bounceOutRight;
|
|
}
|
|
|
|
@-webkit-keyframes bounceOutUp {
|
|
20% {
|
|
-webkit-transform: translate3d(0, -10px, 0);
|
|
transform: translate3d(0, -10px, 0);
|
|
}
|
|
|
|
40%,
|
|
45% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 20px, 0);
|
|
transform: translate3d(0, 20px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes bounceOutUp {
|
|
20% {
|
|
-webkit-transform: translate3d(0, -10px, 0);
|
|
transform: translate3d(0, -10px, 0);
|
|
}
|
|
|
|
40%,
|
|
45% {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 20px, 0);
|
|
transform: translate3d(0, 20px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
}
|
|
|
|
.bounceOutUp {
|
|
-webkit-animation-name: bounceOutUp;
|
|
animation-name: bounceOutUp;
|
|
}
|
|
|
|
@-webkit-keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.fadeIn {
|
|
-webkit-animation-name: fadeIn;
|
|
animation-name: fadeIn;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInDown {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInDown {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInDown {
|
|
-webkit-animation-name: fadeInDown;
|
|
animation-name: fadeInDown;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInDownBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInDownBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInDownBig {
|
|
-webkit-animation-name: fadeInDownBig;
|
|
animation-name: fadeInDownBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInLeft {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInLeft {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInLeft {
|
|
-webkit-animation-name: fadeInLeft;
|
|
animation-name: fadeInLeft;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInLeftBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInLeftBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInLeftBig {
|
|
-webkit-animation-name: fadeInLeftBig;
|
|
animation-name: fadeInLeftBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInRight {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInRight {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInRight {
|
|
-webkit-animation-name: fadeInRight;
|
|
animation-name: fadeInRight;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInRightBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInRightBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInRightBig {
|
|
-webkit-animation-name: fadeInRightBig;
|
|
animation-name: fadeInRightBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInUp {
|
|
-webkit-animation-name: fadeInUp;
|
|
animation-name: fadeInUp;
|
|
}
|
|
|
|
@-webkit-keyframes fadeInUpBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInUpBig {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeInUpBig {
|
|
-webkit-animation-name: fadeInUpBig;
|
|
animation-name: fadeInUpBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.fadeOut {
|
|
-webkit-animation-name: fadeOut;
|
|
animation-name: fadeOut;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutDown {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutDown {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutDown {
|
|
-webkit-animation-name: fadeOutDown;
|
|
animation-name: fadeOutDown;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutDownBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutDownBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, 2000px, 0);
|
|
transform: translate3d(0, 2000px, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutDownBig {
|
|
-webkit-animation-name: fadeOutDownBig;
|
|
animation-name: fadeOutDownBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutLeft {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutLeft {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutLeft {
|
|
-webkit-animation-name: fadeOutLeft;
|
|
animation-name: fadeOutLeft;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutLeftBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutLeftBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-2000px, 0, 0);
|
|
transform: translate3d(-2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutLeftBig {
|
|
-webkit-animation-name: fadeOutLeftBig;
|
|
animation-name: fadeOutLeftBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutRight {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutRight {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutRight {
|
|
-webkit-animation-name: fadeOutRight;
|
|
animation-name: fadeOutRight;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutRightBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutRightBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(2000px, 0, 0);
|
|
transform: translate3d(2000px, 0, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutRightBig {
|
|
-webkit-animation-name: fadeOutRightBig;
|
|
animation-name: fadeOutRightBig;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutUp {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutUp {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutUp {
|
|
-webkit-animation-name: fadeOutUp;
|
|
animation-name: fadeOutUp;
|
|
}
|
|
|
|
@-webkit-keyframes fadeOutUpBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeOutUpBig {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(0, -2000px, 0);
|
|
transform: translate3d(0, -2000px, 0);
|
|
}
|
|
}
|
|
|
|
.fadeOutUpBig {
|
|
-webkit-animation-name: fadeOutUpBig;
|
|
animation-name: fadeOutUpBig;
|
|
}
|
|
|
|
@-webkit-keyframes flip {
|
|
from {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, -360deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);
|
|
-webkit-animation-timing-function: ease-out;
|
|
animation-timing-function: ease-out;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -190deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -190deg);
|
|
-webkit-animation-timing-function: ease-out;
|
|
animation-timing-function: ease-out;
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -170deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -170deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
}
|
|
|
|
@keyframes flip {
|
|
from {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, -360deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);
|
|
-webkit-animation-timing-function: ease-out;
|
|
animation-timing-function: ease-out;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -190deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -190deg);
|
|
-webkit-animation-timing-function: ease-out;
|
|
animation-timing-function: ease-out;
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -170deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
|
|
rotate3d(0, 1, 0, -170deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
|
|
rotate3d(0, 1, 0, 0deg);
|
|
transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
}
|
|
|
|
.animated.flip {
|
|
-webkit-backface-visibility: visible;
|
|
backface-visibility: visible;
|
|
-webkit-animation-name: flip;
|
|
animation-name: flip;
|
|
}
|
|
|
|
@-webkit-keyframes flipInX {
|
|
from {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
opacity: 0;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
}
|
|
|
|
@keyframes flipInX {
|
|
from {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
opacity: 0;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
}
|
|
|
|
.flipInX {
|
|
-webkit-backface-visibility: visible !important;
|
|
backface-visibility: visible !important;
|
|
-webkit-animation-name: flipInX;
|
|
animation-name: flipInX;
|
|
}
|
|
|
|
@-webkit-keyframes flipInY {
|
|
from {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
opacity: 0;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
}
|
|
|
|
@keyframes flipInY {
|
|
from {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
opacity: 0;
|
|
}
|
|
|
|
40% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
}
|
|
|
|
.flipInY {
|
|
-webkit-backface-visibility: visible !important;
|
|
backface-visibility: visible !important;
|
|
-webkit-animation-name: flipInY;
|
|
animation-name: flipInY;
|
|
}
|
|
|
|
@-webkit-keyframes flipOutX {
|
|
from {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes flipOutX {
|
|
from {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.flipOutX {
|
|
-webkit-animation-duration: 0.75s;
|
|
animation-duration: 0.75s;
|
|
-webkit-animation-name: flipOutX;
|
|
animation-name: flipOutX;
|
|
-webkit-backface-visibility: visible !important;
|
|
backface-visibility: visible !important;
|
|
}
|
|
|
|
@-webkit-keyframes flipOutY {
|
|
from {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes flipOutY {
|
|
from {
|
|
-webkit-transform: perspective(400px);
|
|
transform: perspective(400px);
|
|
}
|
|
|
|
30% {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.flipOutY {
|
|
-webkit-animation-duration: 0.75s;
|
|
animation-duration: 0.75s;
|
|
-webkit-backface-visibility: visible !important;
|
|
backface-visibility: visible !important;
|
|
-webkit-animation-name: flipOutY;
|
|
animation-name: flipOutY;
|
|
}
|
|
|
|
@-webkit-keyframes lightSpeedIn {
|
|
from {
|
|
-webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
|
|
transform: translate3d(100%, 0, 0) skewX(-30deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: skewX(20deg);
|
|
transform: skewX(20deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: skewX(-5deg);
|
|
transform: skewX(-5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes lightSpeedIn {
|
|
from {
|
|
-webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
|
|
transform: translate3d(100%, 0, 0) skewX(-30deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
60% {
|
|
-webkit-transform: skewX(20deg);
|
|
transform: skewX(20deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
80% {
|
|
-webkit-transform: skewX(-5deg);
|
|
transform: skewX(-5deg);
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.lightSpeedIn {
|
|
-webkit-animation-name: lightSpeedIn;
|
|
animation-name: lightSpeedIn;
|
|
-webkit-animation-timing-function: ease-out;
|
|
animation-timing-function: ease-out;
|
|
}
|
|
|
|
@-webkit-keyframes lightSpeedOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
|
|
transform: translate3d(100%, 0, 0) skewX(30deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes lightSpeedOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
|
|
transform: translate3d(100%, 0, 0) skewX(30deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.lightSpeedOut {
|
|
-webkit-animation-name: lightSpeedOut;
|
|
animation-name: lightSpeedOut;
|
|
-webkit-animation-timing-function: ease-in;
|
|
animation-timing-function: ease-in;
|
|
}
|
|
|
|
@-webkit-keyframes rotateIn {
|
|
from {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: rotate3d(0, 0, 1, -200deg);
|
|
transform: rotate3d(0, 0, 1, -200deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateIn {
|
|
from {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: rotate3d(0, 0, 1, -200deg);
|
|
transform: rotate3d(0, 0, 1, -200deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.rotateIn {
|
|
-webkit-animation-name: rotateIn;
|
|
animation-name: rotateIn;
|
|
}
|
|
|
|
@-webkit-keyframes rotateInDownLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateInDownLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.rotateInDownLeft {
|
|
-webkit-animation-name: rotateInDownLeft;
|
|
animation-name: rotateInDownLeft;
|
|
}
|
|
|
|
@-webkit-keyframes rotateInDownRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateInDownRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.rotateInDownRight {
|
|
-webkit-animation-name: rotateInDownRight;
|
|
animation-name: rotateInDownRight;
|
|
}
|
|
|
|
@-webkit-keyframes rotateInUpLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateInUpLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.rotateInUpLeft {
|
|
-webkit-animation-name: rotateInUpLeft;
|
|
animation-name: rotateInUpLeft;
|
|
}
|
|
|
|
@-webkit-keyframes rotateInUpRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -90deg);
|
|
transform: rotate3d(0, 0, 1, -90deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateInUpRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -90deg);
|
|
transform: rotate3d(0, 0, 1, -90deg);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.rotateInUpRight {
|
|
-webkit-animation-name: rotateInUpRight;
|
|
animation-name: rotateInUpRight;
|
|
}
|
|
|
|
@-webkit-keyframes rotateOut {
|
|
from {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: rotate3d(0, 0, 1, 200deg);
|
|
transform: rotate3d(0, 0, 1, 200deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateOut {
|
|
from {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: center;
|
|
transform-origin: center;
|
|
-webkit-transform: rotate3d(0, 0, 1, 200deg);
|
|
transform: rotate3d(0, 0, 1, 200deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.rotateOut {
|
|
-webkit-animation-name: rotateOut;
|
|
animation-name: rotateOut;
|
|
}
|
|
|
|
@-webkit-keyframes rotateOutDownLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateOutDownLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 45deg);
|
|
transform: rotate3d(0, 0, 1, 45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.rotateOutDownLeft {
|
|
-webkit-animation-name: rotateOutDownLeft;
|
|
animation-name: rotateOutDownLeft;
|
|
}
|
|
|
|
@-webkit-keyframes rotateOutDownRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateOutDownRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.rotateOutDownRight {
|
|
-webkit-animation-name: rotateOutDownRight;
|
|
animation-name: rotateOutDownRight;
|
|
}
|
|
|
|
@-webkit-keyframes rotateOutUpLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateOutUpLeft {
|
|
from {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: left bottom;
|
|
transform-origin: left bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, -45deg);
|
|
transform: rotate3d(0, 0, 1, -45deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.rotateOutUpLeft {
|
|
-webkit-animation-name: rotateOutUpLeft;
|
|
animation-name: rotateOutUpLeft;
|
|
}
|
|
|
|
@-webkit-keyframes rotateOutUpRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 90deg);
|
|
transform: rotate3d(0, 0, 1, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes rotateOutUpRight {
|
|
from {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform-origin: right bottom;
|
|
transform-origin: right bottom;
|
|
-webkit-transform: rotate3d(0, 0, 1, 90deg);
|
|
transform: rotate3d(0, 0, 1, 90deg);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.rotateOutUpRight {
|
|
-webkit-animation-name: rotateOutUpRight;
|
|
animation-name: rotateOutUpRight;
|
|
}
|
|
|
|
@-webkit-keyframes hinge {
|
|
0% {
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
}
|
|
|
|
20%,
|
|
60% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 80deg);
|
|
transform: rotate3d(0, 0, 1, 80deg);
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
}
|
|
|
|
40%,
|
|
80% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 60deg);
|
|
transform: rotate3d(0, 0, 1, 60deg);
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 700px, 0);
|
|
transform: translate3d(0, 700px, 0);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes hinge {
|
|
0% {
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
}
|
|
|
|
20%,
|
|
60% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 80deg);
|
|
transform: rotate3d(0, 0, 1, 80deg);
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
}
|
|
|
|
40%,
|
|
80% {
|
|
-webkit-transform: rotate3d(0, 0, 1, 60deg);
|
|
transform: rotate3d(0, 0, 1, 60deg);
|
|
-webkit-transform-origin: top left;
|
|
transform-origin: top left;
|
|
-webkit-animation-timing-function: ease-in-out;
|
|
animation-timing-function: ease-in-out;
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 700px, 0);
|
|
transform: translate3d(0, 700px, 0);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.hinge {
|
|
-webkit-animation-duration: 2s;
|
|
animation-duration: 2s;
|
|
-webkit-animation-name: hinge;
|
|
animation-name: hinge;
|
|
}
|
|
|
|
@-webkit-keyframes jackInTheBox {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) rotate(30deg);
|
|
transform: scale(0.1) rotate(30deg);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: rotate(-10deg);
|
|
transform: rotate(-10deg);
|
|
}
|
|
|
|
70% {
|
|
-webkit-transform: rotate(3deg);
|
|
transform: rotate(3deg);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes jackInTheBox {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) rotate(30deg);
|
|
transform: scale(0.1) rotate(30deg);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
}
|
|
|
|
50% {
|
|
-webkit-transform: rotate(-10deg);
|
|
transform: rotate(-10deg);
|
|
}
|
|
|
|
70% {
|
|
-webkit-transform: rotate(3deg);
|
|
transform: rotate(3deg);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: scale(1);
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
.jackInTheBox {
|
|
-webkit-animation-name: jackInTheBox;
|
|
animation-name: jackInTheBox;
|
|
}
|
|
|
|
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
|
|
|
@-webkit-keyframes rollIn {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
|
transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes rollIn {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
|
transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.rollIn {
|
|
-webkit-animation-name: rollIn;
|
|
animation-name: rollIn;
|
|
}
|
|
|
|
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
|
|
|
@-webkit-keyframes rollOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
|
|
transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
|
|
}
|
|
}
|
|
|
|
@keyframes rollOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
|
|
transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
|
|
}
|
|
}
|
|
|
|
.rollOut {
|
|
-webkit-animation-name: rollOut;
|
|
animation-name: rollOut;
|
|
}
|
|
|
|
@-webkit-keyframes zoomIn {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
50% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomIn {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
50% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.zoomIn {
|
|
-webkit-animation-name: zoomIn;
|
|
animation-name: zoomIn;
|
|
}
|
|
|
|
@-webkit-keyframes zoomInDown {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInDown {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomInDown {
|
|
-webkit-animation-name: zoomInDown;
|
|
animation-name: zoomInDown;
|
|
}
|
|
|
|
@-webkit-keyframes zoomInLeft {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInLeft {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomInLeft {
|
|
-webkit-animation-name: zoomInLeft;
|
|
animation-name: zoomInLeft;
|
|
}
|
|
|
|
@-webkit-keyframes zoomInRight {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInRight {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomInRight {
|
|
-webkit-animation-name: zoomInRight;
|
|
animation-name: zoomInRight;
|
|
}
|
|
|
|
@-webkit-keyframes zoomInUp {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomInUp {
|
|
from {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
60% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomInUp {
|
|
-webkit-animation-name: zoomInUp;
|
|
animation-name: zoomInUp;
|
|
}
|
|
|
|
@-webkit-keyframes zoomOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
50% {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomOut {
|
|
from {
|
|
opacity: 1;
|
|
}
|
|
|
|
50% {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.3, 0.3, 0.3);
|
|
transform: scale3d(0.3, 0.3, 0.3);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.zoomOut {
|
|
-webkit-animation-name: zoomOut;
|
|
animation-name: zoomOut;
|
|
}
|
|
|
|
@-webkit-keyframes zoomOutDown {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomOutDown {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomOutDown {
|
|
-webkit-animation-name: zoomOutDown;
|
|
animation-name: zoomOutDown;
|
|
}
|
|
|
|
@-webkit-keyframes zoomOutLeft {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
|
|
transform: scale(0.1) translate3d(-2000px, 0, 0);
|
|
-webkit-transform-origin: left center;
|
|
transform-origin: left center;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomOutLeft {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
|
|
transform: scale(0.1) translate3d(-2000px, 0, 0);
|
|
-webkit-transform-origin: left center;
|
|
transform-origin: left center;
|
|
}
|
|
}
|
|
|
|
.zoomOutLeft {
|
|
-webkit-animation-name: zoomOutLeft;
|
|
animation-name: zoomOutLeft;
|
|
}
|
|
|
|
@-webkit-keyframes zoomOutRight {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
|
|
transform: scale(0.1) translate3d(2000px, 0, 0);
|
|
-webkit-transform-origin: right center;
|
|
transform-origin: right center;
|
|
}
|
|
}
|
|
|
|
@keyframes zoomOutRight {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
|
|
transform: scale(0.1) translate3d(2000px, 0, 0);
|
|
-webkit-transform-origin: right center;
|
|
transform-origin: right center;
|
|
}
|
|
}
|
|
|
|
.zoomOutRight {
|
|
-webkit-animation-name: zoomOutRight;
|
|
animation-name: zoomOutRight;
|
|
}
|
|
|
|
@-webkit-keyframes zoomOutUp {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
@keyframes zoomOutUp {
|
|
40% {
|
|
opacity: 1;
|
|
-webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
|
|
-webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
}
|
|
|
|
to {
|
|
opacity: 0;
|
|
-webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
|
|
transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
|
|
-webkit-transform-origin: center bottom;
|
|
transform-origin: center bottom;
|
|
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
|
|
}
|
|
}
|
|
|
|
.zoomOutUp {
|
|
-webkit-animation-name: zoomOutUp;
|
|
animation-name: zoomOutUp;
|
|
}
|
|
|
|
@-webkit-keyframes slideInDown {
|
|
from {
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideInDown {
|
|
from {
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideInDown {
|
|
-webkit-animation-name: slideInDown;
|
|
animation-name: slideInDown;
|
|
}
|
|
|
|
@-webkit-keyframes slideInLeft {
|
|
from {
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideInLeft {
|
|
from {
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideInLeft {
|
|
-webkit-animation-name: slideInLeft;
|
|
animation-name: slideInLeft;
|
|
}
|
|
|
|
@-webkit-keyframes slideInRight {
|
|
from {
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideInRight {
|
|
from {
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideInRight {
|
|
-webkit-animation-name: slideInRight;
|
|
animation-name: slideInRight;
|
|
}
|
|
|
|
@-webkit-keyframes slideInUp {
|
|
from {
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideInUp {
|
|
from {
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
visibility: visible;
|
|
}
|
|
|
|
to {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideInUp {
|
|
-webkit-animation-name: slideInUp;
|
|
animation-name: slideInUp;
|
|
}
|
|
|
|
@-webkit-keyframes slideOutDown {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideOutDown {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(0, 100%, 0);
|
|
transform: translate3d(0, 100%, 0);
|
|
}
|
|
}
|
|
|
|
.slideOutDown {
|
|
-webkit-animation-name: slideOutDown;
|
|
animation-name: slideOutDown;
|
|
}
|
|
|
|
@-webkit-keyframes slideOutLeft {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideOutLeft {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(-100%, 0, 0);
|
|
transform: translate3d(-100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideOutLeft {
|
|
-webkit-animation-name: slideOutLeft;
|
|
animation-name: slideOutLeft;
|
|
}
|
|
|
|
@-webkit-keyframes slideOutRight {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideOutRight {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(100%, 0, 0);
|
|
transform: translate3d(100%, 0, 0);
|
|
}
|
|
}
|
|
|
|
.slideOutRight {
|
|
-webkit-animation-name: slideOutRight;
|
|
animation-name: slideOutRight;
|
|
}
|
|
|
|
@-webkit-keyframes slideOutUp {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
}
|
|
|
|
@keyframes slideOutUp {
|
|
from {
|
|
-webkit-transform: translate3d(0, 0, 0);
|
|
transform: translate3d(0, 0, 0);
|
|
}
|
|
|
|
to {
|
|
visibility: hidden;
|
|
-webkit-transform: translate3d(0, -100%, 0);
|
|
transform: translate3d(0, -100%, 0);
|
|
}
|
|
}
|
|
|
|
.slideOutUp {
|
|
-webkit-animation-name: slideOutUp;
|
|
animation-name: slideOutUp;
|
|
}
|
|
|
|
.animated {
|
|
-webkit-animation-duration: 1s;
|
|
animation-duration: 1s;
|
|
-webkit-animation-fill-mode: both;
|
|
animation-fill-mode: both;
|
|
}
|
|
|
|
.animated.infinite {
|
|
-webkit-animation-iteration-count: infinite;
|
|
animation-iteration-count: infinite;
|
|
}
|
|
|
|
.animated.delay-1s {
|
|
-webkit-animation-delay: 1s;
|
|
animation-delay: 1s;
|
|
}
|
|
|
|
.animated.delay-2s {
|
|
-webkit-animation-delay: 2s;
|
|
animation-delay: 2s;
|
|
}
|
|
|
|
.animated.delay-3s {
|
|
-webkit-animation-delay: 3s;
|
|
animation-delay: 3s;
|
|
}
|
|
|
|
.animated.delay-4s {
|
|
-webkit-animation-delay: 4s;
|
|
animation-delay: 4s;
|
|
}
|
|
|
|
.animated.delay-5s {
|
|
-webkit-animation-delay: 5s;
|
|
animation-delay: 5s;
|
|
}
|
|
|
|
.animated.fast {
|
|
-webkit-animation-duration: 800ms;
|
|
animation-duration: 800ms;
|
|
}
|
|
|
|
.animated.faster {
|
|
-webkit-animation-duration: 500ms;
|
|
animation-duration: 500ms;
|
|
}
|
|
|
|
.animated.slow {
|
|
-webkit-animation-duration: 2s;
|
|
animation-duration: 2s;
|
|
}
|
|
|
|
.animated.slower {
|
|
-webkit-animation-duration: 3s;
|
|
animation-duration: 3s;
|
|
}
|
|
|
|
@media (prefers-reduced-motion) {
|
|
.animated {
|
|
-webkit-animation: unset !important;
|
|
animation: unset !important;
|
|
-webkit-transition: none !important;
|
|
transition: none !important;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\base-theme.scss
|
|
|
|
// Import all the theming functionality.
|
|
// We can use relative imports for imports from the cdk because we bundle everything
|
|
// up into a single flat scss file for material.
|
|
// We want overlays to always appear over user content, so set a baseline
|
|
// very high z-index for the overlay container, which is where we create the new
|
|
// stacking context for all overlays.
|
|
$cdk-z-index-overlay-container: 1000 !default;
|
|
$cdk-z-index-overlay: 1000 !default;
|
|
$cdk-z-index-overlay-backdrop: 1000 !default;
|
|
|
|
// Background color for all of the backdrops
|
|
$cdk-overlay-dark-backdrop-background: rgba(0, 0, 0, 0.32) !default;
|
|
|
|
// Default backdrop animation is based on the Material Design swift-ease-out.
|
|
$backdrop-animation-duration: 400ms !default;
|
|
$backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
|
|
|
|
|
|
@mixin cdk-overlay() {
|
|
.cdk-overlay-container, .cdk-global-overlay-wrapper {
|
|
// Disable events from being captured on the overlay container.
|
|
pointer-events: none;
|
|
|
|
// The container should be the size of the viewport.
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
// The overlay-container is an invisible element which contains all individual overlays.
|
|
.cdk-overlay-container {
|
|
position: fixed;
|
|
z-index: $cdk-z-index-overlay-container;
|
|
|
|
&:empty {
|
|
// Hide the element when it doesn't have any child nodes. This doesn't
|
|
// include overlays that have been detached, rather than disposed.
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
// We use an extra wrapper element in order to use make the overlay itself a flex item.
|
|
// This makes centering the overlay easy without running into the subpixel rendering
|
|
// problems tied to using `transform` and without interfering with the other position
|
|
// strategies.
|
|
.cdk-global-overlay-wrapper {
|
|
display: flex;
|
|
position: absolute;
|
|
z-index: $cdk-z-index-overlay;
|
|
}
|
|
|
|
// A single overlay pane.
|
|
.cdk-overlay-pane {
|
|
// Note: it's important for this one to start off `absolute`,
|
|
// in order for us to be able to measure it correctly.
|
|
position: absolute;
|
|
pointer-events: auto;
|
|
box-sizing: border-box;
|
|
z-index: $cdk-z-index-overlay;
|
|
|
|
// For connected-position overlays, we set `display: flex` in
|
|
// order to force `max-width` and `max-height` to take effect.
|
|
display: flex;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
|
|
.cdk-overlay-backdrop {
|
|
// TODO(jelbourn): reuse sidenav fullscreen mixin.
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
|
|
z-index: $cdk-z-index-overlay-backdrop;
|
|
pointer-events: auto;
|
|
-webkit-tap-highlight-color: transparent;
|
|
transition: opacity $backdrop-animation-duration $backdrop-animation-timing-function;
|
|
opacity: 0;
|
|
|
|
&.cdk-overlay-backdrop-showing {
|
|
opacity: 1;
|
|
|
|
// In high contrast mode the rgba background will become solid so we need to fall back
|
|
// to making it opaque using `opacity`. Note that we can't use the `cdk-high-contrast`
|
|
// mixin, because we can't normalize the import path to the _a11y.scss both for the
|
|
// source and when this file is distributed. See #10908.
|
|
@media screen and (-ms-high-contrast: active) {
|
|
opacity: 0.6;
|
|
}
|
|
}
|
|
}
|
|
|
|
.cdk-overlay-dark-backdrop {
|
|
background: $cdk-overlay-dark-backdrop-background;
|
|
}
|
|
|
|
.cdk-overlay-transparent-backdrop {
|
|
// Note: as of Firefox 57, having the backdrop be `background: none` will prevent it from
|
|
// capturing the user's mouse scroll events. Since we also can't use something like
|
|
// `rgba(0, 0, 0, 0)`, we work around the inconsistency by not setting the background at
|
|
// all and using `opacity` to make the element transparent.
|
|
&, &.cdk-overlay-backdrop-showing {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
// Overlay parent element used with the connected position strategy. Used to constrain the
|
|
// overlay element's size to fit within the viewport.
|
|
.cdk-overlay-connected-position-bounding-box {
|
|
position: absolute;
|
|
z-index: $cdk-z-index-overlay;
|
|
|
|
// We use `display: flex` on this element exclusively for centering connected overlays.
|
|
// When *not* centering, a top/left/bottom/right will be set which overrides the normal
|
|
// flex layout.
|
|
display: flex;
|
|
|
|
// We use the `column` direction here to avoid some flexbox issues in Edge
|
|
// when using the "grow after open" options.
|
|
flex-direction: column;
|
|
|
|
// Add some dimensions so the element has an `innerText` which some people depend on in tests.
|
|
min-width: 1px;
|
|
min-height: 1px;
|
|
}
|
|
|
|
// Used when disabling global scrolling.
|
|
.cdk-global-scrollblock {
|
|
position: fixed;
|
|
|
|
// Necessary for the content not to lose its width. Note that we're using 100%, instead of
|
|
// 100vw, because 100vw includes the width plus the scrollbar, whereas 100% is the width
|
|
// that the element had before we made it `fixed`.
|
|
width: 100%;
|
|
|
|
// Note: this will always add a scrollbar to whatever element it is on, which can
|
|
// potentially result in double scrollbars. It shouldn't be an issue, because we won't
|
|
// block scrolling on a page that doesn't have a scrollbar in the first place.
|
|
overflow-y: scroll;
|
|
}
|
|
}
|
|
|
|
@mixin cdk-a11y {
|
|
.cdk-visually-hidden {
|
|
border: 0;
|
|
clip: rect(0 0 0 0);
|
|
height: 1px;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
padding: 0;
|
|
position: absolute;
|
|
width: 1px;
|
|
|
|
// Avoid browsers rendering the focus ring in some cases.
|
|
outline: 0;
|
|
|
|
// Avoid some cases where the browser will still render the native controls (see #9049).
|
|
-webkit-appearance: none;
|
|
-moz-appearance: none;
|
|
}
|
|
}
|
|
|
|
// Applies styles for users in high contrast mode. Note that this only applies
|
|
// to Microsoft browsers. Chrome can be included by checking for the `html[hc]`
|
|
// attribute, however Chrome handles high contrast differently.
|
|
//
|
|
// @param target Which kind of high contrast setting to target. Defaults to `active`, can be
|
|
// `white-on-black` or `black-on-white`.
|
|
@mixin cdk-high-contrast($target: active) {
|
|
@media (-ms-high-contrast: $target) {
|
|
@content;
|
|
}
|
|
}
|
|
|
|
// Core styles that enable monitoring autofill state of text fields.
|
|
@mixin cdk-text-field {
|
|
// Keyframes that apply no styles, but allow us to monitor when an text field becomes autofilled
|
|
// by watching for the animation events that are fired when they start. Note: the /*!*/ comment is
|
|
// needed to prevent LibSass from stripping the keyframes out.
|
|
// Based on: https://medium.com/@brunn/detecting-autofilled-fields-in-javascript-aed598d25da7
|
|
@keyframes cdk-text-field-autofill-start {/*!*/}
|
|
@keyframes cdk-text-field-autofill-end {/*!*/}
|
|
|
|
.cdk-text-field-autofill-monitored:-webkit-autofill {
|
|
animation-name: cdk-text-field-autofill-start;
|
|
}
|
|
|
|
.cdk-text-field-autofill-monitored:not(:-webkit-autofill) {
|
|
animation-name: cdk-text-field-autofill-end;
|
|
}
|
|
|
|
// Remove the resize handle on autosizing textareas, because whatever height
|
|
// the user resized to will be overwritten once they start typing again.
|
|
textarea.cdk-textarea-autosize {
|
|
resize: none;
|
|
}
|
|
|
|
// This class is temporarily applied to the textarea when it is being measured. It is immediately
|
|
// removed when measuring is complete. We use `!important` rules here to make sure user-specified
|
|
// rules do not interfere with the measurement.
|
|
textarea.cdk-textarea-autosize-measuring {
|
|
height: auto !important;
|
|
overflow: hidden !important;
|
|
// Having 2px top and bottom padding seems to fix a bug where Chrome gets an incorrect
|
|
// measurement. We just have to account for it later and subtract it off the final result.
|
|
padding: 2px 0 !important;
|
|
box-sizing: content-box !important;
|
|
}
|
|
}
|
|
|
|
// Used to generate UIDs for keyframes used to change the text field autofill styles.
|
|
$cdk-text-field-autofill-color-frame-count: 0;
|
|
|
|
// Mixin used to apply custom background and foreground colors to an autofilled text field.
|
|
// Based on: https://stackoverflow.com/questions/2781549/
|
|
// removing-input-background-colour-for-chrome-autocomplete#answer-37432260
|
|
@mixin cdk-text-field-autofill-color($background, $foreground:'') {
|
|
@keyframes cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count} {
|
|
to {
|
|
background: $background;
|
|
@if $foreground != '' { color: $foreground; }
|
|
}
|
|
}
|
|
|
|
&:-webkit-autofill {
|
|
animation-name: cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count};
|
|
animation-fill-mode: both;
|
|
}
|
|
|
|
&.cdk-text-field-autofill-monitored:-webkit-autofill {
|
|
animation-name: cdk-text-field-autofill-start,
|
|
cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count};
|
|
}
|
|
|
|
$cdk-text-field-autofill-color-frame-count:
|
|
$cdk-text-field-autofill-color-frame-count + 1 !global;
|
|
}
|
|
|
|
|
|
// Core styles that can be used to apply material design treatments to any element.
|
|
// Media queries
|
|
// TODO(josephperrott): Change $mat-xsmall and $mat-small usages to rely on BreakpointObserver,
|
|
$mat-xsmall: 'max-width: 599px';
|
|
$mat-small: 'max-width: 959px';
|
|
|
|
// TODO: Revisit all z-indices before beta
|
|
// z-index master list
|
|
|
|
$z-index-fab: 20 !default;
|
|
$z-index-drawer: 100 !default;
|
|
|
|
// Global constants
|
|
$pi: 3.14159265;
|
|
|
|
// Padding between input toggles and their labels
|
|
$mat-toggle-padding: 8px !default;
|
|
// Width and height of input toggles
|
|
$mat-toggle-size: 20px !default;
|
|
|
|
// Easing Curves
|
|
// TODO(jelbourn): all of these need to be revisited
|
|
|
|
// The default animation curves used by material design.
|
|
$mat-linear-out-slow-in-timing-function: cubic-bezier(0, 0, 0.2, 0.1) !default;
|
|
$mat-fast-out-slow-in-timing-function: cubic-bezier(0.4, 0, 0.2, 1) !default;
|
|
$mat-fast-out-linear-in-timing-function: cubic-bezier(0.4, 0, 1, 1) !default;
|
|
|
|
$ease-in-out-curve-function: cubic-bezier(0.35, 0, 0.25, 1) !default;
|
|
|
|
$swift-ease-out-duration: 400ms !default;
|
|
$swift-ease-out-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default;
|
|
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default;
|
|
|
|
$swift-ease-in-duration: 300ms !default;
|
|
$swift-ease-in-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2) !default;
|
|
$swift-ease-in: all $swift-ease-in-duration $swift-ease-in-timing-function !default;
|
|
|
|
$swift-ease-in-out-duration: 500ms !default;
|
|
$swift-ease-in-out-timing-function: $ease-in-out-curve-function !default;
|
|
$swift-ease-in-out: all $swift-ease-in-out-duration $swift-ease-in-out-timing-function !default;
|
|
|
|
$swift-linear-duration: 80ms !default;
|
|
$swift-linear-timing-function: linear !default;
|
|
$swift-linear: all $swift-linear-duration $swift-linear-timing-function !default;
|
|
|
|
|
|
|
|
// A collection of mixins and CSS classes that can be used to apply elevation to a material
|
|
// element.
|
|
// See: https://material.io/design/environment/elevation.html
|
|
// Examples:
|
|
//
|
|
//
|
|
// .mat-foo {
|
|
// @include $mat-elevation(2);
|
|
//
|
|
// &:active {
|
|
// @include $mat-elevation(8);
|
|
// }
|
|
// }
|
|
//
|
|
// <div id="external-card" class="mat-elevation-z2"><p>Some content</p></div>
|
|
//
|
|
// For an explanation of the design behind how elevation is implemented, see the design doc at
|
|
// https://goo.gl/Kq0k9Z.
|
|
|
|
// Colors for umbra, penumbra, and ambient shadows. As described in the design doc, each elevation
|
|
// level is created using a set of 3 shadow values, one for umbra (the shadow representing the
|
|
// space completely obscured by an object relative to its light source), one for penumbra (the
|
|
// space partially obscured by an object), and one for ambient (the space which contains the object
|
|
// itself). For a further explanation of these terms and their meanings, see
|
|
// https://en.wikipedia.org/wiki/Umbra,_penumbra_and_antumbra.
|
|
|
|
// Maps for the different shadow sets and their values within each z-space. These values were
|
|
// created by taking a few reference shadow sets created by Google's Designers and interpolating
|
|
// all of the values between them.
|
|
|
|
@function _get-umbra-map($color, $opacity) {
|
|
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.2), $color);
|
|
|
|
@return (
|
|
0: '0px 0px 0px 0px #{$shadow-color}',
|
|
1: '0px 2px 1px -1px #{$shadow-color}',
|
|
2: '0px 3px 1px -2px #{$shadow-color}',
|
|
3: '0px 3px 3px -2px #{$shadow-color}',
|
|
4: '0px 2px 4px -1px #{$shadow-color}',
|
|
5: '0px 3px 5px -1px #{$shadow-color}',
|
|
6: '0px 3px 5px -1px #{$shadow-color}',
|
|
7: '0px 4px 5px -2px #{$shadow-color}',
|
|
8: '0px 5px 5px -3px #{$shadow-color}',
|
|
9: '0px 5px 6px -3px #{$shadow-color}',
|
|
10: '0px 6px 6px -3px #{$shadow-color}',
|
|
11: '0px 6px 7px -4px #{$shadow-color}',
|
|
12: '0px 7px 8px -4px #{$shadow-color}',
|
|
13: '0px 7px 8px -4px #{$shadow-color}',
|
|
14: '0px 7px 9px -4px #{$shadow-color}',
|
|
15: '0px 8px 9px -5px #{$shadow-color}',
|
|
16: '0px 8px 10px -5px #{$shadow-color}',
|
|
17: '0px 8px 11px -5px #{$shadow-color}',
|
|
18: '0px 9px 11px -5px #{$shadow-color}',
|
|
19: '0px 9px 12px -6px #{$shadow-color}',
|
|
20: '0px 10px 13px -6px #{$shadow-color}',
|
|
21: '0px 10px 13px -6px #{$shadow-color}',
|
|
22: '0px 10px 14px -6px #{$shadow-color}',
|
|
23: '0px 11px 14px -7px #{$shadow-color}',
|
|
24: '0px 11px 15px -7px #{$shadow-color}'
|
|
);
|
|
}
|
|
|
|
@function _get-penumbra-map($color, $opacity) {
|
|
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.14), $color);
|
|
|
|
@return (
|
|
0: '0px 0px 0px 0px #{$shadow-color}',
|
|
1: '0px 1px 1px 0px #{$shadow-color}',
|
|
2: '0px 2px 2px 0px #{$shadow-color}',
|
|
3: '0px 3px 4px 0px #{$shadow-color}',
|
|
4: '0px 4px 5px 0px #{$shadow-color}',
|
|
5: '0px 5px 8px 0px #{$shadow-color}',
|
|
6: '0px 6px 10px 0px #{$shadow-color}',
|
|
7: '0px 7px 10px 1px #{$shadow-color}',
|
|
8: '0px 8px 10px 1px #{$shadow-color}',
|
|
9: '0px 9px 12px 1px #{$shadow-color}',
|
|
10: '0px 10px 14px 1px #{$shadow-color}',
|
|
11: '0px 11px 15px 1px #{$shadow-color}',
|
|
12: '0px 12px 17px 2px #{$shadow-color}',
|
|
13: '0px 13px 19px 2px #{$shadow-color}',
|
|
14: '0px 14px 21px 2px #{$shadow-color}',
|
|
15: '0px 15px 22px 2px #{$shadow-color}',
|
|
16: '0px 16px 24px 2px #{$shadow-color}',
|
|
17: '0px 17px 26px 2px #{$shadow-color}',
|
|
18: '0px 18px 28px 2px #{$shadow-color}',
|
|
19: '0px 19px 29px 2px #{$shadow-color}',
|
|
20: '0px 20px 31px 3px #{$shadow-color}',
|
|
21: '0px 21px 33px 3px #{$shadow-color}',
|
|
22: '0px 22px 35px 3px #{$shadow-color}',
|
|
23: '0px 23px 36px 3px #{$shadow-color}',
|
|
24: '0px 24px 38px 3px #{$shadow-color}'
|
|
);
|
|
}
|
|
|
|
@function _get-ambient-map($color, $opacity) {
|
|
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.12), $color);
|
|
|
|
@return (
|
|
0: '0px 0px 0px 0px #{$shadow-color}',
|
|
1: '0px 1px 3px 0px #{$shadow-color}',
|
|
2: '0px 1px 5px 0px #{$shadow-color}',
|
|
3: '0px 1px 8px 0px #{$shadow-color}',
|
|
4: '0px 1px 10px 0px #{$shadow-color}',
|
|
5: '0px 1px 14px 0px #{$shadow-color}',
|
|
6: '0px 1px 18px 0px #{$shadow-color}',
|
|
7: '0px 2px 16px 1px #{$shadow-color}',
|
|
8: '0px 3px 14px 2px #{$shadow-color}',
|
|
9: '0px 3px 16px 2px #{$shadow-color}',
|
|
10: '0px 4px 18px 3px #{$shadow-color}',
|
|
11: '0px 4px 20px 3px #{$shadow-color}',
|
|
12: '0px 5px 22px 4px #{$shadow-color}',
|
|
13: '0px 5px 24px 4px #{$shadow-color}',
|
|
14: '0px 5px 26px 4px #{$shadow-color}',
|
|
15: '0px 6px 28px 5px #{$shadow-color}',
|
|
16: '0px 6px 30px 5px #{$shadow-color}',
|
|
17: '0px 6px 32px 5px #{$shadow-color}',
|
|
18: '0px 7px 34px 6px #{$shadow-color}',
|
|
19: '0px 7px 36px 6px #{$shadow-color}',
|
|
20: '0px 8px 38px 7px #{$shadow-color}',
|
|
21: '0px 8px 40px 7px #{$shadow-color}',
|
|
22: '0px 8px 42px 7px #{$shadow-color}',
|
|
23: '0px 9px 44px 8px #{$shadow-color}',
|
|
24: '0px 9px 46px 8px #{$shadow-color}'
|
|
);
|
|
}
|
|
|
|
// The default duration value for elevation transitions.
|
|
$mat-elevation-transition-duration: 280ms !default;
|
|
|
|
// The default easing value for elevation transitions.
|
|
$mat-elevation-transition-timing-function: $mat-fast-out-slow-in-timing-function;
|
|
|
|
// The default color for elevation shadows.
|
|
$mat-elevation-color: black !default;
|
|
|
|
// The default opacity scaling value for elevation shadows.
|
|
$mat-elevation-opacity: 1 !default;
|
|
|
|
// Prefix for elevation-related selectors.
|
|
$_mat-elevation-prefix: 'mat-elevation-z';
|
|
|
|
// Applies the correct css rules to an element to give it the elevation specified by $zValue.
|
|
// The $zValue must be between 0 and 24.
|
|
@mixin mat-elevation($zValue, $color: $mat-elevation-color, $opacity: $mat-elevation-opacity) {
|
|
@if type-of($zValue) != number or not unitless($zValue) {
|
|
@error '$zValue must be a unitless number';
|
|
}
|
|
@if $zValue < 0 or $zValue > 24 {
|
|
@error '$zValue must be between 0 and 24';
|
|
}
|
|
|
|
box-shadow: #{map-get(_get-umbra-map($color, $opacity), $zValue)},
|
|
#{map-get(_get-penumbra-map($color, $opacity), $zValue)},
|
|
#{map-get(_get-ambient-map($color, $opacity), $zValue)};
|
|
}
|
|
|
|
@mixin _mat-theme-elevation($zValue, $theme, $opacity: $mat-elevation-opacity) {
|
|
$foreground: map-get($theme, foreground);
|
|
$elevation-color: map-get($foreground, elevation);
|
|
$elevation-color-or-default: if($elevation-color == null, $mat-elevation-color, $elevation-color);
|
|
|
|
@include mat-elevation($zValue, $elevation-color-or-default, $opacity);
|
|
}
|
|
|
|
// Applies the elevation to an element in a manner that allows
|
|
// consumers to override it via the Material elevation classes.
|
|
@mixin mat-overridable-elevation(
|
|
$zValue,
|
|
$color: $mat-elevation-color,
|
|
$opacity: $mat-elevation-opacity) {
|
|
&:not([class*='#{$_mat-elevation-prefix}']) {
|
|
@include mat-elevation($zValue, $color, $opacity);
|
|
}
|
|
}
|
|
|
|
@mixin _mat-theme-overridable-elevation($zValue, $theme, $opacity: $mat-elevation-opacity) {
|
|
$foreground: map-get($theme, foreground);
|
|
$elevation-color: map-get($foreground, elevation);
|
|
$elevation-color-or-default: if($elevation-color == null, $mat-elevation-color, $elevation-color);
|
|
|
|
@include mat-overridable-elevation($zValue, $elevation-color-or-default, $opacity);
|
|
}
|
|
|
|
// Returns a string that can be used as the value for a transition property for elevation.
|
|
// Calling this function directly is useful in situations where a component needs to transition
|
|
// more than one property.
|
|
//
|
|
// .foo {
|
|
// transition: mat-elevation-transition-property-value(), opacity 100ms ease;
|
|
// }
|
|
@function mat-elevation-transition-property-value(
|
|
$duration: $mat-elevation-transition-duration,
|
|
$easing: $mat-elevation-transition-timing-function) {
|
|
@return box-shadow #{$duration} #{$easing};
|
|
}
|
|
|
|
// Applies the correct css rules needed to have an element transition between elevations.
|
|
// This mixin should be applied to elements whose elevation values will change depending on their
|
|
// context (e.g. when active or disabled).
|
|
//
|
|
// NOTE(traviskaufman): Both this mixin and the above function use default parameters so they can
|
|
// be used in the same way by clients.
|
|
@mixin mat-elevation-transition(
|
|
$duration: $mat-elevation-transition-duration,
|
|
$easing: $mat-elevation-transition-timing-function) {
|
|
transition: mat-elevation-transition-property-value($duration, $easing);
|
|
}
|
|
|
|
// Color palettes from the Material Design spec.
|
|
// See https://material.io/design/color/
|
|
//
|
|
// Contrast colors are hard-coded because it is too difficult (probably impossible) to
|
|
// calculate them. These contrast colors are pulled from the public Material Design spec swatches.
|
|
// While the contrast colors in the spec are not prescriptive, we use them for convenience.
|
|
|
|
|
|
// @deprecated renamed to $dark-primary-text.
|
|
// @breaking-change 8.0.0
|
|
$black-87-opacity: rgba(black, 0.87);
|
|
// @deprecated renamed to $light-primary-text.
|
|
// @breaking-change 8.0.0
|
|
$white-87-opacity: rgba(white, 0.87);
|
|
// @deprecated use $dark-[secondary-text,disabled-text,dividers,focused] instead.
|
|
// @breaking-change 8.0.0
|
|
$black-12-opacity: rgba(black, 0.12);
|
|
// @deprecated use $light-[secondary-text,disabled-text,dividers,focused] instead.
|
|
// @breaking-change 8.0.0
|
|
$white-12-opacity: rgba(white, 0.12);
|
|
// @deprecated use $dark-[secondary-text,disabled-text,dividers,focused] instead.
|
|
// @breaking-change 8.0.0
|
|
$black-6-opacity: rgba(black, 0.06);
|
|
// @deprecated use $light-[secondary-text,disabled-text,dividers,focused] instead.
|
|
// @breaking-change 8.0.0
|
|
$white-6-opacity: rgba(white, 0.06);
|
|
|
|
$dark-primary-text: rgba(black, 0.87);
|
|
$dark-secondary-text: rgba(black, 0.54);
|
|
$dark-disabled-text: rgba(black, 0.38);
|
|
$dark-dividers: rgba(black, 0.12);
|
|
$dark-focused: rgba(black, 0.12);
|
|
$light-primary-text: white;
|
|
$light-secondary-text: rgba(white, 0.7);
|
|
$light-disabled-text: rgba(white, 0.5);
|
|
$light-dividers: rgba(white, 0.12);
|
|
$light-focused: rgba(white, 0.12);
|
|
|
|
$mat-red: (
|
|
50: #ffebee,
|
|
100: #ffcdd2,
|
|
200: #ef9a9a,
|
|
300: #e57373,
|
|
400: #ef5350,
|
|
500: #f44336,
|
|
600: #e53935,
|
|
700: #d32f2f,
|
|
800: #c62828,
|
|
900: #b71c1c,
|
|
A100: #ff8a80,
|
|
A200: #ff5252,
|
|
A400: #ff1744,
|
|
A700: #d50000,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-pink: (
|
|
50: #fce4ec,
|
|
100: #f8bbd0,
|
|
200: #f48fb1,
|
|
300: #f06292,
|
|
400: #ec407a,
|
|
500: #e91e63,
|
|
600: #d81b60,
|
|
700: #c2185b,
|
|
800: #ad1457,
|
|
900: #880e4f,
|
|
A100: #ff80ab,
|
|
A200: #ff4081,
|
|
A400: #f50057,
|
|
A700: #c51162,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-purple: (
|
|
50: #f3e5f5,
|
|
100: #e1bee7,
|
|
200: #ce93d8,
|
|
300: #ba68c8,
|
|
400: #ab47bc,
|
|
500: #9c27b0,
|
|
600: #8e24aa,
|
|
700: #7b1fa2,
|
|
800: #6a1b9a,
|
|
900: #4a148c,
|
|
A100: #ea80fc,
|
|
A200: #e040fb,
|
|
A400: #d500f9,
|
|
A700: #aa00ff,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $light-primary-text,
|
|
400: $light-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-deep-purple: (
|
|
50: #ede7f6,
|
|
100: #d1c4e9,
|
|
200: #b39ddb,
|
|
300: #9575cd,
|
|
400: #7e57c2,
|
|
500: #673ab7,
|
|
600: #5e35b1,
|
|
700: #512da8,
|
|
800: #4527a0,
|
|
900: #311b92,
|
|
A100: #b388ff,
|
|
A200: #7c4dff,
|
|
A400: #651fff,
|
|
A700: #6200ea,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $light-primary-text,
|
|
400: $light-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-indigo: (
|
|
50: #e8eaf6,
|
|
100: #c5cae9,
|
|
200: #9fa8da,
|
|
300: #7986cb,
|
|
400: #5c6bc0,
|
|
500: #3f51b5,
|
|
600: #3949ab,
|
|
700: #303f9f,
|
|
800: #283593,
|
|
900: #1a237e,
|
|
A100: #8c9eff,
|
|
A200: #536dfe,
|
|
A400: #3d5afe,
|
|
A700: #304ffe,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $light-primary-text,
|
|
400: $light-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-blue: (
|
|
50: #e3f2fd,
|
|
100: #bbdefb,
|
|
200: #90caf9,
|
|
300: #64b5f6,
|
|
400: #42a5f5,
|
|
500: #2196f3,
|
|
600: #1e88e5,
|
|
700: #1976d2,
|
|
800: #1565c0,
|
|
900: #0d47a1,
|
|
A100: #82b1ff,
|
|
A200: #448aff,
|
|
A400: #2979ff,
|
|
A700: #2962ff,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $light-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-light-blue: (
|
|
50: #e1f5fe,
|
|
100: #b3e5fc,
|
|
200: #81d4fa,
|
|
300: #4fc3f7,
|
|
400: #29b6f6,
|
|
500: #03a9f4,
|
|
600: #039be5,
|
|
700: #0288d1,
|
|
800: #0277bd,
|
|
900: #01579b,
|
|
A100: #80d8ff,
|
|
A200: #40c4ff,
|
|
A400: #00b0ff,
|
|
A700: #0091ea,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-cyan: (
|
|
50: #e0f7fa,
|
|
100: #b2ebf2,
|
|
200: #80deea,
|
|
300: #4dd0e1,
|
|
400: #26c6da,
|
|
500: #00bcd4,
|
|
600: #00acc1,
|
|
700: #0097a7,
|
|
800: #00838f,
|
|
900: #006064,
|
|
A100: #84ffff,
|
|
A200: #18ffff,
|
|
A400: #00e5ff,
|
|
A700: #00b8d4,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-teal: (
|
|
50: #e0f2f1,
|
|
100: #b2dfdb,
|
|
200: #80cbc4,
|
|
300: #4db6ac,
|
|
400: #26a69a,
|
|
500: #009688,
|
|
600: #00897b,
|
|
700: #00796b,
|
|
800: #00695c,
|
|
900: #004d40,
|
|
A100: #a7ffeb,
|
|
A200: #64ffda,
|
|
A400: #1de9b6,
|
|
A700: #00bfa5,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-green: (
|
|
50: #e8f5e9,
|
|
100: #c8e6c9,
|
|
200: #a5d6a7,
|
|
300: #81c784,
|
|
400: #66bb6a,
|
|
500: #4caf50,
|
|
600: #43a047,
|
|
700: #388e3c,
|
|
800: #2e7d32,
|
|
900: #1b5e20,
|
|
A100: #b9f6ca,
|
|
A200: #69f0ae,
|
|
A400: #00e676,
|
|
A700: #00c853,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-light-green: (
|
|
50: #f1f8e9,
|
|
100: #dcedc8,
|
|
200: #c5e1a5,
|
|
300: #aed581,
|
|
400: #9ccc65,
|
|
500: #8bc34a,
|
|
600: #7cb342,
|
|
700: #689f38,
|
|
800: #558b2f,
|
|
900: #33691e,
|
|
A100: #ccff90,
|
|
A200: #b2ff59,
|
|
A400: #76ff03,
|
|
A700: #64dd17,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $dark-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-lime: (
|
|
50: #f9fbe7,
|
|
100: #f0f4c3,
|
|
200: #e6ee9c,
|
|
300: #dce775,
|
|
400: #d4e157,
|
|
500: #cddc39,
|
|
600: #c0ca33,
|
|
700: #afb42b,
|
|
800: #9e9d24,
|
|
900: #827717,
|
|
A100: #f4ff81,
|
|
A200: #eeff41,
|
|
A400: #c6ff00,
|
|
A700: #aeea00,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $dark-primary-text,
|
|
700: $dark-primary-text,
|
|
800: $dark-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-yellow: (
|
|
50: #fffde7,
|
|
100: #fff9c4,
|
|
200: #fff59d,
|
|
300: #fff176,
|
|
400: #ffee58,
|
|
500: #ffeb3b,
|
|
600: #fdd835,
|
|
700: #fbc02d,
|
|
800: #f9a825,
|
|
900: #f57f17,
|
|
A100: #ffff8d,
|
|
A200: #ffff00,
|
|
A400: #ffea00,
|
|
A700: #ffd600,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $dark-primary-text,
|
|
700: $dark-primary-text,
|
|
800: $dark-primary-text,
|
|
900: $dark-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-amber: (
|
|
50: #fff8e1,
|
|
100: #ffecb3,
|
|
200: #ffe082,
|
|
300: #ffd54f,
|
|
400: #ffca28,
|
|
500: #ffc107,
|
|
600: #ffb300,
|
|
700: #ffa000,
|
|
800: #ff8f00,
|
|
900: #ff6f00,
|
|
A100: #ffe57f,
|
|
A200: #ffd740,
|
|
A400: #ffc400,
|
|
A700: #ffab00,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $dark-primary-text,
|
|
700: $dark-primary-text,
|
|
800: $dark-primary-text,
|
|
900: $dark-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $dark-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-orange: (
|
|
50: #fff3e0,
|
|
100: #ffe0b2,
|
|
200: #ffcc80,
|
|
300: #ffb74d,
|
|
400: #ffa726,
|
|
500: #ff9800,
|
|
600: #fb8c00,
|
|
700: #f57c00,
|
|
800: #ef6c00,
|
|
900: #e65100,
|
|
A100: #ffd180,
|
|
A200: #ffab40,
|
|
A400: #ff9100,
|
|
A700: #ff6d00,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $dark-primary-text,
|
|
700: $dark-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: black,
|
|
)
|
|
);
|
|
|
|
$mat-deep-orange: (
|
|
50: #fbe9e7,
|
|
100: #ffccbc,
|
|
200: #ffab91,
|
|
300: #ff8a65,
|
|
400: #ff7043,
|
|
500: #ff5722,
|
|
600: #f4511e,
|
|
700: #e64a19,
|
|
800: #d84315,
|
|
900: #bf360c,
|
|
A100: #ff9e80,
|
|
A200: #ff6e40,
|
|
A400: #ff3d00,
|
|
A700: #dd2c00,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-brown: (
|
|
50: #efebe9,
|
|
100: #d7ccc8,
|
|
200: #bcaaa4,
|
|
300: #a1887f,
|
|
400: #8d6e63,
|
|
500: #795548,
|
|
600: #6d4c41,
|
|
700: #5d4037,
|
|
800: #4e342e,
|
|
900: #3e2723,
|
|
A100: #d7ccc8,
|
|
A200: #bcaaa4,
|
|
A400: #8d6e63,
|
|
A700: #5d4037,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $light-primary-text,
|
|
400: $light-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
$mat-grey: (
|
|
50: #fafafa,
|
|
100: #f5f5f5,
|
|
200: #eeeeee,
|
|
300: #e0e0e0,
|
|
400: #bdbdbd,
|
|
500: #9e9e9e,
|
|
600: #757575,
|
|
700: #616161,
|
|
800: #424242,
|
|
900: #212121,
|
|
A100: #ffffff,
|
|
A200: #eeeeee,
|
|
A400: #bdbdbd,
|
|
A700: #616161,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $dark-primary-text,
|
|
500: $dark-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $dark-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
// Alias for alternate spelling.
|
|
$mat-gray: $mat-grey;
|
|
|
|
$mat-blue-grey: (
|
|
50: #eceff1,
|
|
100: #cfd8dc,
|
|
200: #b0bec5,
|
|
300: #90a4ae,
|
|
400: #78909c,
|
|
500: #607d8b,
|
|
600: #546e7a,
|
|
700: #455a64,
|
|
800: #37474f,
|
|
900: #263238,
|
|
A100: #cfd8dc,
|
|
A200: #b0bec5,
|
|
A400: #78909c,
|
|
A700: #455a64,
|
|
contrast: (
|
|
50: $dark-primary-text,
|
|
100: $dark-primary-text,
|
|
200: $dark-primary-text,
|
|
300: $dark-primary-text,
|
|
400: $light-primary-text,
|
|
500: $light-primary-text,
|
|
600: $light-primary-text,
|
|
700: $light-primary-text,
|
|
800: $light-primary-text,
|
|
900: $light-primary-text,
|
|
A100: $dark-primary-text,
|
|
A200: $dark-primary-text,
|
|
A400: $light-primary-text,
|
|
A700: $light-primary-text,
|
|
)
|
|
);
|
|
|
|
// Alias for alternate spelling.
|
|
$mat-blue-gray: $mat-blue-grey;
|
|
|
|
|
|
// Background palette for light themes.
|
|
$mat-light-theme-background: (
|
|
status-bar: map_get($mat-grey, 300),
|
|
app-bar: map_get($mat-grey, 100),
|
|
background: map_get($mat-grey, 50),
|
|
hover: rgba(black, 0.04), // TODO(kara): check style with Material Design UX
|
|
card: white,
|
|
dialog: white,
|
|
disabled-button: rgba(black, 0.12),
|
|
raised-button: white,
|
|
focused-button: $dark-focused,
|
|
selected-button: map_get($mat-grey, 300),
|
|
selected-disabled-button: map_get($mat-grey, 400),
|
|
disabled-button-toggle: map_get($mat-grey, 200),
|
|
unselected-chip: map_get($mat-grey, 300),
|
|
disabled-list-option: map_get($mat-grey, 200),
|
|
);
|
|
|
|
// Background palette for dark themes.
|
|
$mat-dark-theme-background: (
|
|
status-bar: black,
|
|
app-bar: map_get($mat-grey, 900),
|
|
background: #303030,
|
|
hover: rgba(white, 0.04), // TODO(kara): check style with Material Design UX
|
|
card: map_get($mat-grey, 800),
|
|
dialog: map_get($mat-grey, 800),
|
|
disabled-button: rgba(white, 0.12),
|
|
raised-button: map-get($mat-grey, 800),
|
|
focused-button: $light-focused,
|
|
selected-button: map_get($mat-grey, 900),
|
|
selected-disabled-button: map_get($mat-grey, 800),
|
|
disabled-button-toggle: black,
|
|
unselected-chip: map_get($mat-grey, 700),
|
|
disabled-list-option: black,
|
|
);
|
|
|
|
// Foreground palette for light themes.
|
|
$mat-light-theme-foreground: (
|
|
base: black,
|
|
divider: $dark-dividers,
|
|
dividers: $dark-dividers,
|
|
disabled: $dark-disabled-text,
|
|
disabled-button: rgba(black, 0.26),
|
|
disabled-text: $dark-disabled-text,
|
|
elevation: black,
|
|
hint-text: $dark-disabled-text,
|
|
secondary-text: $dark-secondary-text,
|
|
icon: rgba(black, 0.54),
|
|
icons: rgba(black, 0.54),
|
|
text: rgba(black, 0.87),
|
|
slider-min: rgba(black, 0.87),
|
|
slider-off: rgba(black, 0.26),
|
|
slider-off-active: rgba(black, 0.38),
|
|
);
|
|
|
|
// Foreground palette for dark themes.
|
|
$mat-dark-theme-foreground: (
|
|
base: white,
|
|
divider: $light-dividers,
|
|
dividers: $light-dividers,
|
|
disabled: $light-disabled-text,
|
|
disabled-button: rgba(white, 0.3),
|
|
disabled-text: $light-disabled-text,
|
|
elevation: black,
|
|
hint-text: $light-disabled-text,
|
|
secondary-text: $light-secondary-text,
|
|
icon: white,
|
|
icons: white,
|
|
text: white,
|
|
slider-min: white,
|
|
slider-off: rgba(white, 0.3),
|
|
slider-off-active: rgba(white, 0.3),
|
|
);
|
|
|
|
|
|
|
|
// For a given hue in a palette, return the contrast color from the map of contrast palettes.
|
|
// @param $color-map
|
|
// @param $hue
|
|
@function mat-contrast($palette, $hue) {
|
|
@return map-get(map-get($palette, contrast), $hue);
|
|
}
|
|
|
|
|
|
// Creates a map of hues to colors for a theme. This is used to define a theme palette in terms
|
|
// of the Material Design hues.
|
|
// @param $color-map
|
|
// @param $primary
|
|
// @param $lighter
|
|
@function mat-palette($base-palette, $default: 500, $lighter: 100, $darker: 700, $text: $default) {
|
|
$result: map_merge($base-palette, (
|
|
default: map-get($base-palette, $default),
|
|
lighter: map-get($base-palette, $lighter),
|
|
darker: map-get($base-palette, $darker),
|
|
text: map-get($base-palette, $text),
|
|
|
|
default-contrast: mat-contrast($base-palette, $default),
|
|
lighter-contrast: mat-contrast($base-palette, $lighter),
|
|
darker-contrast: mat-contrast($base-palette, $darker)
|
|
));
|
|
|
|
// For each hue in the palette, add a "-contrast" color to the map.
|
|
@each $hue, $color in $base-palette {
|
|
$result: map_merge($result, (
|
|
'#{$hue}-contrast': mat-contrast($base-palette, $hue)
|
|
));
|
|
}
|
|
|
|
@return $result;
|
|
}
|
|
|
|
|
|
// Gets a color from a theme palette (the output of mat-palette).
|
|
// The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured
|
|
// hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast".
|
|
//
|
|
// @param $color-map The theme palette (output of mat-palette).
|
|
// @param $hue The hue from the palette to use. If this is a value between 0 and 1, it will
|
|
// be treated as opacity.
|
|
// @param $opacity The alpha channel value for the color.
|
|
@function mat-color($palette, $hue: default, $opacity: null) {
|
|
// If hueKey is a number between zero and one, then it actually contains an
|
|
// opacity value, so recall this function with the default hue and that given opacity.
|
|
@if type-of($hue) == number and $hue >= 0 and $hue <= 1 {
|
|
@return mat-color($palette, default, $hue);
|
|
}
|
|
|
|
$color: map-get($palette, $hue);
|
|
|
|
@if (type-of($color) != color) {
|
|
// If the $color resolved to something different from a color (e.g. a CSS variable),
|
|
// we can't apply the opacity anyway so we return the value as is, otherwise Sass can
|
|
// throw an error or output something invalid.
|
|
@return $color;
|
|
}
|
|
|
|
@return rgba($color, if($opacity == null, opacity($color), $opacity));
|
|
}
|
|
|
|
|
|
// Creates a container object for a light theme to be given to individual component theme mixins.
|
|
@function mat-light-theme($primary, $accent, $warn: mat-palette($mat-red)) {
|
|
@return (
|
|
primary: $primary,
|
|
accent: $accent,
|
|
warn: $warn,
|
|
is-dark: false,
|
|
foreground: $mat-light-theme-foreground,
|
|
background: $mat-light-theme-background,
|
|
);
|
|
}
|
|
|
|
|
|
// Creates a container object for a dark theme to be given to individual component theme mixins.
|
|
@function mat-dark-theme($primary, $accent, $warn: mat-palette($mat-red)) {
|
|
@return (
|
|
primary: $primary,
|
|
accent: $accent,
|
|
warn: $warn,
|
|
is-dark: true,
|
|
foreground: $mat-dark-theme-foreground,
|
|
background: $mat-dark-theme-background,
|
|
);
|
|
}
|
|
|
|
|
|
|
|
$mat-ripple-color-opacity: 0.1;
|
|
|
|
@mixin mat-ripple() {
|
|
|
|
// The host element of an mat-ripple directive should always have a position of "absolute" or
|
|
// "relative" so that the ripples inside are correctly positioned relatively to the container.
|
|
.mat-ripple {
|
|
overflow: hidden;
|
|
|
|
// By default, every ripple container should have position: relative in favor of creating an
|
|
// easy API for developers using the MatRipple directive.
|
|
position: relative;
|
|
}
|
|
|
|
.mat-ripple.mat-ripple-unbounded {
|
|
overflow: visible;
|
|
}
|
|
|
|
.mat-ripple-element {
|
|
position: absolute;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
|
|
transition: opacity, transform 0ms cubic-bezier(0, 0, 0.2, 1);
|
|
transform: scale(0);
|
|
|
|
// In high contrast mode the ripple is opaque, causing it to obstruct the content.
|
|
@include cdk-high-contrast {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Theme for the ripple elements.*/
|
|
@mixin mat-ripple-theme($theme) {
|
|
$foreground: map_get($theme, foreground);
|
|
$foreground-base: map_get($foreground, base);
|
|
|
|
.mat-ripple-element {
|
|
// If the ripple color is resolves to a color *type*, we can use it directly, otherwise
|
|
// (e.g. it resolves to a CSS variable) we fall back to using the color and setting an opacity.
|
|
@if (type-of($foreground-base) == color) {
|
|
background-color: rgba($foreground-base, $mat-ripple-color-opacity);
|
|
}
|
|
@else {
|
|
background-color: $foreground-base;
|
|
opacity: $mat-ripple-color-opacity;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Utility for fetching a nested value from a typography config.
|
|
@function _mat-get-type-value($config, $level, $name) {
|
|
@return map-get(map-get($config, $level), $name);
|
|
}
|
|
|
|
// Gets the font size for a level inside a typography config.
|
|
@function mat-font-size($config, $level) {
|
|
@return _mat-get-type-value($config, $level, font-size);
|
|
}
|
|
|
|
// Gets the line height for a level inside a typography config.
|
|
@function mat-line-height($config, $level) {
|
|
@return _mat-get-type-value($config, $level, line-height);
|
|
}
|
|
|
|
// Gets the font weight for a level inside a typography config.
|
|
@function mat-font-weight($config, $level) {
|
|
@return _mat-get-type-value($config, $level, font-weight);
|
|
}
|
|
|
|
// Gets the letter spacing for a level inside a typography config.
|
|
@function mat-letter-spacing($config, $level) {
|
|
@return _mat-get-type-value($config, $level, letter-spacing);
|
|
}
|
|
|
|
// Gets the font-family from a typography config and removes the quotes around it.
|
|
@function mat-font-family($config, $level: null) {
|
|
$font-family: map-get($config, font-family);
|
|
|
|
@if $level != null {
|
|
$font-family: _mat-get-type-value($config, $level, font-family);
|
|
}
|
|
|
|
// Guard against unquoting non-string values, because it's deprecated.
|
|
@return if(type-of($font-family) == string, unquote($font-family), $font-family);
|
|
}
|
|
|
|
// Outputs the shorthand `font` CSS property, based on a set of typography values. Falls back to
|
|
// the individual properties if a value that isn't allowed in the shorthand is passed in.
|
|
@mixin mat-typography-font-shorthand($font-size, $font-weight, $line-height, $font-family) {
|
|
// If any of the values are set to `inherit`, we can't use the shorthand
|
|
// so we fall back to passing in the individual properties.
|
|
@if ($font-size == inherit or
|
|
$font-weight == inherit or
|
|
$line-height == inherit or
|
|
$font-family == inherit or
|
|
$font-size == null or
|
|
$font-weight == null or
|
|
$line-height == null or
|
|
$font-family == null) {
|
|
|
|
font-size: $font-size;
|
|
font-weight: $font-weight;
|
|
line-height: $line-height;
|
|
font-family: $font-family;
|
|
}
|
|
@else {
|
|
// Otherwise use the shorthand `font`, because it's the least amount of bytes. Note
|
|
// that we need to use interpolation for `font-size/line-height` in order to prevent
|
|
// Sass from dividing the two values.
|
|
font: $font-weight #{$font-size}/#{$line-height} $font-family;
|
|
}
|
|
}
|
|
|
|
// Converts a typography level into CSS styles.
|
|
@mixin mat-typography-level-to-styles($config, $level) {
|
|
$font-size: mat-font-size($config, $level);
|
|
$font-weight: mat-font-weight($config, $level);
|
|
$line-height: mat-line-height($config, $level);
|
|
$font-family: mat-font-family($config, $level);
|
|
|
|
@include mat-typography-font-shorthand($font-size, $font-weight, $line-height, $font-family);
|
|
letter-spacing: mat-letter-spacing($config, $level);
|
|
}
|
|
|
|
|
|
@mixin mat-option-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
.mat-option {
|
|
color: mat-color($foreground, text);
|
|
|
|
&:hover:not(.mat-option-disabled),
|
|
&:focus:not(.mat-option-disabled) {
|
|
background: mat-color($background, hover);
|
|
}
|
|
|
|
// In multiple mode there is a checkbox to show that the option is selected.
|
|
&.mat-selected:not(.mat-option-multiple):not(.mat-option-disabled) {
|
|
background: mat-color($background, hover);
|
|
}
|
|
|
|
&.mat-active {
|
|
background: mat-color($background, hover);
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
&.mat-option-disabled {
|
|
color: mat-color($foreground, hint-text);
|
|
}
|
|
}
|
|
|
|
.mat-primary .mat-option.mat-selected:not(.mat-option-disabled) {
|
|
color: mat-color($primary, text);
|
|
}
|
|
|
|
.mat-accent .mat-option.mat-selected:not(.mat-option-disabled) {
|
|
color: mat-color($accent, text);
|
|
}
|
|
|
|
.mat-warn .mat-option.mat-selected:not(.mat-option-disabled) {
|
|
color: mat-color($warn, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-option-typography($config) {
|
|
.mat-option {
|
|
font: {
|
|
family: mat-font-family($config);
|
|
size: mat-font-size($config, subheading-2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-optgroup-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-optgroup-label {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-optgroup-disabled .mat-optgroup-label {
|
|
color: mat-color($foreground, hint-text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-optgroup-typography($config) {
|
|
.mat-optgroup-label {
|
|
@include mat-typography-level-to-styles($config, body-2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@mixin mat-pseudo-checkbox-theme($theme) {
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
|
|
// NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors,
|
|
// this does not work well with elements layered on top of one another. To get around this we
|
|
// blend the colors together based on the base color and the theme background.
|
|
$white-30pct-opacity-on-dark: #686868;
|
|
$black-26pct-opacity-on-light: #b0b0b0;
|
|
$disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light);
|
|
$colored-box-selector: '.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate';
|
|
|
|
.mat-pseudo-checkbox {
|
|
color: mat-color(map-get($theme, foreground), secondary-text);
|
|
|
|
&::after {
|
|
color: mat-color($background, background);
|
|
}
|
|
}
|
|
|
|
.mat-pseudo-checkbox-disabled {
|
|
color: $disabled-color;
|
|
}
|
|
|
|
.mat-primary .mat-pseudo-checkbox-checked,
|
|
.mat-primary .mat-pseudo-checkbox-indeterminate {
|
|
background: mat-color(map-get($theme, primary));
|
|
}
|
|
|
|
// Default to the accent color. Note that the pseudo checkboxes are meant to inherit the
|
|
// theme from their parent, rather than implementing their own theming, which is why we
|
|
// don't attach to the `mat-*` classes. Also note that this needs to be below `.mat-primary`
|
|
// in order to allow for the color to be overwritten if the checkbox is inside a parent that
|
|
// has `mat-accent` and is placed inside another parent that has `mat-primary`.
|
|
.mat-pseudo-checkbox-checked,
|
|
.mat-pseudo-checkbox-indeterminate,
|
|
.mat-accent .mat-pseudo-checkbox-checked,
|
|
.mat-accent .mat-pseudo-checkbox-indeterminate {
|
|
background: mat-color(map-get($theme, accent));
|
|
}
|
|
|
|
.mat-warn .mat-pseudo-checkbox-checked,
|
|
.mat-warn .mat-pseudo-checkbox-indeterminate {
|
|
background: mat-color(map-get($theme, warn));
|
|
}
|
|
|
|
.mat-pseudo-checkbox-checked,
|
|
.mat-pseudo-checkbox-indeterminate {
|
|
&.mat-pseudo-checkbox-disabled {
|
|
background: $disabled-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Represents a typography level from the Material design spec.
|
|
@function mat-typography-level(
|
|
$font-size,
|
|
$line-height: $font-size,
|
|
$font-weight: 400,
|
|
$font-family: null,
|
|
$letter-spacing: null) {
|
|
|
|
@return (
|
|
font-size: $font-size,
|
|
line-height: $line-height,
|
|
font-weight: $font-weight,
|
|
font-family: $font-family,
|
|
letter-spacing: $letter-spacing
|
|
);
|
|
}
|
|
|
|
// Represents a collection of typography levels.
|
|
// Defaults come from https://material.io/guidelines/style/typography.html
|
|
// Note: The spec doesn't mention letter spacing. The values here come from
|
|
// eyeballing it until it looked exactly like the spec examples.
|
|
@function mat-typography-config(
|
|
$font-family: 'Roboto, "Helvetica Neue", sans-serif',
|
|
$display-4: mat-typography-level(112px, 112px, 300, $letter-spacing: -0.05em),
|
|
$display-3: mat-typography-level(56px, 56px, 400, $letter-spacing: -0.02em),
|
|
$display-2: mat-typography-level(45px, 48px, 400, $letter-spacing: -0.005em),
|
|
$display-1: mat-typography-level(34px, 40px, 400),
|
|
$headline: mat-typography-level(24px, 32px, 400),
|
|
$title: mat-typography-level(20px, 32px, 500),
|
|
$subheading-2: mat-typography-level(16px, 28px, 400),
|
|
$subheading-1: mat-typography-level(15px, 24px, 400),
|
|
$body-2: mat-typography-level(14px, 24px, 500),
|
|
$body-1: mat-typography-level(14px, 20px, 400),
|
|
$caption: mat-typography-level(12px, 20px, 400),
|
|
$button: mat-typography-level(14px, 14px, 500),
|
|
// Line-height must be unit-less fraction of the font-size.
|
|
$input: mat-typography-level(inherit, 1.125, 400)
|
|
) {
|
|
|
|
// Declare an initial map with all of the levels.
|
|
$config: (
|
|
display-4: $display-4,
|
|
display-3: $display-3,
|
|
display-2: $display-2,
|
|
display-1: $display-1,
|
|
headline: $headline,
|
|
title: $title,
|
|
subheading-2: $subheading-2,
|
|
subheading-1: $subheading-1,
|
|
body-2: $body-2,
|
|
body-1: $body-1,
|
|
caption: $caption,
|
|
button: $button,
|
|
input: $input,
|
|
);
|
|
|
|
// Loop through the levels and set the `font-family` of the ones that don't have one to the base.
|
|
// Note that Sass can't modify maps in place, which means that we need to merge and re-assign.
|
|
@each $key, $level in $config {
|
|
@if map-get($level, font-family) == null {
|
|
$new-level: map-merge($level, (font-family: $font-family));
|
|
$config: map-merge($config, ($key: $new-level));
|
|
}
|
|
}
|
|
|
|
// Add the base font family to the config.
|
|
@return map-merge($config, (font-family: $font-family));
|
|
}
|
|
|
|
// Adds the base typography styles, based on a config.
|
|
@mixin mat-base-typography($config, $selector: '.mat-typography') {
|
|
.mat-h1, .mat-headline, #{$selector} h1 {
|
|
@include mat-typography-level-to-styles($config, headline);
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
.mat-h2, .mat-title, #{$selector} h2 {
|
|
@include mat-typography-level-to-styles($config, title);
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
.mat-h3, .mat-subheading-2, #{$selector} h3 {
|
|
@include mat-typography-level-to-styles($config, subheading-2);
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
.mat-h4, .mat-subheading-1, #{$selector} h4 {
|
|
@include mat-typography-level-to-styles($config, subheading-1);
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
// Note: the spec doesn't have anything that would correspond to h5 and h6, but we add these for
|
|
// consistency. The font sizes come from the Chrome user agent styles which have h5 at 0.83em
|
|
// and h6 at 0.67em.
|
|
.mat-h5, #{$selector} h5 {
|
|
@include mat-typography-font-shorthand(
|
|
// calc is used here to support css variables
|
|
calc(#{mat-font-size($config, body-1)} * 0.83),
|
|
mat-font-weight($config, body-1),
|
|
mat-line-height($config, body-1),
|
|
mat-font-family($config, body-1)
|
|
);
|
|
|
|
margin: 0 0 12px;
|
|
}
|
|
|
|
.mat-h6, #{$selector} h6 {
|
|
@include mat-typography-font-shorthand(
|
|
// calc is used here to support css variables
|
|
calc(#{mat-font-size($config, body-1)} * 0.67),
|
|
mat-font-weight($config, body-1),
|
|
mat-line-height($config, body-1),
|
|
mat-font-family($config, body-1)
|
|
);
|
|
|
|
margin: 0 0 12px;
|
|
}
|
|
|
|
.mat-body-strong, .mat-body-2 {
|
|
@include mat-typography-level-to-styles($config, body-2);
|
|
}
|
|
|
|
.mat-body, .mat-body-1, #{$selector} {
|
|
@include mat-typography-level-to-styles($config, body-1);
|
|
|
|
p {
|
|
margin: 0 0 12px;
|
|
}
|
|
}
|
|
|
|
.mat-small, .mat-caption {
|
|
@include mat-typography-level-to-styles($config, caption);
|
|
}
|
|
|
|
.mat-display-4, #{$selector} .mat-display-4 {
|
|
@include mat-typography-level-to-styles($config, display-4);
|
|
margin: 0 0 56px;
|
|
}
|
|
|
|
.mat-display-3, #{$selector} .mat-display-3 {
|
|
@include mat-typography-level-to-styles($config, display-3);
|
|
margin: 0 0 64px;
|
|
}
|
|
|
|
.mat-display-2, #{$selector} .mat-display-2 {
|
|
@include mat-typography-level-to-styles($config, display-2);
|
|
margin: 0 0 64px;
|
|
}
|
|
|
|
.mat-display-1, #{$selector} .mat-display-1 {
|
|
@include mat-typography-level-to-styles($config, display-1);
|
|
margin: 0 0 64px;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@mixin mat-autocomplete-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
|
|
.mat-autocomplete-panel {
|
|
@include _mat-theme-overridable-elevation(4, $theme);
|
|
background: mat-color($background, card);
|
|
color: mat-color($foreground, text);
|
|
|
|
// Selected options in autocompletes should not be gray, but we
|
|
// only want to override the background for selected options if
|
|
// they are *not* in hover or focus state. This change has to be
|
|
// made here because base option styles are shared between the
|
|
// autocomplete and the select.
|
|
.mat-option.mat-selected:not(.mat-active):not(:hover) {
|
|
background: mat-color($background, card);
|
|
|
|
&:not(.mat-option-disabled) {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@mixin mat-autocomplete-typography($config) { }
|
|
|
|
// This contains all of the styles for the badge
|
|
// rather than just the color/theme because of
|
|
// no style sheet support for directives.
|
|
|
|
|
|
|
|
|
|
|
|
$mat-badge-font-size: 12px;
|
|
$mat-badge-font-weight: 600;
|
|
$mat-badge-default-size: 22px !default;
|
|
$mat-badge-small-size: $mat-badge-default-size - 6;
|
|
$mat-badge-large-size: $mat-badge-default-size + 6;
|
|
|
|
// Mixin for building offset given different sizes
|
|
@mixin _mat-badge-size($size) {
|
|
.mat-badge-content {
|
|
width: $size;
|
|
height: $size;
|
|
line-height: $size;
|
|
}
|
|
|
|
&.mat-badge-above {
|
|
.mat-badge-content {
|
|
top: -$size / 2;
|
|
}
|
|
}
|
|
|
|
&.mat-badge-below {
|
|
.mat-badge-content {
|
|
bottom: -$size / 2;
|
|
}
|
|
}
|
|
|
|
&.mat-badge-before {
|
|
.mat-badge-content {
|
|
left: -$size;
|
|
}
|
|
}
|
|
|
|
[dir='rtl'] &.mat-badge-before {
|
|
.mat-badge-content {
|
|
left: auto;
|
|
right: -$size;
|
|
}
|
|
}
|
|
|
|
&.mat-badge-after {
|
|
.mat-badge-content {
|
|
right: -$size;
|
|
}
|
|
}
|
|
|
|
[dir='rtl'] &.mat-badge-after {
|
|
.mat-badge-content {
|
|
right: auto;
|
|
left: -$size;
|
|
}
|
|
}
|
|
|
|
&.mat-badge-overlap {
|
|
&.mat-badge-before {
|
|
.mat-badge-content {
|
|
left: -$size / 2;
|
|
}
|
|
}
|
|
|
|
[dir='rtl'] &.mat-badge-before {
|
|
.mat-badge-content {
|
|
left: auto;
|
|
right: -$size / 2;
|
|
}
|
|
}
|
|
|
|
&.mat-badge-after {
|
|
.mat-badge-content {
|
|
right: -$size / 2;
|
|
}
|
|
}
|
|
|
|
[dir='rtl'] &.mat-badge-after {
|
|
.mat-badge-content {
|
|
right: auto;
|
|
left: -$size / 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-badge-theme($theme) {
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$primary: map-get($theme, primary);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-badge-content {
|
|
color: mat-color($primary, default-contrast);
|
|
background: mat-color($primary);
|
|
|
|
@include cdk-high-contrast {
|
|
outline: solid 1px;
|
|
border-radius: 0;
|
|
}
|
|
}
|
|
|
|
.mat-badge-accent {
|
|
.mat-badge-content {
|
|
background: mat-color($accent);
|
|
color: mat-color($accent, default-contrast);
|
|
}
|
|
}
|
|
|
|
.mat-badge-warn {
|
|
.mat-badge-content {
|
|
color: mat-color($warn, default-contrast);
|
|
background: mat-color($warn);
|
|
}
|
|
}
|
|
|
|
.mat-badge {
|
|
position: relative;
|
|
}
|
|
|
|
.mat-badge-hidden {
|
|
.mat-badge-content {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.mat-badge-disabled {
|
|
.mat-badge-content {
|
|
$app-background: mat-color($background, 'background');
|
|
$badge-color: mat-color($foreground, disabled-button);
|
|
|
|
// The disabled color usually has some kind of opacity, but because the badge is overlayed
|
|
// on top of something else, it won't look good if it's opaque. If it is a color *type*,
|
|
// we convert it into a solid color by taking the opacity from the rgba value and using
|
|
// the value to determine the percentage of the background to put into foreground when
|
|
// mixing the colors together.
|
|
@if (type-of($badge-color) == color and type-of($app-background) == color) {
|
|
$badge-opacity: opacity($badge-color);
|
|
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
|
|
}
|
|
@else {
|
|
background: $badge-color;
|
|
}
|
|
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
}
|
|
|
|
.mat-badge-content {
|
|
position: absolute;
|
|
text-align: center;
|
|
display: inline-block;
|
|
border-radius: 50%;
|
|
transition: transform 200ms ease-in-out;
|
|
transform: scale(0.6);
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.ng-animate-disabled .mat-badge-content,
|
|
.mat-badge-content._mat-animation-noopable {
|
|
transition: none;
|
|
}
|
|
|
|
// The active class is added after the element is added
|
|
// so it can animate scale to default
|
|
.mat-badge-content.mat-badge-active {
|
|
// Scale to `none` instead of `1` to avoid blurry text in some browsers.
|
|
transform: none;
|
|
}
|
|
|
|
.mat-badge-small {
|
|
@include _mat-badge-size($mat-badge-small-size);
|
|
}
|
|
.mat-badge-medium {
|
|
@include _mat-badge-size($mat-badge-default-size);
|
|
}
|
|
.mat-badge-large {
|
|
@include _mat-badge-size($mat-badge-large-size);
|
|
}
|
|
}
|
|
|
|
@mixin mat-badge-typography($config) {
|
|
.mat-badge-content {
|
|
font-weight: $mat-badge-font-weight;
|
|
font-size: $mat-badge-font-size;
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-badge-small .mat-badge-content {
|
|
// Set the font size to 75% of the original.
|
|
font-size: $mat-badge-font-size * 0.75;
|
|
}
|
|
|
|
.mat-badge-large .mat-badge-content {
|
|
font-size: $mat-badge-font-size * 2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-bottom-sheet-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-bottom-sheet-container {
|
|
@include _mat-theme-elevation(16, $theme);
|
|
background: mat-color($background, dialog);
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-bottom-sheet-typography($config) {
|
|
.mat-bottom-sheet-container {
|
|
@include mat-typography-level-to-styles($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$_mat-button-ripple-opacity: 0.1;
|
|
|
|
// Applies a focus style to an mat-button element for each of the supported palettes.
|
|
@mixin _mat-button-focus-overlay-color($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
&.mat-primary .mat-button-focus-overlay {
|
|
background-color: mat-color($primary);
|
|
}
|
|
|
|
&.mat-accent .mat-button-focus-overlay {
|
|
background-color: mat-color($accent);
|
|
}
|
|
|
|
&.mat-warn .mat-button-focus-overlay {
|
|
background-color: mat-color($warn);
|
|
}
|
|
|
|
&[disabled] .mat-button-focus-overlay {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
|
|
// Applies the background color for a ripple. If the value provided is not a Sass color,
|
|
// we assume that we've been given a CSS variable. Since we can't perform alpha-blending
|
|
// on a CSS variable, we instead add the opacity directly to the ripple element.
|
|
@mixin _mat-button-ripple-background($palette, $hue, $opacity) {
|
|
$background-color: mat-color($palette, $hue, $opacity);
|
|
background-color: $background-color;
|
|
@if (type-of($background-color) != color) {
|
|
opacity: $opacity;
|
|
}
|
|
}
|
|
|
|
@mixin _mat-button-ripple-color($theme, $hue, $opacity: $_mat-button-ripple-opacity) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
&.mat-primary .mat-ripple-element {
|
|
@include _mat-button-ripple-background($primary, $hue, $opacity);
|
|
}
|
|
|
|
&.mat-accent .mat-ripple-element {
|
|
@include _mat-button-ripple-background($accent, $hue, $opacity);
|
|
}
|
|
|
|
&.mat-warn .mat-ripple-element {
|
|
@include _mat-button-ripple-background($warn, $hue, $opacity);
|
|
}
|
|
}
|
|
|
|
// Applies a property to an mat-button element for each of the supported palettes.
|
|
@mixin _mat-button-theme-property($theme, $property, $hue) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
&.mat-primary {
|
|
#{$property}: mat-color($primary, $hue);
|
|
}
|
|
&.mat-accent {
|
|
#{$property}: mat-color($accent, $hue);
|
|
}
|
|
&.mat-warn {
|
|
#{$property}: mat-color($warn, $hue);
|
|
}
|
|
|
|
&.mat-primary, &.mat-accent, &.mat-warn, &[disabled] {
|
|
&[disabled] {
|
|
$palette: if($property == 'color', $foreground, $background);
|
|
#{$property}: mat-color($palette, disabled-button);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-button-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-button, .mat-icon-button, .mat-stroked-button {
|
|
// Buttons without a background color should inherit the font color. This is necessary to
|
|
// ensure that the button is readable on custom background colors. It's wrong to always assume
|
|
// that those buttons are always placed inside of containers with the default background
|
|
// color of the theme (e.g. themed toolbars).
|
|
color: inherit;
|
|
background: transparent;
|
|
|
|
@include _mat-button-theme-property($theme, 'color', text);
|
|
@include _mat-button-focus-overlay-color($theme);
|
|
|
|
// Setup the ripple color to be based on the text color. This ensures that the ripples
|
|
// are matching with the current theme palette and are in contrast to the background color
|
|
// (e.g in themed toolbars).
|
|
.mat-ripple-element {
|
|
opacity: $_mat-button-ripple-opacity;
|
|
background-color: currentColor;
|
|
}
|
|
}
|
|
|
|
.mat-button-focus-overlay {
|
|
background: map_get($foreground, base);
|
|
}
|
|
|
|
// Note: this needs a bit extra specificity, because we're not guaranteed the inclusion
|
|
// order of the theme styles and the button reset may end up resetting this as well.
|
|
.mat-stroked-button:not([disabled]) {
|
|
border-color: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-flat-button, .mat-raised-button, .mat-fab, .mat-mini-fab {
|
|
// Default font and background color when not using any color palette.
|
|
color: mat-color($foreground, text);
|
|
background-color: mat-color($background, raised-button);
|
|
|
|
@include _mat-button-theme-property($theme, 'color', default-contrast);
|
|
@include _mat-button-theme-property($theme, 'background-color', default);
|
|
@include _mat-button-ripple-color($theme, default-contrast);
|
|
}
|
|
|
|
.mat-stroked-button, .mat-flat-button {
|
|
@include _mat-theme-overridable-elevation(0, $theme);
|
|
}
|
|
|
|
.mat-raised-button {
|
|
@include _mat-theme-overridable-elevation(2, $theme);
|
|
|
|
&:not([disabled]):active {
|
|
@include _mat-theme-overridable-elevation(8, $theme);
|
|
}
|
|
|
|
&[disabled] {
|
|
@include _mat-theme-overridable-elevation(0, $theme);
|
|
}
|
|
}
|
|
|
|
.mat-fab, .mat-mini-fab {
|
|
@include _mat-theme-overridable-elevation(6, $theme);
|
|
|
|
&:not([disabled]):active {
|
|
@include _mat-theme-overridable-elevation(12, $theme);
|
|
}
|
|
|
|
&[disabled] {
|
|
@include _mat-theme-overridable-elevation(0, $theme);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-button-typography($config) {
|
|
.mat-button, .mat-raised-button, .mat-icon-button, .mat-stroked-button,
|
|
.mat-flat-button, .mat-fab, .mat-mini-fab {
|
|
font: {
|
|
family: mat-font-family($config, button);
|
|
size: mat-font-size($config, button);
|
|
weight: mat-font-weight($config, button);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-button-toggle-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
$divider-color: mat-color($foreground, divider);
|
|
|
|
.mat-button-toggle-standalone,
|
|
.mat-button-toggle-group {
|
|
@include _mat-theme-elevation(2, $theme);
|
|
}
|
|
|
|
.mat-button-toggle-standalone.mat-button-toggle-appearance-standard,
|
|
.mat-button-toggle-group-appearance-standard {
|
|
box-shadow: none;
|
|
}
|
|
|
|
.mat-button-toggle {
|
|
color: mat-color($foreground, hint-text);
|
|
|
|
.mat-button-toggle-focus-overlay {
|
|
background-color: mat-color($background, focused-button);
|
|
}
|
|
}
|
|
|
|
.mat-button-toggle-appearance-standard {
|
|
color: mat-color($foreground, text);
|
|
background: mat-color($background, card);
|
|
|
|
.mat-button-toggle-focus-overlay {
|
|
background-color: mat-color($background, focused-button, 1);
|
|
}
|
|
}
|
|
|
|
.mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle {
|
|
border-left: solid 1px $divider-color;
|
|
}
|
|
|
|
[dir='rtl'] .mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle {
|
|
border-left: none;
|
|
border-right: solid 1px $divider-color;
|
|
}
|
|
|
|
.mat-button-toggle-group-appearance-standard.mat-button-toggle-vertical {
|
|
.mat-button-toggle + .mat-button-toggle {
|
|
border-left: none;
|
|
border-right: none;
|
|
border-top: solid 1px $divider-color;
|
|
}
|
|
}
|
|
|
|
.mat-button-toggle-checked {
|
|
background-color: mat-color($background, selected-button);
|
|
color: mat-color($foreground, secondary-text);
|
|
|
|
&.mat-button-toggle-appearance-standard {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
|
|
.mat-button-toggle-disabled {
|
|
color: mat-color($foreground, disabled-button);
|
|
background-color: mat-color($background, disabled-button-toggle);
|
|
|
|
&.mat-button-toggle-appearance-standard {
|
|
background: mat-color($background, card);
|
|
}
|
|
|
|
&.mat-button-toggle-checked {
|
|
background-color: mat-color($background, selected-disabled-button);
|
|
}
|
|
}
|
|
|
|
.mat-button-toggle-standalone.mat-button-toggle-appearance-standard,
|
|
.mat-button-toggle-group-appearance-standard {
|
|
border: solid 1px $divider-color;
|
|
}
|
|
}
|
|
|
|
@mixin mat-button-toggle-typography($config) {
|
|
.mat-button-toggle {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-card-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-card {
|
|
@include _mat-theme-overridable-elevation(1, $theme);
|
|
background: mat-color($background, card);
|
|
color: mat-color($foreground, text);
|
|
|
|
// Needs extra specificity to be able to override the elevation selectors.
|
|
&.mat-card-flat {
|
|
@include _mat-theme-overridable-elevation(0, $theme);
|
|
}
|
|
}
|
|
|
|
.mat-card-subtitle {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-card-typography($config) {
|
|
.mat-card {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-card-title {
|
|
font: {
|
|
size: mat-font-size($config, headline);
|
|
weight: mat-font-weight($config, title);
|
|
}
|
|
}
|
|
|
|
.mat-card-header .mat-card-title {
|
|
font-size: mat-font-size($config, title);
|
|
}
|
|
|
|
.mat-card-subtitle,
|
|
.mat-card-content {
|
|
font-size: mat-font-size($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-checkbox-theme($theme) {
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
|
|
// The color of the checkbox's checkmark / mixedmark.
|
|
$checkbox-mark-color: mat-color($background, background);
|
|
|
|
// NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors,
|
|
// this does not work well with elements layered on top of one another. To get around this we
|
|
// blend the colors together based on the base color and the theme background.
|
|
$white-30pct-opacity-on-dark: #686868;
|
|
$black-26pct-opacity-on-light: #b0b0b0;
|
|
$disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light);
|
|
|
|
.mat-checkbox-frame {
|
|
border-color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-checkbox-checkmark {
|
|
fill: $checkbox-mark-color;
|
|
}
|
|
|
|
.mat-checkbox-checkmark-path {
|
|
// !important is needed here because a stroke must be set as an
|
|
// attribute on the SVG in order for line animation to work properly.
|
|
stroke: $checkbox-mark-color !important;
|
|
|
|
@include cdk-high-contrast(black-on-white) {
|
|
// Having the one above be !important ends up overriding the browser's automatic
|
|
// color inversion so we need to re-invert it ourselves for black-on-white.
|
|
stroke: #000 !important;
|
|
}
|
|
}
|
|
|
|
.mat-checkbox-mixedmark {
|
|
background-color: $checkbox-mark-color;
|
|
}
|
|
|
|
.mat-checkbox-indeterminate, .mat-checkbox-checked {
|
|
&.mat-primary .mat-checkbox-background {
|
|
background-color: mat-color($primary);
|
|
}
|
|
|
|
&.mat-accent .mat-checkbox-background {
|
|
background-color: mat-color($accent);
|
|
}
|
|
|
|
&.mat-warn .mat-checkbox-background {
|
|
background-color: mat-color($warn);
|
|
}
|
|
}
|
|
|
|
.mat-checkbox-disabled {
|
|
&.mat-checkbox-checked,
|
|
&.mat-checkbox-indeterminate {
|
|
.mat-checkbox-background {
|
|
background-color: $disabled-color;
|
|
}
|
|
}
|
|
|
|
&:not(.mat-checkbox-checked) {
|
|
.mat-checkbox-frame {
|
|
border-color: $disabled-color;
|
|
}
|
|
}
|
|
|
|
.mat-checkbox-label {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
@include cdk-high-contrast {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
// This one is moved down here so it can target both
|
|
// the theme colors and the disabled state.
|
|
@include cdk-high-contrast {
|
|
.mat-checkbox-background {
|
|
// Needs to be removed because it hides the checkbox outline.
|
|
background: none;
|
|
}
|
|
}
|
|
|
|
// Switch this to a solid color since we're using `opacity`
|
|
// to control how opaque the ripple should be.
|
|
.mat-checkbox .mat-ripple-element {
|
|
background-color: map_get(map-get($theme, foreground), base);
|
|
}
|
|
|
|
.mat-checkbox-checked:not(.mat-checkbox-disabled),
|
|
.mat-checkbox:active:not(.mat-checkbox-disabled) {
|
|
&.mat-primary .mat-ripple-element {
|
|
background: mat-color($primary);
|
|
}
|
|
|
|
&.mat-accent .mat-ripple-element {
|
|
background: mat-color($accent);
|
|
}
|
|
|
|
&.mat-warn .mat-ripple-element {
|
|
background: mat-color($warn);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-checkbox-typography($config) {
|
|
.mat-checkbox {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
// TODO(kara): Remove this style when fixing vertical baseline
|
|
.mat-checkbox-layout .mat-checkbox-label {
|
|
line-height: mat-line-height($config, body-2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$mat-chip-remove-font-size: 18px;
|
|
|
|
@mixin mat-chips-color($foreground, $background) {
|
|
background-color: $background;
|
|
color: $foreground;
|
|
|
|
.mat-chip-remove {
|
|
color: $foreground;
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
@mixin mat-chips-theme-color($palette) {
|
|
@include mat-chips-color(mat-color($palette, default-contrast), mat-color($palette));
|
|
|
|
.mat-ripple-element {
|
|
background: mat-color($palette, default-contrast, 0.1);
|
|
}
|
|
}
|
|
|
|
@mixin mat-chips-theme($theme) {
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
$unselected-background: mat-color($background, unselected-chip);
|
|
$unselected-foreground: mat-color($foreground, text);
|
|
|
|
.mat-chip.mat-standard-chip {
|
|
@include mat-chips-color($unselected-foreground, $unselected-background);
|
|
|
|
&:not(.mat-chip-disabled) {
|
|
&:active {
|
|
@include _mat-theme-elevation(3, $theme);
|
|
}
|
|
|
|
.mat-chip-remove:hover {
|
|
opacity: 0.54;
|
|
}
|
|
}
|
|
|
|
&.mat-chip-disabled {
|
|
opacity: 0.4;
|
|
}
|
|
|
|
&::after {
|
|
background: map_get($foreground, base);
|
|
}
|
|
}
|
|
|
|
.mat-chip.mat-standard-chip.mat-chip-selected {
|
|
&.mat-primary {
|
|
@include mat-chips-theme-color($primary);
|
|
}
|
|
|
|
&.mat-warn {
|
|
@include mat-chips-theme-color($warn);
|
|
}
|
|
|
|
&.mat-accent {
|
|
@include mat-chips-theme-color($accent);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-chips-typography($config) {
|
|
.mat-chip {
|
|
font-size: mat-font-size($config, body-2);
|
|
font-weight: mat-font-weight($config, body-2);
|
|
|
|
.mat-chip-trailing-icon.mat-icon,
|
|
.mat-chip-remove.mat-icon {
|
|
font-size: $mat-chip-remove-font-size;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-table-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-table {
|
|
background: mat-color($background, 'card');
|
|
}
|
|
|
|
.mat-table thead, .mat-table tbody, .mat-table tfoot,
|
|
mat-header-row, mat-row, mat-footer-row,
|
|
[mat-header-row], [mat-row], [mat-footer-row],
|
|
.mat-table-sticky {
|
|
background: inherit;
|
|
}
|
|
|
|
mat-row, mat-header-row, mat-footer-row,
|
|
th.mat-header-cell, td.mat-cell, td.mat-footer-cell {
|
|
border-bottom-color: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-header-cell {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-cell, .mat-footer-cell {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-table-typography($config) {
|
|
.mat-table {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-header-cell {
|
|
font-size: mat-font-size($config, caption);
|
|
font-weight: mat-font-weight($config, body-2);
|
|
}
|
|
|
|
.mat-cell, .mat-footer-cell {
|
|
font-size: mat-font-size($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$mat-datepicker-selected-today-box-shadow-width: 1px;
|
|
$mat-datepicker-selected-fade-amount: 0.6;
|
|
$mat-datepicker-today-fade-amount: 0.2;
|
|
$mat-calendar-body-font-size: 13px !default;
|
|
$mat-calendar-weekday-table-font-size: 11px !default;
|
|
|
|
@mixin _mat-datepicker-color($palette) {
|
|
.mat-calendar-body-selected {
|
|
background-color: mat-color($palette);
|
|
color: mat-color($palette, default-contrast);
|
|
}
|
|
|
|
.mat-calendar-body-disabled > .mat-calendar-body-selected {
|
|
$background: mat-color($palette);
|
|
|
|
@if (type-of($background) == color) {
|
|
background-color: fade-out($background, $mat-datepicker-selected-fade-amount);
|
|
}
|
|
@else {
|
|
// If we couldn't resolve to background to a color (e.g. it's a CSS variable),
|
|
// fall back to fading the content out via `opacity`.
|
|
opacity: $mat-datepicker-today-fade-amount;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-today.mat-calendar-body-selected {
|
|
box-shadow: inset 0 0 0 $mat-datepicker-selected-today-box-shadow-width
|
|
mat-color($palette, default-contrast);
|
|
}
|
|
}
|
|
|
|
@mixin mat-datepicker-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
|
|
.mat-calendar-arrow {
|
|
border-top-color: mat-color($foreground, icon);
|
|
}
|
|
|
|
// The prev/next buttons need a bit more specificity to
|
|
// avoid being overwritten by the .mat-icon-button.
|
|
.mat-datepicker-toggle,
|
|
.mat-datepicker-content .mat-calendar-next-button,
|
|
.mat-datepicker-content .mat-calendar-previous-button {
|
|
color: mat-color($foreground, icon);
|
|
}
|
|
|
|
.mat-calendar-table-header {
|
|
color: mat-color($foreground, hint-text);
|
|
}
|
|
|
|
.mat-calendar-table-header-divider::after {
|
|
background: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-calendar-body-label {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-calendar-body-cell-content {
|
|
color: mat-color($foreground, text);
|
|
border-color: transparent;
|
|
}
|
|
|
|
.mat-calendar-body-disabled > .mat-calendar-body-cell-content:not(.mat-calendar-body-selected) {
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
|
|
.mat-calendar-body-cell:not(.mat-calendar-body-disabled):hover,
|
|
.cdk-keyboard-focused .mat-calendar-body-active,
|
|
.cdk-program-focused .mat-calendar-body-active {
|
|
& > .mat-calendar-body-cell-content:not(.mat-calendar-body-selected) {
|
|
background-color: mat-color($background, hover);
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-today:not(.mat-calendar-body-selected) {
|
|
// Note: though it's not text, the border is a hint about the fact that this is today's date,
|
|
// so we use the hint color.
|
|
border-color: mat-color($foreground, hint-text);
|
|
}
|
|
|
|
.mat-calendar-body-disabled > .mat-calendar-body-today:not(.mat-calendar-body-selected) {
|
|
$color: mat-color($foreground, hint-text);
|
|
|
|
@if (type-of($color) == color) {
|
|
border-color: fade-out($color, $mat-datepicker-today-fade-amount);
|
|
}
|
|
@else {
|
|
// If the color didn't resolve to a color value, but something like a CSS variable, we can't
|
|
// fade it out so we fall back to reducing the element opacity. Note that we don't use the
|
|
// $mat-datepicker-today-fade-amount, because hint text usually has some opacity applied
|
|
// to it already and we don't want them to stack on top of each other.
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
@include _mat-datepicker-color(map-get($theme, primary));
|
|
|
|
.mat-datepicker-content {
|
|
@include _mat-theme-elevation(4, $theme);
|
|
background-color: mat-color($background, card);
|
|
color: mat-color($foreground, text);
|
|
|
|
&.mat-accent {
|
|
@include _mat-datepicker-color(map-get($theme, accent));
|
|
}
|
|
|
|
&.mat-warn {
|
|
@include _mat-datepicker-color(map-get($theme, warn));
|
|
}
|
|
}
|
|
|
|
.mat-datepicker-content-touch {
|
|
@include _mat-theme-elevation(0, $theme);
|
|
}
|
|
|
|
.mat-datepicker-toggle-active {
|
|
color: mat-color(map-get($theme, primary), text);
|
|
|
|
&.mat-accent {
|
|
color: mat-color(map-get($theme, accent), text);
|
|
}
|
|
|
|
&.mat-warn {
|
|
color: mat-color(map-get($theme, warn), text);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-datepicker-typography($config) {
|
|
.mat-calendar {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-calendar-body {
|
|
font-size: $mat-calendar-body-font-size;
|
|
}
|
|
|
|
.mat-calendar-body-label,
|
|
.mat-calendar-period-button {
|
|
font: {
|
|
size: mat-font-size($config, button);
|
|
weight: mat-font-weight($config, button);
|
|
}
|
|
}
|
|
|
|
.mat-calendar-table-header th {
|
|
font: {
|
|
size: $mat-calendar-weekday-table-font-size;
|
|
weight: mat-font-weight($config, body-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-dialog-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-dialog-container {
|
|
@include _mat-theme-elevation(24, $theme);
|
|
background: mat-color($background, dialog);
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-dialog-typography($config) {
|
|
.mat-dialog-title {
|
|
@include mat-typography-level-to-styles($config, title);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-expansion-panel-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-expansion-panel {
|
|
@include _mat-theme-overridable-elevation(2, $theme);
|
|
background: mat-color($background, card);
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-action-row {
|
|
border-top-color: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-expansion-panel {
|
|
& .mat-expansion-panel-header.cdk-keyboard-focused,
|
|
& .mat-expansion-panel-header.cdk-program-focused,
|
|
&:not(.mat-expanded) .mat-expansion-panel-header:hover {
|
|
&:not([aria-disabled='true']) {
|
|
background: mat-color($background, hover);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Disable the hover on touch devices since it can appear like it is stuck. We can't use
|
|
// `@media (hover)` above, because the desktop support browser support isn't great.
|
|
@media (hover: none) {
|
|
.mat-expansion-panel:not(.mat-expanded):not([aria-disabled='true'])
|
|
.mat-expansion-panel-header:hover {
|
|
background: mat-color($background, card);
|
|
}
|
|
}
|
|
|
|
.mat-expansion-panel-header-title {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-expansion-panel-header-description,
|
|
.mat-expansion-indicator::after {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-expansion-panel-header[aria-disabled='true'] {
|
|
color: mat-color($foreground, disabled-button);
|
|
|
|
.mat-expansion-panel-header-title,
|
|
.mat-expansion-panel-header-description {
|
|
color: inherit;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-expansion-panel-typography($config) {
|
|
.mat-expansion-panel-header {
|
|
font: {
|
|
family: mat-font-family($config, subheading-1);
|
|
size: mat-font-size($config, subheading-1);
|
|
weight: mat-font-weight($config, subheading-1);
|
|
}
|
|
}
|
|
|
|
.mat-expansion-panel-content {
|
|
@include mat-typography-level-to-styles($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// This mixin will ensure that lines that overflow the container will hide the overflow and
|
|
// truncate neatly with an ellipsis.
|
|
@mixin mat-truncate-line() {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
// Mixin to provide all mat-line styles, changing secondary font size based on whether the list
|
|
// is in dense mode.
|
|
@mixin mat-line-base($secondary-font-size) {
|
|
.mat-line {
|
|
@include mat-truncate-line();
|
|
display: block;
|
|
box-sizing: border-box;
|
|
|
|
// all lines but the top line should have smaller text
|
|
&:nth-child(n+2) {
|
|
font-size: $secondary-font-size;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This mixin normalizes default element styles, e.g. font weight for heading text.
|
|
@mixin mat-normalize-text() {
|
|
& > * {
|
|
margin: 0;
|
|
padding: 0;
|
|
font-weight: normal;
|
|
font-size: inherit;
|
|
}
|
|
}
|
|
|
|
// This mixin provides base styles for the wrapper around mat-line elements in a list.
|
|
@mixin mat-line-wrapper-base() {
|
|
@include mat-normalize-text();
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
overflow: hidden;
|
|
|
|
// Must remove wrapper when lines are empty or it takes up horizontal
|
|
// space and pushes other elements to the right.
|
|
&:empty {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Include this empty mixin for consistency with the other components.
|
|
@mixin mat-grid-list-theme($theme) { }
|
|
|
|
@mixin mat-grid-list-typography($config) {
|
|
.mat-grid-tile-header,
|
|
.mat-grid-tile-footer {
|
|
@include mat-line-base(mat-font-size($config, caption));
|
|
font-size: mat-font-size($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include this empty mixin for consistency with the other components.
|
|
@mixin mat-icon-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-icon {
|
|
&.mat-primary {
|
|
color: mat-color($primary, text);
|
|
}
|
|
|
|
&.mat-accent {
|
|
color: mat-color($accent, text);
|
|
}
|
|
|
|
&.mat-warn {
|
|
color: mat-color($warn, text);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-icon-typography($config) { }
|
|
|
|
|
|
|
|
|
|
|
|
// Renders a gradient for showing the dashed line when the input is disabled.
|
|
// Unlike using a border, a gradient allows us to adjust the spacing of the dotted line
|
|
// to match the Material Design spec.
|
|
@mixin mat-control-disabled-underline($color) {
|
|
background-image: linear-gradient(to right, $color 0%, $color 33%, transparent 0%);
|
|
background-size: 4px 100%;
|
|
background-repeat: repeat-x;
|
|
}
|
|
|
|
// Figures out the color of the placeholder for a form control.
|
|
// Used primarily to prevent the various form controls from
|
|
// becoming out of sync since these colors aren't in a palette.
|
|
@function _mat-control-placeholder-color($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
@return mat-color($foreground, secondary-text, if($is-dark-theme, 0.5, 0.42));
|
|
}
|
|
|
|
|
|
/* stylelint-disable material/no-prefixes */
|
|
@mixin user-select($value) {
|
|
-webkit-user-select: $value;
|
|
-moz-user-select: $value;
|
|
-ms-user-select: $value;
|
|
user-select: $value;
|
|
}
|
|
|
|
@mixin input-placeholder {
|
|
&::placeholder {
|
|
@content;
|
|
}
|
|
|
|
&::-moz-placeholder {
|
|
@content;
|
|
}
|
|
|
|
&::-webkit-input-placeholder {
|
|
@content;
|
|
}
|
|
|
|
&:-ms-input-placeholder {
|
|
@content;
|
|
}
|
|
}
|
|
|
|
@mixin cursor-grab {
|
|
cursor: -webkit-grab;
|
|
cursor: grab;
|
|
}
|
|
|
|
@mixin cursor-grabbing {
|
|
cursor: -webkit-grabbing;
|
|
cursor: grabbing;
|
|
}
|
|
|
|
@mixin backface-visibility($value) {
|
|
-webkit-backface-visibility: $value;
|
|
backface-visibility: $value;
|
|
}
|
|
/* stylelint-enable */
|
|
|
|
|
|
|
|
@mixin mat-input-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-form-field-type-mat-native-select .mat-form-field-infix::after {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-input-element:disabled,
|
|
.mat-form-field-type-mat-native-select.mat-form-field-disabled .mat-form-field-infix::after {
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
|
|
.mat-input-element {
|
|
caret-color: mat-color($primary, text);
|
|
|
|
@include input-placeholder {
|
|
color: _mat-control-placeholder-color($theme);
|
|
}
|
|
|
|
// On dark themes we set the native `select` color to some shade of white,
|
|
// however the color propagates to all of the `option` elements, which are
|
|
// always on a white background inside the dropdown, causing them to blend in.
|
|
// Since we can't change background of the dropdown, we need to explicitly
|
|
// reset the color of the options to something dark.
|
|
@if (map-get($theme, is-dark)) {
|
|
option {
|
|
color: $dark-primary-text;
|
|
}
|
|
|
|
option:disabled {
|
|
color: $dark-disabled-text;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-accent .mat-input-element {
|
|
caret-color: mat-color($accent, text);
|
|
}
|
|
|
|
.mat-warn .mat-input-element,
|
|
.mat-form-field-invalid .mat-input-element {
|
|
caret-color: mat-color($warn, text);
|
|
}
|
|
|
|
.mat-form-field-type-mat-native-select.mat-form-field-invalid .mat-form-field-infix::after {
|
|
color: mat-color($warn, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-input-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
|
|
// The amount of space between the top of the line and the top of the actual text
|
|
// (as a fraction of the font-size).
|
|
$line-spacing: ($line-height - 1) / 2;
|
|
|
|
// <input> elements seem to have their height set slightly too large on Safari causing the text to
|
|
// be misaligned w.r.t. the placeholder. Adding this margin corrects it.
|
|
input.mat-input-element {
|
|
margin-top: -$line-spacing * 1em;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-list-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-list-base {
|
|
.mat-list-item {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-list-option {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-subheader {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
}
|
|
|
|
.mat-list-item-disabled {
|
|
background-color: mat-color($background, disabled-list-option);
|
|
}
|
|
|
|
.mat-list-option,
|
|
.mat-nav-list .mat-list-item,
|
|
.mat-action-list .mat-list-item {
|
|
&:hover, &:focus {
|
|
background: mat-color($background, 'hover');
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-list-typography($config) {
|
|
$font-family: mat-font-family($config);
|
|
|
|
.mat-list-item {
|
|
font-family: $font-family;
|
|
}
|
|
|
|
.mat-list-option {
|
|
font-family: $font-family;
|
|
}
|
|
|
|
// Default list
|
|
.mat-list-base {
|
|
.mat-list-item {
|
|
font-size: mat-font-size($config, subheading-2);
|
|
@include mat-line-base(mat-font-size($config, body-1));
|
|
}
|
|
|
|
.mat-list-option {
|
|
font-size: mat-font-size($config, subheading-2);
|
|
@include mat-line-base(mat-font-size($config, body-1));
|
|
}
|
|
|
|
.mat-subheader {
|
|
font-family: mat-font-family($config, body-2);
|
|
font-size: mat-font-size($config, body-2);
|
|
font-weight: mat-font-weight($config, body-2);
|
|
}
|
|
}
|
|
|
|
// Dense list
|
|
.mat-list-base[dense] {
|
|
.mat-list-item {
|
|
font-size: mat-font-size($config, caption);
|
|
@include mat-line-base(mat-font-size($config, caption));
|
|
}
|
|
|
|
.mat-list-option {
|
|
font-size: mat-font-size($config, caption);
|
|
@include mat-line-base(mat-font-size($config, caption));
|
|
}
|
|
|
|
.mat-subheader {
|
|
font-family: $font-family;
|
|
font-size: mat-font-size($config, caption);
|
|
font-weight: mat-font-weight($config, body-2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-menu-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-menu-panel {
|
|
@include _mat-theme-overridable-elevation(4, $theme);
|
|
background: mat-color($background, 'card');
|
|
}
|
|
|
|
.mat-menu-item {
|
|
background: transparent;
|
|
color: mat-color($foreground, 'text');
|
|
|
|
&[disabled] {
|
|
&, &::after {
|
|
color: mat-color($foreground, 'disabled');
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-menu-item .mat-icon-no-color,
|
|
.mat-menu-item-submenu-trigger::after {
|
|
color: mat-color($foreground, 'icon');
|
|
}
|
|
|
|
.mat-menu-item:hover,
|
|
.mat-menu-item.cdk-program-focused,
|
|
.mat-menu-item.cdk-keyboard-focused,
|
|
.mat-menu-item-highlighted {
|
|
&:not([disabled]) {
|
|
background: mat-color($background, 'hover');
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-menu-typography($config) {
|
|
.mat-menu-item {
|
|
font: {
|
|
family: mat-font-family($config, body-1);
|
|
size: mat-font-size($config, body-1);
|
|
weight: mat-font-weight($config, body-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-paginator-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
|
|
.mat-paginator {
|
|
background: mat-color($background, 'card');
|
|
}
|
|
|
|
.mat-paginator,
|
|
.mat-paginator-page-size .mat-select-trigger {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-paginator-decrement,
|
|
.mat-paginator-increment {
|
|
border-top: 2px solid mat-color($foreground, 'icon');
|
|
border-right: 2px solid mat-color($foreground, 'icon');
|
|
}
|
|
|
|
.mat-paginator-first,
|
|
.mat-paginator-last {
|
|
border-top: 2px solid mat-color($foreground, 'icon');
|
|
}
|
|
|
|
.mat-icon-button[disabled] {
|
|
.mat-paginator-decrement,
|
|
.mat-paginator-increment,
|
|
.mat-paginator-first,
|
|
.mat-paginator-last {
|
|
border-color: mat-color($foreground, 'disabled');
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-paginator-typography($config) {
|
|
.mat-paginator,
|
|
.mat-paginator-page-size .mat-select-trigger {
|
|
font: {
|
|
family: mat-font-family($config, caption);
|
|
size: mat-font-size($config, caption);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-progress-bar-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
.mat-progress-bar-background {
|
|
fill: mat-color($primary, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-buffer {
|
|
background-color: mat-color($primary, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-fill::after {
|
|
background-color: mat-color($primary);
|
|
}
|
|
|
|
.mat-progress-bar.mat-accent {
|
|
.mat-progress-bar-background {
|
|
fill: mat-color($accent, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-buffer {
|
|
background-color: mat-color($accent, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-fill::after {
|
|
background-color: mat-color($accent);
|
|
}
|
|
}
|
|
|
|
.mat-progress-bar.mat-warn {
|
|
.mat-progress-bar-background {
|
|
fill: mat-color($warn, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-buffer {
|
|
background-color: mat-color($warn, lighter);
|
|
}
|
|
|
|
.mat-progress-bar-fill::after {
|
|
background-color: mat-color($warn);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-progress-bar-typography($config) { }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-progress-spinner-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
.mat-progress-spinner, .mat-spinner {
|
|
circle {
|
|
stroke: mat-color($primary);
|
|
}
|
|
|
|
&.mat-accent circle {
|
|
stroke: mat-color($accent);
|
|
}
|
|
|
|
&.mat-warn circle {
|
|
stroke: mat-color($warn);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-progress-spinner-typography($config) { }
|
|
|
|
|
|
|
|
|
|
|
|
@mixin _mat-radio-color($palette) {
|
|
&.mat-radio-checked .mat-radio-outer-circle {
|
|
border-color: mat-color($palette);
|
|
}
|
|
|
|
.mat-radio-inner-circle,
|
|
.mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple),
|
|
&.mat-radio-checked .mat-radio-persistent-ripple,
|
|
&:active .mat-radio-persistent-ripple {
|
|
background-color: mat-color($palette);
|
|
}
|
|
}
|
|
|
|
@mixin mat-radio-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-radio-outer-circle {
|
|
border-color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-radio-button {
|
|
&.mat-primary {
|
|
@include _mat-radio-color($primary);
|
|
}
|
|
|
|
&.mat-accent {
|
|
@include _mat-radio-color($accent);
|
|
}
|
|
|
|
&.mat-warn {
|
|
@include _mat-radio-color($warn);
|
|
}
|
|
|
|
// This needs extra specificity, because the classes above are combined
|
|
// (e.g. `.mat-radio-button.mat-accent`) which increases their specificity a lot.
|
|
// TODO: consider making the selectors into descendants (`.mat-primary .mat-radio-button`).
|
|
&.mat-radio-disabled {
|
|
&.mat-radio-checked .mat-radio-outer-circle,
|
|
.mat-radio-outer-circle {
|
|
border-color: mat-color($foreground, disabled);
|
|
}
|
|
|
|
.mat-radio-ripple .mat-ripple-element,
|
|
.mat-radio-inner-circle {
|
|
background-color: mat-color($foreground, disabled);
|
|
}
|
|
|
|
.mat-radio-label-content {
|
|
color: mat-color($foreground, disabled);
|
|
}
|
|
}
|
|
|
|
// Switch this to a solid color since we're using `opacity`
|
|
// to control how opaque the ripple should be.
|
|
.mat-ripple-element {
|
|
background-color: map_get($foreground, base);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-radio-typography($config) {
|
|
.mat-radio-button {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-select-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
|
|
.mat-select-value {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-select-placeholder {
|
|
color: _mat-control-placeholder-color($theme);
|
|
}
|
|
|
|
.mat-select-disabled .mat-select-value {
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
|
|
.mat-select-arrow {
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-select-panel {
|
|
background: mat-color($background, card);
|
|
@include _mat-theme-overridable-elevation(4, $theme);
|
|
|
|
.mat-option.mat-selected:not(.mat-option-multiple) {
|
|
background: mat-color($background, hover, 0.12);
|
|
}
|
|
}
|
|
|
|
.mat-form-field {
|
|
&.mat-focused {
|
|
&.mat-primary .mat-select-arrow {
|
|
color: mat-color($primary, text);
|
|
}
|
|
|
|
&.mat-accent .mat-select-arrow {
|
|
color: mat-color($accent, text);
|
|
}
|
|
|
|
&.mat-warn .mat-select-arrow {
|
|
color: mat-color($warn, text);
|
|
}
|
|
}
|
|
|
|
.mat-select.mat-select-invalid .mat-select-arrow {
|
|
color: mat-color($warn, text);
|
|
}
|
|
|
|
.mat-select.mat-select-disabled .mat-select-arrow {
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-select-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
|
|
.mat-select {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-select-trigger {
|
|
height: $line-height * 1em;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-sidenav-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
$drawer-background-color: mat-color($background, dialog);
|
|
$drawer-container-background-color: mat-color($background, background);
|
|
$drawer-push-background-color: mat-color($background, dialog);
|
|
$drawer-side-border: solid 1px mat-color($foreground, divider);
|
|
|
|
.mat-drawer-container {
|
|
background-color: $drawer-container-background-color;
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-drawer {
|
|
background-color: $drawer-background-color;
|
|
color: mat-color($foreground, text);
|
|
|
|
&.mat-drawer-push {
|
|
background-color: $drawer-push-background-color;
|
|
}
|
|
|
|
&:not(.mat-drawer-side) {
|
|
// The elevation of z-16 is noted in the design specifications.
|
|
// See https://material.io/design/components/navigation-drawer.html
|
|
@include _mat-theme-elevation(16, $theme);
|
|
}
|
|
}
|
|
|
|
.mat-drawer-side {
|
|
border-right: $drawer-side-border;
|
|
|
|
&.mat-drawer-end {
|
|
border-left: $drawer-side-border;
|
|
border-right: none;
|
|
}
|
|
}
|
|
|
|
[dir='rtl'] .mat-drawer-side {
|
|
border-left: $drawer-side-border;
|
|
border-right: none;
|
|
|
|
&.mat-drawer-end {
|
|
border-left: none;
|
|
border-right: $drawer-side-border;
|
|
}
|
|
}
|
|
|
|
.mat-drawer-backdrop.mat-drawer-shown {
|
|
$opacity: 0.6;
|
|
$backdrop-color: mat-color($background, card, $opacity);
|
|
|
|
@if (type-of($backdrop-color) == color) {
|
|
// We use invert() here to have the darken the background color expected to be used. If the
|
|
// background is light, we use a dark backdrop. If the background is dark,
|
|
// we use a light backdrop.
|
|
background-color: invert($backdrop-color);
|
|
}
|
|
@else {
|
|
// If we couldn't resolve the backdrop color to a color value, fall back to using
|
|
// `opacity` to make it opaque since its end value could be a solid color.
|
|
background-color: $backdrop-color;
|
|
opacity: $opacity;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-sidenav-typography($config) { }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin _mat-slide-toggle-checked($palette, $thumb-checked-hue) {
|
|
&.mat-checked {
|
|
.mat-slide-toggle-thumb {
|
|
background-color: mat-color($palette, $thumb-checked-hue);
|
|
}
|
|
|
|
.mat-slide-toggle-bar {
|
|
// Opacity is determined from the specs for the selection controls.
|
|
// See: https://material.io/design/components/selection-controls.html#specs
|
|
background-color: mat-color($palette, $thumb-checked-hue, 0.54);
|
|
}
|
|
|
|
.mat-ripple-element {
|
|
// Set no opacity for the ripples because the ripple opacity will be adjusted dynamically
|
|
// based on the type of interaction with the slide-toggle (e.g. for hover, focus)
|
|
background-color: mat-color($palette, $thumb-checked-hue);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-slide-toggle-theme($theme) {
|
|
$is-dark: map_get($theme, is-dark);
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
// Color hues are based on the specs which briefly show the hues that are applied to a switch.
|
|
// The 2018 specs no longer describe how dark switches should look like. Due to the lack of
|
|
// information for dark themed switches, we partially keep the old behavior that is based on
|
|
// the previous specifications. For the checked color we always use the `default` hue because
|
|
// that follows MDC and also makes it easier for people to create a custom theme without needing
|
|
// to specify each hue individually.
|
|
$thumb-unchecked-hue: if($is-dark, 400, 50);
|
|
$thumb-checked-hue: default;
|
|
|
|
$bar-unchecked-color: mat-color($foreground, disabled);
|
|
$ripple-unchecked-color: mat-color($foreground, base);
|
|
|
|
.mat-slide-toggle {
|
|
@include _mat-slide-toggle-checked($accent, $thumb-checked-hue);
|
|
|
|
&.mat-primary {
|
|
@include _mat-slide-toggle-checked($primary, $thumb-checked-hue);
|
|
}
|
|
|
|
&.mat-warn {
|
|
@include _mat-slide-toggle-checked($warn, $thumb-checked-hue);
|
|
}
|
|
|
|
&:not(.mat-checked) .mat-ripple-element {
|
|
// Set no opacity for the ripples because the ripple opacity will be adjusted dynamically
|
|
// based on the type of interaction with the slide-toggle (e.g. for hover, focus)
|
|
background-color: $ripple-unchecked-color;
|
|
}
|
|
}
|
|
|
|
.mat-slide-toggle-thumb {
|
|
@include _mat-theme-elevation(1, $theme);
|
|
background-color: mat-color($mat-grey, $thumb-unchecked-hue);
|
|
}
|
|
|
|
.mat-slide-toggle-bar {
|
|
background-color: $bar-unchecked-color;
|
|
}
|
|
}
|
|
|
|
@mixin mat-slide-toggle-typography($config) {
|
|
.mat-slide-toggle-content {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin _mat-slider-inner-content-theme($palette) {
|
|
.mat-slider-track-fill,
|
|
.mat-slider-thumb,
|
|
.mat-slider-thumb-label {
|
|
background-color: mat-color($palette);
|
|
}
|
|
|
|
.mat-slider-thumb-label-text {
|
|
color: mat-color($palette, default-contrast);
|
|
}
|
|
}
|
|
|
|
@mixin mat-slider-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
$mat-slider-off-color: mat-color($foreground, slider-off);
|
|
$mat-slider-off-focused-color: mat-color($foreground, slider-off-active);
|
|
$mat-slider-disabled-color: mat-color($foreground, slider-off);
|
|
$mat-slider-labeled-min-value-thumb-color: mat-color($foreground, slider-min);
|
|
$mat-slider-labeled-min-value-thumb-label-color: mat-color($foreground, slider-off);
|
|
$mat-slider-focus-ring-color: mat-color($accent, default, 0.2);
|
|
$mat-slider-focus-ring-min-value-color: mat-color($foreground, base, 0.12);
|
|
$mat-slider-tick-color: mat-color($foreground, base, 0.7);
|
|
$mat-slider-tick-size: 2px;
|
|
|
|
.mat-slider-track-background {
|
|
background-color: $mat-slider-off-color;
|
|
}
|
|
|
|
.mat-primary {
|
|
@include _mat-slider-inner-content-theme($primary);
|
|
}
|
|
|
|
.mat-accent {
|
|
@include _mat-slider-inner-content-theme($accent);
|
|
}
|
|
|
|
.mat-warn {
|
|
@include _mat-slider-inner-content-theme($warn);
|
|
}
|
|
|
|
.mat-slider-focus-ring {
|
|
background-color: $mat-slider-focus-ring-color;
|
|
}
|
|
|
|
.mat-slider:hover,
|
|
.cdk-focused {
|
|
.mat-slider-track-background {
|
|
background-color: $mat-slider-off-focused-color;
|
|
}
|
|
}
|
|
|
|
.mat-slider-disabled {
|
|
.mat-slider-track-background,
|
|
.mat-slider-track-fill,
|
|
.mat-slider-thumb {
|
|
background-color: $mat-slider-disabled-color;
|
|
}
|
|
|
|
&:hover {
|
|
.mat-slider-track-background {
|
|
background-color: $mat-slider-disabled-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-slider-min-value {
|
|
.mat-slider-focus-ring {
|
|
background-color: $mat-slider-focus-ring-min-value-color;
|
|
}
|
|
|
|
&.mat-slider-thumb-label-showing {
|
|
.mat-slider-thumb,
|
|
.mat-slider-thumb-label {
|
|
background-color: $mat-slider-labeled-min-value-thumb-color;
|
|
}
|
|
|
|
&.cdk-focused {
|
|
.mat-slider-thumb,
|
|
.mat-slider-thumb-label {
|
|
background-color: $mat-slider-labeled-min-value-thumb-label-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
&:not(.mat-slider-thumb-label-showing) {
|
|
.mat-slider-thumb {
|
|
border-color: $mat-slider-off-color;
|
|
background-color: transparent;
|
|
}
|
|
|
|
&:hover,
|
|
&.cdk-focused {
|
|
.mat-slider-thumb {
|
|
border-color: $mat-slider-off-focused-color;
|
|
}
|
|
|
|
&.mat-slider-disabled .mat-slider-thumb {
|
|
border-color: $mat-slider-disabled-color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-slider-has-ticks .mat-slider-wrapper::after {
|
|
border-color: $mat-slider-tick-color;
|
|
}
|
|
|
|
.mat-slider-horizontal .mat-slider-ticks {
|
|
background-image: repeating-linear-gradient(to right, $mat-slider-tick-color,
|
|
$mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent);
|
|
// Firefox doesn't draw the gradient correctly with 'to right'
|
|
// (see https://bugzilla.mozilla.org/show_bug.cgi?id=1314319).
|
|
background-image: -moz-repeating-linear-gradient(0.0001deg, $mat-slider-tick-color,
|
|
$mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent);
|
|
}
|
|
|
|
.mat-slider-vertical .mat-slider-ticks {
|
|
background-image: repeating-linear-gradient(to bottom, $mat-slider-tick-color,
|
|
$mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent);
|
|
}
|
|
}
|
|
|
|
@mixin mat-slider-typography($config) {
|
|
.mat-slider-thumb-label-text {
|
|
font: {
|
|
family: mat-font-family($config);
|
|
size: mat-font-size($config, caption);
|
|
weight: mat-font-weight($config, body-2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-stepper-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$background: map-get($theme, background);
|
|
$primary: map-get($theme, primary);
|
|
$warn: map-get($theme, warn);
|
|
|
|
.mat-step-header {
|
|
&.cdk-keyboard-focused,
|
|
&.cdk-program-focused,
|
|
&:hover {
|
|
background-color: mat-color($background, hover);
|
|
}
|
|
|
|
// On touch devices the :hover state will linger on the element after a tap.
|
|
// Reset it via `@media` after the declaration, because the media query isn't
|
|
// supported by all browsers yet.
|
|
@media (hover: none) {
|
|
&:hover {
|
|
background: none;
|
|
}
|
|
}
|
|
|
|
.mat-step-label,
|
|
.mat-step-optional {
|
|
// TODO(josephperrott): Update to using a corrected disabled-text contrast
|
|
// instead of secondary-text.
|
|
color: mat-color($foreground, secondary-text);
|
|
}
|
|
|
|
.mat-step-icon {
|
|
// TODO(josephperrott): Update to using a corrected disabled-text contrast
|
|
// instead of secondary-text.
|
|
background-color: mat-color($foreground, secondary-text);
|
|
color: mat-color($primary, default-contrast);
|
|
}
|
|
|
|
.mat-step-icon-selected,
|
|
.mat-step-icon-state-done,
|
|
.mat-step-icon-state-edit {
|
|
background-color: mat-color($primary);
|
|
color: mat-color($primary, default-contrast);
|
|
}
|
|
|
|
.mat-step-icon-state-error {
|
|
background-color: transparent;
|
|
color: mat-color($warn, text);
|
|
}
|
|
|
|
.mat-step-label.mat-step-label-active {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-step-label.mat-step-label-error {
|
|
color: mat-color($warn, text);
|
|
}
|
|
}
|
|
|
|
.mat-stepper-horizontal, .mat-stepper-vertical {
|
|
background-color: mat-color($background, card);
|
|
}
|
|
|
|
.mat-stepper-vertical-line::before {
|
|
border-left-color: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-horizontal-stepper-header::before,
|
|
.mat-horizontal-stepper-header::after,
|
|
.mat-stepper-horizontal-line {
|
|
border-top-color: mat-color($foreground, divider);
|
|
}
|
|
}
|
|
|
|
@mixin mat-stepper-typography($config) {
|
|
.mat-stepper-vertical, .mat-stepper-horizontal {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-step-label {
|
|
font: {
|
|
size: mat-font-size($config, body-1);
|
|
weight: mat-font-weight($config, body-1);
|
|
};
|
|
}
|
|
|
|
.mat-step-sub-label-error {
|
|
font-weight: normal;
|
|
}
|
|
|
|
.mat-step-label-error {
|
|
font-size: mat-font-size($config, body-2);
|
|
}
|
|
|
|
.mat-step-label-selected {
|
|
font: {
|
|
size: mat-font-size($config, body-2);
|
|
weight: mat-font-weight($config, body-2);
|
|
};
|
|
}
|
|
}
|
|
|
|
@mixin mat-sort-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-sort-header-arrow {
|
|
$table-background: mat-color($background, 'card');
|
|
$text-color: mat-color($foreground, secondary-text);
|
|
|
|
// Because the arrow is made up of multiple elements that are stacked on top of each other,
|
|
// we can't use the semi-trasparent color from the theme directly. If the value is a color
|
|
// *type*, we convert it into a solid color by taking the opacity from the rgba value and
|
|
// using the value to determine the percentage of the background to put into foreground
|
|
// when mixing the colors together. Otherwise, if it resolves to something different
|
|
// (e.g. it resolves to a CSS variable), we use the color directly.
|
|
@if (type-of($table-background) == color and type-of($text-color) == color) {
|
|
$text-opacity: opacity($text-color);
|
|
color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%);
|
|
}
|
|
@else {
|
|
color: $text-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-sort-typography($config) { }
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-tabs-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
$header-border: 1px solid mat-color($foreground, divider);
|
|
|
|
.mat-tab-nav-bar,
|
|
.mat-tab-header {
|
|
border-bottom: $header-border;
|
|
}
|
|
|
|
.mat-tab-group-inverted-header {
|
|
.mat-tab-nav-bar,
|
|
.mat-tab-header {
|
|
border-top: $header-border;
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
.mat-tab-label, .mat-tab-link {
|
|
color: mat-color($foreground, text);
|
|
|
|
&.mat-tab-disabled {
|
|
color: mat-color($foreground, disabled-text);
|
|
}
|
|
}
|
|
|
|
.mat-tab-header-pagination-chevron {
|
|
border-color: mat-color($foreground, text);
|
|
}
|
|
|
|
.mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron {
|
|
border-color: mat-color($foreground, disabled-text);
|
|
}
|
|
|
|
// Remove header border when there is a background color
|
|
.mat-tab-group[class*='mat-background-'] .mat-tab-header,
|
|
.mat-tab-nav-bar[class*='mat-background-'] {
|
|
border-bottom: none;
|
|
border-top: none;
|
|
}
|
|
|
|
.mat-tab-group, .mat-tab-nav-bar {
|
|
$theme-colors: (
|
|
primary: $primary,
|
|
accent: $accent,
|
|
warn: $warn
|
|
);
|
|
|
|
@each $name, $color in $theme-colors {
|
|
// Set the foreground color of the tabs
|
|
&.mat-#{$name} {
|
|
@include _mat-tab-label-focus($color);
|
|
@include _mat-ink-bar($color);
|
|
|
|
// Override ink bar when background color is the same
|
|
&.mat-background-#{$name} {
|
|
@include _mat-ink-bar($color, default-contrast);
|
|
}
|
|
}
|
|
}
|
|
|
|
@each $name, $color in $theme-colors {
|
|
// Set background color of the tabs and override focus color
|
|
&.mat-background-#{$name} {
|
|
@include _mat-tab-label-focus($color);
|
|
@include _mat-tabs-background($color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin _mat-ink-bar($color, $hue: default) {
|
|
.mat-ink-bar {
|
|
background-color: mat-color($color, $hue);
|
|
}
|
|
}
|
|
|
|
@mixin _mat-tab-label-focus($tab-focus-color) {
|
|
.mat-tab-label,
|
|
.mat-tab-link {
|
|
&.cdk-keyboard-focused,
|
|
&.cdk-program-focused {
|
|
&:not(.mat-tab-disabled) {
|
|
background-color: mat-color($tab-focus-color, lighter, 0.3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin _mat-tabs-background($background-color) {
|
|
// Set background color for the tab group
|
|
.mat-tab-header, .mat-tab-links, .mat-tab-header-pagination {
|
|
background-color: mat-color($background-color);
|
|
}
|
|
|
|
// Set labels to contrast against background
|
|
.mat-tab-label, .mat-tab-link {
|
|
color: mat-color($background-color, default-contrast);
|
|
|
|
&.mat-tab-disabled {
|
|
color: mat-color($background-color, default-contrast, 0.4);
|
|
}
|
|
}
|
|
|
|
// Set pagination chevrons to contrast background
|
|
.mat-tab-header-pagination-chevron {
|
|
border-color: mat-color($background-color, default-contrast);
|
|
}
|
|
|
|
.mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron {
|
|
border-color: mat-color($background-color, default-contrast, 0.4);
|
|
}
|
|
|
|
// Set ripples color to be the contrast color of the new background. Otherwise the ripple
|
|
// color will be based on the app background color.
|
|
.mat-ripple-element {
|
|
background-color: mat-color($background-color, default-contrast, 0.12);
|
|
}
|
|
}
|
|
|
|
@mixin mat-tabs-typography($config) {
|
|
.mat-tab-group {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-tab-label, .mat-tab-link {
|
|
font: {
|
|
family: mat-font-family($config, button);
|
|
size: mat-font-size($config, button);
|
|
weight: mat-font-weight($config, button);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin _mat-toolbar-color($palette) {
|
|
background: mat-color($palette);
|
|
color: mat-color($palette, default-contrast);
|
|
}
|
|
|
|
@mixin _mat-toolbar-form-field-overrides {
|
|
.mat-form-field-underline,
|
|
.mat-form-field-ripple,
|
|
.mat-focused .mat-form-field-ripple {
|
|
background-color: currentColor;
|
|
}
|
|
|
|
.mat-form-field-label,
|
|
.mat-focused .mat-form-field-label,
|
|
.mat-select-value,
|
|
.mat-select-arrow,
|
|
.mat-form-field.mat-focused .mat-select-arrow {
|
|
color: inherit;
|
|
}
|
|
|
|
.mat-input-element {
|
|
caret-color: currentColor;
|
|
}
|
|
}
|
|
|
|
@mixin mat-toolbar-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-toolbar {
|
|
background: mat-color($background, app-bar);
|
|
color: mat-color($foreground, text);
|
|
|
|
&.mat-primary {
|
|
@include _mat-toolbar-color($primary);
|
|
}
|
|
|
|
&.mat-accent {
|
|
@include _mat-toolbar-color($accent);
|
|
}
|
|
|
|
&.mat-warn {
|
|
@include _mat-toolbar-color($warn);
|
|
}
|
|
|
|
@include _mat-toolbar-form-field-overrides;
|
|
}
|
|
}
|
|
|
|
@mixin mat-toolbar-typography($config) {
|
|
.mat-toolbar,
|
|
.mat-toolbar h1,
|
|
.mat-toolbar h2,
|
|
.mat-toolbar h3,
|
|
.mat-toolbar h4,
|
|
.mat-toolbar h5,
|
|
.mat-toolbar h6 {
|
|
@include mat-typography-level-to-styles($config, title);
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$mat-tooltip-target-height: 22px;
|
|
$mat-tooltip-font-size: 10px;
|
|
$mat-tooltip-vertical-padding: ($mat-tooltip-target-height - $mat-tooltip-font-size) / 2;
|
|
|
|
$mat-tooltip-handset-target-height: 30px;
|
|
$mat-tooltip-handset-font-size: 14px;
|
|
$mat-tooltip-handset-vertical-padding:
|
|
($mat-tooltip-handset-target-height - $mat-tooltip-handset-font-size) / 2;
|
|
|
|
@mixin mat-tooltip-theme($theme) {
|
|
.mat-tooltip {
|
|
background: mat-color($mat-grey, 700, 0.9);
|
|
}
|
|
}
|
|
|
|
@mixin mat-tooltip-typography($config) {
|
|
.mat-tooltip {
|
|
font-family: mat-font-family($config);
|
|
font-size: $mat-tooltip-font-size;
|
|
padding-top: $mat-tooltip-vertical-padding;
|
|
padding-bottom: $mat-tooltip-vertical-padding;
|
|
}
|
|
|
|
.mat-tooltip-handset {
|
|
font-size: $mat-tooltip-handset-font-size;
|
|
padding-top: $mat-tooltip-handset-vertical-padding;
|
|
padding-bottom: $mat-tooltip-handset-vertical-padding;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-snack-bar-theme($theme) {
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
$accent: map-get($theme, accent);
|
|
|
|
.mat-snack-bar-container {
|
|
// Use the primary text on the dark theme, even though the lighter one uses
|
|
// a secondary, because the contrast on the light primary text is poor.
|
|
color: if($is-dark-theme, $dark-primary-text, $light-secondary-text);
|
|
background: if($is-dark-theme, map-get($mat-grey, 50), #323232);
|
|
|
|
@include _mat-theme-elevation(6, $theme);
|
|
}
|
|
|
|
.mat-simple-snackbar-action {
|
|
color: if($is-dark-theme, inherit, mat-color($accent, text));
|
|
}
|
|
}
|
|
|
|
@mixin mat-snack-bar-typography($config) {
|
|
.mat-simple-snackbar {
|
|
font: {
|
|
family: mat-font-family($config, body-1);
|
|
size: mat-font-size($config, body-1);
|
|
}
|
|
}
|
|
|
|
.mat-simple-snackbar-action {
|
|
line-height: 1;
|
|
font: {
|
|
family: inherit;
|
|
size: inherit;
|
|
weight: mat-font-weight($config, button);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Theme styles that only apply to the fill appearance of the form-field.
|
|
|
|
@mixin mat-form-field-fill-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
|
|
$fill-background: mat-color($foreground, base, if($is-dark-theme, 0.1, 0.04));
|
|
$fill-disabled-background: mat-color($foreground, base, if($is-dark-theme, 0.05, 0.02));
|
|
$underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.5, 0.42));
|
|
$label-disabled-color: mat-color($foreground, disabled-text);
|
|
|
|
.mat-form-field-appearance-fill {
|
|
.mat-form-field-flex {
|
|
background-color: $fill-background;
|
|
}
|
|
|
|
&.mat-form-field-disabled .mat-form-field-flex {
|
|
background-color: $fill-disabled-background;
|
|
}
|
|
|
|
.mat-form-field-underline::before {
|
|
background-color: $underline-color;
|
|
}
|
|
|
|
&.mat-form-field-disabled {
|
|
.mat-form-field-label {
|
|
color: $label-disabled-color;
|
|
}
|
|
|
|
.mat-form-field-underline::before {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used to make instances of the _mat-form-field-label-floating mixin negligibly different,
|
|
// and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some
|
|
// of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters
|
|
// an unknown pseudo-class it will discard the entire rule set.
|
|
$mat-form-field-fill-dedupe: 0;
|
|
|
|
// Applies a floating label above the form field control itself.
|
|
@mixin _mat-form-field-fill-label-floating($font-scale, $infix-padding, $infix-margin-top) {
|
|
transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-fill-dedupe)
|
|
scale($font-scale);
|
|
width: 100% / $font-scale + $mat-form-field-fill-dedupe;
|
|
|
|
$mat-form-field-fill-dedupe: $mat-form-field-fill-dedupe + 0.00001 !global;
|
|
}
|
|
|
|
@mixin mat-form-field-fill-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
// The amount to scale the font for the floating label and subscript.
|
|
$subscript-font-scale: 0.75;
|
|
// The padding on top of the infix.
|
|
$infix-padding-top: 0.25em;
|
|
// The padding below the infix.
|
|
$infix-padding-bottom: 0.75em;
|
|
// The margin applied to the form-field-infix to reserve space for the floating label.
|
|
$infix-margin-top: 1em * $line-height * $subscript-font-scale;
|
|
// The amount we offset the label from the input text in the fill appearance.
|
|
$fill-appearance-label-offset: -0.5em;
|
|
|
|
.mat-form-field-appearance-fill {
|
|
.mat-form-field-infix {
|
|
padding: $infix-padding-top 0 $infix-padding-bottom 0;
|
|
}
|
|
|
|
.mat-form-field-label {
|
|
top: $infix-margin-top + $infix-padding-top;
|
|
margin-top: $fill-appearance-label-offset;
|
|
}
|
|
|
|
&.mat-form-field-can-float {
|
|
&.mat-form-field-should-float .mat-form-field-label,
|
|
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label {
|
|
@include _mat-form-field-fill-label-floating(
|
|
$subscript-font-scale, $infix-padding-top + $fill-appearance-label-offset,
|
|
$infix-margin-top);
|
|
}
|
|
|
|
// Server-side rendered matInput with a label attribute but label not shown
|
|
// (used as a pure CSS stand-in for mat-form-field-should-float).
|
|
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-fill-label-floating(
|
|
$subscript-font-scale, $infix-padding-top + $fill-appearance-label-offset,
|
|
$infix-margin-top);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Theme styles that only apply to the legacy appearance of the form-field.
|
|
|
|
@mixin mat-form-field-legacy-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
|
|
$label-color: mat-color($foreground, secondary-text);
|
|
$underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.7, 0.42));
|
|
|
|
.mat-form-field-appearance-legacy {
|
|
.mat-form-field-label {
|
|
color: $label-color;
|
|
}
|
|
|
|
.mat-hint {
|
|
color: $label-color;
|
|
}
|
|
|
|
.mat-form-field-underline {
|
|
background-color: $underline-color;
|
|
}
|
|
|
|
&.mat-form-field-disabled .mat-form-field-underline {
|
|
@include mat-control-disabled-underline($underline-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used to make instances of the _mat-form-field-label-floating mixin negligibly different,
|
|
// and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some
|
|
// of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters
|
|
// an unknown pseudo-class it will discard the entire rule set.
|
|
$mat-form-field-legacy-dedupe: 0;
|
|
|
|
// Applies a floating label above the form field control itself.
|
|
@mixin _mat-form-field-legacy-label-floating($font-scale, $infix-padding, $infix-margin-top) {
|
|
// We use perspective to fix the text blurriness as described here:
|
|
// http://www.useragentman.com/blog/2014/05/04/fixing-typography-inside-of-2-d-css-transforms/
|
|
// This results in a small jitter after the label floats on Firefox, which the
|
|
// translateZ fixes.
|
|
transform: translateY(-$infix-margin-top - $infix-padding) scale($font-scale) perspective(100px)
|
|
translateZ(0.001px + $mat-form-field-legacy-dedupe);
|
|
// The tricks above used to smooth out the animation on chrome and firefox actually make things
|
|
// worse on IE, so we don't include them in the IE version.
|
|
-ms-transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-legacy-dedupe)
|
|
scale($font-scale);
|
|
|
|
width: 100% / $font-scale + $mat-form-field-legacy-dedupe;
|
|
|
|
$mat-form-field-legacy-dedupe: $mat-form-field-legacy-dedupe + 0.00001 !global;
|
|
}
|
|
|
|
// Same as mixin above, but omits the translateZ for printing purposes.
|
|
@mixin _mat-form-field-legacy-label-floating-print($font-scale, $infix-padding, $infix-margin-top) {
|
|
// This results in a small jitter after the label floats on Firefox, which the
|
|
// translateZ fixes.
|
|
transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-legacy-dedupe)
|
|
scale($font-scale);
|
|
// The tricks above used to smooth out the animation on chrome and firefox actually make things
|
|
// worse on IE, so we don't include them in the IE version.
|
|
$mat-form-field-legacy-dedupe: $mat-form-field-legacy-dedupe + 0.00001 !global;
|
|
}
|
|
|
|
@mixin mat-form-field-legacy-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
// The amount to scale the font for the floating label and subscript.
|
|
$subscript-font-scale: 0.75;
|
|
// The amount of space between the top of the line and the top of the actual text
|
|
// (as a fraction of the font-size).
|
|
$line-spacing: ($line-height - 1) / 2;
|
|
// The padding on the infix. Mocks show half of the text size, but seem to measure from the edge
|
|
// of the text itself, not the edge of the line; therefore we subtract off the line spacing.
|
|
$infix-padding: 0.5em - $line-spacing;
|
|
// The margin applied to the form-field-infix to reserve space for the floating label.
|
|
$infix-margin-top: 1em * $line-height * $subscript-font-scale;
|
|
// The space between the bottom of the .mat-form-field-flex area and the subscript wrapper.
|
|
// Mocks show half of the text size, but this margin is applied to an element with the subscript
|
|
// text font size, so we need to divide by the scale factor to make it half of the original text
|
|
// size. We again need to subtract off the line spacing since the mocks measure to the edge of the
|
|
// text, not the edge of the line.
|
|
$subscript-margin-top: 0.5em / $subscript-font-scale - ($line-spacing * 2);
|
|
// The padding applied to the form-field-wrapper to reserve space for the subscript, since it's
|
|
// absolutely positioned. This is a combination of the subscript's margin and line-height, but we
|
|
// need to multiply by the subscript font scale factor since the wrapper has a larger font size.
|
|
$wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale;
|
|
|
|
.mat-form-field-appearance-legacy {
|
|
.mat-form-field-wrapper {
|
|
padding-bottom: $wrapper-padding-bottom;
|
|
}
|
|
|
|
.mat-form-field-infix {
|
|
padding: $infix-padding 0;
|
|
}
|
|
|
|
&.mat-form-field-can-float {
|
|
&.mat-form-field-should-float .mat-form-field-label,
|
|
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
|
|
// @breaking-change 8.0.0 will rely on AutofillMonitor instead.
|
|
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
|
|
// Server-side rendered matInput with a label attribute but label not shown
|
|
// (used as a pure CSS stand-in for mat-form-field-should-float).
|
|
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
}
|
|
|
|
.mat-form-field-label {
|
|
top: $infix-margin-top + $infix-padding;
|
|
}
|
|
|
|
.mat-form-field-underline {
|
|
// We want the underline to start at the end of the content box, not the padding box,
|
|
// so we move it up by the padding amount.
|
|
bottom: $wrapper-padding-bottom;
|
|
}
|
|
|
|
.mat-form-field-subscript-wrapper {
|
|
margin-top: $subscript-margin-top;
|
|
|
|
// We want the subscript to start at the end of the content box, not the padding box,
|
|
// so we move it up by the padding amount (adjusted for the smaller font size);
|
|
top: calc(100% - #{$wrapper-padding-bottom / $subscript-font-scale});
|
|
}
|
|
}
|
|
|
|
// translateZ causes the label to not appear while printing, so we override it to not
|
|
// apply translateZ while printing
|
|
@media print {
|
|
.mat-form-field-appearance-legacy {
|
|
&.mat-form-field-can-float {
|
|
&.mat-form-field-should-float .mat-form-field-label,
|
|
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating-print(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
|
|
// @breaking-change 8.0.0 will rely on AutofillMonitor instead.
|
|
.mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating-print(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
|
|
// Server-side rendered matInput with a label attribute but label not shown
|
|
// (used as a pure CSS stand-in for mat-form-field-should-float).
|
|
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-legacy-label-floating-print(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Theme styles that only apply to the outline appearance of the form-field.
|
|
|
|
@mixin mat-form-field-outline-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
|
|
$label-disabled-color: mat-color($foreground, disabled-text);
|
|
$outline-color: mat-color($foreground, divider, if($is-dark-theme, 0.3, 0.12));
|
|
$outline-color-hover: mat-color($foreground, divider, if($is-dark-theme, 1, 0.87));
|
|
$outline-color-primary: mat-color($primary);
|
|
$outline-color-accent: mat-color($accent);
|
|
$outline-color-warn: mat-color($warn);
|
|
$outline-color-disabled: mat-color($foreground, divider, if($is-dark-theme, 0.15, 0.06));
|
|
|
|
.mat-form-field-appearance-outline {
|
|
.mat-form-field-outline {
|
|
color: $outline-color;
|
|
}
|
|
|
|
.mat-form-field-outline-thick {
|
|
color: $outline-color-hover;
|
|
}
|
|
|
|
&.mat-focused {
|
|
.mat-form-field-outline-thick {
|
|
color: $outline-color-primary;
|
|
}
|
|
|
|
&.mat-accent .mat-form-field-outline-thick {
|
|
color: $outline-color-accent;
|
|
}
|
|
|
|
&.mat-warn .mat-form-field-outline-thick {
|
|
color: $outline-color-warn;
|
|
}
|
|
}
|
|
|
|
// Class repeated so that rule is specific enough to override focused accent color case.
|
|
&.mat-form-field-invalid.mat-form-field-invalid {
|
|
.mat-form-field-outline-thick {
|
|
color: $outline-color-warn;
|
|
}
|
|
}
|
|
|
|
&.mat-form-field-disabled {
|
|
.mat-form-field-label {
|
|
color: $label-disabled-color;
|
|
}
|
|
|
|
.mat-form-field-outline {
|
|
color: $outline-color-disabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used to make instances of the _mat-form-field-label-floating mixin negligibly different,
|
|
// and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some
|
|
// of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters
|
|
// an unknown pseudo-class it will discard the entire rule set.
|
|
$mat-form-field-outline-dedupe: 0;
|
|
|
|
// Applies a floating label above the form field control itself.
|
|
@mixin _mat-form-field-outline-label-floating($font-scale, $infix-padding, $infix-margin-top) {
|
|
transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-outline-dedupe)
|
|
scale($font-scale);
|
|
width: 100% / $font-scale + $mat-form-field-outline-dedupe;
|
|
|
|
$mat-form-field-outline-dedupe: $mat-form-field-outline-dedupe + 0.00001 !global;
|
|
}
|
|
|
|
@mixin mat-form-field-outline-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
// The amount to scale the font for the floating label and subscript.
|
|
$subscript-font-scale: 0.75;
|
|
// The padding above and below the infix.
|
|
$infix-padding: 1em;
|
|
// The margin applied to the form-field-infix to reserve space for the floating label.
|
|
$infix-margin-top: 1em * $line-height * $subscript-font-scale;
|
|
// The space between the bottom of the .mat-form-field-flex area and the subscript wrapper.
|
|
// Mocks show half of the text size, but this margin is applied to an element with the subscript
|
|
// text font size, so we need to divide by the scale factor to make it half of the original text
|
|
// size.
|
|
$subscript-margin-top: 0.5em / $subscript-font-scale;
|
|
// The padding applied to the form-field-wrapper to reserve space for the subscript, since it's
|
|
// absolutely positioned. This is a combination of the subscript's margin and line-height, but we
|
|
// need to multiply by the subscript font scale factor since the wrapper has a larger font size.
|
|
$wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale;
|
|
// The amount we offset the label from the input text in the outline appearance.
|
|
$outline-appearance-label-offset: -0.25em;
|
|
|
|
.mat-form-field-appearance-outline {
|
|
.mat-form-field-infix {
|
|
padding: $infix-padding 0 $infix-padding 0;
|
|
}
|
|
|
|
.mat-form-field-label {
|
|
top: $infix-margin-top + $infix-padding;
|
|
margin-top: $outline-appearance-label-offset;
|
|
}
|
|
|
|
&.mat-form-field-can-float {
|
|
&.mat-form-field-should-float .mat-form-field-label,
|
|
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label {
|
|
@include _mat-form-field-outline-label-floating(
|
|
$subscript-font-scale, $infix-padding + $outline-appearance-label-offset,
|
|
$infix-margin-top);
|
|
}
|
|
|
|
// Server-side rendered matInput with a label attribute but label not shown
|
|
// (used as a pure CSS stand-in for mat-form-field-should-float).
|
|
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-outline-label-floating(
|
|
$subscript-font-scale, $infix-padding + $outline-appearance-label-offset,
|
|
$infix-margin-top);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Theme styles that only apply to the standard appearance of the form-field.
|
|
|
|
@mixin mat-form-field-standard-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
|
|
$underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.7, 0.42));
|
|
|
|
.mat-form-field-appearance-standard {
|
|
.mat-form-field-underline {
|
|
background-color: $underline-color;
|
|
}
|
|
|
|
&.mat-form-field-disabled .mat-form-field-underline {
|
|
@include mat-control-disabled-underline($underline-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin mat-form-field-standard-typography($config) {}
|
|
|
|
|
|
// Theme styles that apply to all appearances of the form-field.
|
|
@mixin mat-form-field-theme($theme) {
|
|
$primary: map-get($theme, primary);
|
|
$accent: map-get($theme, accent);
|
|
$warn: map-get($theme, warn);
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
$is-dark-theme: map-get($theme, is-dark);
|
|
|
|
// Label colors. Required is used for the `*` star shown in the label.
|
|
$label-color: mat-color($foreground, secondary-text, if($is-dark-theme, 0.7, 0.6));
|
|
$focused-label-color: mat-color($primary, text);
|
|
$required-label-color: mat-color($accent, text);
|
|
|
|
// Underline colors.
|
|
$underline-color-base: mat-color($foreground, divider, if($is-dark-theme, 1, 0.87));
|
|
$underline-color-accent: mat-color($accent, text);
|
|
$underline-color-warn: mat-color($warn, text);
|
|
$underline-focused-color: mat-color($primary, text);
|
|
|
|
.mat-form-field-label {
|
|
color: $label-color;
|
|
}
|
|
|
|
.mat-hint {
|
|
color: $label-color;
|
|
}
|
|
|
|
.mat-form-field.mat-focused .mat-form-field-label {
|
|
color: $focused-label-color;
|
|
|
|
&.mat-accent {
|
|
color: $underline-color-accent;
|
|
}
|
|
|
|
&.mat-warn {
|
|
color: $underline-color-warn;
|
|
}
|
|
}
|
|
|
|
.mat-focused .mat-form-field-required-marker {
|
|
color: $required-label-color;
|
|
}
|
|
|
|
.mat-form-field-ripple {
|
|
background-color: $underline-color-base;
|
|
}
|
|
|
|
.mat-form-field.mat-focused {
|
|
.mat-form-field-ripple {
|
|
background-color: $underline-focused-color;
|
|
|
|
&.mat-accent {
|
|
background-color: $underline-color-accent;
|
|
}
|
|
|
|
&.mat-warn {
|
|
background-color: $underline-color-warn;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid) {
|
|
.mat-form-field-infix::after {
|
|
color: $underline-focused-color;
|
|
}
|
|
|
|
&.mat-accent .mat-form-field-infix::after {
|
|
color: $underline-color-accent;
|
|
}
|
|
|
|
&.mat-warn .mat-form-field-infix::after {
|
|
color: $underline-color-warn;
|
|
}
|
|
}
|
|
|
|
// Styling for the error state of the form field. Note that while the same can be
|
|
// achieved with the ng-* classes, we use this approach in order to ensure that the same
|
|
// logic is used to style the error state and to show the error messages.
|
|
.mat-form-field.mat-form-field-invalid {
|
|
.mat-form-field-label {
|
|
color: $underline-color-warn;
|
|
|
|
&.mat-accent,
|
|
.mat-form-field-required-marker {
|
|
color: $underline-color-warn;
|
|
}
|
|
}
|
|
|
|
.mat-form-field-ripple,
|
|
.mat-form-field-ripple.mat-accent {
|
|
background-color: $underline-color-warn;
|
|
}
|
|
}
|
|
|
|
.mat-error {
|
|
color: $underline-color-warn;
|
|
}
|
|
|
|
@include mat-form-field-legacy-theme($theme);
|
|
@include mat-form-field-standard-theme($theme);
|
|
@include mat-form-field-fill-theme($theme);
|
|
@include mat-form-field-outline-theme($theme);
|
|
}
|
|
|
|
// Used to make instances of the _mat-form-field-label-floating mixin negligibly different,
|
|
// and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some
|
|
// of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters
|
|
// an unknown pseudo-class it will discard the entire rule set.
|
|
$mat-form-field-dedupe: 0;
|
|
|
|
// Applies a floating label above the form field control itself.
|
|
@mixin _mat-form-field-label-floating($font-scale, $infix-padding, $infix-margin-top) {
|
|
transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-dedupe)
|
|
scale($font-scale);
|
|
width: 100% / $font-scale + $mat-form-field-dedupe;
|
|
|
|
$mat-form-field-dedupe: $mat-form-field-dedupe + 0.00001 !global;
|
|
}
|
|
|
|
@mixin mat-form-field-typography($config) {
|
|
// The unit-less line-height from the font config.
|
|
$line-height: mat-line-height($config, input);
|
|
|
|
// The amount to scale the font for the floating label and subscript.
|
|
$subscript-font-scale: 0.75;
|
|
// The amount to scale the font for the prefix and suffix icons.
|
|
$prefix-suffix-icon-font-scale: 1.5;
|
|
|
|
// The padding on the infix. Mocks show half of the text size.
|
|
$infix-padding: 0.5em;
|
|
// The margin applied to the form-field-infix to reserve space for the floating label.
|
|
$infix-margin-top: 1em * $line-height * $subscript-font-scale;
|
|
// Font size to use for the label and subscript text.
|
|
$subscript-font-size: $subscript-font-scale * 100%;
|
|
// Font size to use for the for the prefix and suffix icons.
|
|
$prefix-suffix-icon-font-size: $prefix-suffix-icon-font-scale * 100%;
|
|
// The space between the bottom of the .mat-form-field-flex area and the subscript wrapper.
|
|
// Mocks show half of the text size, but this margin is applied to an element with the subscript
|
|
// text font size, so we need to divide by the scale factor to make it half of the original text
|
|
// size.
|
|
$subscript-margin-top: 0.5em / $subscript-font-scale;
|
|
// The padding applied to the form-field-wrapper to reserve space for the subscript, since it's
|
|
// absolutely positioned. This is a combination of the subscript's margin and line-height, but we
|
|
// need to multiply by the subscript font scale factor since the wrapper has a larger font size.
|
|
$wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale;
|
|
|
|
.mat-form-field {
|
|
@include mat-typography-level-to-styles($config, input);
|
|
}
|
|
|
|
.mat-form-field-wrapper {
|
|
padding-bottom: $wrapper-padding-bottom;
|
|
}
|
|
|
|
.mat-form-field-prefix,
|
|
.mat-form-field-suffix {
|
|
// Allow icons in a prefix or suffix to adapt to the correct size.
|
|
.mat-icon {
|
|
font-size: $prefix-suffix-icon-font-size;
|
|
line-height: $line-height;
|
|
}
|
|
|
|
// Allow icon buttons in a prefix or suffix to adapt to the correct size.
|
|
.mat-icon-button {
|
|
height: $prefix-suffix-icon-font-scale * 1em;
|
|
width: $prefix-suffix-icon-font-scale * 1em;
|
|
|
|
.mat-icon {
|
|
height: $line-height * 1em;
|
|
line-height: $line-height;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-form-field-infix {
|
|
padding: $infix-padding 0;
|
|
// Throws off the baseline if we do it as a real margin, so we do it as a border instead.
|
|
border-top: $infix-margin-top solid transparent;
|
|
}
|
|
|
|
.mat-form-field-can-float {
|
|
&.mat-form-field-should-float .mat-form-field-label,
|
|
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label {
|
|
@include _mat-form-field-label-floating(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
|
|
// Server-side rendered matInput with a label attribute but label not shown
|
|
// (used as a pure CSS stand-in for mat-form-field-should-float).
|
|
.mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper
|
|
.mat-form-field-label {
|
|
@include _mat-form-field-label-floating(
|
|
$subscript-font-scale, $infix-padding, $infix-margin-top);
|
|
}
|
|
}
|
|
|
|
.mat-form-field-label-wrapper {
|
|
top: -$infix-margin-top;
|
|
padding-top: $infix-margin-top;
|
|
}
|
|
|
|
.mat-form-field-label {
|
|
top: $infix-margin-top + $infix-padding;
|
|
}
|
|
|
|
.mat-form-field-underline {
|
|
// We want the underline to start at the end of the content box, not the padding box,
|
|
// so we move it up by the padding amount.
|
|
bottom: $wrapper-padding-bottom;
|
|
}
|
|
|
|
.mat-form-field-subscript-wrapper {
|
|
font-size: $subscript-font-size;
|
|
margin-top: $subscript-margin-top;
|
|
|
|
// We want the subscript to start at the end of the content box, not the padding box,
|
|
// so we move it up by the padding amount (adjusted for the smaller font size);
|
|
top: calc(100% - #{$wrapper-padding-bottom / $subscript-font-scale});
|
|
}
|
|
|
|
@include mat-form-field-legacy-typography($config);
|
|
@include mat-form-field-standard-typography($config);
|
|
@include mat-form-field-fill-typography($config);
|
|
@include mat-form-field-outline-typography($config);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-tree-theme($theme) {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-tree {
|
|
background: mat-color($background, 'card');
|
|
}
|
|
|
|
.mat-tree-node,
|
|
.mat-nested-tree-node {
|
|
color: mat-color($foreground, text);
|
|
}
|
|
}
|
|
|
|
@mixin mat-tree-typography($config) {
|
|
.mat-tree {
|
|
font-family: mat-font-family($config);
|
|
}
|
|
|
|
.mat-tree-node,
|
|
.mat-nested-tree-node {
|
|
font-weight: mat-font-weight($config, body-1);
|
|
font-size: mat-font-size($config, body-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Includes all of the typographic styles.
|
|
@mixin angular-material-typography($config: null) {
|
|
@if $config == null {
|
|
$config: mat-typography-config();
|
|
}
|
|
|
|
@include mat-badge-typography($config);
|
|
@include mat-base-typography($config);
|
|
@include mat-autocomplete-typography($config);
|
|
@include mat-bottom-sheet-typography($config);
|
|
@include mat-button-typography($config);
|
|
@include mat-button-toggle-typography($config);
|
|
@include mat-card-typography($config);
|
|
@include mat-checkbox-typography($config);
|
|
@include mat-chips-typography($config);
|
|
@include mat-table-typography($config);
|
|
@include mat-datepicker-typography($config);
|
|
@include mat-dialog-typography($config);
|
|
@include mat-expansion-panel-typography($config);
|
|
@include mat-form-field-typography($config);
|
|
@include mat-grid-list-typography($config);
|
|
@include mat-icon-typography($config);
|
|
@include mat-input-typography($config);
|
|
@include mat-menu-typography($config);
|
|
@include mat-paginator-typography($config);
|
|
@include mat-progress-bar-typography($config);
|
|
@include mat-progress-spinner-typography($config);
|
|
@include mat-radio-typography($config);
|
|
@include mat-select-typography($config);
|
|
@include mat-sidenav-typography($config);
|
|
@include mat-slide-toggle-typography($config);
|
|
@include mat-slider-typography($config);
|
|
@include mat-stepper-typography($config);
|
|
@include mat-sort-typography($config);
|
|
@include mat-tabs-typography($config);
|
|
@include mat-toolbar-typography($config);
|
|
@include mat-tooltip-typography($config);
|
|
@include mat-list-typography($config);
|
|
@include mat-option-typography($config);
|
|
@include mat-optgroup-typography($config);
|
|
@include mat-snack-bar-typography($config);
|
|
@include mat-tree-typography($config);
|
|
}
|
|
|
|
|
|
// Mixin that renders all of the core styles that are not theme-dependent.
|
|
@mixin mat-core($typography-config: null) {
|
|
@include angular-material-typography($typography-config);
|
|
@include mat-ripple();
|
|
@include cdk-a11y();
|
|
@include cdk-overlay();
|
|
@include cdk-text-field();
|
|
}
|
|
|
|
// Mixin that renders all of the core styles that depend on the theme.
|
|
@mixin mat-core-theme($theme) {
|
|
@include mat-ripple-theme($theme);
|
|
@include mat-option-theme($theme);
|
|
@include mat-optgroup-theme($theme);
|
|
@include mat-pseudo-checkbox-theme($theme);
|
|
|
|
// Provides external CSS classes for each elevation value. Each CSS class is formatted as
|
|
// `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is
|
|
// elevated.
|
|
@for $zValue from 0 through 24 {
|
|
.#{$_mat-elevation-prefix}#{$zValue} {
|
|
@include _mat-theme-elevation($zValue, $theme);
|
|
}
|
|
}
|
|
|
|
// Wrapper element that provides the theme background when the user's content isn't
|
|
// inside of a `mat-sidenav-container`. Note that we need to exclude the ampersand
|
|
// selector in case the mixin is included at the top level.
|
|
.mat-app-background#{if(&, ', &.mat-app-background', '')} {
|
|
$background: map-get($theme, background);
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
background-color: mat-color($background, background);
|
|
color: mat-color($foreground, text);
|
|
}
|
|
|
|
// Marker that is used to determine whether the user has added a theme to their page.
|
|
@at-root {
|
|
.mat-theme-loaded-marker {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@mixin mat-divider-theme($theme) {
|
|
$foreground: map-get($theme, foreground);
|
|
|
|
.mat-divider {
|
|
border-top-color: mat-color($foreground, divider);
|
|
}
|
|
|
|
.mat-divider-vertical {
|
|
border-right-color: mat-color($foreground, divider);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a theme.
|
|
@mixin angular-material-theme($theme) {
|
|
@include mat-core-theme($theme);
|
|
@include mat-autocomplete-theme($theme);
|
|
@include mat-badge-theme($theme);
|
|
@include mat-bottom-sheet-theme($theme);
|
|
@include mat-button-theme($theme);
|
|
@include mat-button-toggle-theme($theme);
|
|
@include mat-card-theme($theme);
|
|
@include mat-checkbox-theme($theme);
|
|
@include mat-chips-theme($theme);
|
|
@include mat-table-theme($theme);
|
|
@include mat-datepicker-theme($theme);
|
|
@include mat-dialog-theme($theme);
|
|
@include mat-divider-theme($theme);
|
|
@include mat-expansion-panel-theme($theme);
|
|
@include mat-form-field-theme($theme);
|
|
@include mat-grid-list-theme($theme);
|
|
@include mat-icon-theme($theme);
|
|
@include mat-input-theme($theme);
|
|
@include mat-list-theme($theme);
|
|
@include mat-menu-theme($theme);
|
|
@include mat-paginator-theme($theme);
|
|
@include mat-progress-bar-theme($theme);
|
|
@include mat-progress-spinner-theme($theme);
|
|
@include mat-radio-theme($theme);
|
|
@include mat-select-theme($theme);
|
|
@include mat-sidenav-theme($theme);
|
|
@include mat-slide-toggle-theme($theme);
|
|
@include mat-slider-theme($theme);
|
|
@include mat-stepper-theme($theme);
|
|
@include mat-sort-theme($theme);
|
|
@include mat-tabs-theme($theme);
|
|
@include mat-toolbar-theme($theme);
|
|
@include mat-tooltip-theme($theme);
|
|
@include mat-tree-theme($theme);
|
|
@include mat-snack-bar-theme($theme);
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\custom-effects.scss
|
|
|
|
//
|
|
button:hover:not([disabled]),
|
|
ion-button:hover:not([disabled]) {
|
|
@include animation("flash", 1500ms);
|
|
}
|
|
|
|
.picker-opt-disabled {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.action-sheet-cancel,
|
|
.action-sheet-setructive,
|
|
.action-sheet-group-cancel {
|
|
color: var(--x-color-danger) !important;
|
|
}
|
|
|
|
//
|
|
// Dialog Theme ...
|
|
::ng-deep.mat-card,
|
|
::ng-deep.mat-expansion-panel,
|
|
::ng-deep.mat-dialog-container {
|
|
color: var(--x-color-light-contrast);
|
|
background-color: var(--x-color-light);
|
|
}
|
|
|
|
::ng-deep.full-with {
|
|
.x-wrapper {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.full-with {
|
|
width: 100%;
|
|
}
|
|
|
|
.x-minimal-popover {
|
|
.popover-content {
|
|
width: 90px !important;
|
|
max-width: 90px !important;
|
|
}
|
|
}
|
|
|
|
.dynamic-slot {
|
|
flex: 0 auto !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\fab-theme.scss
|
|
|
|
//
|
|
//#region Fab ...
|
|
$isRTL: var(--is-rtl);
|
|
$fabMargin: 16px;
|
|
|
|
x-fab[pageFab] {
|
|
//
|
|
ion-fab {
|
|
//
|
|
@if $isRTL {
|
|
left: $fabMargin !important;
|
|
right: auto !important;
|
|
} @else {
|
|
right: $fabMargin !important;
|
|
left: auto !important;
|
|
}
|
|
|
|
//
|
|
position: fixed !important;
|
|
margin-top: calc(var(--content-offset-bottom) * -1);
|
|
margin-bottom: calc(var(--content-offset-bottom) * -1);
|
|
|
|
//
|
|
transition: transform 250ms ease 0s, opacity 250ms ease 0s;
|
|
}
|
|
|
|
//
|
|
&.start-scroll {
|
|
ion-fab {
|
|
transform: translateY(200px) scale3d(0, 0, 0) !important;
|
|
}
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\markdown-theme.scss
|
|
|
|
/**
|
|
* MIT License
|
|
* Copyright (c) 2021 Ayush Saini
|
|
* Holi Theme for prism.js
|
|
* @author Ayush Saini <@AyushCodes on Twitter>
|
|
*/
|
|
|
|
code[class*='language-'],
|
|
pre[class*='language-'] {
|
|
color: #d6e7ff;
|
|
background: #030314;
|
|
text-shadow: none;
|
|
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
|
font-size: 1em;
|
|
line-height: 1.5;
|
|
letter-spacing: .2px;
|
|
white-space: pre;
|
|
word-spacing: normal;
|
|
word-break: normal;
|
|
word-wrap: normal;
|
|
text-align: left;
|
|
|
|
-moz-tab-size: 4;
|
|
-o-tab-size: 4;
|
|
tab-size: 4;
|
|
|
|
-webkit-hyphens: none;
|
|
-moz-hyphens: none;
|
|
-ms-hyphens: none;
|
|
hyphens: none;
|
|
}
|
|
|
|
pre[class*='language-']::-moz-selection,
|
|
pre[class*='language-'] ::-moz-selection,
|
|
code[class*='language-']::-moz-selection,
|
|
code[class*='language-'] ::-moz-selection,
|
|
pre[class*='language-']::selection,
|
|
pre[class*='language-'] ::selection,
|
|
code[class*='language-']::selection,
|
|
code[class*='language-'] ::selection {
|
|
color: inherit;
|
|
background: #1d3b54;
|
|
text-shadow: none;
|
|
}
|
|
|
|
pre[class*='language-'] {
|
|
border: 1px solid #2a4555;
|
|
border-radius: 5px;
|
|
padding: 1.5em 1em;
|
|
margin: 1em 0;
|
|
overflow: auto;
|
|
}
|
|
|
|
:not(pre) > code[class*='language-'] {
|
|
color: #f0f6f6;
|
|
background: #2a4555;
|
|
padding: 0.2em 0.3em;
|
|
border-radius: 0.2em;
|
|
box-decoration-break: clone;
|
|
}
|
|
|
|
.token.comment,
|
|
.token.prolog,
|
|
.token.doctype,
|
|
.token.cdata {
|
|
color: #446e69;
|
|
}
|
|
|
|
.token.punctuation {
|
|
color: #d6b007;
|
|
}
|
|
|
|
.token.property,
|
|
.token.tag,
|
|
.token.boolean,
|
|
.token.number,
|
|
.token.constant,
|
|
.token.symbol,
|
|
.token.deleted {
|
|
color: #d6e7ff;
|
|
}
|
|
|
|
.token.selector,
|
|
.token.attr-name,
|
|
.token.builtin,
|
|
.token.inserted {
|
|
color: #e60067;
|
|
}
|
|
|
|
.token.string,
|
|
.token.char {
|
|
color: #49c6ec;
|
|
}
|
|
|
|
.token.operator,
|
|
.token.entity,
|
|
.token.url,
|
|
.language-css .token.string,
|
|
.style .token.string {
|
|
color: #ec8e01;
|
|
background: transparent;
|
|
}
|
|
|
|
.token.atrule,
|
|
.token.attr-value,
|
|
.token.keyword {
|
|
color: #0fe468;
|
|
}
|
|
|
|
.token.function,
|
|
.token.class-name {
|
|
color: #78f3e9;
|
|
}
|
|
|
|
.token.regex,
|
|
.token.important,
|
|
.token.variable {
|
|
color: #d6e7ff;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\material-fonts.scss
|
|
|
|
//
|
|
//#region Material Fonts ...
|
|
/* cyrillic-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fCRc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
|
|
U+FE2E-FE2F;
|
|
}
|
|
/* cyrillic */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fABc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
}
|
|
/* greek-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fCBc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+1F00-1FFF;
|
|
}
|
|
/* greek */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fBxc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0370-03FF;
|
|
}
|
|
/* vietnamese */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fCxc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
|
}
|
|
/* latin-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
|
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
/* latin */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: local("Roboto Light"), local("Roboto-Light"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
|
U+FEFF, U+FFFD;
|
|
}
|
|
/* Persian */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 300;
|
|
src: url("../assets/font/irsans.ttf");
|
|
unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A,
|
|
U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632,
|
|
U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A,
|
|
U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647,
|
|
U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698,
|
|
U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667,
|
|
U+0668, U+0669, U+064A, U+0643;
|
|
}
|
|
|
|
/* cyrillic-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
|
|
U+FE2E-FE2F;
|
|
}
|
|
/* cyrillic */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
}
|
|
/* greek-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+1F00-1FFF;
|
|
}
|
|
/* greek */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0370-03FF;
|
|
}
|
|
/* vietnamese */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
|
}
|
|
/* latin-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
|
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
/* latin */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: local("Roboto"), local("Roboto-Regular"),
|
|
url("../assets/font/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
|
U+FEFF, U+FFFD;
|
|
}
|
|
/* Persian */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: url("../assets/font/irsans.ttf");
|
|
unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A,
|
|
U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632,
|
|
U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A,
|
|
U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647,
|
|
U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698,
|
|
U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667,
|
|
U+0668, U+0669, U+064A, U+0643;
|
|
}
|
|
|
|
|
|
/* cyrillic-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fCRc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
|
|
U+FE2E-FE2F;
|
|
}
|
|
/* cyrillic */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
}
|
|
/* greek-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fCBc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+1F00-1FFF;
|
|
}
|
|
/* greek */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0370-03FF;
|
|
}
|
|
/* vietnamese */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
|
}
|
|
/* latin-ext */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
|
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
/* latin */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: local("Roboto Medium"), local("Roboto-Medium"),
|
|
url("../assets/font/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2")
|
|
format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
|
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
|
U+FEFF, U+FFFD;
|
|
}
|
|
/* Persian */
|
|
@font-face {
|
|
font-family: "Roboto";
|
|
font-style: normal;
|
|
font-weight: 500;
|
|
src: url("../assets/font/irsans.ttf");
|
|
unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A,
|
|
U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632,
|
|
U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A,
|
|
U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647,
|
|
U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698,
|
|
U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667,
|
|
U+0668, U+0669, U+064A, U+0643;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Material Design Icons ...
|
|
@font-face {
|
|
font-family: "Material Icons";
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: url("../assets/font/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2")
|
|
format("woff2");
|
|
}
|
|
|
|
.material-icons {
|
|
font-family: "Material Icons";
|
|
font-weight: normal;
|
|
font-style: normal;
|
|
font-size: 24px;
|
|
line-height: 1;
|
|
letter-spacing: normal;
|
|
text-transform: none;
|
|
display: inline-block;
|
|
white-space: nowrap;
|
|
word-wrap: normal;
|
|
direction: ltr;
|
|
-webkit-font-feature-settings: "liga";
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
//#endregion
|
|
|
|
|
|
@mixin x-toolbar-typography($config) {
|
|
.mat-toolbar {
|
|
@include mat-typography-level-to-styles($config, body-2);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h1 {
|
|
@include mat-typography-level-to-styles($config, headline);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h2 {
|
|
@include mat-typography-level-to-styles($config, title);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h3 {
|
|
@include mat-typography-level-to-styles($config, subheading-2);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h4 {
|
|
@include mat-typography-level-to-styles($config, subheading-1);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h5 {
|
|
@include mat-typography-level-to-styles($config, body-1);
|
|
margin: 0;
|
|
}
|
|
|
|
.mat-toolbar h6 {
|
|
@include mat-typography-level-to-styles($config, caption);
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
|
|
body {
|
|
@extend .mat-typography;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\material-icons.scss
|
|
|
|
@font-face {
|
|
font-family: 'Material Icons';
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
src: url('../assets/font/MaterialIcons-Regular.eot'); /* For IE6-8 */
|
|
src: local('Material Icons'), local('MaterialIcons-Regular'),
|
|
url('../assets/font/MaterialIcons-Regular.woff2') format('woff2'),
|
|
url('../assets/font/MaterialIcons-Regular.woff') format('woff'),
|
|
url('../assets/font/MaterialIcons-Regular.ttf') format('truetype');
|
|
}
|
|
|
|
.material-icons {
|
|
font-family: 'Material Icons';
|
|
font-weight: normal;
|
|
font-style: normal;
|
|
font-size: 24px; /* Preferred icon size */
|
|
display: inline-block;
|
|
line-height: 1;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
word-wrap: normal;
|
|
white-space: nowrap;
|
|
direction: ltr;
|
|
|
|
/* Support for all WebKit browsers. */
|
|
-webkit-font-smoothing: antialiased;
|
|
/* Support for Safari and Chrome. */
|
|
text-rendering: optimizeLegibility;
|
|
|
|
/* Support for Firefox. */
|
|
-moz-osx-font-smoothing: grayscale;
|
|
|
|
/* Support for IE. */
|
|
font-feature-settings: 'liga';
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\theme.scss
|
|
|
|
@import "./base-theme.scss";
|
|
@import "./material-icons.scss";
|
|
@import "./material-fonts.scss";
|
|
@import "./markdown-theme.scss";
|
|
@import "./fab-theme.scss";
|
|
|
|
@include mat-core();
|
|
|
|
$x-primary: mat-palette($mat-blue);
|
|
$x-accent: mat-palette($mat-cyan);
|
|
$x-warn: mat-palette($mat-red);
|
|
|
|
// Create the theme object (a Sass map containing all of the palettes).
|
|
$x-theme: mat-light-theme($x-primary, $x-accent, $x-warn);
|
|
@include angular-material-theme($x-theme);
|
|
|
|
//
|
|
@function generate-x-theme($primary, $accent, $warn) {
|
|
//
|
|
$x-primary: $primary;
|
|
$x-accent: $accent;
|
|
$x-warn: $warn;
|
|
|
|
//
|
|
$x-theme: mat-light-theme($primary, $accent, $warn);
|
|
|
|
//
|
|
@return $x-theme;
|
|
}
|
|
|
|
//
|
|
@mixin x-theme($theme) {
|
|
@include angular-material-theme($theme);
|
|
}
|
|
|
|
//
|
|
@mixin x-ion-color() {
|
|
//
|
|
// XFramework Color Mechanism ...
|
|
:root {
|
|
--x-color-primary: var(--ion-color-primary);
|
|
--x-color-primary-shade: var(--ion-color-primary-shade);
|
|
--x-color-primary-tint: var(--ion-color-primary-tint);
|
|
|
|
--x-color-secondary: var(--ion-color-secondary);
|
|
--x-color-secondary-shade: var(--ion-color-secondary-shade);
|
|
--x-color-secondary-tint: var(--ion-color-secondary-tint);
|
|
|
|
--x-color-tertiary: var(--ion-color-tertiary);
|
|
--x-color-tertiary-shade: var(--ion-color-tertiary-shade);
|
|
--x-color-tertiary-tint: var(--ion-color-tertiary-tint);
|
|
|
|
--x-color-success: var(--ion-color-success);
|
|
--x-color-success-shade: var(--ion-color-success-shade);
|
|
--x-color-success-tint: var(--ion-color-success-tint);
|
|
|
|
--x-color-warning: var(--ion-color-warning);
|
|
--x-color-warning-shade: var(--ion-color-warning-shade);
|
|
--x-color-warning-tint: var(--ion-color-warning-tint);
|
|
|
|
--x-color-danger: var(--ion-color-danger);
|
|
--x-color-danger-shade: var(--ion-color-danger-shade);
|
|
--x-color-danger-tint: var(--ion-color-danger-tint);
|
|
|
|
--x-color-dark: var(--ion-color-dark);
|
|
--x-color-dark-shade: var(--ion-color-dark-shade);
|
|
--x-color-dark-tint: var(--ion-color-dark-tint);
|
|
|
|
--x-color-medium: var(--ion-color-medium);
|
|
--x-color-medium-shade: var(--ion-color-medium-shade);
|
|
--x-color-medium-tint: var(--ion-color-medium-tint);
|
|
|
|
--x-color-light: var(--ion-color-light);
|
|
--x-color-light-shade: var(--ion-color-light-shade);
|
|
--x-color-light-tint: var(--ion-color-light-tint);
|
|
|
|
--x-color-primary-contrast: var(--ion-color-primary-contrast);
|
|
--x-color-primary-shade-contrast: var(--ion-color-primary-contrast);
|
|
--x-color-primary-tint-contrast: var(--ion-color-primary-contrast);
|
|
|
|
--x-color-secondary-contrast: var(--ion-color-secondary-contrast);
|
|
--x-color-secondary-shade-contrast: var(--ion-color-secondary-contrast);
|
|
--x-color-secondary-tint-contrast: var(--ion-color-secondary-contrast);
|
|
|
|
--x-color-tertiary-contrast: var(--ion-color-tertiary-contrast);
|
|
--x-color-tertiary-shade-contrast: var(--ion-color-tertiary-contrast);
|
|
--x-color-tertiary-tint-contrast: var(--ion-color-tertiary-contrast);
|
|
|
|
--x-color-success-contrast: var(--ion-color-success-contrast);
|
|
--x-color-success-shade-contrast: var(--ion-color-success-contrast);
|
|
--x-color-success-tint-contrast: var(--ion-color-success-contrast);
|
|
|
|
--x-color-warning-contrast: var(--ion-color-warning-contrast);
|
|
--x-color-warning-shade-contrast: var(--ion-color-warning-contrast);
|
|
--x-color-warning-tint-contrast: var(--ion-color-warning-contrast);
|
|
|
|
--x-color-danger-contrast: var(--ion-color-danger-contrast);
|
|
--x-color-danger-shade-contrast: var(--ion-color-danger-contrast);
|
|
--x-color-danger-tint-contrast: var(--ion-color-danger-contrast);
|
|
|
|
--x-color-dark-contrast: var(--ion-color-dark-contrast);
|
|
--x-color-dark-shade-contrast: var(--ion-color-dark-contrast);
|
|
--x-color-dark-tint-contrast: var(--ion-color-dark-contrast);
|
|
|
|
--x-color-medium-contrast: var(--ion-color-medium-contrast);
|
|
--x-color-medium-shade-contrast: var(--ion-color-medium-contrast);
|
|
--x-color-medium-tint-contrast: var(--ion-color-medium-contrast);
|
|
|
|
--x-color-light-contrast: var(--ion-color-light-contrast);
|
|
--x-color-light-shade-contrast: var(--ion-color-light-contrast);
|
|
--x-color-light-tint-contras: var(--ion-color-light-contrast);
|
|
}
|
|
|
|
//
|
|
// Define a Palette Based on Collection ...
|
|
$m-color-palette: mat-palette($m-color-collection, m-ionic);
|
|
|
|
//
|
|
// Merge Defined Palette to Theme Object ...
|
|
$x-theme: map_merge(
|
|
$x-theme,
|
|
(
|
|
m-ionic: $m-color-palette,
|
|
)
|
|
);
|
|
|
|
//
|
|
// Generate a General Object for feauture Usages ...
|
|
$x-ionic: map-get($x-theme, m-ionic);
|
|
}
|
|
|
|
//
|
|
@mixin x-to-ion-color() {
|
|
//
|
|
// XFramework Color Mechanism ...
|
|
:root {
|
|
--ion-color-primary: var(--x-color-primary);
|
|
--ion-color-primary-shade: var(--x-color-primary-shade);
|
|
--ion-color-primary-tint: var(--x-color-primary-tint);
|
|
|
|
--ion-color-primary-contrast: var(--x-color-primary-contrast);
|
|
--ion-color-primary-contrast: var(--x-color-primary-contrast);
|
|
--ion-color-primary-contrast: var(--x-color-primary-contrast);
|
|
|
|
--ion-color-secondary: var(--x-color-secondary);
|
|
--ion-color-secondary-shade: var(--x-color-secondary-shade);
|
|
--ion-color-secondary-tint: var(--x-color-secondary-tint);
|
|
|
|
--ion-color-secondary-contrast: var(--x-color-secondary-contrast);
|
|
--ion-color-secondary-contrast: var(--x-color-secondary-contrast);
|
|
--ion-color-secondary-contrast: var(--x-color-secondary-contrast);
|
|
|
|
--ion-color-tertiary: var(--x-color-tertiary);
|
|
--ion-color-tertiary-shade: var(--x-color-tertiary-shade);
|
|
--ion-color-tertiary-tint: var(--x-color-tertiary-tint);
|
|
|
|
--ion-color-tertiary-contrast: var(--x-color-tertiary-contrast);
|
|
--ion-color-tertiary-contrast: var(--x-color-tertiary-contrast);
|
|
--ion-color-tertiary-contrast: var(--x-color-tertiary-contrast);
|
|
|
|
--ion-color-success: var(--x-color-success);
|
|
--ion-color-success-shade: var(--x-color-success-shade);
|
|
--ion-color-success-tint: var(--x-color-success-tint);
|
|
|
|
--ion-color-success-contrast: var(--x-color-success-contrast);
|
|
--ion-color-success-contrast: var(--x-color-success-contrast);
|
|
--ion-color-success-contrast: var(--x-color-success-contrast);
|
|
|
|
--ion-color-warning: var(--x-color-warning);
|
|
--ion-color-warning-shade: var(--x-color-warning-shade);
|
|
--ion-color-warning-tint: var(--x-color-warning-tint);
|
|
|
|
--ion-color-warning-contrast: var(--x-color-warning-contrast);
|
|
--ion-color-warning-contrast: var(--x-color-warning-contrast);
|
|
--ion-color-warning-contrast: var(--x-color-warning-contrast);
|
|
|
|
--ion-color-danger: var(--x-color-danger);
|
|
--ion-color-danger-shade: var(--x-color-danger-shade);
|
|
--ion-color-danger-tint: var(--x-color-danger-tint);
|
|
|
|
--ion-color-danger-contrast: var(--x-color-danger-contrast);
|
|
--ion-color-danger-contrast: var(--x-color-danger-contrast);
|
|
--ion-color-danger-contrast: var(--x-color-danger-contrast);
|
|
|
|
--ion-color-dark: var(--x-color-dark);
|
|
--ion-color-dark-shade: var(--x-color-dark-shade);
|
|
--ion-color-dark-tint: var(--x-color-dark-tint);
|
|
|
|
--ion-color-dark-contrast: var(--x-color-dark-contrast);
|
|
--ion-color-dark-contrast: var(--x-color-dark-contrast);
|
|
--ion-color-dark-contrast: var(--x-color-dark-contrast);
|
|
|
|
--ion-color-medium: var(--x-color-medium);
|
|
--ion-color-medium-shade: var(--x-color-medium-shade);
|
|
--ion-color-medium-tint: var(--x-color-medium-tint);
|
|
|
|
--ion-color-medium-contrast: var(--x-color-medium-contrast);
|
|
--ion-color-medium-contrast: var(--x-color-medium-contrast);
|
|
--ion-color-medium-contrast: var(--x-color-medium-contrast);
|
|
|
|
--ion-color-light: var(--x-color-light);
|
|
--ion-color-light-shade: var(--x-color-light-shade);
|
|
--ion-color-light-tint: var(--x-color-light-tint);
|
|
|
|
--ion-color-light-contrast: var(--x-color-light-contrast);
|
|
--ion-color-light-contrast: var(--x-color-light-contrast);
|
|
--ion-color-light-contrast: var(--x-color-light-contrast);
|
|
}
|
|
|
|
//
|
|
// Define a Palette Based on Collection ...
|
|
$m-color-palette: mat-palette($m-color-collection, m-ionic);
|
|
|
|
//
|
|
// Merge Defined Palette to Theme Object ...
|
|
$x-theme: map_merge(
|
|
$x-theme,
|
|
(
|
|
m-ionic: $m-color-palette,
|
|
)
|
|
);
|
|
|
|
//
|
|
// Generate a General Object for feauture Usages ...
|
|
$x-ionic: map-get($x-theme, m-ionic);
|
|
}
|
|
|
|
//
|
|
//#region Custom Ionic Based Colors ...
|
|
|
|
//
|
|
//#region Define a Collection ...
|
|
$m-color-collection: (
|
|
primary: var(--x-color-primary),
|
|
primary-shade: var(--x-color-primary-shade),
|
|
primary-tint: var(--x-color-primary-tint),
|
|
secondary: var(--x-color-secondary),
|
|
secondary-shade: var(--x-color-secondary-shade),
|
|
secondary-tint: var(--x-color-secondary-tint),
|
|
tertiary: var(--x-color-tertiary),
|
|
tertiary-shade: var(--x-color-tertiary-shade),
|
|
tertiary-tint: var(--x-color-tertiary-tint),
|
|
success: var(--x-color-success),
|
|
success-shade: var(--x-color-success-shade),
|
|
success-tint: var(--x-color-success-tint),
|
|
warning: var(--x-color-warning),
|
|
warning-shade: var(--x-color-warning-shade),
|
|
warning-tint: var(--x-color-warning-tint),
|
|
danger: var(--x-color-danger),
|
|
danger-shade: var(--x-color-danger-shade),
|
|
danger-tint: var(--x-color-danger-tint),
|
|
dark: var(--x-color-dark),
|
|
dark-shade: var(--x-color-dark-shade),
|
|
dark-tint: var(--x-color-dark-tint),
|
|
medium: var(--x-color-medium),
|
|
medium-shade: var(--x-color-medium-shade),
|
|
medium-tint: var(--x-color-medium-tint),
|
|
light: var(--x-color-light),
|
|
light-shade: var(--x-color-light-shade),
|
|
light-tint: var(--x-color-light-tint),
|
|
contrast: (
|
|
primary: var(--x-color-primary-contrast),
|
|
primary-shade: var(--x-color-primary-shade-contrast),
|
|
primary-tint: var(--x-color-primary-tint-contrast),
|
|
secondary: var(--x-color-secondary-contrast),
|
|
secondary-shade: var(--x-color-secondary-shade-contrast),
|
|
secondary-tint: var(--x-color-secondary-tint-contrast),
|
|
tertiary: var(--x-color-tertiary-contrast),
|
|
tertiary-shade: var(--x-color-tertiary-shade-contrast),
|
|
tertiary-tint: var(--x-color-tertiary-tint-contrast),
|
|
success: var(--x-color-success-contrast),
|
|
success-shade: var(--x-color-success-shade-contrast),
|
|
success-tint: var(--x-color-success-tint-contrast),
|
|
warning: var(--x-color-warning-contrast),
|
|
warning-shade: var(--x-color-warning-shade-contrast),
|
|
warning-tint: var(--x-color-warning-tint-contrast),
|
|
danger: var(--x-color-danger-contrast),
|
|
danger-shade: var(--x-color-danger-shade-contrast),
|
|
danger-tint: var(--x-color-danger-tint-contrast),
|
|
dark: var(--x-color-dark-contrast),
|
|
dark-shade: var(--x-color-dark-shade-contrast),
|
|
dark-tint: var(--x-color-dark-tint-contrast),
|
|
medium: var(--x-color-medium-contrast),
|
|
medium-shade: var(--x-color-medium-shade-contrast),
|
|
medium-tint: var(--x-color-medium-tint-contrast),
|
|
light: var(--x-color-light-contrast),
|
|
light-shade: var(--x-color-light-shade-contrast),
|
|
light-tint: var(--x-color-light-tint-contrast),
|
|
),
|
|
);
|
|
//#endregion
|
|
|
|
//
|
|
// Define a Palette Based on Collection ...
|
|
$m-color-palette: mat-palette($m-color-collection, m-ionic);
|
|
|
|
//
|
|
// Merge Defined Palette to Theme Object ...
|
|
$x-theme: map_merge(
|
|
$x-theme,
|
|
(
|
|
m-ionic: $m-color-palette,
|
|
)
|
|
);
|
|
|
|
//
|
|
// Generate a General Object for feauture Usages ...
|
|
$x-ionic: map-get($x-theme, m-ionic);
|
|
|
|
//
|
|
//#region Generate General Classes for Support these Colors ...
|
|
//
|
|
//#region Primary ...
|
|
.mat-primary {
|
|
//
|
|
color: mat-color($x-ionic, primary-contrast) !important;
|
|
background-color: mat-color($x-ionic, primary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary-contrast) !important;
|
|
--background: mat-color($x-ionic, primary) !important;
|
|
}
|
|
|
|
.mat-primary-shade {
|
|
//
|
|
color: mat-color($x-ionic, primary-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, primary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, primary-shade) !important;
|
|
}
|
|
|
|
.mat-primary-tint {
|
|
//
|
|
color: mat-color($x-ionic, primary-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, primary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, primary-tint) !important;
|
|
}
|
|
|
|
.c-primary {
|
|
//
|
|
color: mat-color($x-ionic, primary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary) !important;
|
|
}
|
|
|
|
.c-primary-shade {
|
|
//
|
|
color: mat-color($x-ionic, primary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary-shade) !important;
|
|
}
|
|
|
|
.c-primary-tint {
|
|
//
|
|
color: mat-color($x-ionic, primary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, primary-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Secondary ...
|
|
.mat-secondary {
|
|
//
|
|
color: mat-color($x-ionic, secondary-contrast) !important;
|
|
background-color: mat-color($x-ionic, secondary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary-contrast) !important;
|
|
--background: mat-color($x-ionic, secondary) !important;
|
|
}
|
|
|
|
.mat-secondary-shade {
|
|
//
|
|
color: mat-color($x-ionic, secondary-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, secondary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, secondary-shade) !important;
|
|
}
|
|
|
|
.mat-secondary-tint {
|
|
//
|
|
color: mat-color($x-ionic, secondary-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, secondary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, secondary-tint) !important;
|
|
}
|
|
|
|
.c-secondary {
|
|
//
|
|
color: mat-color($x-ionic, secondary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary) !important;
|
|
}
|
|
|
|
.c-secondary-shade {
|
|
//
|
|
color: mat-color($x-ionic, secondary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary-shade) !important;
|
|
}
|
|
|
|
.c-secondary-tint {
|
|
//
|
|
color: mat-color($x-ionic, secondary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, secondary-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tertiary ...
|
|
.mat-tertiary {
|
|
//
|
|
color: mat-color($x-ionic, tertiary-contrast) !important;
|
|
background-color: mat-color($x-ionic, tertiary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary-contrast) !important;
|
|
--background: mat-color($x-ionic, tertiary) !important;
|
|
}
|
|
|
|
.mat-tertiary-shade {
|
|
//
|
|
color: mat-color($x-ionic, tertiary-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, tertiary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, tertiary-shade) !important;
|
|
}
|
|
|
|
.mat-tertiary-tint {
|
|
//
|
|
color: mat-color($x-ionic, tertiary-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, tertiary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, tertiary-tint) !important;
|
|
}
|
|
|
|
.c-tertiary {
|
|
//
|
|
color: mat-color($x-ionic, tertiary) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary) !important;
|
|
}
|
|
|
|
.c-tertiary-shade {
|
|
//
|
|
color: mat-color($x-ionic, tertiary-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary-shade) !important;
|
|
}
|
|
|
|
.c-tertiary-tint {
|
|
//
|
|
color: mat-color($x-ionic, tertiary-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, tertiary-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Success ...
|
|
.mat-success {
|
|
//
|
|
color: mat-color($x-ionic, success-contrast) !important;
|
|
background-color: mat-color($x-ionic, success) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success-contrast) !important;
|
|
--background: mat-color($x-ionic, success) !important;
|
|
}
|
|
|
|
.mat-success-shade {
|
|
//
|
|
color: mat-color($x-ionic, success-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, success-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, success-shade) !important;
|
|
}
|
|
|
|
.mat-success-tint {
|
|
//
|
|
color: mat-color($x-ionic, success-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, success-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, success-tint) !important;
|
|
}
|
|
|
|
.c-success {
|
|
//
|
|
color: mat-color($x-ionic, success) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success) !important;
|
|
}
|
|
|
|
.c-success-shade {
|
|
//
|
|
color: mat-color($x-ionic, success-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success-shade) !important;
|
|
}
|
|
|
|
.c-success-tint {
|
|
//
|
|
color: mat-color($x-ionic, success-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, success-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Warning ...
|
|
.mat-warning {
|
|
//
|
|
color: mat-color($x-ionic, warning-contrast) !important;
|
|
background-color: mat-color($x-ionic, warning) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning-contrast) !important;
|
|
--background: mat-color($x-ionic, warning) !important;
|
|
}
|
|
|
|
.mat-warning-shade {
|
|
//
|
|
color: mat-color($x-ionic, warning-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, warning-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, warning-shade) !important;
|
|
}
|
|
|
|
.mat-warning-tint {
|
|
//
|
|
color: mat-color($x-ionic, warning-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, warning-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, warning-tint) !important;
|
|
}
|
|
|
|
.c-warning {
|
|
//
|
|
color: mat-color($x-ionic, warning) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning) !important;
|
|
}
|
|
|
|
.c-warning-shade {
|
|
//
|
|
color: mat-color($x-ionic, warning-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning-shade) !important;
|
|
}
|
|
|
|
.c-warning-tint {
|
|
//
|
|
color: mat-color($x-ionic, warning-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, warning-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Danger ...
|
|
.mat-danger {
|
|
//
|
|
color: mat-color($x-ionic, danger-contrast) !important;
|
|
background-color: mat-color($x-ionic, danger) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger-contrast) !important;
|
|
--background: mat-color($x-ionic, danger) !important;
|
|
}
|
|
|
|
.mat-danger-shade {
|
|
//
|
|
color: mat-color($x-ionic, danger-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, danger-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, danger-shade) !important;
|
|
}
|
|
|
|
.mat-danger-tint {
|
|
//
|
|
color: mat-color($x-ionic, danger-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, danger-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, danger-tint) !important;
|
|
}
|
|
|
|
.c-danger {
|
|
//
|
|
color: mat-color($x-ionic, danger) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger) !important;
|
|
}
|
|
|
|
.c-danger-shade {
|
|
//
|
|
color: mat-color($x-ionic, danger-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger-shade) !important;
|
|
}
|
|
|
|
.c-danger-tint {
|
|
//
|
|
color: mat-color($x-ionic, danger-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, danger-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Dark ...
|
|
.mat-dark {
|
|
//
|
|
color: mat-color($x-ionic, dark-contrast) !important;
|
|
background-color: mat-color($x-ionic, dark) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark-contrast) !important;
|
|
--background: mat-color($x-ionic, dark) !important;
|
|
}
|
|
|
|
.mat-dark-shade {
|
|
//
|
|
color: mat-color($x-ionic, dark-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, dark-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, dark-shade) !important;
|
|
}
|
|
|
|
.mat-dark-tint {
|
|
//
|
|
color: mat-color($x-ionic, dark-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, dark-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, dark-tint) !important;
|
|
}
|
|
|
|
.c-dark {
|
|
//
|
|
color: mat-color($x-ionic, dark) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark) !important;
|
|
}
|
|
|
|
.c-dark-shade {
|
|
//
|
|
color: mat-color($x-ionic, dark-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark-shade) !important;
|
|
}
|
|
|
|
.c-dark-tint {
|
|
//
|
|
color: mat-color($x-ionic, dark-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, dark-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Medium ...
|
|
.mat-medium {
|
|
//
|
|
color: mat-color($x-ionic, medium-contrast) !important;
|
|
background-color: mat-color($x-ionic, medium) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium-contrast) !important;
|
|
--background: mat-color($x-ionic, medium) !important;
|
|
}
|
|
|
|
.mat-medium-shade {
|
|
//
|
|
color: mat-color($x-ionic, medium-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, medium-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, medium-shade) !important;
|
|
}
|
|
|
|
.mat-medium-tint {
|
|
//
|
|
color: mat-color($x-ionic, medium-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, medium-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, medium-tint) !important;
|
|
}
|
|
|
|
.c-medium {
|
|
//
|
|
color: mat-color($x-ionic, medium) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium) !important;
|
|
}
|
|
|
|
.c-medium-shade {
|
|
//
|
|
color: mat-color($x-ionic, medium-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium-shade) !important;
|
|
}
|
|
|
|
.c-medium-tint {
|
|
//
|
|
color: mat-color($x-ionic, medium-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, medium-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Light ...
|
|
.mat-light {
|
|
//
|
|
color: mat-color($x-ionic, light-contrast) !important;
|
|
background-color: mat-color($x-ionic, light) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light-contrast) !important;
|
|
--background: mat-color($x-ionic, light) !important;
|
|
}
|
|
|
|
.mat-light-shade {
|
|
//
|
|
color: mat-color($x-ionic, light-shade-contrast) !important;
|
|
background-color: mat-color($x-ionic, light-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light-shade-contrast) !important;
|
|
--background: mat-color($x-ionic, light-shade) !important;
|
|
}
|
|
|
|
.mat-light-tint {
|
|
//
|
|
color: mat-color($x-ionic, light-tint-contrast) !important;
|
|
background-color: mat-color($x-ionic, light-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light-tint-contrast) !important;
|
|
--background: mat-color($x-ionic, light-tint) !important;
|
|
}
|
|
|
|
.c-light {
|
|
//
|
|
color: mat-color($x-ionic, light) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light) !important;
|
|
}
|
|
|
|
.c-light-shade {
|
|
//
|
|
color: mat-color($x-ionic, light-shade) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light-shade) !important;
|
|
}
|
|
|
|
.c-light-tint {
|
|
//
|
|
color: mat-color($x-ionic, light-tint) !important;
|
|
|
|
//
|
|
--color: mat-color($x-ionic, light-tint) !important;
|
|
}
|
|
|
|
//#endregion
|
|
//#endregion
|
|
|
|
.cb-inherit {
|
|
//
|
|
color: inherit !important;
|
|
--color: inherit !important;
|
|
|
|
//
|
|
background-color: inherit !important;
|
|
--background-color: inherit !important;
|
|
}
|
|
|
|
.transparent {
|
|
--background: transparent !important;
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Custom Styles ...
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow-x: hidden;
|
|
font-family: Roboto, "Helvetica Neue", sans-serif;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
*::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
@import "_tools";
|
|
|
|
//
|
|
// Since here we must able to use all Capabilities,
|
|
// so we import this at the end ...
|
|
@import "./custom-effects.scss";
|
|
|
|
//
|
|
// Implement to ionic them ...
|
|
@include x-to-ion-color();
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\tokens\x-injectable-tokens.ts
|
|
|
|
import { InjectionToken } from '@angular/core';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export const X_FRAMEWORK_COMPONENTS_CONFIG = new InjectionToken<
|
|
XFrameworkComponentsConfig
|
|
>('x_config');
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.html
|
|
|
|
<ion-toolbar
|
|
class="x-actions-bar x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
*ngIf="hasChild(preparedActions)"
|
|
[xColor]="getValue(color) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Start Slot Actions -->
|
|
<ion-buttons slot="start">
|
|
<ng-container *ngFor="let item of getStartSoltItems() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="actionRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
|
|
<!-- End Slot Actions -->
|
|
<ion-buttons slot="end">
|
|
<ng-container *ngFor="let item of getEndSoltItems() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="actionRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
</ion-toolbar>
|
|
|
|
<!-- Action Template -->
|
|
<ng-template #actionRef let-action>
|
|
<ng-container *ngIf="action && !(isHidedAction(action) | async)">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(isOnlyIcon(action) | async) ? iconRef : buttonRef;
|
|
context: {
|
|
$implicit: action,
|
|
clickable: true,
|
|
color:
|
|
(isOnlyIcon(action) | async)
|
|
? (getValue(action.iconColor) | async)
|
|
: (getValue(action.color) | async)
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Button Template -->
|
|
<ng-template #buttonRef let-action>
|
|
<x-button
|
|
[loading]="loading"
|
|
class="x-action-bar-item"
|
|
[type]="ButtonTypes.Raised"
|
|
[color]="getValue(action.color) | async"
|
|
[ngClass]="getValue(action.cssClass) | async"
|
|
(clicked)="handleActionClicked(action, $event)"
|
|
*ngIf="!(getOptionalValue(action.hidden) | async)"
|
|
[uiDisabled]="
|
|
uiDisabled ||
|
|
(isDisabledAction(action) | async) ||
|
|
(getOptionalValue(action.disabled) | async)
|
|
"
|
|
[class.disabled]="
|
|
uiDisabled ||
|
|
(isDisabledAction(action) | async) ||
|
|
(getOptionalValue(action.disabled) | async)
|
|
"
|
|
>
|
|
<div class="x-action-bar-item-inner">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
$implicit: action,
|
|
clickable: false,
|
|
color: getValue(action.iconColor) | async
|
|
}
|
|
"
|
|
></ng-container>
|
|
|
|
<span
|
|
[isForeground]="true"
|
|
[xColor]="getValue(action.titleColor) | async"
|
|
*ngIf="action.title && (notEmptyValue(action.title) | async)"
|
|
>{{ getResourceValue(action.title) | async }}</span
|
|
>
|
|
</div>
|
|
</x-button>
|
|
</ng-template>
|
|
|
|
<!-- Icon Template -->
|
|
<ng-template #iconRef let-action let-color="color" let-clickable="clickable">
|
|
<x-icon
|
|
[color]="color"
|
|
[loading]="loading"
|
|
class="x-action-bar-item"
|
|
[clickable]="
|
|
clickable &&
|
|
!loading &&
|
|
!uiDisabled &&
|
|
!(getValue(action.disabled) | async)
|
|
"
|
|
[name]="getValue(action.icon) | async"
|
|
(clicked)="handleActionClicked(action, $event)"
|
|
[matTooltip]="getResourceValue(action.title) | async"
|
|
[uiDisabled]="
|
|
uiDisabled ||
|
|
(isDisabledAction(action) | async) ||
|
|
(getOptionalValue(action.disabled) | async)
|
|
"
|
|
[class.disabled]="
|
|
uiDisabled ||
|
|
(isDisabledAction(action) | async) ||
|
|
(getOptionalValue(action.disabled) | async)
|
|
"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.scss
|
|
|
|
$action-item-margin: var(--action-items-offset, 2px);
|
|
$action-item-gutter: var(--action-items-gutter, 8px);
|
|
|
|
.x-actions-bar {
|
|
padding: {
|
|
left: $action-item-gutter !important;
|
|
right: $action-item-gutter !important;
|
|
}
|
|
}
|
|
|
|
.x-action-bar-item {
|
|
margin: {
|
|
left: $action-item-margin !important;
|
|
right: $action-item-margin !important;
|
|
}
|
|
}
|
|
|
|
.x-action-bar-item-inner {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
> * {
|
|
margin: {
|
|
left: 2px !important;
|
|
right: 2px !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.ts
|
|
|
|
import {
|
|
sort,
|
|
nameof,
|
|
toArray,
|
|
isFunction,
|
|
filterList,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarAction,
|
|
XActionBarItemSlot,
|
|
XActionBarActionModel,
|
|
XActionBarActionIdentifier,
|
|
XActionBarItemSlotIdentifier,
|
|
XActionBarContainerComponent,
|
|
} from './x-action-bar.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-action-bar',
|
|
templateUrl: './x-action-bar.component.html',
|
|
styleUrls: ['./x-action-bar.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XActionBarComponent extends XActionBarContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
private ACTIONS: XActionBarItem[] = [];
|
|
private ACTIONS_HIDDEN: Map<XActionBarActionIdentifier, boolean> = new Map();
|
|
private ACTIONS_DISABLED: Map<XActionBarActionIdentifier, boolean> =
|
|
new Map();
|
|
|
|
//
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
|
|
get preparedActions() {
|
|
return this.ACTIONS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Actions Changed ...
|
|
//
|
|
const isActionsChanged = changeKeys.includes(
|
|
nameof<XActionBarComponent>('actions')
|
|
);
|
|
if (isActionsChanged) {
|
|
await this.prepareActions();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Provider Changed ...
|
|
//
|
|
const isActionProviderChaged = changeKeys.includes(
|
|
nameof<XActionBarComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChaged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
//#region Slot Based Items Fetcher ...
|
|
getSlotItems(slot: XActionBarItemSlotIdentifier) {
|
|
return filterList(this.actions, (action) =>
|
|
this.getValue(action.slot).pipe(map((iSlot) => iSlot === slot))
|
|
);
|
|
}
|
|
|
|
getStartSoltItems() {
|
|
return this.getSlotItems(XActionBarItemSlot.START);
|
|
}
|
|
|
|
getEndSoltItems() {
|
|
return this.getSlotItems(XActionBarItemSlot.END);
|
|
}
|
|
|
|
isOnlyIcon(item: XActionBarItem) {
|
|
return this.getOptionalValue(item.onlyIcon).pipe(
|
|
map((onlyIcon) => !!onlyIcon)
|
|
);
|
|
}
|
|
|
|
isDisabledAction(item: XActionBarItem) {
|
|
//
|
|
if (!item) {
|
|
return this.getValue(false);
|
|
}
|
|
|
|
//
|
|
return this.getValue(item.id).pipe(
|
|
map((id) =>
|
|
isNullOrEmptyString(id)
|
|
? false
|
|
: this.ACTIONS_DISABLED.has(id)
|
|
? this.ACTIONS_DISABLED.get(id)
|
|
: false
|
|
)
|
|
);
|
|
}
|
|
|
|
isHidedAction(item: XActionBarItem) {
|
|
//
|
|
if (!item) {
|
|
return this.getValue(false);
|
|
}
|
|
|
|
//
|
|
return this.getValue(item.id).pipe(
|
|
map((id) =>
|
|
isNullOrEmptyString(id)
|
|
? false
|
|
: this.ACTIONS_HIDDEN.has(id)
|
|
? this.ACTIONS_HIDDEN.get(id)
|
|
: false
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
async getActionIds() {
|
|
//
|
|
if (!this.hasChild(this.preparedActions)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
const IDS = this.preparedActions.map((a) => this.getValueAsync(a.id));
|
|
|
|
//
|
|
return await Promise.all(IDS);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleActionClicked(item: XActionBarItem, event: Event) {
|
|
//
|
|
const disabled = await this.getValueAsync(item.disabled);
|
|
if (disabled || this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const id = await this.getValueAsync(item.id);
|
|
|
|
//
|
|
if (item.handler && isFunction(item.handler)) {
|
|
await item.handler({
|
|
action: id,
|
|
event,
|
|
});
|
|
}
|
|
|
|
//
|
|
this.actionFired.emit({
|
|
action: id,
|
|
event,
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* check an action with specific id exists in actions or not ...
|
|
*
|
|
* @param id required action id ...
|
|
*/
|
|
async isActionExists(id: string) {
|
|
return (await this.getActionIds()).findIndex((i) => i === id) > -1;
|
|
}
|
|
|
|
/**
|
|
* retrieve all actions ...
|
|
*/
|
|
async getActions() {
|
|
//
|
|
const ACTIONS_TYPE = await this.getValueAsync(this.actions);
|
|
if (!ACTIONS_TYPE) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return toArray(ACTIONS_TYPE);
|
|
}
|
|
|
|
/**
|
|
* retrieve an action ...
|
|
*
|
|
* @param id action id
|
|
*/
|
|
async getAction(id: string) {
|
|
//
|
|
const isExists = await this.isActionExists(id);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const ACTIONS = await this.getActions();
|
|
if (!this.hasChild(ACTIONS)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const existsAction = ACTIONS.find(
|
|
async (a) => (await this.getValueAsync(a.id)) === id
|
|
);
|
|
|
|
//
|
|
return this.toPreparedAction(existsAction);
|
|
}
|
|
|
|
/**
|
|
* manually fire a registered action
|
|
*
|
|
* @param id action id
|
|
*/
|
|
async fireAction(id: string, event?: Event) {
|
|
//
|
|
const isExist = await this.isActionExists(id);
|
|
if (!isExist) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const action = await this.getAction(id);
|
|
if (!action) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const canFire =
|
|
!this.uiDisabled &&
|
|
!this.loading &&
|
|
!(await this.getOptionalValueAsync(action.disabled));
|
|
if (!canFire) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleActionClicked(action, event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XActionBarActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(
|
|
async (action) => await this.handleActionProviderAction(action)
|
|
);
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
private async prepareActions() {
|
|
//
|
|
this.ACTIONS = null;
|
|
if (!this.actions) {
|
|
//
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const ACTIONS_TYPE = await this.getValueAsync(this.actions);
|
|
if (!ACTIONS_TYPE) {
|
|
//
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const ACTIONS = toArray(ACTIONS_TYPE);
|
|
if (!this.hasChild(ACTIONS)) {
|
|
//
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTIONS = [
|
|
...sort(ACTIONS, (a, b) => (a.index && b.index ? a.index - b.index : -1)),
|
|
];
|
|
|
|
//
|
|
for (const a of this.ACTIONS) {
|
|
//
|
|
const id = await this.getValueAsync(a.id);
|
|
|
|
//
|
|
if (!this.ACTIONS_DISABLED.has(id)) {
|
|
this.ACTIONS_DISABLED.set(id, false);
|
|
}
|
|
|
|
//
|
|
if (!this.ACTIONS_HIDDEN.has(id)) {
|
|
this.ACTIONS_HIDDEN.set(id, false);
|
|
}
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async actionsCount() {
|
|
return (await this.getActions()).length || 0;
|
|
}
|
|
|
|
private async findActionIdex(id: string) {
|
|
//
|
|
const isExists = await this.isActionExists(id);
|
|
if (!isExists) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
const ACTIONS_TYPE = await this.getValueAsync(this.actions);
|
|
if (!ACTIONS_TYPE) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const ACTIONS = toArray(ACTIONS_TYPE);
|
|
if (!this.hasChild(ACTIONS)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return ACTIONS.findIndex(
|
|
async (a) => (await this.getValueAsync(a.id)) === id
|
|
);
|
|
}
|
|
|
|
private async toPreparedAction(item: XActionBarItem) {
|
|
//
|
|
if (!item) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return {
|
|
index: item.index,
|
|
handler: item.handler,
|
|
id: await this.getValueAsync(item.id),
|
|
icon: await this.getValueAsync(item.icon),
|
|
slot: await this.getValueAsync(item.slot),
|
|
color: await this.getValueAsync(item.color),
|
|
title: await this.getValueAsync(item.title),
|
|
hidden: await this.getValueAsync(item.hidden),
|
|
onlyIcon: await this.getValueAsync(item.onlyIcon),
|
|
disabled: await this.getValueAsync(item.disabled),
|
|
cssClass: await this.getValueAsync(item.cssClass),
|
|
iconColor: await this.getValueAsync(item.iconColor),
|
|
titleColor: await this.getValueAsync(item.titleColor),
|
|
} as XActionBarItem;
|
|
}
|
|
|
|
private async handleActionProviderAction(model: XActionBarActionModel) {
|
|
//
|
|
if (!model || isNullOrEmptyString(model.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const actionId = await this.getValueAsync(model.id);
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XActionBarAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.FireAction:
|
|
await this.fireAction(model.id, model.event);
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.EnableAction:
|
|
//
|
|
if (this.ACTIONS_DISABLED.has(actionId)) {
|
|
//
|
|
this.ACTIONS_DISABLED.set(actionId, false);
|
|
this.detectChanges();
|
|
} else {
|
|
if (!this.hasChild(this.ACTIONS)) {
|
|
setTimeout(() => this.handleActionProviderAction(model), 500);
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.DisbaleAction:
|
|
//
|
|
if (this.ACTIONS_DISABLED.has(actionId)) {
|
|
//
|
|
this.ACTIONS_DISABLED.set(actionId, true);
|
|
this.detectChanges();
|
|
} else {
|
|
if (!this.hasChild(this.ACTIONS)) {
|
|
setTimeout(() => this.handleActionProviderAction(model), 500);
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.ShowAction:
|
|
//
|
|
if (this.ACTIONS_HIDDEN.has(actionId)) {
|
|
//
|
|
this.ACTIONS_HIDDEN.set(actionId, false);
|
|
this.detectChanges();
|
|
} else {
|
|
if (!this.hasChild(this.ACTIONS)) {
|
|
setTimeout(() => this.handleActionProviderAction(model), 500);
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.HideAction:
|
|
//
|
|
if (this.ACTIONS_HIDDEN.has(actionId)) {
|
|
//
|
|
this.ACTIONS_HIDDEN.set(actionId, true);
|
|
this.detectChanges();
|
|
} else {
|
|
if (!this.hasChild(this.ACTIONS)) {
|
|
setTimeout(() => this.handleActionProviderAction(model), 500);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XActionBarComponent } from './x-action-bar.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XActionBarComponent],
|
|
imports: [XIconModule, CommonModule, XButtonModule, XBaseComponentModule],
|
|
exports: [
|
|
XIconModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XActionBarComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XActionBarModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.typings.ts
|
|
|
|
import {
|
|
XColor,
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseComponentContainer,
|
|
XBaseContainerComponent,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { map } from 'rxjs/operators';
|
|
import { Observable, forkJoin, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XIconNames, XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region ActionBar Item ...
|
|
export enum XActionBarItemSlot {
|
|
START = 'start',
|
|
END = 'end',
|
|
}
|
|
|
|
export type XActionBarItemSlotIdentifier = XActionBarItemSlot | string;
|
|
|
|
export interface XActionBarItem {
|
|
index?: number;
|
|
id: XStandardType<string>;
|
|
hidden?: XStandardType<boolean>;
|
|
onlyIcon?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
icon: XStandardType<XIconIdentifier>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
title?: XStandardType<XResourceIdentifier>;
|
|
iconColor?: XStandardType<XColorIdentifier>;
|
|
titleColor?: XStandardType<XColorIdentifier>;
|
|
cssClass?: XStandardType<XOneOrManyType<string>>;
|
|
slot: XStandardType<XActionBarItemSlotIdentifier>;
|
|
handler?: (model?: XActionBarActionFiredModel) => XStandardType<any>;
|
|
}
|
|
|
|
export interface XActionBarActionFiredModel {
|
|
action: string;
|
|
event?: Event;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Provider ...
|
|
export enum XActionBarAction {
|
|
Refresh = 'refresh',
|
|
FireAction = 'fire_action',
|
|
HideAction = 'hide_action',
|
|
ShowAction = 'show_action',
|
|
EnableAction = 'enable_action',
|
|
DisbaleAction = 'disable_action',
|
|
}
|
|
|
|
export type XActionBarActionIdentifier = XActionBarAction | string;
|
|
|
|
export interface XActionBarActionModel
|
|
extends XBaseActionModel<XActionBarActionIdentifier> {
|
|
id?: string;
|
|
event?: Event;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Default Actionbar Item IDs ...
|
|
export enum DefaultActionBarItemIds {
|
|
Add = 'add',
|
|
Set = 'set',
|
|
Edit = 'edit',
|
|
Remove = 'remove',
|
|
Upload = 'upload',
|
|
Download = 'download',
|
|
SelectAll = 'select_all',
|
|
DeSelectAll = 'de_select_all',
|
|
SelectAllGroup = 'select_all_group',
|
|
InverseSelection = 'inverse_selection',
|
|
DeSelectAllGroup = 'de_select_all_group',
|
|
}
|
|
|
|
export type DefaultActionBarItemIdsIdentifier =
|
|
| DefaultActionBarItemIds
|
|
| string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Default Items ...
|
|
export const defaultActionBarRemoveItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Danger,
|
|
icon: XIconNames.remove,
|
|
iconColor: XColor.Danger,
|
|
title: XResourceIDs.delete,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Remove,
|
|
};
|
|
|
|
export const defaultActionBarUploadItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
icon: XIconNames.upload,
|
|
iconColor: XColor.Tertiary,
|
|
title: XResourceIDs.upload,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Upload,
|
|
};
|
|
|
|
export const defaultActionBarDownloadItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
icon: XIconNames.download,
|
|
iconColor: XColor.Tertiary,
|
|
title: XResourceIDs.download,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Download,
|
|
};
|
|
|
|
export const defaultActionBarSelectAllItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
iconColor: XColor.Tertiary,
|
|
icon: XIconNames.select_all,
|
|
slot: XActionBarItemSlot.END,
|
|
title: XResourceIDs.select_all,
|
|
id: DefaultActionBarItemIds.SelectAll,
|
|
};
|
|
|
|
export const defaultActionBarDeSelectAllItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
iconColor: XColor.Tertiary,
|
|
slot: XActionBarItemSlot.END,
|
|
icon: XIconNames.deselect_all,
|
|
title: XResourceIDs.deselect_all,
|
|
id: DefaultActionBarItemIds.DeSelectAll,
|
|
};
|
|
|
|
export const defaultActionBarSelectAllGroupItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
iconColor: XColor.Tertiary,
|
|
slot: XActionBarItemSlot.END,
|
|
icon: XIconNames.select_all_group,
|
|
title: XResourceIDs.select_all_group,
|
|
id: DefaultActionBarItemIds.SelectAllGroup,
|
|
};
|
|
|
|
export const defaultActionBarDeSelectAllGroupItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
iconColor: XColor.Tertiary,
|
|
slot: XActionBarItemSlot.END,
|
|
icon: XIconNames.deselect_all_group,
|
|
title: XResourceIDs.deselect_all_group,
|
|
id: DefaultActionBarItemIds.DeSelectAllGroup,
|
|
};
|
|
|
|
export const defaultActionBarInverseSelectionItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Tertiary,
|
|
iconColor: XColor.Tertiary,
|
|
slot: XActionBarItemSlot.END,
|
|
icon: XIconNames.inverse_selection,
|
|
title: XResourceIDs.inverse_selection,
|
|
id: DefaultActionBarItemIds.InverseSelection,
|
|
};
|
|
|
|
export const defaultActionBarAddItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
icon: XIconNames.add,
|
|
color: XColor.Success,
|
|
title: XResourceIDs.add,
|
|
iconColor: XColor.Success,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Add,
|
|
};
|
|
|
|
export const defaultActionBarSetItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
color: XColor.Success,
|
|
icon: XIconNames.done,
|
|
title: XResourceIDs.set,
|
|
iconColor: XColor.Success,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Set,
|
|
};
|
|
|
|
export const defaultActionBarEditItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
icon: XIconNames.edit,
|
|
color: XColor.Warning,
|
|
title: XResourceIDs.edit,
|
|
iconColor: XColor.Warning,
|
|
slot: XActionBarItemSlot.START,
|
|
id: DefaultActionBarItemIds.Edit,
|
|
};
|
|
//#endregion
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXActionBarContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XActionBarActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
actions: XStandardType<XOneOrManyType<XActionBarItem>>;
|
|
|
|
//
|
|
actionFired: EventEmitter<XActionBarActionFiredModel>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XActionBarContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXActionBarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XActionBarActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly actions: XStandardType<XOneOrManyType<XActionBarItem>>;
|
|
|
|
//
|
|
readonly actionFired = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XActionBarContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXActionBarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
actions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actions;
|
|
|
|
//
|
|
@Output()
|
|
actionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XActionBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXActionBarContainer
|
|
): Observable<IXActionBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
|
|
//
|
|
actions: this.getValue(container ? container.actions : this.actions),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
actionFired: this.actionFired,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentActionBarContainer = {
|
|
[TKey in keyof IXActionBarContainer as `actionBar${Capitalize<
|
|
string & TKey
|
|
>}`]: IXActionBarContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentActionBarContainer
|
|
extends TXComponentActionBarContainer,
|
|
IXBaseComponentContainer {
|
|
showActionBar: XStandardType<boolean>;
|
|
actionBarColor: XStandardType<XColorIdentifier>;
|
|
actionBarForegroundColor: XStandardType<boolean>;
|
|
actionBarActionProvider: Subject<XActionBarActionModel>;
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>>;
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel>;
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentActionBarContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentActionBarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showActionBar: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actions;
|
|
|
|
//
|
|
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.propertyProvider.actionFired;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XActionBarContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XComponentActionBarContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentActionBarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
|
|
//
|
|
@Output()
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentActionBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentActionBarContainer
|
|
): Observable<IXComponentActionBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
|
|
//
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
|
|
//
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
|
|
//
|
|
actionBarActions: this.getValue(
|
|
container ? container.actionBarActions : this.actionBarActions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionBarActionProvider: container
|
|
? container.actionBarActionProvider
|
|
: this.actionBarActionProvider,
|
|
|
|
//
|
|
actionBarActionFired: this.actionBarActionFired,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<!-- Avatar Container -->
|
|
<div
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
class="x-avatar-container x-wrapper"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- File Upload Input -->
|
|
<input
|
|
hidden
|
|
#fileInput
|
|
type="file"
|
|
multiple="false"
|
|
(change)="handleFilesSelected()"
|
|
[disabled]="loading || uiDisabled"
|
|
/>
|
|
|
|
<!-- File Drop -->
|
|
<ng-container *ngIf="getValue(showFileDropArea) | async">
|
|
<ng-container *ngTemplateOutlet="fileDragAreaRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Wrapper of Thumbnail -->
|
|
<div class="thumbnail-wrapper">
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[layout]="SlotLayout.HORIZONTAL"
|
|
[startTopSlotCssClass]="'ion-text-start'"
|
|
[endBottomSlotCssClass]="['ion-text-center']"
|
|
>
|
|
<x-slot [name]="SlotNames.START" [cssClass]="">
|
|
<!-- Thumbnail -->
|
|
<x-thumbnail
|
|
class="x-thumb"
|
|
[circular]="true"
|
|
[loading]="loading"
|
|
[cssClass]="'thumbnail'"
|
|
[uiDisabled]="uiDisabled"
|
|
[type]="ThumbnailTypes.CUSTOM"
|
|
[identifier]="avatar || (getValue(placeHolderAvatar) | async)"
|
|
>
|
|
</x-thumbnail>
|
|
</x-slot>
|
|
|
|
<x-slot [name]="SlotNames.END" cssClass="ion-text-end">
|
|
<div
|
|
class="avatar-actions ion-text-end"
|
|
*ngIf="hasChildValue(actions) | async"
|
|
>
|
|
<!-- Action Buttons -->
|
|
<ng-container *ngFor="let action of getActions() | async">
|
|
<!-- Crop -->
|
|
<ng-container *ngIf="action.name === ActionButtonNames.Crop">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionButtonRef;
|
|
context: {
|
|
$implicit: action,
|
|
showCondition: isCroppableImage()
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Clear -->
|
|
<ng-container *ngIf="action.name === ActionButtonNames.Clear">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionButtonRef;
|
|
context: {
|
|
$implicit: action,
|
|
showCondition: avatar
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Select -->
|
|
<ng-container *ngIf="action.name === ActionButtonNames.Select">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionButtonRef;
|
|
context: {
|
|
$implicit: action,
|
|
showCondition: !avatar
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- File Drop Area Template -->
|
|
<ng-template #fileDragAreaRef>
|
|
<div class="x-file-drag-drop-wrapper">
|
|
<x-file-drop-area
|
|
[loading]="loading"
|
|
[uiDisabled]="uiDisabled"
|
|
[supportsMultipleFiles]="false"
|
|
[icon]="getValue(fileDropAreaIcon) | async"
|
|
[actionProvider]="fileDropAreaActionProvider"
|
|
[color]="getValue(fileDropAreaColor) | async"
|
|
(filesChangeEmiter)="handleFileDropped($event)"
|
|
[cssClass]="getValue(fileDropAreaCssClass) | async"
|
|
[isInPage]="getValue(fileDropAreaIsInPage) | async"
|
|
[cardColor]="getValue(fileDropAreaCardColor) | async"
|
|
[errorColor]="getValue(fileDropAreaErrorColor) | async"
|
|
[accentColor]="getValue(fileDropAreaAccentColor) | async"
|
|
[message]="getResourceValue(fileDropAreaMessage) | async"
|
|
[wrapWithCard]="getValue(fileDropAreaWrapWithCard) | async"
|
|
[successColor]="getValue(fileDropAreaSuccessColor) | async"
|
|
[dragDisabled]="getValue(fileDropAreaDragDisabled) | async"
|
|
[cardTitle]="getResourceValue(fileDropAreaCardTitle) | async"
|
|
[allowedExtensions]="getArrayValue(allowedExtensions) | async"
|
|
[cardShowFooter]="getValue(fileDropAreaCardShowFooter) | async"
|
|
[foregroundColor]="getValue(fileDropAreaForegroundColor) | async"
|
|
[contentTemplate]="getValue(fileDropAreaContentTemplate) | async"
|
|
[cardSubTitle]="getResourceValue(fileDropAreaCardSubTitle) | async"
|
|
[disableFileCheck]="getValue(fileDropAreaDisableFileCheck) | async"
|
|
[cardForegroundColor]="getValue(fileDropAreaCardForegroundColor) | async"
|
|
></x-file-drop-area>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Action Button Template -->
|
|
<ng-template #actionButtonRef let-descriptor let-showCondition="showCondition">
|
|
<x-button
|
|
*ngIf="showCondition"
|
|
[loading]="loading"
|
|
[uiDisabled]="uiDisabled"
|
|
[type]="ButtonTypes.Icon"
|
|
[color]="getValue(descriptor.color) | async"
|
|
(clicked)="handleActionButtonClicked(descriptor.name)"
|
|
[matTooltip]="getResourceValue(descriptor.tooltip) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { $implicit: descriptor }"
|
|
></ng-container>
|
|
</x-button>
|
|
</ng-template>
|
|
|
|
<!-- Icon Template -->
|
|
<ng-template #iconRef let-descriptor>
|
|
<x-icon
|
|
[name]="getValue(descriptor.icon) | async"
|
|
[color]="getValue(descriptor.color) | async"
|
|
[foregroundColor]="getValue(foregroundColor) | async"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.scss
|
|
|
|
//
|
|
:host {
|
|
--avatar-size: 64px;
|
|
--top-radius: 5px;
|
|
--padding: 6px;
|
|
}
|
|
|
|
.x-file-drag-drop-wrapper {
|
|
padding-bottom: var(--padding);
|
|
border-top-left-radius: var(--top-radius);
|
|
border-top-right-radius: var(--top-radius);
|
|
}
|
|
|
|
.x-avatar-container {
|
|
padding: 6px;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.thumbnail-wrapper {
|
|
height: var(--avatar-size, 64px) !important;
|
|
}
|
|
|
|
x-thumbnail {
|
|
--thumbnail-size: var(--avatar-size, 64px);
|
|
}
|
|
|
|
x-file-drop-area {
|
|
--padding: 0px;
|
|
}
|
|
|
|
.avatar-actions {
|
|
//
|
|
@extend .thumbnail-wrapper;
|
|
|
|
//
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: stretch;
|
|
justify-content: flex-end;
|
|
|
|
//
|
|
* {
|
|
flex: 0 0 auto;
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
}
|
|
|
|
//
|
|
* {
|
|
margin: {
|
|
left: 3px;
|
|
right: 3px;
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
sort,
|
|
nameof,
|
|
isArray,
|
|
toArray,
|
|
hasChild,
|
|
toBoolean,
|
|
getArrayOf,
|
|
XDialogResult,
|
|
isExtensionOk,
|
|
getErrorException,
|
|
getImageDimensions,
|
|
XColorWithBrightness,
|
|
XExceptionIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XAvatarStatus,
|
|
XAvatarUploadAction,
|
|
XAvatarUploadActionModel,
|
|
XAvatarUploadActionButtonName,
|
|
XAvatarUploadContainerComponent,
|
|
} from './x-avatar-upload.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { XThumbnailType } from '../x-thumbnail/x-thumbnail.typings';
|
|
import { XSlotName, XSlotLayout } from '../x-slotter/x-slotter.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-avatar-upload',
|
|
templateUrl: './x-avatar-upload.component.html',
|
|
styleUrls: ['./x-avatar-upload.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XAvatarUploadComponent extends XAvatarUploadContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private SELECTED_AVATAR: File;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly IconNames = Object.assign({}, XIconNames);
|
|
readonly SlotLayout = Object.assign({}, XSlotLayout);
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
readonly ThumbnailTypes = Object.assign({}, XThumbnailType);
|
|
readonly ColorNames = Object.assign({}, XColorWithBrightness);
|
|
readonly ActionButtonNames = Object.assign({}, XAvatarUploadActionButtonName);
|
|
|
|
//
|
|
selectedFileWidth = 0;
|
|
selectedFileHeight = 0;
|
|
|
|
//
|
|
@ViewChild('fileInput', { static: false })
|
|
private fileInputRef!: ElementRef;
|
|
|
|
set avatar(v: File) {
|
|
//
|
|
this.SELECTED_AVATAR = v;
|
|
|
|
//
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
getImageDimensions(v).then((dimension) => {
|
|
if (dimension) {
|
|
//
|
|
this.selectedFileWidth = dimension.width;
|
|
this.selectedFileHeight = dimension.height;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
});
|
|
}
|
|
|
|
get avatar() {
|
|
return this.SELECTED_AVATAR;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Provider ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XAvatarUploadComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
getActions() {
|
|
return this.getArrayValue(this.actions).pipe(
|
|
map((actions) => sort(actions, (a1, a2) => a1.index - a2.index))
|
|
);
|
|
}
|
|
|
|
isCroppableImage() {
|
|
return (
|
|
this.avatar &&
|
|
this.selectedFileWidth > 0 &&
|
|
this.selectedFileHeight > 0 &&
|
|
this.selectedFileWidth >= this.config.minAllowedImageSize &&
|
|
this.selectedFileHeight >= this.config.minAllowedImageSize
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//
|
|
handleFilesSelected() {
|
|
//
|
|
if (!this.fileInputRef) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fileInput = this.fileInputRef.nativeElement;
|
|
if (!fileInput || !fileInput.files) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const files = getArrayOf<File>(fileInput.files);
|
|
|
|
//
|
|
if (!files || files.length === 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const file = files[0];
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
fileInput.value = null;
|
|
|
|
//
|
|
this.handleFileDropped(files);
|
|
}
|
|
|
|
//
|
|
async handleFileDropped(files: File | File[]) {
|
|
//
|
|
if (!files) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.loading = true;
|
|
|
|
//
|
|
let file: File;
|
|
if (!isArray(files) && files instanceof File) {
|
|
file = files as File;
|
|
} else {
|
|
//
|
|
const filesArr = files as File[];
|
|
if (hasChild(filesArr)) {
|
|
file = filesArr[0];
|
|
}
|
|
}
|
|
|
|
//
|
|
this.loading = false;
|
|
|
|
//
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const status = await this.getFileStatus(file);
|
|
if (status !== XAvatarStatus.OK) {
|
|
this.loading = false;
|
|
await this.handleFileStatus(status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.avatar = file;
|
|
this.avatarChange.emit(file);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
async handleActionButtonClicked(name: XAvatarUploadActionButtonName) {
|
|
switch (name) {
|
|
//
|
|
case XAvatarUploadActionButtonName.Crop:
|
|
this.loadCropper();
|
|
break;
|
|
|
|
//
|
|
case XAvatarUploadActionButtonName.Clear:
|
|
await this.clear();
|
|
break;
|
|
|
|
//
|
|
case XAvatarUploadActionButtonName.Select:
|
|
this.select();
|
|
break;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//
|
|
select() {
|
|
//
|
|
if (!this.fileInputRef || !this.fileInputRef.nativeElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.fileInputRef.nativeElement.click();
|
|
}
|
|
|
|
//
|
|
async clear(force = false) {
|
|
//
|
|
if (!this.avatar) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (force) {
|
|
this.clearImage();
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
|
|
this.clearImage();
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XAvatarUploadActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XAvatarUploadAction.Clear:
|
|
await this.clear(toBoolean(model.payload));
|
|
break;
|
|
|
|
//
|
|
case XAvatarUploadAction.Select:
|
|
this.select();
|
|
break;
|
|
|
|
//
|
|
case XAvatarUploadAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private loadCropper() {
|
|
this.imageCropperService.showCropper(this.avatar);
|
|
|
|
//
|
|
const s = this.applyTakeUntilWrapper(
|
|
this.imageCropperService.onResult.asObservable()
|
|
).subscribe((res) => {
|
|
//
|
|
if (res.result === XDialogResult.Ok && res.file) {
|
|
//
|
|
this.avatar = null;
|
|
setTimeout(() => {
|
|
//
|
|
this.avatar = res.file;
|
|
this.avatarChange.emit(res.file);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}, 100);
|
|
}
|
|
|
|
//
|
|
s.unsubscribe();
|
|
});
|
|
}
|
|
|
|
private clearImage() {
|
|
//
|
|
if (!this.avatar) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.avatar = null;
|
|
this.selectedFileWidth = 0;
|
|
this.selectedFileHeight = 0;
|
|
this.avatarChange.emit(null);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async getFileStatus(file: File) {
|
|
//
|
|
// Check Not Empty File ...
|
|
if (!file || file.size === 0) {
|
|
return XAvatarStatus.EMPTY;
|
|
}
|
|
|
|
//
|
|
// Check File Extension Validation ...
|
|
const isExtensionIsOk = await this.isExtensionOk(file);
|
|
if (!isExtensionIsOk) {
|
|
return XAvatarStatus.NOT_ALLOWED_TYPE;
|
|
}
|
|
|
|
//
|
|
// Check File Min Size Ok ...
|
|
const isMinAllowedFileSizeOk = await this.isMinAllowedFileSizeOk(file);
|
|
if (!isMinAllowedFileSizeOk) {
|
|
return XAvatarStatus.MIN_SIZE_NOT_REACHED;
|
|
}
|
|
|
|
//
|
|
// Check File Max Size Ok ...
|
|
const isMaxAllowedFileSizeOk = await this.isMaxAllowedFileSizeOk(file);
|
|
if (!isMaxAllowedFileSizeOk) {
|
|
return XAvatarStatus.SIZE_EXCEEDED;
|
|
}
|
|
|
|
//
|
|
// Everythings Ok ...
|
|
return XAvatarStatus.OK;
|
|
}
|
|
|
|
private async handleFileStatus(status: XAvatarStatus) {
|
|
//
|
|
let identifier: XExceptionIdentifier = null;
|
|
switch (status) {
|
|
//
|
|
case XAvatarStatus.EMPTY:
|
|
identifier = await this.getValueAsync(this.emptyFileException);
|
|
break;
|
|
|
|
//
|
|
case XAvatarStatus.NOT_ALLOWED_TYPE:
|
|
identifier = await this.getValueAsync(this.notAllowedFileException);
|
|
break;
|
|
|
|
//
|
|
case XAvatarStatus.SIZE_EXCEEDED:
|
|
identifier = await this.getValueAsync(this.maxAllowedFileSizeException);
|
|
break;
|
|
|
|
//
|
|
case XAvatarStatus.MIN_SIZE_NOT_REACHED:
|
|
identifier = await this.getValueAsync(this.minAllowedFileSizeException);
|
|
break;
|
|
}
|
|
|
|
//
|
|
const exception = getErrorException(identifier);
|
|
if (exception) {
|
|
this.managerService.notificationService.presentErrorNotification({
|
|
exception,
|
|
dissmissable: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region File Selection Policies ...
|
|
/**
|
|
* Check File Extension ...
|
|
*/
|
|
private async isExtensionOk(file: File) {
|
|
//
|
|
if (!file) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const allowedExtensionsType = await this.getValueAsync(
|
|
this.allowedExtensions
|
|
);
|
|
if (!allowedExtensionsType) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const allowedExtensions = toArray(allowedExtensionsType);
|
|
if (!hasChild(allowedExtensions)) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const result = isExtensionOk(file, allowedExtensions);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Size less than or Equals Max Required Size ...
|
|
*/
|
|
private async isMaxAllowedFileSizeOk(file: File) {
|
|
//
|
|
const maxAllowedFileSize = await this.getValueAsync(
|
|
this.maxAllowedFileSize
|
|
);
|
|
|
|
//
|
|
const result =
|
|
maxAllowedFileSize && maxAllowedFileSize > 0
|
|
? file.size <= maxAllowedFileSize
|
|
: true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Size satisfied Min Required Size ...
|
|
*/
|
|
private async isMinAllowedFileSizeOk(file: File) {
|
|
//
|
|
const minAllowedFileSize = await this.getValueAsync(
|
|
this.minAllowedFileSize
|
|
);
|
|
|
|
//
|
|
const result =
|
|
minAllowedFileSize && minAllowedFileSize > 0
|
|
? file.size >= minAllowedFileSize
|
|
: true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XAvatarUploadComponent } from './x-avatar-upload.component';
|
|
import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module';
|
|
|
|
@NgModule({
|
|
declarations: [XAvatarUploadComponent],
|
|
imports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XSlotterModule,
|
|
XThumbnailModule,
|
|
XFileDropAreaModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XButtonModule,
|
|
XSlotterModule,
|
|
XThumbnailModule,
|
|
XFileDropAreaModule,
|
|
XBaseComponentModule,
|
|
XAvatarUploadComponent,
|
|
],
|
|
})
|
|
export class XAvatarUploadModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XColor,
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardFileFileDropContainer,
|
|
IXCardFileFileDropContainer,
|
|
XCardFileFileDropContainerComponent,
|
|
} from '../classes/i-x-file.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XImageCropperService } from '../x-image-cropper/x-image-cropper.service';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XAvatarUploadAction {
|
|
//
|
|
Clear = 'clear',
|
|
Select = 'select',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XAvatarUploadActionIdentifier = XAvatarUploadAction | string;
|
|
|
|
export interface XAvatarUploadActionModel
|
|
extends XBaseActionModel<XAvatarUploadActionIdentifier> {}
|
|
|
|
export enum XAvatarStatus {
|
|
OK = 'ok',
|
|
EMPTY = 'empty',
|
|
SIZE_EXCEEDED = 'size_exceeded',
|
|
NOT_ALLOWED_TYPE = 'not_allowed_type',
|
|
MIN_SIZE_NOT_REACHED = 'min_size_not_reached',
|
|
}
|
|
|
|
export type XAvatarStatusIdentifier = XAvatarStatus | string;
|
|
|
|
export enum XAvatarUploadActionButtonName {
|
|
Crop,
|
|
Clear,
|
|
Select,
|
|
}
|
|
|
|
export interface XAvatarUploadActionButton {
|
|
index?: number;
|
|
name: XAvatarUploadActionButtonName;
|
|
icon?: XStandardType<XIconIdentifier>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
export const defaultAvatarUploadActionButtons: XAvatarUploadActionButton[] = [
|
|
//
|
|
// Select ...
|
|
{
|
|
index: 0,
|
|
color: XColor.Success,
|
|
icon: XIconNames.touch,
|
|
tooltip: XResourceIDs.select,
|
|
name: XAvatarUploadActionButtonName.Select,
|
|
},
|
|
//
|
|
// Crop ...
|
|
{
|
|
index: 1,
|
|
icon: XIconNames.crop,
|
|
color: XColor.Tertiary,
|
|
tooltip: XResourceIDs.crop,
|
|
name: XAvatarUploadActionButtonName.Crop,
|
|
},
|
|
//
|
|
// Clear ...
|
|
{
|
|
index: 2,
|
|
color: XColor.Warning,
|
|
icon: XIconNames.clear,
|
|
tooltip: XResourceIDs.clear,
|
|
name: XAvatarUploadActionButtonName.Clear,
|
|
},
|
|
];
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXAvatarUploadContainer extends IXCardFileFileDropContainer {
|
|
//
|
|
actionProvider: Subject<XAvatarUploadActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
placeHolderAvatar: XStandardType<string>;
|
|
|
|
//
|
|
actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>>;
|
|
|
|
//
|
|
avatarChange: EventEmitter<File>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XAvatarUploadContainer
|
|
extends XCardFileFileDropContainer
|
|
implements Readonly<IXAvatarUploadContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XAvatarUploadActionModel> =
|
|
new Subject<XAvatarUploadActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly placeHolderAvatar: XStandardType<string>;
|
|
|
|
//
|
|
readonly actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>> =
|
|
defaultAvatarUploadActionButtons;
|
|
|
|
//
|
|
readonly avatarChange: EventEmitter<File> = new EventEmitter<File>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XAvatarUploadContainerComponent
|
|
extends XCardFileFileDropContainerComponent
|
|
implements IXAvatarUploadContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XAvatarUploadActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
placeHolderAvatar: XStandardType<string> =
|
|
this.propertyProvider.placeHolderAvatar;
|
|
|
|
//
|
|
@Input()
|
|
actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>> =
|
|
this.propertyProvider.actions;
|
|
|
|
//
|
|
@Output()
|
|
avatarChange: EventEmitter<File> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
public imageCropperService: XImageCropperService,
|
|
protected propertyProvider: XAvatarUploadContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXAvatarUploadContainer
|
|
): Observable<IXAvatarUploadContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
placeHolderAvatar: this.getValue(
|
|
container ? container.placeHolderAvatar : this.placeHolderAvatar
|
|
),
|
|
actions: this.getValue(
|
|
container ? container.actions : this.actions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
avatarChange: this.avatarChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.html
|
|
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: { $implicit: getValue(this.type) | async }
|
|
"
|
|
></ng-container>
|
|
|
|
<ng-template #buttonRef let-type>
|
|
<!-- Raised -->
|
|
<button
|
|
mat-raised-button
|
|
class="x-button x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
*ngIf="type === XButtonTypes.Raised"
|
|
[disabled]="uiDisabled || loading"
|
|
(click)="handleButtonClicked($event)"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[disableRipple]="uiDisabled || loading"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Has Icon -->
|
|
<ng-container *ngIf="hasIcon() | async">
|
|
<ng-container *ngTemplateOutlet="bothRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Hasn't Icon -->
|
|
<ng-container *ngIf="!(hasIcon() | async)">
|
|
<ng-container
|
|
*ngTemplateOutlet="contentRef; context: { $implicit: true }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</button>
|
|
|
|
<!-- Icon -->
|
|
<button
|
|
mat-icon-button
|
|
class="x-button x-wrapper"
|
|
(click)="handleButtonClicked()"
|
|
*ngIf="type === XButtonTypes.Icon"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[disabled]="uiDisabled || loading"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[disableRipple]="uiDisabled || loading"
|
|
[matTooltip]="getResourceValue(title) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="contentRef; context: { $implicit: false }"
|
|
></ng-container>
|
|
</button>
|
|
</ng-template>
|
|
|
|
<ng-template #bothRef>
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[startTopSlotCssClass]="'ion-text-center'"
|
|
[endBottomSlotCssClass]="'ion-text-center'"
|
|
[layout]="
|
|
(isVerticalLayout() | async)
|
|
? XSlotLayouts.VERTICAL
|
|
: XSlotLayouts.HORIZONTAL
|
|
"
|
|
>
|
|
<!-- icon slot -->
|
|
<x-slot
|
|
[name]="iconSlotName() | async"
|
|
[cssClass]="'x-button-icon-wrapper'"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="contentRef; context: { $implicit: false }"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- title slot -->
|
|
<x-slot [name]="titleSlotName() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="contentRef; context: { $implicit: true }"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</ng-template>
|
|
|
|
<ng-template #contentRef let-showTitle>
|
|
<!-- if Title Not Provided -->
|
|
<ng-container *ngIf="!showTitle || !title || !(getValue(title) | async)">
|
|
<!-- Has Icon -->
|
|
<ng-container *ngIf="hasIcon() | async">
|
|
<x-icon
|
|
[name]="getValue(icon) | async"
|
|
[color]="getValue(iconColor) | async"
|
|
[foregroundColor]="getValue(foregroundColor) | async"
|
|
></x-icon>
|
|
</ng-container>
|
|
|
|
<!-- Hasn't Icon -->
|
|
<ng-container *ngIf="!(hasIcon() | async)">
|
|
<ng-content></ng-content>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- if Title Provided -->
|
|
<ng-container *ngIf="showTitle && title && (getValue(title) | async)">
|
|
{{ getResourceValue(title) | async }}
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.scss
|
|
|
|
:host ::ng-deep .x-button-icon-wrapper {
|
|
vertical-align: middle;
|
|
display: inline-grid;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
isNullOrUndefined,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XButtonType,
|
|
XButtonAction,
|
|
XButtonActionModel,
|
|
XButtonIconPosition,
|
|
XButtonContainerComponent,
|
|
} from './x-button.typings';
|
|
import { concatMap, map, switchMap } from 'rxjs/operators';
|
|
import { of, Observable, Subscription, Subject } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-button',
|
|
templateUrl: './x-button.component.html',
|
|
styleUrls: ['./x-button.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XButtonComponent extends XButtonContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly XSlotNames = Object.assign({}, XSlotName);
|
|
readonly XButtonTypes = Object.assign({}, XButtonType);
|
|
readonly XSlotLayouts = Object.assign({}, XSlotLayout);
|
|
readonly XButtonIconPositions = Object.assign({}, XButtonIconPosition);
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Provider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XButtonComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region is IconPositionChanged ...
|
|
const isIconPositionChanged = changeKeys.includes(
|
|
nameof<XButtonComponent>('iconPosition')
|
|
);
|
|
if (isIconPositionChanged && isNullOrUndefined(this.iconPosition)) {
|
|
//
|
|
this.iconPosition = XButtonIconPosition.Start;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
hasIcon() {
|
|
return this.notNullOrUndefinedValue(this.icon);
|
|
}
|
|
|
|
hasTitle() {
|
|
return this.notNullOrUndefinedValue(this.title);
|
|
}
|
|
|
|
useSlot() {
|
|
return this.hasIcon().pipe(
|
|
concatMap((hasIcon) =>
|
|
this.hasTitle().pipe(map((hasTitle) => hasIcon && hasTitle))
|
|
)
|
|
);
|
|
}
|
|
|
|
isVerticalLayout() {
|
|
return this.useSlot().pipe(
|
|
concatMap((useSlot) => {
|
|
//
|
|
if (!useSlot) {
|
|
return of(false);
|
|
}
|
|
|
|
//
|
|
return this.getValue(this.iconPosition).pipe(
|
|
map(
|
|
(iPos) =>
|
|
iPos === this.XButtonIconPositions.Above ||
|
|
iPos === this.XButtonIconPositions.Below
|
|
)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
iconSlotName(): Observable<XSlotName> {
|
|
return this.getValue(this.iconPosition).pipe(
|
|
map((iPos) => {
|
|
//
|
|
switch (iPos) {
|
|
//
|
|
case this.XButtonIconPositions.Start:
|
|
return this.XSlotNames.START;
|
|
|
|
//
|
|
case this.XButtonIconPositions.End:
|
|
return this.XSlotNames.END;
|
|
|
|
//
|
|
case this.XButtonIconPositions.Above:
|
|
return this.XSlotNames.TOP;
|
|
|
|
//
|
|
case this.XButtonIconPositions.Below:
|
|
return this.XSlotNames.BOTTOM;
|
|
|
|
//
|
|
default:
|
|
return this.XSlotNames.START;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
titleSlotName(): Observable<XSlotName> {
|
|
return this.iconSlotName().pipe(
|
|
map((iSlot) => {
|
|
//
|
|
switch (iSlot) {
|
|
//
|
|
case this.XSlotNames.START:
|
|
return this.XSlotNames.END;
|
|
|
|
//
|
|
case this.XSlotNames.END:
|
|
return this.XSlotNames.START;
|
|
|
|
//
|
|
case this.XSlotNames.TOP:
|
|
return this.XSlotNames.BOTTOM;
|
|
|
|
//
|
|
case this.XSlotNames.BOTTOM:
|
|
return this.XSlotNames.TOP;
|
|
|
|
//
|
|
default:
|
|
return this.XSlotNames.CENTER;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
getButtonColor() {
|
|
return this.hasIcon().pipe(
|
|
switchMap((hasIcon) =>
|
|
this.getValue(hasIcon ? XColorWithBrightness.Transparent : this.color)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
handleButtonClicked(event?: Event) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.clicked.emit(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XButtonActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XButtonAction.Click:
|
|
this.clicked.emit();
|
|
break;
|
|
|
|
//
|
|
case XButtonAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XButtonComponent } from './x-button.component';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XButtonComponent],
|
|
imports: [CommonModule, XIconModule, XSlotterModule, XBaseComponentModule],
|
|
exports: [
|
|
CommonModule,
|
|
XIconModule,
|
|
XSlotterModule,
|
|
XButtonComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XButtonModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Renderer2,
|
|
Component,
|
|
Injectable,
|
|
ElementRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseContainer } from './../classes/i-x-base.container';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XButtonType {
|
|
Raised = 'raised',
|
|
Icon = 'icon',
|
|
}
|
|
|
|
export type XButtonTypeIdentifier = XButtonType | string;
|
|
|
|
export enum XButtonIconPosition {
|
|
Above = 'above',
|
|
Start = 'strat',
|
|
Below = 'below',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XButtonIconPositionIdentifier = XButtonIconPosition | string;
|
|
|
|
export enum XButtonAction {
|
|
Click = 'click',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XButtonActionIdentifier = XButtonAction | string;
|
|
|
|
export interface XButtonActionModel
|
|
extends XBaseActionModel<XButtonActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXButtonContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XButtonActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
type: XStandardType<XButtonTypeIdentifier>;
|
|
title: XStandardType<XResourceIdentifier>;
|
|
icon: XStandardType<XIconIdentifier>;
|
|
iconPosition: XStandardType<XButtonIconPositionIdentifier>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
iconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
clicked: EventEmitter<Event>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XButtonContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXButtonContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XButtonActionModel> =
|
|
new Subject<XButtonActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly type: XStandardType<XButtonTypeIdentifier> = XButtonType.Raised;
|
|
readonly title: XStandardType<XResourceIdentifier>;
|
|
readonly icon: XStandardType<XIconIdentifier>;
|
|
readonly iconPosition: XStandardType<XButtonIconPositionIdentifier> =
|
|
XButtonIconPosition.Start;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
readonly iconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
|
|
//
|
|
readonly clicked: EventEmitter<Event> = new EventEmitter<Event>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XButtonContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXButtonContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XButtonActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
type: XStandardType<XButtonTypeIdentifier> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
|
|
|
|
@Input()
|
|
icon: XStandardType<XIconIdentifier> = this.propertyProvider.icon;
|
|
|
|
@Input()
|
|
iconPosition: XStandardType<XButtonIconPositionIdentifier> =
|
|
this.propertyProvider.iconPosition;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
|
|
|
|
//
|
|
@Output()
|
|
clicked: EventEmitter<Event> = new EventEmitter<Event>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XButtonContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXButtonContainer
|
|
): Observable<IXButtonContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
type: this.getValue(container ? container.type : this.type),
|
|
title: this.getValue(container ? container.title : this.title),
|
|
icon: this.getValue(container ? container.icon : this.icon),
|
|
iconPosition: this.getValue(
|
|
container ? container.iconPosition : this.iconPosition
|
|
),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
iconColor: this.getValue(
|
|
container ? container.iconColor : this.iconColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
clicked: this.clicked,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.html
|
|
|
|
<mat-card
|
|
class="x-card x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[class.no-text]="isNoTextCard() | async"
|
|
[class.page-card]="getValue(isInPage) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Card Header -->
|
|
<mat-card-header class="x-header" *ngIf="getValue(showHeader) | async">
|
|
<!-- Avatar Image -->
|
|
<section
|
|
*ngIf="notEmptyValue(avatarUrl) | async"
|
|
mat-card-avatar
|
|
class="x-avatar"
|
|
>
|
|
<img
|
|
mat-card-avatar
|
|
class="x-avatar"
|
|
[src]="getValue(avatarUrl) | async"
|
|
*ngIf="
|
|
(notEmptyValue(avatarUrl) | async) &&
|
|
!(notNullOrUndefinedValue(avatarTemplate) | async)
|
|
"
|
|
/>
|
|
<ng-container *ngIf="notNullOrUndefinedValue(avatarTemplate) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
avatarTemplate;
|
|
context: {
|
|
avatarUrl: getValue(avatarUrl) | async
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</section>
|
|
|
|
<!-- Card Title -->
|
|
<mat-card-title class="x-title" *ngIf="notEmptyValue(title) | async">
|
|
{{ getResourceValue(title) | async }}
|
|
</mat-card-title>
|
|
|
|
<!-- Card Sub Title -->
|
|
<mat-card-subtitle
|
|
class="x-sub-title"
|
|
*ngIf="notEmptyValue(subTitle) | async"
|
|
>
|
|
{{ getResourceValue(subTitle) | async }}</mat-card-subtitle
|
|
>
|
|
|
|
<!-- Header Content -->
|
|
<ng-content select="[header]"></ng-content>
|
|
</mat-card-header>
|
|
|
|
<!-- Card Image -->
|
|
<img
|
|
mat-card-image
|
|
class="x-image"
|
|
[src]="getValue(imageUrl) | async"
|
|
*ngIf="notEmptyValue(imageUrl) | async"
|
|
[alt]="getResourceValue(imageDescription) | async"
|
|
/>
|
|
|
|
<!-- Card Content -->
|
|
<mat-card-content class="x-content" *ngIf="getValue(showContent) | async">
|
|
<ng-content></ng-content>
|
|
</mat-card-content>
|
|
|
|
<!-- Card Actions -->
|
|
<mat-card-actions class="x-actions" *ngIf="getValue(showActions) | async">
|
|
<ng-content select="[actions]"></ng-content>
|
|
</mat-card-actions>
|
|
|
|
<!-- Card Footer -->
|
|
<mat-card-footer
|
|
#footer
|
|
class="x-footer"
|
|
*ngIf="getValue(showFooter) | async"
|
|
>
|
|
<ng-content select="[footer]"></ng-content>
|
|
</mat-card-footer>
|
|
</mat-card>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.scss
|
|
|
|
//
|
|
@import '../theme/theme.scss';
|
|
|
|
//
|
|
:host::ng-deep.x-card.no-text {
|
|
.mat-card-header-text {
|
|
display: none;
|
|
visibility: hidden;
|
|
}
|
|
}
|
|
|
|
//
|
|
.x-card {
|
|
@extend .p-0;
|
|
width: inherit;
|
|
height: var(--height, inherit);
|
|
}
|
|
|
|
.x-card.page-card {
|
|
@include push-auto();
|
|
@include applyWidthHeight();
|
|
@include m-tb($d-l);
|
|
@include animation('fadeInUp');
|
|
|
|
&.mobile {
|
|
box-sizing: border-box;
|
|
width: $d-100p;
|
|
max-width: $d-100p;
|
|
min-width: $d-100p;
|
|
@include m(0);
|
|
margin-bottom: $d-l;
|
|
}
|
|
}
|
|
|
|
.x-header,
|
|
.x-content,
|
|
.x-actions,
|
|
.x-footer {
|
|
@include p($d-md);
|
|
}
|
|
|
|
.x-footer {
|
|
margin: 0px !important;
|
|
}
|
|
|
|
.x-image {
|
|
width: 100% !important;
|
|
@extend .m-0;
|
|
}
|
|
|
|
.x-actions {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.x-header:empty,
|
|
.x-footer:empty,
|
|
.x-actions:empty {
|
|
display: none;
|
|
visibility: hidden;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.ts
|
|
|
|
import {
|
|
XCardAction,
|
|
XCardActionModel,
|
|
XCardContainerComponent,
|
|
} from './x-card.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { nameof, isNullOrEmptyString } from 'x-framework-core';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-card',
|
|
templateUrl: './x-card.component.html',
|
|
styleUrls: ['./x-card.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XCardComponent extends XCardContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Provider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XCardComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
isNoTextCard() {
|
|
return this.getResourceValue(this.title).pipe(
|
|
concatMap((title) =>
|
|
this.getResourceValue(this.subTitle).pipe(
|
|
map((subTitle) => {
|
|
return {
|
|
title,
|
|
subTitle,
|
|
};
|
|
}),
|
|
map((object) => {
|
|
return (
|
|
isNullOrEmptyString(object.title) &&
|
|
isNullOrEmptyString(object.subTitle)
|
|
);
|
|
})
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XCardActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XCardAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardComponent } from './x-card.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [
|
|
XCardComponent
|
|
],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XCardComponent],
|
|
})
|
|
export class XCardModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
TemplateRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseComponentContainer,
|
|
XBaseContainerComponent,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XCardAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XCardActionIdentifier = XCardAction | string;
|
|
|
|
export interface XCardActionModel
|
|
extends XBaseActionModel<XCardActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXCardContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XCardActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
showHeader: XStandardType<boolean>;
|
|
title: XStandardType<XResourceIdentifier>;
|
|
subTitle: XStandardType<XResourceIdentifier>;
|
|
avatarUrl: XStandardType<string>;
|
|
avatarTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
imageUrl: XStandardType<string>;
|
|
imageDescription: XStandardType<XResourceIdentifier>;
|
|
|
|
//
|
|
isInPage: XStandardType<boolean>;
|
|
|
|
//
|
|
showContent: XStandardType<boolean>;
|
|
showActions: XStandardType<boolean>;
|
|
showFooter: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCardContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXCardContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XCardActionModel> =
|
|
new Subject<XCardActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly showHeader: XStandardType<boolean> = false;
|
|
readonly title: XStandardType<XResourceIdentifier>;
|
|
readonly subTitle: XStandardType<XResourceIdentifier>;
|
|
readonly avatarUrl: XStandardType<string>;
|
|
readonly avatarTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly imageUrl: XStandardType<string>;
|
|
readonly imageDescription: XStandardType<XResourceIdentifier>;
|
|
|
|
//
|
|
readonly isInPage: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly showContent: XStandardType<boolean> = true;
|
|
readonly showActions: XStandardType<boolean> = false;
|
|
readonly showFooter: XStandardType<boolean> = false;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XCardContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXCardContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
|
|
|
|
@Input()
|
|
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
|
|
|
|
@Input()
|
|
subTitle: XStandardType<XResourceIdentifier> = this.propertyProvider.subTitle;
|
|
|
|
@Input()
|
|
avatarUrl: XStandardType<string> = this.propertyProvider.avatarUrl;
|
|
|
|
@Input()
|
|
avatarTemplate: TemplateRef<any> = this.propertyProvider.avatarTemplate;
|
|
|
|
//
|
|
@Input()
|
|
imageUrl: XStandardType<string> = this.propertyProvider.imageUrl;
|
|
|
|
@Input()
|
|
imageDescription: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.imageDescription;
|
|
|
|
//
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
//
|
|
@Input()
|
|
showContent: XStandardType<boolean> = this.propertyProvider.showContent;
|
|
|
|
@Input()
|
|
showActions: XStandardType<boolean> = this.propertyProvider.showActions;
|
|
|
|
@Input()
|
|
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCardContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCardContainer
|
|
): Observable<IXCardContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
|
|
//
|
|
showHeader: this.getValue(
|
|
container ? container.showHeader : this.showHeader
|
|
),
|
|
title: this.getValue(container ? container.title : this.title),
|
|
subTitle: this.getValue(container ? container.subTitle : this.subTitle),
|
|
avatarUrl: this.getValue(
|
|
container ? container.avatarUrl : this.avatarUrl
|
|
),
|
|
avatarTemplate: this.getValue(
|
|
container ? container.avatarTemplate : this.avatarTemplate
|
|
),
|
|
|
|
//
|
|
imageUrl: this.getValue(container ? container.imageUrl : this.imageUrl),
|
|
imageDescription: this.getValue(
|
|
container ? container.imageDescription : this.imageDescription
|
|
),
|
|
|
|
//
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
|
|
//
|
|
showContent: this.getValue(
|
|
container ? container.showContent : this.showContent
|
|
),
|
|
showActions: this.getValue(
|
|
container ? container.showActions : this.showActions
|
|
),
|
|
showFooter: this.getValue(
|
|
container ? container.showFooter : this.showFooter
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentCardContainer = {
|
|
[TKey in keyof Pick<
|
|
IXCardContainer,
|
|
| 'actionProvider'
|
|
| 'cssClass'
|
|
| 'color'
|
|
| 'foregroundColor'
|
|
| 'title'
|
|
| 'subTitle'
|
|
| 'showFooter'
|
|
| 'showActions'
|
|
> as `card${Capitalize<string & TKey>}`]: IXCardContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentCardContainer
|
|
extends TXComponentCardContainer,
|
|
IXBaseComponentContainer {
|
|
isInPage: XStandardType<boolean>;
|
|
wrapWithCard: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentCardContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentCardContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly isInPage: XStandardType<boolean> = false;
|
|
readonly wrapWithCard: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.title;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.subTitle;
|
|
|
|
//
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.propertyProvider.showFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.showActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XCardContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XComponentCardContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentCardContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
//
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
|
|
//
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
//
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentCardContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentCardContainer
|
|
): Observable<IXComponentCardContainer> {
|
|
return forkJoin({
|
|
//
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardCssClass: this.getValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.html
|
|
|
|
<div
|
|
class="x-color x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
*ngIf="getValue(value) | async as item"
|
|
>
|
|
<!-- Color Title -->
|
|
<div
|
|
class="x-color-title text-truncate"
|
|
*ngIf="item.key && (getValue(showLabel) | async)"
|
|
>
|
|
<span [xColor]="getValue(labelColor) | async" [isForeground]="true">{{
|
|
item.key
|
|
}}</span>
|
|
</div>
|
|
|
|
<!-- Spacer -->
|
|
<div class="x-spacer"></div>
|
|
|
|
<!-- Color Value -->
|
|
<button
|
|
*ngIf="item.value"
|
|
[matTooltip]="item.value"
|
|
class="x-color-value-button"
|
|
(click)="handleCopyToClipboard(item.value)"
|
|
>
|
|
<div class="x-color-value" [style.backgroundColor]="item.value"></div>
|
|
</button>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.scss
|
|
|
|
:host {
|
|
--size: 32px;
|
|
}
|
|
|
|
.x-color {
|
|
direction: ltr !important;
|
|
width: 100%;
|
|
display: flex;
|
|
}
|
|
|
|
.x-color-title {
|
|
flex: 1 1 auto;
|
|
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
|
|
max-width: 230px;
|
|
}
|
|
|
|
.x-spacer {
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.x-color-value-button {
|
|
background-color: transparent;
|
|
}
|
|
|
|
.x-color-value {
|
|
opacity: 0.7;
|
|
width: var(--size);
|
|
border-radius: 50%;
|
|
height: var(--size);
|
|
border-style: var(--border-style);
|
|
border-color: var(--border-color);
|
|
border-width: var(--border-width);
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XColorAction,
|
|
XColorCssVars,
|
|
XColorActionModel,
|
|
XColorContainerComponent,
|
|
} from './x-color.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'x-color',
|
|
templateUrl: './x-color.component.html',
|
|
styleUrls: ['./x-color.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XColorComponent extends XColorContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.applyDefaults();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Size Changed ...
|
|
const isSizeChanged = changeKeys.includes(nameof<XColorComponent>('size'));
|
|
if (isSizeChanged) {
|
|
await this.applySize();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region borderWidth Changed ...
|
|
const isBorderWidthChanged = changeKeys.includes(
|
|
nameof<XColorComponent>('borderWidth')
|
|
);
|
|
if (isBorderWidthChanged) {
|
|
await this.applyBorderWith();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region borderStyle Changed ...
|
|
const isBorderStyleChanged = changeKeys.includes(
|
|
nameof<XColorComponent>('borderStyle')
|
|
);
|
|
if (isBorderStyleChanged) {
|
|
await this.applyBorderStyle();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region borderColor Changed ...
|
|
const isBorderColorChanged = changeKeys.includes(
|
|
nameof<XColorComponent>('borderColor')
|
|
);
|
|
if (isBorderColorChanged) {
|
|
await this.applyBorderColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XColorComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleCopyToClipboard(value: string) {
|
|
this.managerService.saveToClipboard(value);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XColorActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XColorAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Appliers ...
|
|
private async applyDefaults() {
|
|
//
|
|
await this.applySize();
|
|
await this.applyBorderWith();
|
|
await this.applyBorderColor();
|
|
await this.applyBorderStyle();
|
|
}
|
|
|
|
private async applySize() {
|
|
//
|
|
let size = await this.getValueAsync(this.size);
|
|
size = !size || size === 0 ? 32 : size;
|
|
|
|
//
|
|
this.setCssVar(XColorCssVars.Size, `${size}px`);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyBorderWith() {
|
|
//
|
|
let borderWidth = await this.getValueAsync(this.borderWidth);
|
|
|
|
//
|
|
this.setCssVar(XColorCssVars.BorderWidth, `${borderWidth}px`);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyBorderStyle() {
|
|
//
|
|
let borderStyle = await this.getValueAsync(this.borderStyle);
|
|
|
|
//
|
|
this.setCssVar(XColorCssVars.BorderStyle, `${borderStyle}`);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyBorderColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.borderColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XColorCssVars.BorderColor, `var(${bgColor})`);
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XColorComponent } from './x-color.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XColorComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [CommonModule, XColorComponent, XBaseComponentModule],
|
|
})
|
|
export class XColorModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XBorderStyle,
|
|
XStandardType,
|
|
XColorKeyValue,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
XBorderStyleIdentifier,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XColorAction {
|
|
Refresh = 'refresh',
|
|
SetSelectedColor = 'set_selected_color',
|
|
}
|
|
|
|
export type XColorActionIdentifier = XColorAction | string;
|
|
|
|
export interface XColorActionModel
|
|
extends XBaseActionModel<XColorActionIdentifier> {}
|
|
|
|
export enum XColorCssVars {
|
|
Size = 'size',
|
|
BorderWidth = 'border-width',
|
|
BorderColor = 'border-color',
|
|
BorderStyle = 'border-style',
|
|
}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXColorContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XColorActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
showLabel: XStandardType<boolean>;
|
|
labelColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
size: XStandardType<number>;
|
|
value: XStandardType<XColorKeyValue>;
|
|
|
|
//
|
|
borderWidth: XStandardType<number>;
|
|
borderStyle: XStandardType<XBorderStyleIdentifier>;
|
|
borderColor: XStandardType<XColorIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XColorContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXColorContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XColorActionModel> =
|
|
new Subject<XColorActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly showLabel: XStandardType<boolean> = true;
|
|
readonly labelColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
//
|
|
readonly size: XStandardType<number> = 32;
|
|
|
|
//
|
|
readonly value: XStandardType<XColorKeyValue>;
|
|
|
|
//
|
|
readonly borderWidth: XStandardType<number> = 1;
|
|
readonly borderStyle: XStandardType<XBorderStyleIdentifier> =
|
|
XBorderStyle.Solid;
|
|
readonly borderColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XColorContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXColorContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XColorActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
showLabel: XStandardType<boolean> = this.propertyProvider.showLabel;
|
|
|
|
@Input()
|
|
labelColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.labelColor;
|
|
|
|
//
|
|
@Input()
|
|
size: XStandardType<number> = this.propertyProvider.size;
|
|
|
|
@Input()
|
|
value: XStandardType<XColorKeyValue> = this.propertyProvider.value;
|
|
|
|
//
|
|
@Input()
|
|
borderWidth: XStandardType<number> = this.propertyProvider.borderWidth;
|
|
|
|
@Input()
|
|
borderStyle: XStandardType<XBorderStyleIdentifier> =
|
|
this.propertyProvider.borderStyle;
|
|
|
|
@Input()
|
|
borderColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.borderColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XColorContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXColorContainer
|
|
): Observable<IXColorContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
showLabel: this.getValue(
|
|
container ? container.showLabel : this.showLabel
|
|
),
|
|
labelColor: this.getValue(
|
|
container ? container.labelColor : this.labelColor
|
|
),
|
|
|
|
//
|
|
size: this.getValue(container ? container.size : this.size),
|
|
|
|
//
|
|
value: this.getValue(container ? container.value : this.value),
|
|
|
|
//
|
|
borderWidth: this.getValue(
|
|
container ? container.borderWidth : this.borderWidth
|
|
),
|
|
borderStyle: this.getValue(
|
|
container ? container.borderStyle : this.borderStyle
|
|
),
|
|
borderColor: this.getValue(
|
|
container ? container.borderColor : this.borderColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<!-- Color Palette/Slider Box ... -->
|
|
<div
|
|
#colorPicker
|
|
class="x-color-picker x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Force LTR Direction -->
|
|
<div class="x-force-ltr">
|
|
<!-- Color Pallete -->
|
|
<div
|
|
xSlider
|
|
[rgX]="1"
|
|
[rgY]="1"
|
|
#paletteSlider
|
|
class="x-color-palette"
|
|
[style.background-color]="hueSliderColor"
|
|
*ngIf="getValue(showPaletteChannel) | async"
|
|
(newValue)="setSaturationAndBrightness($event)"
|
|
>
|
|
<!-- Cursor -->
|
|
<div
|
|
*ngIf="slider"
|
|
class="x-cursor"
|
|
[style.top.px]="slider.v"
|
|
[style.left.px]="slider.s"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- Color Sliders -->
|
|
<div class="x-info-box">
|
|
<!-- Start -->
|
|
<div class="x-start" *ngIf="getValue(showSelectedColorPreview) | async">
|
|
<!-- Background -->
|
|
<div class="x-selected-color-background"></div>
|
|
|
|
<!-- Selected Color -->
|
|
<div
|
|
class="x-selected-color"
|
|
[style.background-color]="selectedColor"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- Margin -->
|
|
<div class="x-margin"></div>
|
|
|
|
<!-- End -->
|
|
<div class="x-end">
|
|
<!-- Hue Slider -->
|
|
<div
|
|
xSlider
|
|
[rgX]="1"
|
|
#hueSlider
|
|
class="x-color-hue"
|
|
(newValue)="setHue($event)"
|
|
*ngIf="getValue(showHueChannel) | async"
|
|
>
|
|
<!-- Cursor -->
|
|
<div
|
|
*ngIf="slider"
|
|
class="x-cursor"
|
|
[style.left.px]="slider.h"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- Alpha Slider -->
|
|
<div
|
|
xSlider
|
|
[rgX]="1"
|
|
#alphaSlider
|
|
class="x-color-alpha"
|
|
(newValue)="setAlpha($event)"
|
|
*ngIf="getValue(showAlphaChannel) | async"
|
|
[style.background-color]="alphaSliderColor"
|
|
>
|
|
<!-- Cursor -->
|
|
<div
|
|
*ngIf="slider"
|
|
class="x-cursor"
|
|
[style.left.px]="slider.a"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Color Value -->
|
|
<div
|
|
class="x-color-value"
|
|
*ngIf="
|
|
atLeastHasOneValue(true, showColorValue, showCopyToClipboard) | async
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngIf="getArrayValue(representColorFormats) | async as outputFormats;"
|
|
>
|
|
<!-- Hex Value -->
|
|
<div class="x-hex" *ngIf="outputFormats.includes(ColorFormats.XHEX)">
|
|
<!-- Color Text -->
|
|
<span
|
|
class="x-color-text"
|
|
*ngIf="getValue(showColorValue) | async"
|
|
>{{ hexValue }}</span
|
|
>
|
|
|
|
<!-- Clipboard Icon ... -->
|
|
<div class="x-icon-wrapper">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconActionsRef;
|
|
context: { $implicit: hexValue }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RGBA Value -->
|
|
<div
|
|
class="x-rgba"
|
|
*ngIf="outputFormats.includes(ColorFormats.XRGBA)"
|
|
>
|
|
<!-- Color Text -->
|
|
<span
|
|
class="x-color-text"
|
|
*ngIf="getValue(showColorValue) | async"
|
|
>{{ rgbaValue }}</span
|
|
>
|
|
|
|
<!-- Clipboard Icon ... -->
|
|
<div class="x-icon-wrapper">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconActionsRef;
|
|
context: { $implicit: rgbaValue }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HSLA Value -->
|
|
<div
|
|
class="x-hsla"
|
|
*ngIf="outputFormats.includes(ColorFormats.XHSLA)"
|
|
>
|
|
<!-- Color Text -->
|
|
<span
|
|
class="x-color-text"
|
|
*ngIf="getValue(showColorValue) | async"
|
|
>{{ hslaValue }}</span
|
|
>
|
|
|
|
<!-- Clipboard Icon ... -->
|
|
<div class="x-icon-wrapper">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconActionsRef;
|
|
context: { $implicit: hslaValue }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Color Input -->
|
|
<div class="x-color-input-box" *ngIf="getValue(showColorInput) | async">
|
|
<div fxLayout="row" fxLayoutAlign="none">
|
|
<!-- Input Icon -->
|
|
<div>
|
|
<x-icon
|
|
name="input"
|
|
[clickable]="true"
|
|
(clicked)="handleInputColor()"
|
|
[color]="getValue(colorInputIconColor) | async"
|
|
[matTooltip]="getResourceValue(colorInputIconLabel) | async"
|
|
></x-icon>
|
|
</div>
|
|
|
|
<!-- Input Box -->
|
|
<div fxFlex>
|
|
<input
|
|
class="x-color-input"
|
|
[isForeground]="true"
|
|
[(ngModel)]="inputColor"
|
|
(xOnEnter)="handleInputColor($event)"
|
|
[xColor]="getValue(colorTextColor) | async"
|
|
[placeholder]="
|
|
getResourceValue(ResourceIDs.input_color_description) | async
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Preset Colors -->
|
|
<div
|
|
class="x-preset-colors-wrapper"
|
|
*ngIf="
|
|
(getValue(showPresetColors) | async) &&
|
|
(hasChildValue(presetColors) | async)
|
|
"
|
|
>
|
|
<hr class="x-hr" />
|
|
|
|
<!-- Lable -->
|
|
<span
|
|
class="x-preset-label"
|
|
*ngIf="notEmptyValue(presetColorsLable) | async"
|
|
>{{ getResourceValue(presetColorsLable) | async }}</span
|
|
>
|
|
|
|
<!-- Preset Colors Boxes -->
|
|
<div
|
|
class="x-preset-colors-box"
|
|
*ngIf="getArrayValue(presetColors) | async as pColors;"
|
|
>
|
|
<div
|
|
class="x-preset-color"
|
|
(click)="setHexColor(color)"
|
|
*ngFor="let color of pColors"
|
|
[style.backgroundColor]="color"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Icon Action Template -->
|
|
<ng-template #iconActionsRef let-value>
|
|
<!-- Copy To Clipboard -->
|
|
<x-icon
|
|
name="clipboard"
|
|
[clickable]="true"
|
|
*ngIf="getValue(showCopyToClipboard) | async"
|
|
[color]="getValue(copyToClipboardIconColor) | async"
|
|
(clicked)="handleSaveSelectedColorInClipboard(value)"
|
|
[matTooltip]="getResourceValue(copyToClipboardIconLabel) | async"
|
|
></x-icon>
|
|
|
|
<!-- Clear Color -->
|
|
<x-icon
|
|
name="clear"
|
|
[clickable]="true"
|
|
(clicked)="handleClearSelectedColor()"
|
|
*ngIf="notEmptyValue(selectedColor) | async"
|
|
[color]="getValue(clearColorIconColor) | async"
|
|
[matTooltip]="getResourceValue(clearColorIconLabel) | async"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.scss
|
|
|
|
:host {
|
|
display: block;
|
|
width: inherit;
|
|
--cursor-color: val(--x-color-dark);
|
|
}
|
|
|
|
:host ::ng-deep .x-on-top {
|
|
z-index: 10000;
|
|
}
|
|
|
|
@mixin boder-radius($radius) {
|
|
-moz-border-radius: $radius;
|
|
-webkit-border-radius: $radius;
|
|
border-radius: $radius;
|
|
-khtml-border-radius: $radius;
|
|
}
|
|
|
|
.x-force-ltr {
|
|
direction: ltr !important;
|
|
}
|
|
|
|
.x-color-picker {
|
|
//
|
|
margin: 0;
|
|
font-size: 11px;
|
|
|
|
//
|
|
box-sizing: border-box;
|
|
-moz-box-sizing: border-box;
|
|
-webkit-box-sizing: border-box;
|
|
|
|
//
|
|
height: auto;
|
|
width: inherit;
|
|
cursor: default;
|
|
min-width: 200px;
|
|
|
|
//
|
|
-webkit-touch-callout: none;
|
|
-webkit-user-select: none;
|
|
-khtml-user-select: none;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
user-select: none;
|
|
}
|
|
|
|
.x-color-palette {
|
|
//
|
|
width: 100%;
|
|
border: none;
|
|
cursor: pointer;
|
|
min-height: 130px;
|
|
margin-bottom: 8px;
|
|
background-size: 100% 100%;
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACCCAYAAABSD7T3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwksPWR6lgAAIABJREFUeNrtnVuT47gRrAHN+P//Or/61Y5wONZ7mZ1u3XAeLMjJZGZVgdKsfc5xR3S0RIIUW+CHzCpc2McYo7XGv3ex7UiZd57rjyzzv+v+33X/R/+3r/f7vR386Y+TvKNcf/wdhTLPcv9qU2wZd74uth0t1821jkIZLPcsI/6nWa4XvutquU0Z85mnx80S/ZzgpnLnOtHNt7/ofx1TKXcSNzN/7qbMQ3ju7rNQmMYYd/4s2j9aa+P+gGaMcZrb1M/tdrvf7/d2v99P9/t93O/3cbvdxu12G9frdVwul3E+n8c///nP+2+//Xb66aefxl//+tfx5z//2YK5Al2rgvf4UsbpdGrB52bAvArXpuzjmiqAVSGz5eDmGYXzhbAZmCrnmzddpUU+8Y1dAOYeXCtDUwVwV7YCGH6uAmyMcZ9l5vkUaBPGMUZ7/J5w/792/fvv9Xq93263dr/fTxPECeME8nK5jM/Pz/HTTz/dv337dvrll1/GP/7xj/G3v/1t/OUvfwkVswongjdOp9PzH3U3D3zmWGnZVXn4jCqs7wC2BKP4/8tAzkZsoWx6XrqeHZymvp4ABCBJhTQwKfDT8gzrZCIqi5AhiACjBfEB2rP8/X63MM7f6/V6v9/v7Xa7bYC83W7jcrlsVHIq5ffv30+//fbb+OWXX8ZPP/00/v73v4+ff/75JSvbeu+bL2WMMaFbAlpBNM85QX+ct6qoSqkPAwuQlBVKqGNFSUOAA3Bmu7gC5hNOd15nSwvAOUW7C4giUCV8Sgn5L9hNFIqTsp0GxI0ysioyjAjkY/tGJVEpz+fz+OWXX+7fv38//f777+Pbt2/j119/HT///PP49ddfx8fHRwrmTjV779EXu2px2xhjwtdJZQcAWQIPLPISsMJaSwiD8gzIKrwSyATE5j5nAbR5c1dBUwBlsEWW0h6LqiYsqFPAQxCyRZ3wOSARxmlXMX5k64pQfvv27f75+dk+Pj5OHx8f4/v37+Pbt2/jt99+G9++fRsfHx/jcrmUFLO31gYDWblxRIs/TqfT7ousxJsAxXA2Gc7TA9XdgfdoHbFsj76X2+1WArgI1ageGwA3qupqoHsmcbI6Fu93quggFa9d7LeDtgKfAFHBJ+NEByIkcJ5KervdTmhhGcgJJSZ5vn//fj+fz+18Pp8+Pz/H5+fnmGD+/vvv4/v37+Pj42N8fn6O2+1Ws7JjjP6wraMI5E4RZ8x2vV5TSwkquotV7/d7Tz6HFWsD/qNcdw0CQ3q/321c686TwDVIdbuy73zNldhSHb8I2klZznm+InBS4U6n0302aBFsLhHDAKJVJVglfI9jhvu53W53sLANYNxAiDA6MCeUHx8f9+v12i6XS7tcLqcZW57P5yeY8/fz83Ocz+fnsSmYUyknWEG85WBst9stzSLyMdfr9Qi08iY15UZ0LlDGLhR3o5zK2j7OPUTD0E+nU3tk7Xb/16NFbhloAMuY1zjLUOO3BKeIDe+Z8s3/J4gFo4TM5jPmuRg28foUKKVSwo16TgA5npywcWLHgYl/Pz8/73/605/ab7/91m63W7tcLie0sZj4mao5gTyfz88E0f1+j8EcYzwTPEG2cqjyfHNF0M8fuqEiaOVnRzZZQNh5fwQyHg/HDGfJo89Q1zb/quu5XC6773I2XKfTqd/v9+d3wuqWva/YTdUdEV3fhIv/Viyps6YE3x3r43K5bJQS66zaxVGFsvd+//j4aF+/fm3fv39vt9utff36tf3+++/tdrudvn37ZuNLBaaCMgUzC+rZRiFowxUuJI8YMqcCp9Opq5vagaYU6lGJA1XQqejchw6Cj0Gw5nYBrGw01A2O206n04BGouNNyTfp/FwElhUey6nXrIKw7QQWddxuN2ldL5fL839gSPF8ahu/JvBO48CPSuqMf8Vp9/P53L58+dLu93s7n8/tfr8/39/v9/b5+TkhPJ3P56mQ436/j+/fv+/iSgbzer0+AZx/5+88bv6OMda6S5z6kd21fYC9dxv7cIJJ2d9AOS30fPMzyHiTM8B4DF6XUlYHp4KQW3W+1t77MNB1vGHxWq7Xa7vf78+y5/N5A+H1et29xuP5dbYtyaRu4AksbPq6936fjRzXRxBbPr/b+b18+fKljTHaBBBfn8/n0/1+H1++fBnn8zm0sB8fH5u4cr5GuBhMVk0EEn9RsctgVhM+ixlJtMA23R8B6yysAstBOgFXIKKCMIgToMqNEu2fYMH7ztc732dQKkCj1ytAZtY0Kx8pIr8GGJ+AT3V+2Hirhl++fBmXy2Wz73w+b17P8p+fn8/tUwGVleVkTyUb68DkfayWY4zxNRihU4EpLJPZVrK+u7J4/mgfKqeLW9X2REWlItL1diynbDDb3+jXgYjQqn0rrxWc+NkILP7F7xIbMvx7vV53x40xnlbWJF12ZSag/N0pW6t+ZzmOMzHjajKwDfond78zYTdfq18up97zr2q8v3IioBprRtBl0EZ9og5WBRGOdOHjIjXF7UotFbgOWnXzIJyzYvjG5IYgsmMOxHkz8OsMSrVNWeq5T8DaOcbEv1Od5rbs9aO7YvMet63EkF++fMExq+MRl4/L5bLZN/+ez+fnZ6KazuMqXSQVO5spJXflHAIzes/xJseckRJiDMog9d6VfRrqXMr6KpVV27jRwJacGovOAM1zMdQMnwK1AubK63kdCChvI1C7g0z9nf/D+Xze2Vj8H7Gx4P9duQlsYCrqyN8XqG3Hm/10Oj3jw/n+crlstuM+jPmmxT2dTuPz83Pzt2pn1XsEHX/bnPaVqVmh0xwOt0o6XLLAHePUU203wHfcrspCwmV3TryB5s0Mseeg97x/BwzCjBlbB+pRAPla0BVQuT6V6QHdBlj3d0KG147b+DqxQeUymDO43W4dQar+TIjwmAd0z8/h65vf0/yLv3Pb5XLpru/ydDo9s7ET0I+Pj6dKK9VUEIeKWQWPAOrJ8LKd4vE+t91Y3e7UFlWatg2VwJnb+HPmtvm/sfK59/OaWF3x/eP1UPHvA5DDYDpYXfb0drv1V2DkBkxtw/tEWVVlXWdC9pFYs5/jfh9dS/16vW7s6lTG+TfqsxSJHxkXXq/Xdr1eu4LsfD6P3vsT3N77DkL+zPm5jSdKL4zR3AxQd6rHkLkYlSowsrq7znzu6wSwdsMJOXmA5fBcjxtgMGBYHlr5zokhtsMCTgXLQOW4XC6dEyEMprL8mAQzXRgduix2yZzorxkYsDn3hB1VeMLGsXsVtgl2pW8S3svk0vw7R4hNaHvv4cACl5HFzwIH0Kc6zu4XjDPR/jpAVxWzO1Xk2DDb3vTcxeGU1iWZHkmIDWziWKvirCJ4Dravs6IJ/GG6cTqWdXDy+fArQDVVkLqkVjAoZIITdmmIqXwqa95N3+MGYoZQdRVNO53Y1xRkhO16vY7eu507Ca9lJnbGpxOemQhSw/AQsmmp5zU9BiU8G6wvX76M6/U6Pj4+do0Bz4CpgiknTUeDqwlKBmg3u4OVjrZ1A+rAcgaejWq6eJCvCYFDONSwOgHX4EQRw8lxbzDOdEK6gZ3Hk1b+8g2o1JFtKXyv/fEdTXuWjWXdAZiBp6ADeDrCFiim7B6ZFneeI7Gvm/PMkUDX67W7xI8b0D7/v8dA9qfN5oaCf74WZjH0mf1cmfY1Y0JUFmVrTWu8uzkNcLtEj7u5FXBTkfC6GOA5q8YMxO8KVvF6sAVGdcrUbsKODcQKkLMOMdmlxum642YrPm26AlhZW1YB1R+rrGswE8TaYAWeUMxdf+WjwSvZ2Ef3ytOyfn5+PpVPAaqOn43MtNBqvmjjxbjM4lZjZY4gqNMI5ktaW/sYKNwS+9lFQzGihmMCKPa7+Z0V6Eb0GRmobtpX8JljWu5FMLN5ja6hG9kwQgZqf5+1NH5UxzkFReCdWhJ8XdlGUkxO7HRlYRm4mVO43W7ter12TPJEw/rmEN3L5SKHIWZg9mz+pUoKOYq5bJTJdX2gme1UcxMZQFaEQIlHct32M+Y1BzGkGuzfiyAN9z+ugplZ1symCrDCYYkGxDTpI9RzBy0rHyeDUC1nWaeUaD9n4xkNyYMBDZtzZ3B++fJlY21XFDOcARJlabOyiS3uCpLI9jrZjCDkaVvcCCjwognKShWdzXZWlZMvVTgD8LpqlCLrqgbcB+qYwrgKYpT0ccCqbKyCValkEabn/FynogCrPKfqf51xJ7sGB2ZXcZmxoSOztjx300DZi7a0/2AIR0UlBag9SuDw6KcAzlaB7vHZvWpjK90dyrq6bKyDUZQbR0B05biLQkHIcSUmgIK+SwuqgHCnoio2RQU1yj+BnBy9pphVKLGyC7ZzFK1pxWK+E8IhVCWLN/uLtnUU4ayoYLoaANz8FdtaSvY4pV0BEW2ls61czqllBKpTyKgMAhrZ1cdc1RROtPmvWNkdcKZ7ZKxaWjiPLJMpp7OZKxA+rqG/oJLjxf0pnJlqLoDZo3gyU0mKGys2taKecj/d1C+rJSplBqlTyAqgR+D8KjKlmRL2gtUcAdCtsL+ijCNT1oqqqkH2OHEbG5sDFnUg5Aa+yLou2VU1ptj1S2ZQqv1ORZN9IWzRfgaRBxKoBE8UWyqlJFtrIc0AxNjSjed99CTY/XDfSzCz5M0IZoVEsWnPFNTsl8ooVC1TzbGgqFZNDSgVwKK+1sGDMKqxZCWGVMDysiEr1jVSQJUYwj5iHOlThdHt44SQg9CN+nl8D90NMIgAdgr46JqRiR9I8vRdFvbr17m/yxUMKjNLMiVUADwu2CWGhhi+F55TWM9M9cogzms1dnM4uOF/LAEYWdcqnM7yFmyq3IfwmOROd7Y1iFWtOjoY8To41mTV5IysgFFuRzsbWFGbNIIJCDv1dOo4lZG7jWBwRFtVTKuWyeCByJKOan8oZ3ep9XddNl0tDuaywLz9cXPYeDAA0SpkBO9sbVcTOVWldPv4uyzEkzxHtjvonHoSkFEWNoo1d8DhcQputd2ppNon4BzoAiJ1hBFQg0dVtdbGHHDQWushmNEQukLM2QO1G2Y8bgTXqFhcBJj7EjPgcPts8US8qPpPB/dXznOh5Z438tzH5ec6QgrOKrRRfKmysBmUDB+PhYabMlVPER+GCSITTzr7am2tArH3bgcEzPJm+cr5jJ4NnHNFDVrFXcI5Le9k5Jnw+bedbV+FfRzZIHaOOaOsLY0/7UGs58DjrGwKMIMFIGzOEW1/jGsdAtCN6hEAI4hBe9YXeRROBSVPAVPAqvIM5bx5hVKWAMP6zBRy3iescridVdFBinBxXDnG2GRY2XbCvp1lhvGtO9Bxu5h908XQu42lnSArMFdizMim8uwRCxPGnnOS8lwpnbOiDqTAjsrRN/PcoAScCbaACqVM40ylnjjTBs+bwWlAG23/UKbdkiwKWIQPGzWaczpoSlxPEj822cNWkpS7FyzsDrqpfgpG3jahw2vgbaSQAxuLWZYt7JzyNe8JoZpNAcvDFOdw0wqYT9AK1rZz/DdbSlLPp0ryIxgQJlK9AZlEq7IOXpohg9PIhrCng88JsOxiV4ZWAYfg4sikx/8ky2Z9l862uqwrfscIH8+ugTmVGyiddeVYUgEMn4GZzg14EwIsh9sx2cKKiWXReuOE5gzGOQgdlRKVVdlevqb279Xq0Qnsts2VDaBO0coezsruWtHApu6sKG4IBhN0aGU2kLrMKGRTN3HmbCDwKV14zvkMEDG4QfZVspVlaNU2mhc5TEZ3N1h/zqTheuLpW05ZWTGVjb3dbnNmxKZBnN8JqidaVLKAOyARNLS+MB54Z2+VaqoMLKroVBlngefnTPAcoHNWCSvlfA8CI0HEmBNBnBlXyMrzU7A7WVm94PPqQ2gmqKx+WDGsnvilmcSOBJqOK1nYyAIzuAyesq3UdSK3KfWcYKD95HmfYOU3qser2CtYEUA+FpfqdNvgPBZUBhDrGONRVlQsh8rLcaUCykHG0OOUwTlLBrsh5soEMGezi1E4HRVt1icp5wZEFXdibCkG8Y8vX75sbO4E0iom9z+hjSiOfy3DhpXItpVhE+UGQdvoWjtChmrGHf4YAzKgBNnGtuJxFCeGdhUAfQLLK8kBYAP6gvFJZajMG3Xkycy8KuC0q4Eyymwtwdxdv2M0mIBtK0LKnf640j00Auq4gUkdWGlhs22qJc6dZCsL19oxnlTJG4SYVRIGpD8TPFBuM6OElbS1pldid4mGAyN6ZIupbC5bXJN9fdpbThSxLUaI8IG1XIYBxW3Tjs6KQosKcxfxcQmdnwRGM10GnFcCy2XYunLMyAkdgk4mePiczsLygthcBut6goOqS7YVFXADLjaosB6s6ofcZWAZSIRYqSUkizYwttYab3vUOQ9w2HRxIIg8WwRVeE68xi4UtL3zRphxplzwuZrcqYCq1I3jPI5dnJIygEohMbPqVJSzrwzxBJTs5zN+ReUSgxikPQVF3JVBeNQxbHENrEMNvEdFZVV9lH9+ORGEsNZQpyTNc4C3AG7XF4ngzq+DrO2zbuaaOXgdaFcdkEotoSFBVX2qJ0C8OWZeG4KGlpghA0XfTOPCqV2qqwQ26QWfF2PMLhI2w1lVAa2aPsYd0za25MQRwgcZN6uQDCi+ZxiD4XEM2kZxOT41FnZnaRlcpZouzlRqqdbQVWopQoSB58RV50lBNrHi/AwXS5LrwDVlpY3Fc3ByiYGc52Trist6kOXdwInAQtJpp5QchyaquYOV7Su+fxVMaV3dc0RE2S6mUY0gLt2pMcYqrKIQ9w2l1gpQUMtQYcmmbt5DTNxdhnUCjQqtbK9SUSzvrC0mmhhE1e2FS2+oxypy/ZASutkmtjx3vcBC24PX65nbqkBCRhfjS9kIYPnee8cMagVOhI/3T1fAmdtAWZsCswTJCkQVNa0qWKSKPOpHAUhD9DrbVcyoYkwqhvh17vYAayXLQyKGYdxlUDFp494rBXRjYgO17DDYetNIUj/ezp6S0lnlpEwsWmJMkOwsKXeZKEAjIHn0EQJISaRBcO6UMINz7p/bEjjnw4ft+xmDvksxX4G2rIris7qaeKwAFMP2Oi7n4criuZwtpSUwpfLxSnORSrIqusc5ZFaXysqRWjiZ2DyAWEIL35tVSoQElFACjOeGGSE7AHEQgdo/LSvCOgGBvkxsmDbvlS3Fp5vhaB2TAGqRKrKKMrhLVpaGzEVjZ0OQxDhaCTA+QyRR1d15aQzrJntL3RibsipjG6jlgL4yqbS0sNYg1e84vhbBVrElK64CUcWYXDfKxhpIuxiVJZUxsbMy/uRBKTNRQ4kQ3LdRYLS0rJjRPlTPqY6gdJsEDc+aQXAn+HgsNUCbRuF0Oj0zwnA7bWDkbhO5Ens00qeQhS1laBMl5M/cAaxsLF8rKyql+Tf7ELLEGu/ixiimdCvo0TjfpjKwaggen4eh5v7LokLKbLuyvHhcZG8dhGrEDx7Hg93ZppJF7qBqO3iVveXEDQNInzeoe8Yq6ePaZBZ2JviM3W2UAGotekRCAGq4EkF1X3DOnR11yRsBL1tRa0PVcZiNFXZ2c34FskvomInQQ6lzpJoZbJxk43NwKJFBquJSsrByHydxKOnTxQASBmS3j+JMnsHSla3Ec6K9VWoJVn9zfjwOM7hqYAAqJQwE2a3nA48J2QGegRkpZNivSY+ys3EkKd4oJIwsvIHl3cWgLt5k4NH6OmtLWdpurOkwEMupYc7eMtDRhOcI2ui5JhVIzXzLyto/GAPuZoyo8wkoduVgJglCt7OhGbgID4Mq4si+63zUS1FuFFXFlqyaj2emHlLMcBqYu0FMuR28BbB7lOxRMSiCQXFhCKuwkhZ+pYDiGSgbsKKV8MiSRsuHSIWM9rklRiIlZZuqXjsQK8ooYJMgq3JKWVkhHbhsVxFUzthOWPkYijcbx54IKsSdT+uLr3crGKyoYgFiGR9iBk4kfloUX+JIlQRQqabmpgnhqtpQpb6RVQ1WH5DnrS4hEoGZqaerQ2dhFbz8XePxShmDbo70eISjoorO2vK8SJXI4SUmEU4zWKDzUDtWTYw7xXlbSTEj4FRg7zKnKoGRALv0Gs9Tgc1BpCywGZRQAtqVz2xrBcAMzEpfZwFSa2G5W0QBFjSMapWAEFa3HcGN7CxDzECyIkJ97qwrqWNTWVo876PPsjPkj2wvgroM5lLZKMETKVql/CvnWVFiFa/SzJUQwkoZsr67Y6vlSRV3/2tmNTOY3vnaxYwMuoPKqdzR1w7IqHymlPxaAThfU7Ko2ZXYj4AYJHL+kNdKwRQYESTRa5fsUZ/rVC1TMTyWVyYoqNtuzaHsMyv2tvoarxdfqwYgU1axFo/cnql1FGsqK+uAROV8BX4GU8WcZTATi2q7Qcyi0O0V+GhWBMNRUkn8H1SsWVE5By3Gi0ECqUeJoBfAtDa4amkdXG37AGP5Ggeb84p7UazpoKRzdFzeQ8HkoHGxprKy/Hpm5t12p47J6xTYDEz7uINEXSuxYXvFskYAc+ySxH9sf5ftKzU6IbwVBcUGg5e5FMCEXSErZR0wGayV19woM9guPjTqJdVTqR4uE4nJnLldWVkECCZLd2VLF+xtamex7IpiriSDUpvrpn9lrwGMCHyppMH+ps6LILsuFGUj1XEOXiqbqSHPUKnClpWV68kqtURVNDY4TNaocykoYeTU5ngGEQa/S1DnnE4AeXMcKjHPAmFVjCBENaeyLVNHfr3px8xUstJ94hIpfH4HKE/eDaArK6lSyVVFbdt1gxTIVk3pppVlFXi4pEhVBTObquohU85MLXn1iahvUkHJjSCMc01tLFveVVBx0DodM6jftCu7DOtIzYxrc0qp1JGP2ayYFz2Gb6HvMrO8cnGtV6Gjm3uImSfD2GpWK6uowbZGMxFKQCo1pOMtcMXFpRst+hXGoAomF3sSTBGgTglbBKWwsQ3tZqaYSp0Z1CimRDWFcCJUPYJ00BI5FkKYNoifuQxmN88SWVXWLMaUqqqgC0BmQJR6sk3u9NCf6jYLXxAfqsYEgVLAhRY2AtgtflZNFmFyhxdrLkAdWlk4D88M2ixHyepIdhMHrG/iR1ZGtq0MGpbDbRPYOXeSY1M6Ny4ZstvGSktK+XbFPATj2D371saPEsAMXhXrsZ0km/XStkhhMyBfsa6uXFZe2VCe+YMr1+GKgwrQyNYq1VRrB+EizAow6NsdNKcyVEkYeM73ys6q4kAHp6BiFklTkIrVC5oYV7uzwOGCz4UJ0Stq2lWMJy4wtb+RetL6tZFicnJmBw5UjCvXXMZVJX2MQkbf+XN5EWd78Vz8/JEsMZTBiKNzsm1inLRUQ74H4NidaqI68j5sAFgxcRveC7ieLJXfQYxjZZ2CsiWFewZXJmBIlZ1tdtrX4hSuateKso/RZOtOKW2nmq1oTzeK6dRWAWu2NRVb4hq0SXm1GvtugHrbr5IXqmSktg5CuDE2MSlPwsY5kNE2Wp3AqiZbWVLAxiBF+2iBZbuNj6MB6rsMLC7FyasaYDyo7KkoPyEtw3pEMXfPvxAJi2jAQQgjrz0rLIZSWZlIoNhwd5xK4AR9mYNjWAaLrnuImJeBVN9zBORObVvbr+mTTfFSEJLSRnHo7hEJoIi8MFqjxmvgmF5URZz4zLFgZZ8Ctu2X7ggVccKm9gVxIsOHqxXgNMKnFWZYnf1dBnOhayXq17QwFlWW09eNKyVJFmXqaONGA5aCegMbJ3UUkGY1ic3nKWgjq8qfVYGQG1gRt6rs62a6HiqqUOqdesK5NmX4nGofJoiE1d0dF9lVVkvT1/kEEaaCoYOwFpcVcoLM+7669PxC9rWqktH0sWUYld0VCpuBZ/stVRcGgy9WX2+U1Qthi9SzAqSxzZsy+OiFzBYnySGV6Gku44rD8BCOZBV3BvD5+AKRHNwMEsB6EzHnJpkTAeiUlEGkcECeB6GDZTp5YEJTlvdrknxYjTllMkfNtXwDjM7uVjK5JXUUn43rrqpK2jytaxHW0M5G8DC8rtHMYs7KSgduVQMGTYFqFvVS6rkD3sDJ46afdYFwoq11AOKCBLhvwoUgc8IGANycR6knZrdJPdsuxnyjfd3FovTlRMdEdtOl5CMV5EHsXQBis7TOwvIDZaGj2Vnpbh7cpK63VwYEMLwqbjzyl699sawFFkF1yqjUU31HfC6sW1ZFVFuXVXVgz9keEaw0ys1lWfm+azQAQSWA+hKYVfsZjPncAcUB9oIayy/UZXRNckDGji77GsWbvBo6tPrWPqOyVkBUq+INeqpzNdYs/u0ifh5qmpqIW+33JVSUcwY70KL4U9lYdU6ljtSls7lmfi9g3YzeQfVkaGFaV3ODCnaD2N8wsEDFklE3RzM3ZghdYkWHsszq70FIecnKkVkt8ezMzRq9bkGuKojRLBVSod3Y1yPqKgYW7JRQTPVyy5xIYLjOgxgT52RKJUY1dOrIiRd4futQx/A5AcSmEjz0vFWrkLzvbWAu9HOWbGgxFk1VNTpnBKk6TgwisI/HcxYXP1uAWO72ULFlBTq+aSu2VTUs6hrxM2CF+hEor1VIA9ZmFUaab1lSSgZsVs4sxzHlVLoJHr9H4DhONTkI1XC0/wiY2NoWAG5RlnHFnq6oLccpQddMuJ/O17JVA5OHLi0BqCztq7Y1++ucCd98qLI8MIHBV/cKjxQTme3hFBS3MyCqnDsuym2o80HjvFFTtrURmNaGJsmVahImjTsUXKtQZTAVs7Mvv8/+fzUrZAXcLJ6M4koe6XP0b6SmWWNDzyUpQ8bl+LtWx4tuqZ36cRYV3yuVxPNwvIiqiQCSmu7srgTzR6nkyhpCarXwFy1vGd5iP2cY06lFr5Njhhg1Y6+NB28ftbK83s8rf7kLJbKwDFPbLg25a0AdZJEiqr5phixKMDlRUtcssq1hriLqGoH+zeNgVm9OemjsETV8JdF0NHnkIFxWY1OB4Yrp7rtWJ7NgAAAPXklEQVQ3oNs5nplyVf8u2FoLu1JrHveaZWQjqAkshtFa2gzsSG3Zpkbvg3HafF9slPPlldjFlK80Gysm8Mr4MPhneNWENPGjAIpmilTPATdTRTXlCBYHYAQuPwA36xIpWtGN4q3Y2MhiGsUpuSSnlEJRD8PorC7CFYVw+F51qThgabxsTxWzCGY0ZSsb3lfqAy0OPNjNy8xiQQKsHYFQ2HBZVvVbBuq3m1oWKajqaonsM6uZUr6CjXWNZ0l5E3h3jURma6kP3MJIiy1Lm+kahQq41N2iZja5sjtlLYNZHZrH6qUGm4vMbDp6Rw2CFmvuyFkrBcCyMtFqBaECmsHoK9BZ2LA/lJcRqSaDqnaWbrZdGaz3DLgIvBln4woGztbyJGqslwxkhhHrTjTYFXCtOoKS8uLdofVdAbOylGU6nlYpXWZts4nXBq6WxJitMNokHUJnbnJplQm+aGpY2a5GMV2QD1hRubBPFKdumf5OHkLHz0F9luE5kjBjRa0nFE5CUGqHw32MmjZ6xkgINVnSnZ1VZStK2qKlRaLlQgK7uTq7JFXJwM+3SOEKyhZNI+tJ0I5qMYy9k2qJD7dVWdqKXa0CKNR0Ccjg+B2IYu2fcBZJZkMFgM11r0X92wilghFGgzVnexlqB7xL9mS29SiYUVY2nXOZjNBRsyDsQPRWW5hrZ4XcdC4HVWRbjgJr4sFofK5SzjQ7rhI1UebdPdEbj6sqIvTZQZ5va08rABsAW0UxeWytAk7A2KJ9ZpxzCioB24XFtYAeXYxr6anSqhLgppEqWbGwLunTgrV+IjWlL29ljaAl4EQMGsErp4apeZiquwRXLXAqOCeru32mmydc6oWTSWpFAGdzeTB8RTHVMEtlM90CbbQCYhPjq3egYr1FGdYIQjiuDGZ5zZ/AzobKGOyLxti6c4Rwtv2anyWlLICnlLhxJRXt6A5ebDBWFNONbxWZ2d02mnu4S9YECpeppV1zSWRBWxHYzVIv1CXSouwqqX3jBBBDZdYQbpTQW4ZQlS8r5kH4suSRmg2++3JN10x1PaAmEkmtYlEdeGpJEM6kOuCqCR22oSujj5IV2HdT0zj5prLKTjXFAPjdQlyq7xIBxAQP5yMczG4VxAKw0n6ilZ2QBce2pLulkuxxqnoIzFfgqyqjil9S1VNwBrFmeyeops8yOjZUybZdfS8CuaTIJumzs5tODaNtLpFDQ/PcJGweLhmeL1nB0KqiUDScsiUVD89Di3HtrKtSULw3RLiygZD+7sF8JTObgYsrGvDNUFRGl1iy0Ll1YkUc2aJYMog920I8qW6YDCg1Mqk0JHJFKXkbgbRreI+qpYNOZHrVcDUba7pjsphSJNtK6upgRNAVoOS0mugBeN4bIZgHhuPZ/s1ENaX6KsVr+YNrh1Nb7ipR0PE5zbNRegCbrHRUw6Yf07dLBJl1f8KB9as2V1nNqAsl62LBBhehwalerkHmB1JFIEZKSEusdl5JQj1nJlHXSCF342gJ9CYGrXelknJIXqVP8sD+qtplCR3XH2qfKq0ygMp+KnVkKxNlZ8m2YkIlVMiCnXUwl7qznBKSvQz3m3Pt6oQbXO5b5FixCh/fHxUQW/AEcK6zCNqKQnL9sywqmKuwvqSYzT/aPVNNpVyhvRW21aqciCsjdWvBwILUvh5VyCzbWoC1pJjJ680CWsl+udKB6T5RwG1mlohnlpbg47iz5U9ha0FGtmRLFYBtO99y97Ap0z+ZDTAog6kSLZsMHg/IFkkgp6CpvU2U0cYVSdnmkjwBdOmXbxTWNWzuIbipMioVxEckZEoahSOiy2M3K0jcC1LhVDwaqG0ZvkcWqCnrG4GIxykrqlbWdw6LQyBaZR8HmLRIhQWsHswD42ZXVLNkf9l+FlW0HVQ2lwFsC/Z1FdzlQR0KaPfo+Fdfu+/dwVRICu1CGR7AEIiAhc+AZUF0kOBaPxmUqg4i64vQnU4nFDYJ9Nz+1fVXveH9qmr+kPILx8oKcRV/BFbxbE0JMT0kSD4w6L/lNY8ocsqagVdU3A3MjxhxcGuqzsPH4irpaow1q6OyrVjvp9Npc59E91LldboYVzJWdimWfAW2SNEKcDaX2FmBLLA/uKxlmhh613Is1URQApbKfttwxL02q6Onx5pQxSbPojAg+v5hAnN6LHVRDXIsvKtRjiS0qJUyZTAXVbAK82ElFJWaQdVoqUC1Unt7BVaTQudM6SuqexjQJN4+0icaxv/utbKv83ETbT8H8gjcOKxOJmbUa6OOVXht3dFY6rHv9XoNzFLceEA1o8+pKm0LAHPHZ2rYKjFq0hfZFixsqHJgD3eD5n+U0kb1mFjXkn2lvMSSOsNE/CdIAKF0Sytq6urOHUN5gwg4GZosgbmggM5ucra2qrS2Ig1cbiBBcxYzgzUDNLCvL8GbZXNp6ORy3LmS+Kk83zRIAK6A1ioKa2I9NapIuiUFdfC9766PFZUtqUr6KbWk+zZU1a/ZrIXEztrjTOfz7hwKziCeXIaraHtbZIMz+2pGgazCmw4qWAFvEdhodYp0Xq0pV7G1YWYWbO4qhGq42+Z8BYtrLWvluNPpZAeaFFS1vubPgbgxsqcpnAaszBovKaFoDQ8BGtjfUOl4NAG2nmQV04feJgumvX2fsrQEWZghL0JnVdYkn3DOZIeRN86RqPWCmsvGVqEMRnwxQAxwS8EMYo3IzmY2+BCcLp4MKiuyuhImamlbZFcNoNl7tp+RHd18ZjQIRKyXdFRhN98/hyKqwXWNo7O1wiaXoHN108REZZWEq6grnIfjzeg8jdRf1XEL4kkXa5bBjKxoKaljBjeHlVxQ4GaycpW4lDOAKtnTxHAtOfzOtZwHAM7sqVXkV6yu6kap1nHkXKqWF/4XHqjenNKqBjpR3l1ch3Ejg1+EsgdQhsdG0B4FM9sWAVWpuAyiwTPleZxt9VyZVS2qXfReWqTAilpr9ApoWTjxymit7NwV4JTriZyOA9B0k7HFfULourmKYHVnRQvqGL5HMHdqFcR2qWpmcK6eTwx2dipWrviDilr+fKWq3OWRWdHKwA4eu8wjchbeRzFilqjjZN3ufCpfkJ0/scVpnYk6L0PI77lxdWCZ87WiWm7B/AGquQSnujGKsB8CJmiJq8q1pKIVWyqOiTK66r18BN8r74/AE71fdC3yPS2MxdOpnE1tlVxD9JmVOoggN+r4PjAXVFPa3Eg5jVJGFVUGNolH20GVrUB7BOySWq6WqYQdWR92pcFMYMwckbSgCKCqD67DiiWu1g8MQC9ByfcFqW1L+jL714qNCuznoSxt0da2gtWN1G8F0BK0NN0nuimelUF9dIdAfjO44UT3CjQLoUeLHJFTO3gmpRuIIOvwBQCbqNeo3qtZ9iF6xVK13GRlo4zqimq+CGdTiR1uRY8oqgE02hZBa79kZXPMquxRHKla2saZWN4mRqZUj0vLCKhkjKnqOQHNuSZVJoKvAqS1wpEquvWDC1B2ypwrCPsRMEPVTODMLJMDv6qeKXwi2JYV5Sq4qKyvgGsHCLiuj2jR59V8gMqSJ2FJZRXEHVRHj3sFPrct6OpqlW1GpatQdt0GvwfM6n63InsGVFhJGaBqgqqIV6IsXllZgySPq4R3bnt3wi5cv+cN2yqQLW1T95KYVsWWtKk4cB9W53WQQflQYR6Wl4HaJZjvVE0D5yvq+RKgZCs5qdBEP5sD94cAvQLlSgNaSMAtHx88BuNQ41zdFsX30zKbcs0MLD/ihkpQzl0wiTqKLTfbKmCmyYICnK0IbaieC4CG9iSyLQ7cIMGQwau6TKoq60Apl3WN40LZpca1CKKK9VQyyIEn8w0F8F6CL2h8o3ixGwC7s7EWzCOqmcApYxYD4jsAzVS0sl2t98pA7vrKophCVSonbYpgH6mvSn24pTBV4sdtV3BtMq5k82y+IADvUJ0uAlkCVTxIaPm+UNu/qkV4F1TzHXCGrXIAqItBKypqK99VtAOVs64O4ObX7pHLVCpYHcRmwvLR7TvYAKBBN58LGVzDuFz+hQbWgncQyCZAk+VbsPSouf93261iZgmfCpwRbAvqmSqriU2PwhjaoOyYqtIegVXViTsmyta6bGySpY3gyRrpIyAeaWDDxtpsXwKyalMDKNP7YBXMqEskUsi2uC8FNAPxAKTVfT1o6VzM0E0jF+1rWcUuHvdyg7vgoFplX8HpvHpMCOMRUPHzZkInsqlFKNX/EIO52E0SxSzOwob2VmRLW5D1XIU0rbgM1AzWgyC7fe8G7xUAK/taEBat7luqtyP7EmsaJQOj5F+mrnZfCuYCfBUAWwShyd6pMY/vAHG1UqOYpbI/gy5T0CMKm+UO3gFuC85dgfDVeguPDfITrIBLsLrcgdh3CFgFZjaKJ4Iv3F8ANEqvuxR1tVKOgLoCa1jxboBAkj6v7j/icFbA7f4rfRnQDLRViG13i0vqBQrYVqBbADZT0ZpiHoSzvQpopKIFS3sE1HfBWlHXd0H7LnArqvougMtljHBgZnh3Eoz/BKjLML4Z2Aq0+hEJr9jaVUBbvNzCIUiroC7AWmmFw4o5AK3MtB5VypZMSFgs05JyGVwlwBqsEGAAa2ZU1CjUexXGsE4rKriilBvFzOKKo3AuAroE6QFQU3u8YpNXwS5k+1TZt5UrwouN4KiUEw+k3ZWDp1RXHNRqXb21Ts39945yZSg3VnZFNQ9CF3XeZyr5DgBXKiwCMa2MxeTDYXgP1Fsf9QNKZc0k81RJk3r6EQ3rCmBVyLL75EjZ1pIVDHoFtiOAHoB0BdTVylqBsKKKS+AeBXJVLY+CXASuGvO/Auq7GuEjDfGKg1oKa1z/dmmi9I9SUGNhl0AtfulHAawoYrnSkmNXAVuGEhrEVXvUF+A5Ct2PqNOjDetyna4CmeUolmeXLN4Aq7C5Sj10Q7yjgl+t6CNxSRHmI5X+CpwreYB3Qfdqna4q21KdBuc4GoZsn49ZOOiVinwHqK9WzjvgeweEh2AU5+vtxZ9Cd9Wqkh49V18E5oj6vVyn0RStAyGIO5edXRKd5B0VGVXq2yr3xYp+5Ut+C4QJ4P1N339pQMjRejj4vb/Dcr6rQc3O/0rjmtZpeYCBiCHfCemRbNhbK/pNUPc3wfKy5f2D7OlL3/uPhve/oU4T0F8f+VNM2vyoiv0jK+KHQfdHq+0bncz4oz73/+Y6LbKw1o/5B7eOf1Rl/0du9B9tn/9bvrf/j+v0h6ttn2tp/r/4819y4/zv5391uvzzfwDifz6phT1MPgAAAABJRU5ErkJggg==');
|
|
}
|
|
|
|
.x-cursor {
|
|
cursor: default;
|
|
width: 16px;
|
|
height: 16px;
|
|
border-width: 2px;
|
|
position: relative;
|
|
border-style: solid;
|
|
@include boder-radius(50%);
|
|
border-color: var(--cursor-color);
|
|
}
|
|
|
|
.x-info-box {
|
|
//
|
|
display: flex;
|
|
margin-bottom: 8px;
|
|
|
|
//
|
|
.x-start {
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
|
|
position: relative;
|
|
}
|
|
|
|
//
|
|
.x-margin {
|
|
width: 2px;
|
|
height: auto;
|
|
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
//
|
|
.x-end {
|
|
flex: 1 1 auto;
|
|
}
|
|
}
|
|
|
|
.x-selected-color {
|
|
top: 0;
|
|
left: 0;
|
|
width: 40px;
|
|
height: 40px;
|
|
position: absolute;
|
|
@include boder-radius(50%);
|
|
}
|
|
|
|
.x-selected-color-background {
|
|
width: 40px;
|
|
height: 40px;
|
|
@include boder-radius(50%);
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAh0lEQVRYR+2W0QlAMQgD60zdfwOdqa8TmI/wQMr5K0I5bZLIzLOa2nt37VVVbd+dDx5obgCC3KBLwJ2ff4PnVidkf+ucIhw80HQaCLo3DMH3CRK3iFsmAWVl6hPNDwt8EvNE5q+YuEXcMgkonVM6SdyCoEvAnZ8v1Hjx817MilmxSUB5rdLJDycZgUAZUch/AAAAAElFTkSuQmCC');
|
|
}
|
|
|
|
.x-color-hue {
|
|
width: 100%;
|
|
height: 16px;
|
|
border: none;
|
|
cursor: pointer;
|
|
margin-bottom: 8px;
|
|
background-size: 100% 100%;
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwkUFWbCCAAAAFxJREFUaN7t0kEKg0AQAME2x83/n2qu5qCgD1iDhCoYdpnbQC9bbY1qVO/jvc6k3ad91s7/7F1/csgPrujuQ17BDYSFsBAWwgJhISyEBcJCWAgLhIWwEBYIi2f7Ar/1TCgFH2X9AAAAAElFTkSuQmCC');
|
|
}
|
|
|
|
.x-color-alpha {
|
|
width: 100%;
|
|
height: 16px;
|
|
border: none;
|
|
cursor: pointer;
|
|
background-size: 100% 100%;
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwYQlZMa3gAAAWVJREFUaN7tmEGO6jAQRCsOArHgBpyAJYGjcGocxAm4A2IHpmoWE0eBH+ezmFlNvU06shJ3W6VEelWMUQAIIF9f6qZpimsA1LYtS2uF51/u27YVAFZVRUkEoGHdPV/sIcbIEIIkUdI/9Xa7neyv61+SWFUVAVCSct00TWn2fv6u3+Ecfd3tXzy/0+nEUu+SPjo/kqzrmiQpScN6v98XewfA8/lMkiLJ2WxGSUopcT6fM6U0NX9/frfbjev1WtfrlZfLhYfDQQHG/AIOlnGwjINlHCxjHCzjYJm/TJWdCwquJXseFFzGwDNNeiKMOJTO8xQdDQaeB29+K9efeLaBo9J7vdvtJj1RjFFjfiv7qv95tjx/7leSQgh93e1ffMeIp6O+YQjho/N791t1XVOSSI7N//K+4/GoxWLBx+PB5/Op5XLJ+/3OlJJWqxU3m83ovv5iGf8KjYNlHCxjHCzjYBkHy5gf5gusvQU7U37jTAAAAABJRU5ErkJggg==');
|
|
}
|
|
|
|
.x-color-value {
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.x-hex,
|
|
.x-rgba,
|
|
.x-hsla {
|
|
display: flex;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.x-color-text {
|
|
display: block;
|
|
flex: 1 1 auto;
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
}
|
|
|
|
.x-color-input {
|
|
//
|
|
width: 100%;
|
|
background-color: transparent !important;
|
|
|
|
//
|
|
border: {
|
|
top: unset;
|
|
left: unset;
|
|
right: unset;
|
|
}
|
|
|
|
&:focus {
|
|
outline: unset;
|
|
}
|
|
}
|
|
|
|
.x-preset-colors-wrapper {
|
|
* {
|
|
text-align: start;
|
|
}
|
|
}
|
|
|
|
.x-preset-label {
|
|
display: block;
|
|
}
|
|
|
|
.x-preset-colors-box {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
}
|
|
|
|
.x-preset-color {
|
|
width: 18px;
|
|
height: 18px;
|
|
cursor: pointer;
|
|
display: inline-block;
|
|
margin: 6px 6px 8px 6px;
|
|
@include boder-radius(25%);
|
|
border: #a9a9a9 solid 1px;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
rgbString,
|
|
XHSVAColor,
|
|
hslaToHsva,
|
|
hsvaToHsla,
|
|
rgbaString,
|
|
rgbaToHsva,
|
|
hsvaToRgba,
|
|
rgbaToHex1,
|
|
hslaString,
|
|
parseXColor,
|
|
stringToHsva,
|
|
toNormalString,
|
|
denormalizeRGBA,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
XSliderValueEventModel,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XSliderPosition,
|
|
XSliderDimension,
|
|
XColorPickerAction,
|
|
XColorPickerCssVar,
|
|
XColorPickerActionModel,
|
|
XColorPickerOutputFormat,
|
|
DEFAULT_COLOR_PICKER_COLOR,
|
|
XColorPickerContainerComponent,
|
|
} from './x-color-picker.typings';
|
|
import { Subscription, Subject } from 'rxjs';
|
|
|
|
@Component({
|
|
selector: 'x-color-picker',
|
|
templateUrl: './x-color-picker.component.html',
|
|
styleUrls: ['./x-color-picker.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XColorPickerComponent extends XColorPickerContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private LAST_OUTPUT_COLOR: string;
|
|
|
|
//
|
|
readonly ColorFormats = Object.assign({}, XColorPickerOutputFormat);
|
|
|
|
//
|
|
hexValue: string;
|
|
hslaValue: string;
|
|
rgbaValue: string;
|
|
|
|
//
|
|
hsva: XHSVAColor = {
|
|
h: 0,
|
|
s: 0,
|
|
v: 0,
|
|
a: 1,
|
|
};
|
|
hueSliderColor: string;
|
|
slider: XSliderPosition;
|
|
alphaSliderColor: string;
|
|
sliderDimMax: XSliderDimension;
|
|
|
|
//
|
|
inputColor: string;
|
|
|
|
//
|
|
//#region View Childs ...
|
|
//
|
|
//#region ColorPicker ViewChild ...
|
|
private COLOR_PICKER: ElementRef<any>;
|
|
|
|
@ViewChild('colorPicker', { static: false })
|
|
set colorPicker(v: ElementRef<any>) {
|
|
//
|
|
this.COLOR_PICKER = v;
|
|
this.initializeComponent();
|
|
}
|
|
|
|
get colorPicker() {
|
|
return this.COLOR_PICKER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region PaletteSlider ViewChild ...
|
|
private PALETTE_SLIDER: ElementRef<any>;
|
|
|
|
@ViewChild('paletteSlider', { static: false })
|
|
set paletteSlider(v: ElementRef<any>) {
|
|
//
|
|
this.PALETTE_SLIDER = v;
|
|
this.initializeComponent();
|
|
}
|
|
|
|
get paletteSlider() {
|
|
return this.PALETTE_SLIDER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region HueSlider ViewChild ...
|
|
private HUE_SLIDER: ElementRef<any>;
|
|
|
|
@ViewChild('hueSlider', { static: false })
|
|
set hueSlider(v: ElementRef<any>) {
|
|
//
|
|
this.HUE_SLIDER = v;
|
|
this.initializeComponent();
|
|
}
|
|
|
|
get hueSlider() {
|
|
return this.HUE_SLIDER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region AlphaSlider ViewChild ...
|
|
private ALPHA_SLIDER: ElementRef<any>;
|
|
|
|
@ViewChild('alphaSlider', { static: false })
|
|
set alphaSlider(v: ElementRef<any>) {
|
|
//
|
|
this.ALPHA_SLIDER = v;
|
|
this.initializeComponent();
|
|
}
|
|
|
|
get alphaSlider() {
|
|
return this.ALPHA_SLIDER;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.applyColors();
|
|
await this.initializeComponent();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Colors Changed ...
|
|
const isCursorColorChanged = changeKeys.includes(
|
|
nameof<XColorPickerComponent>('cursorColor')
|
|
);
|
|
if (isCursorColorChanged) {
|
|
await this.applyColors();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region SelectedColor Changed ...
|
|
const isSelectedColorChanged = changeKeys.includes(
|
|
nameof<XColorPickerComponent>('selectedColor')
|
|
);
|
|
if (isSelectedColorChanged) {
|
|
//
|
|
const selectedColor = await this.getValueAsync(this.selectedColor);
|
|
if (isNullOrEmptyString(selectedColor)) {
|
|
this.LAST_OUTPUT_COLOR = DEFAULT_COLOR_PICKER_COLOR;
|
|
} else {
|
|
this.LAST_OUTPUT_COLOR = selectedColor;
|
|
}
|
|
|
|
//
|
|
await this.initializeComponent();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XColorPickerComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
}
|
|
|
|
async onResize() {
|
|
super.onResize();
|
|
|
|
//
|
|
await this.initializeComponent();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleSaveSelectedColorInClipboard(color: string) {
|
|
//
|
|
if (isNullOrEmptyString(color)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isSaved = this.managerService.saveToClipboard(color);
|
|
if (!isSaved) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.notificationService.presentDefaultSuccessNotification();
|
|
}
|
|
|
|
async handleClearSelectedColor() {
|
|
//
|
|
this.selectedColor = DEFAULT_COLOR_PICKER_COLOR;
|
|
this.LAST_OUTPUT_COLOR = DEFAULT_COLOR_PICKER_COLOR;
|
|
|
|
//
|
|
this.detectChanges();
|
|
this.colorSelected.emit('');
|
|
}
|
|
|
|
async handleInputColor(event?: any) {
|
|
//
|
|
if (isNullOrEmptyString(this.inputColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const color = toNormalString(this.inputColor);
|
|
this.selectedColor = color;
|
|
await this.initializeComponent();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async setR(model: XSliderValueEventModel) {
|
|
//
|
|
const rgba = hsvaToRgba(this.hsva);
|
|
rgba.r = model.v / model.rg;
|
|
this.hsva = rgbaToHsva(rgba);
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setG(model: XSliderValueEventModel) {
|
|
//
|
|
const rgba = hsvaToRgba(this.hsva);
|
|
rgba.g = model.v / model.rg;
|
|
this.hsva = rgbaToHsva(rgba);
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setB(model: XSliderValueEventModel) {
|
|
//
|
|
const rgba = hsvaToRgba(this.hsva);
|
|
rgba.b = model.v / model.rg;
|
|
this.hsva = rgbaToHsva(rgba);
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setHue(model: XSliderValueEventModel) {
|
|
//
|
|
this.hsva.h = model.v / model.rg;
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setHexColor(model: string) {
|
|
//
|
|
let hsva = stringToHsva(model);
|
|
if (!hsva) {
|
|
hsva = stringToHsva(model);
|
|
}
|
|
|
|
//
|
|
if (hsva) {
|
|
//
|
|
this.hsva = hsva;
|
|
await this.update();
|
|
}
|
|
}
|
|
|
|
async setAlpha(model: XSliderValueEventModel) {
|
|
//
|
|
this.hsva.a = model.v / model.rg;
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setSaturation(model: XSliderValueEventModel) {
|
|
//
|
|
const hsla = hsvaToHsla(this.hsva);
|
|
hsla.s = model.v / model.rg;
|
|
this.hsva = hslaToHsva(hsla);
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setLightness(model: XSliderValueEventModel) {
|
|
//
|
|
const hsla = hsvaToHsla(this.hsva);
|
|
hsla.l = model.v / model.rg;
|
|
this.hsva = hslaToHsva(hsla);
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
async setSaturationAndBrightness(model: XSliderValueEventModel) {
|
|
//
|
|
this.hsva.s = model.s / model.rgX;
|
|
this.hsva.v = model.v / model.rgY;
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XColorPickerActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XColorPickerAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XColorPickerAction.SetSelectedColor:
|
|
//
|
|
if (model.payload) {
|
|
//
|
|
this.selectedColor = model.payload as string;
|
|
await this.initializeComponent();
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async applyColors() {
|
|
//
|
|
let cursorColor = await this.getValueAsync(this.cursorColor);
|
|
if (!cursorColor) {
|
|
cursorColor = XColorWithBrightness.Dark;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(cursorColor);
|
|
if (!colorDescriptor) {
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XColorPickerCssVar.CursorColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async initializeComponent() {
|
|
//
|
|
if (!this.colorPicker) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorPickerElement = this.colorPicker.nativeElement as HTMLElement;
|
|
if (!colorPickerElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let paletteWidth = 0;
|
|
let paletteHeight = 0;
|
|
let hueOffsetWith = 0;
|
|
let alphaOffsetWith = 0;
|
|
|
|
//
|
|
//#region Check Palette ...
|
|
const hasPaletteChannel = await this.getValueAsync(this.showPaletteChannel);
|
|
if (hasPaletteChannel) {
|
|
//
|
|
if (!this.paletteSlider) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const paletteElement = this.paletteSlider.nativeElement as HTMLElement;
|
|
if (!paletteElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
paletteWidth = paletteElement.offsetWidth;
|
|
if (paletteWidth === 0) {
|
|
setTimeout(() => this.initializeComponent(), 100);
|
|
return;
|
|
}
|
|
|
|
//
|
|
paletteHeight = paletteElement.offsetHeight;
|
|
if (paletteHeight === 0) {
|
|
setTimeout(() => this.initializeComponent(), 100);
|
|
return;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Check Hue ...
|
|
const hasHueChannel = await this.getValueAsync(this.showHueChannel);
|
|
if (hasHueChannel) {
|
|
//
|
|
if (!this.hueSlider) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hueElement = this.hueSlider.nativeElement as HTMLElement;
|
|
if (!hueElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
hueOffsetWith = hueElement.offsetWidth;
|
|
if (hueOffsetWith === 0) {
|
|
setTimeout(() => this.initializeComponent(), 100);
|
|
return;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Check Alpha ...
|
|
const hasAlphaChannel = await this.getValueAsync(this.showAlphaChannel);
|
|
if (hasAlphaChannel) {
|
|
//
|
|
if (!this.alphaSlider) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const alphaElement = this.alphaSlider.nativeElement as HTMLElement;
|
|
if (!alphaElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
alphaOffsetWith = alphaElement.offsetWidth;
|
|
if (alphaOffsetWith === 0) {
|
|
setTimeout(() => this.initializeComponent(), 100);
|
|
return;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.sliderDimMax = {
|
|
h: hueOffsetWith,
|
|
s: paletteWidth,
|
|
v: paletteHeight,
|
|
a: alphaOffsetWith,
|
|
};
|
|
|
|
//
|
|
this.slider = {
|
|
h: 0,
|
|
s: 0,
|
|
v: 0,
|
|
a: 0,
|
|
};
|
|
|
|
//
|
|
let selectedColor = await this.getValueAsync(this.selectedColor);
|
|
if (isNullOrEmptyString(selectedColor)) {
|
|
selectedColor = DEFAULT_COLOR_PICKER_COLOR;
|
|
}
|
|
|
|
//
|
|
let hsva = stringToHsva(selectedColor);
|
|
if (hsva) {
|
|
//
|
|
this.hsva = hsva;
|
|
|
|
//
|
|
await this.update();
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async getSelectedColor() {
|
|
//
|
|
const rgba = denormalizeRGBA(hsvaToRgba(this.hsva));
|
|
|
|
//
|
|
let outputFormat = await this.getValueAsync(this.outputFormat);
|
|
if (isNullOrEmptyString(outputFormat)) {
|
|
outputFormat = XColorPickerOutputFormat.XHEX;
|
|
}
|
|
|
|
//
|
|
let result = '';
|
|
switch (outputFormat) {
|
|
//
|
|
case XColorPickerOutputFormat.XHEX:
|
|
result = rgbaToHex1(rgba, true);
|
|
break;
|
|
|
|
//
|
|
case XColorPickerOutputFormat.XHSLA:
|
|
//
|
|
const hsla = hsvaToHsla(this.hsva);
|
|
result = hslaString(hsla);
|
|
break;
|
|
|
|
//
|
|
case XColorPickerOutputFormat.XRGBA:
|
|
result = rgbaString(rgba);
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private async update() {
|
|
//
|
|
const rgba = denormalizeRGBA(hsvaToRgba(this.hsva));
|
|
const hsla = hsvaToHsla(this.hsva);
|
|
|
|
//
|
|
const hHsva: XHSVAColor = {
|
|
h: this.hsva.h,
|
|
s: 1,
|
|
v: 1,
|
|
a: 1,
|
|
};
|
|
const hueRgba = denormalizeRGBA(hsvaToRgba(hHsva));
|
|
|
|
//
|
|
this.hexValue = rgbaToHex1(rgba, true);
|
|
this.rgbaValue = rgbaString(rgba);
|
|
this.hslaValue = hslaString(hsla);
|
|
|
|
//
|
|
this.alphaSliderColor = rgbString(rgba);
|
|
this.hueSliderColor = rgbString(hueRgba);
|
|
|
|
//
|
|
this.selectedColor = await this.getSelectedColor();
|
|
const selectedColor = await this.getValueAsync(this.selectedColor);
|
|
|
|
//
|
|
this.slider = {
|
|
h: this.hsva.h * this.sliderDimMax.h - 8,
|
|
s: this.hsva.s * this.sliderDimMax.s - 8,
|
|
v: (1 - this.hsva.v) * this.sliderDimMax.v - 8,
|
|
a: this.hsva.a * this.sliderDimMax.a - 8,
|
|
};
|
|
|
|
//
|
|
if (
|
|
!isNullOrEmptyString(this.LAST_OUTPUT_COLOR) &&
|
|
this.LAST_OUTPUT_COLOR !== selectedColor
|
|
) {
|
|
//
|
|
this.LAST_OUTPUT_COLOR = selectedColor;
|
|
this.colorSelected.emit(selectedColor);
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XColorPickerComponent } from './x-color-picker.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XColorTextDirective } from './directives/x-color-text.directive';
|
|
import { XColorPickerDialogService } from './x-color-picker-dialog/x-color-picker-dialog.service';
|
|
import { XColorPickerDialogComponent } from './x-color-picker-dialog/x-color-picker-dialog.component';
|
|
|
|
@NgModule({
|
|
providers: [XColorPickerDialogService],
|
|
entryComponents: [XColorPickerDialogComponent],
|
|
declarations: [
|
|
XColorTextDirective,
|
|
XColorPickerComponent,
|
|
XColorPickerDialogComponent,
|
|
],
|
|
imports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XColorTextDirective,
|
|
XBaseComponentModule,
|
|
XColorPickerComponent,
|
|
XColorPickerDialogComponent,
|
|
],
|
|
})
|
|
export class XColorPickerModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XHSVAColor,
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XColorPickerAction {
|
|
Refresh = 'refresh',
|
|
SetSelectedColor = 'set_selected_color',
|
|
}
|
|
|
|
export type XColorPickerActionIdentifier = XColorPickerAction | string;
|
|
|
|
export interface XColorPickerActionModel
|
|
extends XBaseActionModel<XColorPickerActionIdentifier> {}
|
|
|
|
export interface XSliderPosition extends Required<XHSVAColor> {}
|
|
|
|
export interface XSliderDimension extends Required<XHSVAColor> {}
|
|
|
|
export enum XColorPickerOutputFormat {
|
|
XHEX = 'hex',
|
|
XRGBA = 'rgba',
|
|
XHSLA = 'hsla',
|
|
}
|
|
|
|
export type XColorPickerOutputFormatIdentifier =
|
|
| XColorPickerOutputFormat
|
|
| string;
|
|
|
|
export enum XColorPickerCssVar {
|
|
CursorColor = 'cursor-color',
|
|
}
|
|
|
|
export const DEFAULT_COLOR_PICKER_COLOR = '#ffffffff';
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXColorPickerContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XColorPickerActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
colorSelected: EventEmitter<string>;
|
|
|
|
//
|
|
//#region Colors ...
|
|
selectedColor: XStandardType<string>;
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
copyToClipboardIconColor: XStandardType<XColorIdentifier>;
|
|
colorInputIconColor: XStandardType<XColorIdentifier>;
|
|
clearColorIconColor: XStandardType<XColorIdentifier>;
|
|
colorTextColor: XStandardType<XColorIdentifier>;
|
|
presetColorsLableColor: XStandardType<XColorIdentifier>;
|
|
cursorColor: XStandardType<XColorIdentifier>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Labels ...
|
|
colorInputIconLabel: XStandardType<XResourceIdentifier>;
|
|
copyToClipboardIconLabel: XStandardType<XResourceIdentifier>;
|
|
clearColorIconLabel: XStandardType<XResourceIdentifier>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region PresetColors ...
|
|
presetColorsLable: XStandardType<XResourceIdentifier>;
|
|
presetColors: XStandardType<XOneOrManyType<string>>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Represent Color Value ...
|
|
representColorFormats: XStandardType<
|
|
XOneOrManyType<XColorPickerOutputFormatIdentifier>
|
|
>;
|
|
outputFormat: XStandardType<XColorPickerOutputFormatIdentifier>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Parts Props ...
|
|
showColorInput: XStandardType<boolean>;
|
|
showCopyToClipboard: XStandardType<boolean>;
|
|
showSelectedColorPreview: XStandardType<boolean>;
|
|
showPaletteChannel: XStandardType<boolean>;
|
|
showHueChannel: XStandardType<boolean>;
|
|
showAlphaChannel: XStandardType<boolean>;
|
|
showColorValue: XStandardType<boolean>;
|
|
showPresetColors: XStandardType<boolean>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XColorPickerContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXColorPickerContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XColorPickerActionModel> =
|
|
new Subject<XColorPickerActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly colorSelected: EventEmitter<string> = new EventEmitter();
|
|
|
|
//
|
|
//#region Colors ...
|
|
readonly selectedColor: XStandardType<string> = DEFAULT_COLOR_PICKER_COLOR;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly copyToClipboardIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryShade;
|
|
|
|
readonly colorInputIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.SecondaryShade;
|
|
|
|
readonly clearColorIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
|
|
readonly colorTextColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
readonly presetColorsLableColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
readonly cursorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Labels ...
|
|
readonly colorInputIconLabel: XStandardType<XResourceIdentifier> =
|
|
XResourceIDs.input;
|
|
|
|
readonly copyToClipboardIconLabel: XStandardType<XResourceIdentifier> =
|
|
XResourceIDs.copy_to_clipboard;
|
|
|
|
readonly clearColorIconLabel: XStandardType<XResourceIdentifier> =
|
|
XResourceIDs.clear;
|
|
//#endregion
|
|
|
|
//
|
|
//#region PresetColors ...
|
|
readonly presetColorsLable: XStandardType<XResourceIdentifier>;
|
|
readonly presetColors: XStandardType<XOneOrManyType<string>>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Represent Color Value ...
|
|
readonly representColorFormats: XStandardType<
|
|
XOneOrManyType<XColorPickerOutputFormatIdentifier>
|
|
> = [XColorPickerOutputFormat.XHEX];
|
|
|
|
readonly outputFormat: XStandardType<XColorPickerOutputFormatIdentifier> =
|
|
XColorPickerOutputFormat.XHEX;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Parts Props ...
|
|
readonly showColorInput: XStandardType<boolean> = true;
|
|
readonly showCopyToClipboard: XStandardType<boolean> = false;
|
|
readonly showSelectedColorPreview: XStandardType<boolean> = true;
|
|
readonly showPaletteChannel: XStandardType<boolean> = true;
|
|
readonly showHueChannel: XStandardType<boolean> = true;
|
|
readonly showAlphaChannel: XStandardType<boolean> = true;
|
|
readonly showColorValue: XStandardType<boolean> = true;
|
|
readonly showPresetColors: XStandardType<boolean> = true;
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XColorPickerContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXColorPickerContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XColorPickerActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Output()
|
|
colorSelected: EventEmitter<string> = new EventEmitter();
|
|
|
|
//
|
|
//#region Colors ...
|
|
@Input()
|
|
selectedColor: XStandardType<string> = this.propertyProvider.selectedColor;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
copyToClipboardIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.copyToClipboardIconColor;
|
|
|
|
@Input()
|
|
colorInputIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.colorInputIconColor;
|
|
|
|
@Input()
|
|
clearColorIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.clearColorIconColor;
|
|
|
|
@Input()
|
|
colorTextColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.colorTextColor;
|
|
|
|
@Input()
|
|
presetColorsLableColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.presetColorsLableColor;
|
|
|
|
@Input()
|
|
cursorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.cursorColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Labels ...
|
|
@Input()
|
|
colorInputIconLabel: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.colorInputIconLabel;
|
|
|
|
@Input()
|
|
copyToClipboardIconLabel: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.copyToClipboardIconLabel;
|
|
|
|
@Input()
|
|
clearColorIconLabel: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.clearColorIconLabel;
|
|
//#endregion
|
|
|
|
//
|
|
//#region PresetColors ...
|
|
@Input()
|
|
presetColorsLable: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.presetColorsLable;
|
|
|
|
@Input()
|
|
presetColors: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.presetColors;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Represent Color Value ...
|
|
@Input()
|
|
representColorFormats: XStandardType<
|
|
XOneOrManyType<XColorPickerOutputFormatIdentifier>
|
|
> = this.propertyProvider.representColorFormats;
|
|
|
|
@Input()
|
|
outputFormat: XStandardType<XColorPickerOutputFormatIdentifier> =
|
|
this.propertyProvider.outputFormat;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Parts Props ...
|
|
@Input()
|
|
showColorInput: XStandardType<boolean> = this.propertyProvider.showColorInput;
|
|
|
|
@Input()
|
|
showCopyToClipboard: XStandardType<boolean> =
|
|
this.propertyProvider.showCopyToClipboard;
|
|
|
|
@Input()
|
|
showSelectedColorPreview: XStandardType<boolean> =
|
|
this.propertyProvider.showSelectedColorPreview;
|
|
|
|
@Input()
|
|
showPaletteChannel: XStandardType<boolean> =
|
|
this.propertyProvider.showPaletteChannel;
|
|
|
|
@Input()
|
|
showHueChannel: XStandardType<boolean> = this.propertyProvider.showHueChannel;
|
|
|
|
@Input()
|
|
showAlphaChannel: XStandardType<boolean> =
|
|
this.propertyProvider.showAlphaChannel;
|
|
|
|
@Input()
|
|
showColorValue: XStandardType<boolean> = this.propertyProvider.showColorValue;
|
|
|
|
@Input()
|
|
showPresetColors: XStandardType<boolean> =
|
|
this.propertyProvider.showPresetColors;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XColorPickerContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXColorPickerContainer
|
|
): Observable<IXColorPickerContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
//#region Colors ...
|
|
selectedColor: this.getValue(
|
|
container ? container.selectedColor : this.selectedColor
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
copyToClipboardIconColor: this.getValue(
|
|
container
|
|
? container.copyToClipboardIconColor
|
|
: this.copyToClipboardIconColor
|
|
),
|
|
colorInputIconColor: this.getValue(
|
|
container
|
|
? container.colorInputIconColor
|
|
: this.colorInputIconColor
|
|
),
|
|
clearColorIconColor: this.getValue(
|
|
container
|
|
? container.clearColorIconColor
|
|
: this.clearColorIconColor
|
|
),
|
|
colorTextColor: this.getValue(
|
|
container ? container.colorTextColor : this.colorTextColor
|
|
),
|
|
presetColorsLableColor: this.getValue(
|
|
container
|
|
? container.presetColorsLableColor
|
|
: this.presetColorsLableColor
|
|
),
|
|
cursorColor: this.getValue(
|
|
container ? container.cursorColor : this.cursorColor
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Labels ...
|
|
colorInputIconLabel: this.getValue(
|
|
container
|
|
? container.colorInputIconLabel
|
|
: this.colorInputIconLabel
|
|
),
|
|
copyToClipboardIconLabel: this.getValue(
|
|
container
|
|
? container.copyToClipboardIconLabel
|
|
: this.copyToClipboardIconLabel
|
|
),
|
|
clearColorIconLabel: this.getValue(
|
|
container
|
|
? container.clearColorIconLabel
|
|
: this.clearColorIconLabel
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region PresetColors ...
|
|
presetColorsLable: this.getValue(
|
|
container ? container.presetColorsLable : this.presetColorsLable
|
|
),
|
|
presetColors: this.getValue(
|
|
container ? container.presetColors : this.presetColors
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Represent Color Value ...
|
|
representColorFormats: this.getValue(
|
|
container
|
|
? container.representColorFormats
|
|
: this.representColorFormats
|
|
),
|
|
outputFormat: this.getValue(
|
|
container ? container.outputFormat : this.outputFormat
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Parts Props ...
|
|
showColorInput: this.getValue(
|
|
container ? container.showColorInput : this.showColorInput
|
|
),
|
|
showCopyToClipboard: this.getValue(
|
|
container
|
|
? container.showCopyToClipboard
|
|
: this.showCopyToClipboard
|
|
),
|
|
showSelectedColorPreview: this.getValue(
|
|
container
|
|
? container.showSelectedColorPreview
|
|
: this.showSelectedColorPreview
|
|
),
|
|
showPaletteChannel: this.getValue(
|
|
container ? container.showPaletteChannel : this.showPaletteChannel
|
|
),
|
|
showHueChannel: this.getValue(
|
|
container ? container.showHueChannel : this.showHueChannel
|
|
),
|
|
showAlphaChannel: this.getValue(
|
|
container ? container.showAlphaChannel : this.showAlphaChannel
|
|
),
|
|
showColorValue: this.getValue(
|
|
container ? container.showColorValue : this.showColorValue
|
|
),
|
|
showPresetColors: this.getValue(
|
|
container ? container.showPresetColors : this.showPresetColors
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
colorSelected: this.colorSelected,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\directives\x-color-text.directive.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Directive,
|
|
EventEmitter,
|
|
HostListener,
|
|
} from '@angular/core';
|
|
|
|
@Directive({
|
|
selector: '[xColorText]',
|
|
})
|
|
export class XColorTextDirective {
|
|
//
|
|
@Input()
|
|
text: any;
|
|
|
|
@Input()
|
|
rg: number;
|
|
|
|
//
|
|
@Output()
|
|
newValue = new EventEmitter<any>();
|
|
|
|
//
|
|
@HostListener('input', ['$event.target.value'])
|
|
changeInput(value: string) {
|
|
//
|
|
if (this.rg === undefined) {
|
|
this.newValue.emit(value);
|
|
} else {
|
|
//
|
|
const numeric = parseFloat(value);
|
|
|
|
//
|
|
if (!isNaN(numeric) && numeric >= 0 && numeric <= this.rg) {
|
|
this.newValue.emit({ v: numeric, rg: this.rg });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.html
|
|
|
|
<!-- Title Toolbar -->
|
|
<ion-toolbar class="v-toolbar" [xColor]="'primary'">
|
|
<!-- Slots -->
|
|
<div class="toolbar-area">
|
|
<x-slotter>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'ion-float-start']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleBack()"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="backIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<ion-title class="toolbar-item center-vertical-flex">
|
|
<h3>
|
|
{{ getTitle() | async }}
|
|
</h3>
|
|
</ion-title>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
[cssClass]="['ion-text-end', 'ion-float-end']"
|
|
>
|
|
<div
|
|
matRipple
|
|
*ngIf="canSelect()"
|
|
(click)="handleSelect()"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="selectIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</ion-toolbar>
|
|
|
|
<!-- ColorPicker Component -->
|
|
<x-color-picker
|
|
[isInPage]="true"
|
|
[wrapWithCard]="true"
|
|
[uiDisabled]="uiDisabled"
|
|
[color]="getColor() | async"
|
|
[actionProvider]="actionProvider"
|
|
[cssClass]="getCssClass() | async"
|
|
[cardColor]="getCardColor() | async"
|
|
[cardTitle]="getCardTitle() | async"
|
|
[cursorColor]="getCursorColor() | async"
|
|
[cardSubTitle]="getCardSubTitle() | async"
|
|
[presetColors]="getPresetColors() | async"
|
|
[outputFormat]="getOutputFormat() | async"
|
|
[showHueChannel]="showHueChannel() | async"
|
|
[showColorValue]="showColorValue() | async"
|
|
[showColorInput]="showColorInput() | async"
|
|
[selectedColor]="getSelectedColor() | async"
|
|
(colorSelected)="handleColorSelected($event)"
|
|
[colorTextColor]="getColorTextColor() | async"
|
|
[foregroundColor]="isForegroundColor() | async"
|
|
[showPresetColors]="showPresetColors() | async"
|
|
[showAlphaChannel]="showAlphaChannel() | async"
|
|
[showPaletteChannel]="showPaletteChannel() | async"
|
|
[presetColorsLable]="getPresetColorsLable() | async"
|
|
[showCopyToClipboard]="showCopyToClipboard() | async"
|
|
[cardForegroundColor]="isCardForegroundColor() | async"
|
|
[clearColorIconColor]="getClearColorIconColor() | async"
|
|
[clearColorIconLabel]="getClearColorIconLabel() | async"
|
|
[representColorFormats]="getRepresentColorFormats() | async"
|
|
[presetColorsLableColor]="getPresetColorsLableColor() | async"
|
|
[colorInputIconColor]="getColorInputIconColor() | async"
|
|
[colorInputIconLabel]="getColorInputIconLabel() | async"
|
|
[showSelectedColorPreview]="showSelectedColorPreview() | async"
|
|
[copyToClipboardIconColor]="getCopyToClipboardIconColor() | async"
|
|
[copyToClipboardIconLabel]="getCopyToClipboardIconLabel() | async"
|
|
>
|
|
</x-color-picker>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.scss
|
|
|
|
::ng-deep.fullscreen-dialog {
|
|
//
|
|
width: 80vw !important;
|
|
max-width: 80vw !important;
|
|
|
|
//
|
|
height: 80vh !important;
|
|
max-height: 80vh !important;
|
|
|
|
//
|
|
&.mobile {
|
|
//
|
|
width: 100vw !important;
|
|
max-width: 100vw !important;
|
|
|
|
//
|
|
height: 100vh !important;
|
|
max-height: 100vh !important;
|
|
}
|
|
|
|
//
|
|
.mat-dialog-container {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
|
|
x-icon {
|
|
--size: 24px;
|
|
}
|
|
|
|
.toolbar-area {
|
|
margin: 8px;
|
|
}
|
|
|
|
.toolbar-item {
|
|
width: auto;
|
|
height: 48px;
|
|
}
|
|
|
|
.toolbar-button {
|
|
width: 32px;
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.ts
|
|
|
|
import {
|
|
Inject,
|
|
NgZone,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XColor,
|
|
hasChild,
|
|
isFunction,
|
|
XResourceIDs,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XColorPickerActionModel,
|
|
XColorPickerOutputFormat,
|
|
} from '../x-color-picker.typings';
|
|
import { Subject, of } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XBasePage } from '../../classes/x-base-page';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconNames } from '../../x-icon/x-icon.typings';
|
|
import { XSlotName } from '../../x-slotter/x-slotter.typings';
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
import { XColorPickerDialogConfig } from './x-color-picker-dialog.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from './../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-color-picker-dialog',
|
|
templateUrl: './x-color-picker-dialog.component.html',
|
|
styleUrls: ['./x-color-picker-dialog.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XColorPickerDialogComponent extends XBasePage {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
selectIcon = XIconNames.checked;
|
|
backIcon = XIconNames.arrow_back;
|
|
SlotNames = Object.assign({}, XSlotName);
|
|
|
|
//
|
|
isMobileUi$ = this.managerService.isMobileUi$;
|
|
isNotMobile$ = this.managerService.isNotMobileUi$;
|
|
|
|
//
|
|
actionProvider = new Subject<XColorPickerActionModel>();
|
|
|
|
//
|
|
selectedColor: string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
|
public dialogRef: MatDialogRef<XColorPickerDialogComponent>
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
this.preventBack = true;
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
getData() {
|
|
return this.getValue(this.data as XColorPickerDialogConfig);
|
|
}
|
|
|
|
hasData() {
|
|
return !isNullOrUndefined(this.getData());
|
|
}
|
|
|
|
canSelect() {
|
|
return !isNullOrEmptyString(this.selectedColor);
|
|
}
|
|
|
|
getTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.title))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve selectedColor value ...
|
|
*/
|
|
getSelectedColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.selectedColor))
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Colors ...
|
|
/**
|
|
* retrieve color value ...
|
|
*/
|
|
getColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.color)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines is Foureground color or not ...
|
|
*/
|
|
isForegroundColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.foregroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve cursorColor value ...
|
|
*/
|
|
getCursorColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.cursorColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve colorTextColor value ...
|
|
*/
|
|
getColorTextColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.colorTextColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve clearColorIconColor value ...
|
|
*/
|
|
getClearColorIconColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.clearColorIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Danger))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve colorInputIconColor value ...
|
|
*/
|
|
getColorInputIconColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.colorInputIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Secondary))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve presetColorsLableColor value ...
|
|
*/
|
|
getPresetColorsLableColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.presetColorsLableColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve copyToClipboardIconColor value ...
|
|
*/
|
|
getCopyToClipboardIconColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.copyToClipboardIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Tertiary))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Labels ...
|
|
/**
|
|
* retrieve presetColorsLable value ...
|
|
*/
|
|
getPresetColorsLable() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.presetColorsLable)),
|
|
map((value) =>
|
|
!isNullOrEmptyString(value) ? value : XResourceIDs.preset_colors
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve clearColorIconLabel value ...
|
|
*/
|
|
getClearColorIconLabel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.clearColorIconLabel)),
|
|
map((value) => (!isNullOrEmptyString(value) ? value : XResourceIDs.clear))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve colorInputIconLabel value ...
|
|
*/
|
|
getColorInputIconLabel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.colorInputIconLabel)),
|
|
map((value) => (!isNullOrEmptyString(value) ? value : XResourceIDs.input))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve copyToClipboardIconLabel value ...
|
|
*/
|
|
getCopyToClipboardIconLabel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getResourceValue(config.copyToClipboardIconLabel)
|
|
),
|
|
map((value) =>
|
|
!isNullOrEmptyString(value) ? value : XResourceIDs.copy_to_clipboard
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Preset Colors ...
|
|
getPresetColors() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config.presetColors))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Represent Format ...
|
|
/**
|
|
* retrieve representColorFormats value ...
|
|
*/
|
|
getRepresentColorFormats() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config.representColorFormats)),
|
|
map((formats) =>
|
|
hasChild(formats) ? formats : [XColorPickerOutputFormat.XHEX]
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve outputFormat value ...
|
|
*/
|
|
getOutputFormat() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.outputFormat)),
|
|
map((format) =>
|
|
!isNullOrEmptyString(format) ? format : XColorPickerOutputFormat.XHEX
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Parts ...
|
|
/**
|
|
* determines showCopyToClipboard or not ...
|
|
*/
|
|
showCopyToClipboard() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showCopyToClipboard))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showColorInput or not ...
|
|
*/
|
|
showColorInput() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showColorInput)
|
|
? this.getOptionalValue(config.showColorInput)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showSelectedColorPreview or not ...
|
|
*/
|
|
showSelectedColorPreview() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showSelectedColorPreview)
|
|
? this.getOptionalValue(config.showSelectedColorPreview)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showPaletteChannel or not ...
|
|
*/
|
|
showPaletteChannel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showPaletteChannel)
|
|
? this.getOptionalValue(config.showPaletteChannel)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showHueChannel or not ...
|
|
*/
|
|
showHueChannel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showHueChannel)
|
|
? this.getOptionalValue(config.showHueChannel)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showAlphaChannel or not ...
|
|
*/
|
|
showAlphaChannel() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showAlphaChannel)
|
|
? this.getOptionalValue(config.showAlphaChannel)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showColorValue or not ...
|
|
*/
|
|
showColorValue() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config.showColorValue)
|
|
? this.getOptionalValue(config.showColorValue)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines showPresetColors or not ...
|
|
*/
|
|
showPresetColors() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
config.showPresetColors
|
|
? this.getOptionalValue(config.showPresetColors)
|
|
: of(null)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
/**
|
|
* retrieve css classes ...
|
|
*/
|
|
getCssClass() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config.cssClass))
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region
|
|
/**
|
|
* retireve cardColor value ...
|
|
*/
|
|
getCardColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.cardColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines is cardForegroundColor or not ...
|
|
*/
|
|
isCardForegroundColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardForegroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve cardTitle value ...
|
|
*/
|
|
getCardTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve cardSubTitle value ...
|
|
*/
|
|
getCardSubTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardSubTitle))
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleBack() {
|
|
this.dialogRef.close();
|
|
}
|
|
|
|
async handleColorSelected(event: string) {
|
|
//
|
|
this.selectedColor = event;
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (!config || !config.colorSelected || !isFunction(config.colorSelected)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.colorSelected.emit(event);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleSelect() {
|
|
//
|
|
if (!this.canSelect()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dialogRef.close({
|
|
result: XDialogResult.Ok,
|
|
payload: this.selectedColor,
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.service.ts
|
|
|
|
import {
|
|
XResourceIDs,
|
|
XBaseService,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import {
|
|
MatDialog,
|
|
MatDialogRef,
|
|
MatDialogConfig,
|
|
} from '@angular/material/dialog';
|
|
import {
|
|
XColorPickerDialogResult,
|
|
XColorPickerDialogConfig,
|
|
} from './x-color-picker-dialog.typings';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { Injectable, Inject, Output, EventEmitter } from '@angular/core';
|
|
import { XColorPickerDialogComponent } from './x-color-picker-dialog.component';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from './../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XColorPickerDialogService extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
private MOBILE_CLASS_NAME = 'mobile';
|
|
private DIALOG_REF: MatDialogRef<XColorPickerDialogComponent>;
|
|
|
|
//
|
|
isMobile$ = this.managerService.isMobileUi$;
|
|
|
|
// tslint:disable-next-line:no-output-on-prefix
|
|
@Output()
|
|
onResult = new EventEmitter<XColorPickerDialogResult>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
private dialog: MatDialog,
|
|
private managerService: XManagerService
|
|
) {
|
|
super(config);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* Open Select Map Dialog ...
|
|
*/
|
|
async openDialog(config?: XColorPickerDialogConfig) {
|
|
//
|
|
// Prevent Double Bubble ...
|
|
if (this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare Config ...
|
|
if (!config) {
|
|
config = {};
|
|
}
|
|
|
|
//
|
|
// Set Default Title ...
|
|
if (config && !config.title) {
|
|
config.title = XResourceIDs.color_picker_dialog_title;
|
|
}
|
|
|
|
//
|
|
// Prepare Dialog Config ...
|
|
const data: MatDialogConfig = {
|
|
data: config,
|
|
};
|
|
|
|
//
|
|
data.panelClass = 'fullscreen-dialog';
|
|
|
|
//
|
|
// Show Cropper inside a Dialog ...
|
|
this.DIALOG_REF = this.dialog.open(XColorPickerDialogComponent, data);
|
|
this.DIALOG_REF.disableClose = true;
|
|
|
|
//
|
|
// Attach Mobile Class ...
|
|
this.isMobile$.subscribe((isMobile) => {
|
|
//
|
|
if (isMobile) {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
} else {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
// Handle Backdrop ...
|
|
this.DIALOG_REF.backdropClick().subscribe(() => {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
|
|
//
|
|
this.closeDialog();
|
|
});
|
|
|
|
//
|
|
// Handle Dialog Result ...
|
|
this.DIALOG_REF.afterClosed().subscribe(
|
|
(model: XColorPickerDialogResult) => {
|
|
//
|
|
if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
} else {
|
|
//
|
|
// Handle Results ...
|
|
this.onResult.emit(model);
|
|
}
|
|
|
|
//
|
|
this.closeDialog();
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Close Select Map Dialog ...
|
|
*/
|
|
closeDialog() {
|
|
//
|
|
// Prevent Go Forward ...
|
|
if (!this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Close Dialog ...
|
|
this.DIALOG_REF.close();
|
|
this.DIALOG_REF = null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.typings.ts
|
|
|
|
import { XDialogResult } from 'x-framework-core';
|
|
import { IXColorPickerContainer } from '../x-color-picker.typings';
|
|
import { XBaseDialogConfig } from '../../classes/i-x-base-dialog.container';
|
|
|
|
export interface XColorPickerDialogResult {
|
|
payload?: string;
|
|
result: XDialogResult;
|
|
}
|
|
|
|
export interface XColorPickerDialogConfig
|
|
extends XBaseDialogConfig,
|
|
Partial<IXColorPickerContainer> {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<h4
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
class="
|
|
x-wrapper x-counter
|
|
display-message-container
|
|
ion-no-padding ion-no-margin
|
|
"
|
|
>
|
|
{{ displayMessage }}
|
|
</h4>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.scss
|
|
|
|
.display-message-container {
|
|
margin: 2px;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.ts
|
|
|
|
import {
|
|
XCounterTick,
|
|
XCounterType,
|
|
XCounterState,
|
|
XCounterAction,
|
|
XCounterActionModel,
|
|
XCounterTypeIdentifier,
|
|
XCounterContainerComponent,
|
|
} from './x-counter.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subscription, interval, Subject } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'x-counter',
|
|
templateUrl: './x-counter.component.html',
|
|
styleUrls: ['./x-counter.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XCounterComponent extends XCounterContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
private StepCount: number;
|
|
private IsCounting: boolean;
|
|
private TYPE: XCounterTypeIdentifier;
|
|
private TimerSubscription: Subscription;
|
|
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
displayMessage = '';
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Handle Values ...
|
|
const isStopValueChanged = changeKeys.includes(
|
|
nameof<XCounterComponent>('stopValue')
|
|
);
|
|
const isStartValueChanged = changeKeys.includes(
|
|
nameof<XCounterComponent>('startValue')
|
|
);
|
|
const isCurrentValueChanged = changeKeys.includes(
|
|
nameof<XCounterComponent>('currentValue')
|
|
);
|
|
if (isStopValueChanged || isStartValueChanged || isCurrentValueChanged) {
|
|
this.setBoundaries(this.startValue, this.stopValue, this.currentValue);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handle Type Changed ...
|
|
const isTypeChanged = changeKeys.includes(
|
|
nameof<XCounterComponent>('type')
|
|
);
|
|
if (isTypeChanged) {
|
|
await this.prepareType();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XCounterComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareType();
|
|
|
|
//
|
|
// Try to Show Start Value ...
|
|
this.updateDisplayMessage();
|
|
|
|
//
|
|
await this.handleAutoStart();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
if (this.TimerSubscription) {
|
|
this.TimerSubscription.unsubscribe();
|
|
this.TimerSubscription = null;
|
|
}
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
setBoundaries(start: number, stop: number, current: number) {
|
|
//
|
|
this.startValue = start;
|
|
this.stopValue = stop;
|
|
this.currentValue = current;
|
|
}
|
|
|
|
async start() {
|
|
//
|
|
const isUpdated = await this.updateValues();
|
|
|
|
//
|
|
if (isUpdated && !this.TimerSubscription && this.getStepsCount() > 0) {
|
|
this.startCounter();
|
|
}
|
|
}
|
|
|
|
pause() {
|
|
//
|
|
if (this.TimerSubscription) {
|
|
this.IsCounting = false;
|
|
this.TimerSubscription.unsubscribe();
|
|
this.TimerSubscription = null;
|
|
}
|
|
}
|
|
|
|
cancel() {
|
|
this.currentValue = this.stopValue;
|
|
}
|
|
|
|
getCounterState(): XCounterState {
|
|
//
|
|
if (
|
|
this.TYPE === XCounterType.CountDown &&
|
|
this.currentValue === this.startValue
|
|
) {
|
|
return XCounterState.Start;
|
|
}
|
|
|
|
//
|
|
if (
|
|
this.TYPE === XCounterType.CountUp &&
|
|
this.currentValue === this.stopValue
|
|
) {
|
|
return XCounterState.Start;
|
|
}
|
|
|
|
//
|
|
if (this.isLastStep()) {
|
|
return XCounterState.Stop;
|
|
}
|
|
|
|
//
|
|
if (
|
|
this.TYPE === XCounterType.CountDown &&
|
|
this.currentValue > this.startValue
|
|
) {
|
|
return XCounterState.Tick;
|
|
}
|
|
|
|
//
|
|
if (
|
|
this.TYPE === XCounterType.CountUp &&
|
|
this.currentValue < this.startValue
|
|
) {
|
|
return XCounterState.Tick;
|
|
}
|
|
|
|
//
|
|
return XCounterState.Stop;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XCounterActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XCounterAction.START:
|
|
await this.start();
|
|
break;
|
|
|
|
//
|
|
case XCounterAction.PAUSE:
|
|
this.pause();
|
|
break;
|
|
|
|
//
|
|
case XCounterAction.CANCEL:
|
|
this.cancel();
|
|
break;
|
|
|
|
//
|
|
case XCounterAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private startCounter() {
|
|
//
|
|
this.StepCount = this.getStepsCount();
|
|
|
|
//
|
|
if (!this.IsCounting && this.StepCount && this.StepCount > 0) {
|
|
//
|
|
this.IsCounting = true;
|
|
this.TimerSubscription = interval(this.delay).subscribe(() => {
|
|
//
|
|
this.updateDisplayMessage();
|
|
|
|
//
|
|
const eventModel = this.getTickModel();
|
|
|
|
//
|
|
if (eventModel.state === XCounterState.Start) {
|
|
this.counterStart.emit(eventModel);
|
|
}
|
|
|
|
//
|
|
if (eventModel.state === XCounterState.Stop) {
|
|
this.counterStop.emit(eventModel);
|
|
}
|
|
|
|
//
|
|
this.counterTtick.emit(eventModel);
|
|
|
|
//
|
|
if (this.isLastStep()) {
|
|
this.pause();
|
|
} else if (this.TYPE === XCounterType.CountDown) {
|
|
this.currentValue--;
|
|
} else if (this.TYPE === XCounterType.CountUp) {
|
|
this.currentValue++;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private getTickModel(): XCounterTick {
|
|
return {
|
|
type: this.TYPE,
|
|
start: this.startValue,
|
|
stop: this.stopValue,
|
|
current: this.currentValue,
|
|
delay: this.delay,
|
|
state: this.getCounterState(),
|
|
} as XCounterTick;
|
|
}
|
|
|
|
private getStepsCount() {
|
|
//
|
|
let count = -1;
|
|
|
|
//
|
|
switch (this.TYPE) {
|
|
case XCounterType.CountDown:
|
|
count = this.startValue - this.stopValue;
|
|
break;
|
|
|
|
case XCounterType.CountUp:
|
|
count = this.stopValue - this.startValue;
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (isNaN(count)) {
|
|
count = -1;
|
|
}
|
|
|
|
//
|
|
return count;
|
|
}
|
|
|
|
private isLastStep() {
|
|
//
|
|
switch (this.TYPE) {
|
|
//
|
|
case XCounterType.CountDown:
|
|
return this.currentValue <= this.stopValue;
|
|
|
|
//
|
|
default:
|
|
case XCounterType.CountUp:
|
|
return this.currentValue >= this.startValue;
|
|
}
|
|
}
|
|
|
|
private updateValues() {
|
|
return new Promise<boolean>((res) => {
|
|
//
|
|
switch (this.TYPE) {
|
|
case XCounterType.CountDown:
|
|
//
|
|
if (this.startValue < this.stopValue) {
|
|
res(false);
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.currentValue) {
|
|
this.currentValue = this.startValue;
|
|
}
|
|
break;
|
|
|
|
case XCounterType.CountUp:
|
|
if (this.startValue > this.stopValue) {
|
|
res(false);
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.currentValue) {
|
|
this.currentValue = this.stopValue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
res(true);
|
|
});
|
|
}
|
|
|
|
private updateDisplayMessage() {
|
|
//
|
|
this.displayMessage = this.displayPattern(
|
|
this.stopValue,
|
|
this.startValue,
|
|
this.currentValue
|
|
);
|
|
}
|
|
|
|
//
|
|
private async prepareType() {
|
|
this.TYPE = await this.getValueAsync(this.type);
|
|
}
|
|
|
|
//
|
|
private async handleAutoStart() {
|
|
//
|
|
const isAutoStart = await this.getValueAsync(this.autoStart);
|
|
if (!isAutoStart) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.start();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XCounterComponent } from './x-counter.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XCounterComponent],
|
|
imports: [XCardModule, CommonModule, XBaseComponentModule],
|
|
exports: [XCardModule, CommonModule, XCounterComponent, XBaseComponentModule],
|
|
})
|
|
export class XCounterModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XCounterType {
|
|
CountUp = 'count_up',
|
|
CountDown = 'count_down',
|
|
}
|
|
|
|
export type XCounterTypeIdentifier = XCounterType | string;
|
|
|
|
export enum XCounterState {
|
|
Start,
|
|
Tick,
|
|
Stop,
|
|
}
|
|
|
|
export interface XCounterTick {
|
|
type: XCounterType;
|
|
start: number;
|
|
stop: number;
|
|
current: number;
|
|
delay: number;
|
|
state: XCounterState;
|
|
}
|
|
|
|
export const defaultStringPatternMaker = (
|
|
max: number,
|
|
min: number,
|
|
current: number
|
|
) => {
|
|
return `${current}`;
|
|
};
|
|
|
|
export enum XCounterAction {
|
|
START = 'start',
|
|
PAUSE = 'pause',
|
|
CANCEL = 'cancel',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XCounterActionIdentifier = XCounterAction | string;
|
|
|
|
export interface XCounterActionModel
|
|
extends XBaseActionModel<XCounterActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXCounterContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XCounterActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
type: XStandardType<XCounterTypeIdentifier>;
|
|
autoStart: XStandardType<boolean>;
|
|
stopValue: number;
|
|
startValue: number;
|
|
currentValue: number;
|
|
delay: number;
|
|
|
|
//
|
|
displayPattern: (min: number, max: number, current: number) => string;
|
|
|
|
//
|
|
counterStart: EventEmitter<XCounterTick>;
|
|
counterTtick: EventEmitter<XCounterTick>;
|
|
counterStop: EventEmitter<XCounterTick>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XCounterContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXCounterContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XCounterActionModel> =
|
|
new Subject<XCounterActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly type: XStandardType<XCounterTypeIdentifier> = XCounterType.CountDown;
|
|
readonly autoStart: XStandardType<boolean> = false;
|
|
readonly stopValue: number;
|
|
readonly startValue: number;
|
|
readonly currentValue: number;
|
|
readonly delay: number = 1000;
|
|
|
|
//
|
|
readonly displayPattern: (
|
|
min: number,
|
|
max: number,
|
|
current: number
|
|
) => string = defaultStringPatternMaker;
|
|
|
|
//
|
|
readonly counterStart: EventEmitter<XCounterTick> =
|
|
new EventEmitter<XCounterTick>();
|
|
readonly counterTtick: EventEmitter<XCounterTick> =
|
|
new EventEmitter<XCounterTick>();
|
|
readonly counterStop: EventEmitter<XCounterTick> =
|
|
new EventEmitter<XCounterTick>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XCounterContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXCounterContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XCounterActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
type: XStandardType<XCounterTypeIdentifier> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
autoStart: XStandardType<boolean> = false;
|
|
|
|
@Input()
|
|
stopValue: number = this.propertyProvider.stopValue;
|
|
|
|
@Input()
|
|
startValue: number = this.propertyProvider.startValue;
|
|
|
|
@Input()
|
|
currentValue: number = this.propertyProvider.currentValue;
|
|
|
|
@Input()
|
|
delay = this.propertyProvider.delay;
|
|
|
|
@Input()
|
|
displayPattern: (min: number, max: number, current: number) => string =
|
|
this.propertyProvider.displayPattern;
|
|
|
|
//
|
|
@Output()
|
|
counterStart: EventEmitter<XCounterTick> = new EventEmitter();
|
|
|
|
@Output()
|
|
counterTtick: EventEmitter<XCounterTick> = new EventEmitter();
|
|
|
|
@Output()
|
|
counterStop: EventEmitter<XCounterTick> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XCounterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXCounterContainer
|
|
): Observable<IXCounterContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
type: this.getValue(container ? container.type : this.type),
|
|
autoStart: this.getValue(
|
|
container ? container.autoStart : this.autoStart
|
|
),
|
|
stopValue: this.getValue(
|
|
container ? container.stopValue : this.stopValue
|
|
),
|
|
startValue: this.getValue(
|
|
container ? container.startValue : this.startValue
|
|
),
|
|
currentValue: this.getValue(
|
|
container ? container.currentValue : this.currentValue
|
|
),
|
|
delay: this.getValue(container ? container.delay : this.delay),
|
|
displayPattern: this.getValue(
|
|
container ? container.displayPattern : this.displayPattern
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
counterStart: this.counterStart,
|
|
counterTtick: this.counterTtick,
|
|
counterStop: this.counterStop,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<div
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
class="x-wrapper x-data-pager ion-no-padding"
|
|
>
|
|
<!-- Above Pager -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(paginatorPosition) | async) ===
|
|
DataPagerPaginatorPositions.Above &&
|
|
result &&
|
|
hasChildValue(result.items)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Custom Contet -->
|
|
<ng-content select="[content]"> </ng-content>
|
|
|
|
<!-- Items or Empty -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
result && (hasChildValue(result.items) | async)
|
|
? itemsRef
|
|
: emptyListTemplate
|
|
? emptyListTemplate
|
|
: defaultEmptyListRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Below Pager -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(paginatorPosition) | async) ===
|
|
DataPagerPaginatorPositions.Below &&
|
|
result &&
|
|
hasChildValue(result.items)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Items Presenting -->
|
|
<ng-template #itemsRef>
|
|
<ng-container *ngIf="itemTemplate">
|
|
<!-- Item Type Handler -->
|
|
<ng-container
|
|
*ngIf="(getValue(type) | async) === DataPagerPresetTypes.Item"
|
|
>
|
|
<ng-container *ngFor="let item of result.items">
|
|
<ng-container
|
|
*ngTemplateOutlet="itemTemplate; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Page Type Handler -->
|
|
<ng-container
|
|
*ngIf="(getValue(type) | async) === DataPagerPresetTypes.Page"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="itemTemplate; context: { $implicit: result.items }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<ng-template #paginatorRef>
|
|
<ion-toolbar
|
|
class="x-paginator-bar"
|
|
*ngIf="
|
|
(getValue(showPaginator) | async) &&
|
|
(notNullOrUndefinedValue(preparedPaginatorOptions) | async)
|
|
"
|
|
[xColor]="getValue(paginatorColor) | async"
|
|
>
|
|
<!-- Mat Paginator Component -->
|
|
<mat-paginator
|
|
#matPaginator
|
|
[hidden]="true"
|
|
[disabled]="loading || uiDisabled"
|
|
[pageSize]="getValue(preparedPaginatorOptions.pageSize) | async"
|
|
></mat-paginator>
|
|
|
|
<!-- Start Slot Contents -->
|
|
<ion-buttons slot="start" *ngIf="preparedPaginatorOptions">
|
|
<!-- First -->
|
|
<ion-button
|
|
#first
|
|
(click)="firstPage()"
|
|
*ngIf="preparedPaginatorOptions.first"
|
|
[hidden]="getValue(preparedPaginatorOptions.first.hidden) | async"
|
|
[disabled]="
|
|
loading ||
|
|
uiDisabled ||
|
|
(getValue(preparedPaginatorOptions.first.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.first.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.first.title) | async,
|
|
color: getValue(preparedPaginatorOptions.first.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
|
|
<!-- Previous -->
|
|
<ion-button
|
|
#previous
|
|
(click)="previousPage()"
|
|
*ngIf="preparedPaginatorOptions.prev"
|
|
[hidden]="getValue(preparedPaginatorOptions.prev.hidden) | async"
|
|
[disabled]="
|
|
loading ||
|
|
uiDisabled ||
|
|
(getValue(preparedPaginatorOptions.prev.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.prev.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.prev.title) | async,
|
|
color: getValue(preparedPaginatorOptions.prev.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
|
|
<!-- Pagination Info -->
|
|
<div class="x-paginator-wrapper">
|
|
<div fxLayout="row" fxLayoutAlign="center stretch">
|
|
<!-- Current Page -->
|
|
<div fxFlex="auto">
|
|
<ion-button
|
|
fill="clear"
|
|
expand="full"
|
|
class="cb-inherit"
|
|
*ngIf="!showPageNumberInput"
|
|
(click)="showPageNumberInput = true"
|
|
[disabled]="loading || uiDisabled"
|
|
>
|
|
{{
|
|
preparedPaginatorOptions.pageInfoProvider(
|
|
managerService.currentLocale,
|
|
currentPage,
|
|
pageSize,
|
|
totalPages,
|
|
totalItems
|
|
)
|
|
}}
|
|
</ion-button>
|
|
|
|
<!-- Change Current Page -->
|
|
<ion-input
|
|
step="1"
|
|
[min]="1"
|
|
type="number"
|
|
debounce="500"
|
|
required="true"
|
|
autofocus="true"
|
|
[max]="totalPages"
|
|
class="cb-inherit"
|
|
inputmode="numeric"
|
|
[value]="currentPage"
|
|
*ngIf="showPageNumberInput"
|
|
(ionBlur)="showPageNumberInput = false"
|
|
[disabled]="loading || uiDisabled"
|
|
(ionChange)="handlePageChange($event)"
|
|
></ion-input>
|
|
</div>
|
|
|
|
<!-- Page Size -->
|
|
<div fxFlex="auto">
|
|
<ion-button
|
|
fill="clear"
|
|
expand="full"
|
|
*ngIf="pageSize"
|
|
class="cb-inherit"
|
|
[disabled]="loading || uiDisabled"
|
|
(click)="handlePageSizeChange($event)"
|
|
>
|
|
{{ applyLocale(pageSize) }}
|
|
</ion-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- End Slot Content -->
|
|
<ion-buttons slot="end">
|
|
<!-- Noxt -->
|
|
<ion-button
|
|
#next
|
|
(click)="nextPage()"
|
|
*ngIf="preparedPaginatorOptions.next"
|
|
[hidden]="getValue(preparedPaginatorOptions.next.hidden) | async"
|
|
[disabled]="
|
|
loading ||
|
|
uiDisabled ||
|
|
(getValue(preparedPaginatorOptions.next.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.next.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.next.title) | async,
|
|
color: getValue(preparedPaginatorOptions.next.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
|
|
<!-- Last -->
|
|
<ion-button
|
|
#last
|
|
(click)="lastPage()"
|
|
*ngIf="preparedPaginatorOptions.last"
|
|
[hidden]="getValue(preparedPaginatorOptions.last.hidden) | async"
|
|
[disabled]="
|
|
loading ||
|
|
uiDisabled ||
|
|
(getValue(preparedPaginatorOptions.last.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.last.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.last.title) | async,
|
|
color: getValue(preparedPaginatorOptions.prev.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
</ion-toolbar>
|
|
</ng-template>
|
|
|
|
<!-- Default Empty Content -->
|
|
<ng-template #defaultEmptyListRef>
|
|
<!-- Empty Handler -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(showEmpty) | async) &&
|
|
(!result || !(hasChildValue(result.items) | async))
|
|
"
|
|
>
|
|
<x-empty
|
|
(refresh)="emptyRefresh.emit($event)"
|
|
[color]="getValue(emptyColor) | async"
|
|
[message]="getResourceValue(emptyMessage) | async"
|
|
[refreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
[messageColor]="getValue(emptyMessageColor) | async"
|
|
[hasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[foregroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[foregroundColor]="getValue(emptyForegroundColor) | async"
|
|
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
|
|
></x-empty> </ng-container
|
|
></ng-template>
|
|
|
|
<!-- Icon Template Ref -->
|
|
<ng-template
|
|
#iconRef
|
|
let-name="name"
|
|
let-tooltip="tooltip"
|
|
let-color="color"
|
|
let-applyDirection="applyDirection"
|
|
>
|
|
<x-icon
|
|
[name]="name"
|
|
[color]="color"
|
|
[loading]="loading"
|
|
[matTooltip]="tooltip"
|
|
[foregroundColor]="true"
|
|
[uiDisabled]="uiDisabled"
|
|
[applyDirection]="applyDirection"
|
|
[cssClass]="!color ? 'cb-inherit' : null"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
XLocale,
|
|
toNumber,
|
|
hasChild,
|
|
applyLocale,
|
|
XModalButtonRole,
|
|
XPickerColumnOption,
|
|
XBaseDataPagerQuery,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XDataPagerAction,
|
|
XDataPagerActionModel,
|
|
XDataPagerPresentType,
|
|
XDataPagerPaginatorOptions,
|
|
XDataPagerPaginatorPosition,
|
|
XDataPagerContainerComponent,
|
|
} from './x-data-pager.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ViewChild } from '@angular/core';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { ChangeDetectionStrategy } from '@angular/core';
|
|
import { MatPaginator } from '@angular/material/paginator';
|
|
|
|
@Component({
|
|
selector: 'x-data-pager',
|
|
templateUrl: './x-data-pager.component.html',
|
|
styleUrls: ['./x-data-pager.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XDataPagerComponent extends XDataPagerContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private MODAL: any;
|
|
private PAGE_SIZE: number;
|
|
private TOTAL_PAGES: number;
|
|
private TOTAL_ITEMS: number;
|
|
private CURRENT_PAGE: number;
|
|
private PAGINATOR: MatPaginator;
|
|
private PAGINATOR_PAGE_SUBSCRIPTION: Subscription;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private PAGINATOR_OPTIONS: XDataPagerPaginatorOptions;
|
|
|
|
//
|
|
readonly DataPagerPresetTypes = Object.assign({}, XDataPagerPresentType);
|
|
readonly DataPagerPaginatorPositions = Object.assign(
|
|
{},
|
|
XDataPagerPaginatorPosition
|
|
);
|
|
|
|
//
|
|
showPageNumberInput: boolean;
|
|
|
|
//
|
|
@ViewChild(MatPaginator, { static: false })
|
|
set paginator(v: MatPaginator) {
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PAGINATOR = v;
|
|
this.setPaginatorData();
|
|
}
|
|
|
|
get paginator() {
|
|
return this.PAGINATOR;
|
|
}
|
|
|
|
get pageSize() {
|
|
return this.PAGE_SIZE;
|
|
}
|
|
|
|
get currentPage() {
|
|
return this.CURRENT_PAGE;
|
|
}
|
|
|
|
get totalPages() {
|
|
return this.TOTAL_PAGES;
|
|
}
|
|
|
|
get totalItems() {
|
|
return this.TOTAL_ITEMS;
|
|
}
|
|
|
|
get preparedPaginatorOptions() {
|
|
return this.PAGINATOR_OPTIONS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
await this.preparePaginatorOptions();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XDataPagerComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region PaginatorOptionChanged ...
|
|
const isPaginatorOptionsChanged = changeKeys.includes(
|
|
nameof<XDataPagerComponent>('paginatorOptions')
|
|
);
|
|
if (isPaginatorOptionsChanged) {
|
|
await this.preparePaginatorOptions();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Query Changed ...
|
|
const isTaskChanged = changeKeys.includes(
|
|
nameof<XDataPagerComponent>('task')
|
|
);
|
|
const isQueryChanged = changeKeys.includes(
|
|
nameof<XDataPagerComponent>('query')
|
|
);
|
|
if (isQueryChanged || isTaskChanged) {
|
|
await this.handleQueryChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Result Changed ...
|
|
const isResultChanged = changeKeys.includes(
|
|
nameof<XDataPagerComponent>('result')
|
|
);
|
|
if (isResultChanged) {
|
|
await this.handleResultChanged();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handlePageChange(event: CustomEvent | any) {
|
|
//
|
|
const selectedPage = (event.detail.value as number) || undefined;
|
|
if (!selectedPage) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.toPage(selectedPage);
|
|
}
|
|
|
|
async handlePageSizeChange(event?: any) {
|
|
//
|
|
if (!this.preparedPaginatorOptions || !this.pageSize) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const pageSizes = await this.getValueAsync(
|
|
this.preparedPaginatorOptions.pageSizes
|
|
);
|
|
if (!hasChild(pageSizes)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const options: XPickerColumnOption[] = pageSizes.map((ps) => {
|
|
//
|
|
const opt: XPickerColumnOption = {
|
|
text: this.applyLocale(ps.toString()),
|
|
value: ps,
|
|
disabled: ps === this.pageSize,
|
|
};
|
|
|
|
//
|
|
return opt;
|
|
});
|
|
|
|
//
|
|
if (this.MODAL) {
|
|
await this.managerService.dialogService.pickerController.dismiss();
|
|
this.MODAL = null;
|
|
}
|
|
|
|
//
|
|
this.MODAL = await this.managerService.dialogService.presentPicker({
|
|
buttons: [
|
|
{
|
|
text: this.resourceProvider(this.ResourceIDs.accept),
|
|
role: XModalButtonRole.Selected,
|
|
handler: (value) => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const pageSize = value.pageSize.value;
|
|
this.changePageSize(pageSize);
|
|
},
|
|
},
|
|
{
|
|
text: this.resourceProvider(this.ResourceIDs.cancel),
|
|
role: XModalButtonRole.Cancel,
|
|
},
|
|
],
|
|
columns: [{ name: 'pageSize', options }],
|
|
});
|
|
|
|
//
|
|
await this.MODAL.onWillDismiss();
|
|
this.MODAL = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//
|
|
//#region Pager Actions ...
|
|
async firstPage() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.firstPage();
|
|
}
|
|
|
|
async lastPage() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.lastPage();
|
|
}
|
|
|
|
async nextPage() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.nextPage();
|
|
}
|
|
|
|
async previousPage() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.previousPage();
|
|
}
|
|
|
|
async toPage(index: number) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
index = index === 0 ? 1 : index;
|
|
|
|
//
|
|
this.paginator.pageIndex = index - 1;
|
|
this.paginator.page.next({
|
|
pageIndex: index - 1,
|
|
pageSize: this.pageSize,
|
|
length: this.totalItems,
|
|
});
|
|
}
|
|
|
|
async changePageSize(size: number) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!size || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.pageSize = size;
|
|
this.paginator.page.next({
|
|
pageIndex: 0,
|
|
pageSize: size,
|
|
length: this.totalItems,
|
|
});
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XDataPagerActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XDataPagerAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.GoFirst:
|
|
await this.firstPage();
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.GoLast:
|
|
await this.lastPage();
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.GoNext:
|
|
await this.nextPage();
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.GoPrev:
|
|
await this.previousPage();
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.ToPage:
|
|
if (model.payload) {
|
|
await this.toPage(model.payload);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XDataPagerAction.ChangePageSize:
|
|
if (model.payload) {
|
|
await this.changePageSize(model.payload);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
private async handleQueryChanged() {
|
|
//
|
|
this.result = null;
|
|
|
|
//
|
|
if (!this.query || !this.task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const mTask = this.task(this.query);
|
|
|
|
//
|
|
this.taskReady.emit(mTask);
|
|
}
|
|
|
|
private async handleResultChanged() {
|
|
//
|
|
if (!this.result) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Extract Required Options ...
|
|
this.CURRENT_PAGE = this.query.pageNumber;
|
|
this.PAGE_SIZE = this.query.rowsInPage;
|
|
this.TOTAL_PAGES = this.calculatePageCount(
|
|
this.result.count,
|
|
this.query.rowsInPage
|
|
);
|
|
this.TOTAL_ITEMS = this.result.count;
|
|
//#endregion
|
|
|
|
//
|
|
if (!this.preparedPaginatorOptions) {
|
|
await this.preparePaginatorOptions();
|
|
}
|
|
|
|
//
|
|
await this.setPaginatorData();
|
|
}
|
|
|
|
private async setPaginatorData() {
|
|
//
|
|
if (!this.PAGINATOR) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PAGINATOR.pageSize = this.PAGE_SIZE;
|
|
this.PAGINATOR.pageIndex = this.CURRENT_PAGE - 1;
|
|
this.PAGINATOR.length = this.TOTAL_ITEMS;
|
|
|
|
//
|
|
// Prepare Paginator Options ...
|
|
await this.preparePaginatorOptions();
|
|
await this.registerPaginatorHandlers();
|
|
}
|
|
|
|
private async preparePaginatorOptions() {
|
|
//
|
|
if (!this.result) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Preparing Options ...
|
|
//
|
|
const defaultOptions = this.defaultPaginatorOptions();
|
|
const options = await this.getValueAsync(this.paginatorOptions);
|
|
const preparedOptions: XDataPagerPaginatorOptions = {
|
|
...defaultOptions,
|
|
...options,
|
|
pageSize: this.query.rowsInPage,
|
|
};
|
|
|
|
//
|
|
if (options) {
|
|
//
|
|
if (!options.first) {
|
|
preparedOptions.first = undefined;
|
|
} else {
|
|
//
|
|
const first = options.first;
|
|
|
|
//
|
|
if (first.disabled) {
|
|
const firstDisabled = await this.getValueAsync(first.disabled);
|
|
preparedOptions.first.disabled =
|
|
defaultOptions.first.disabled && firstDisabled;
|
|
} else {
|
|
preparedOptions.first.disabled = defaultOptions.first.disabled;
|
|
}
|
|
|
|
//
|
|
if (!first.icon) {
|
|
preparedOptions.first.icon = defaultOptions.first.icon;
|
|
}
|
|
|
|
//
|
|
if (!first.title) {
|
|
preparedOptions.first.title = defaultOptions.first.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.last) {
|
|
preparedOptions.last = undefined;
|
|
} else {
|
|
//
|
|
const last = options.last;
|
|
|
|
//
|
|
if (last.disabled) {
|
|
const lastDisabled = await this.getValueAsync(last.disabled);
|
|
preparedOptions.last.disabled =
|
|
defaultOptions.last.disabled && lastDisabled;
|
|
} else {
|
|
preparedOptions.last.disabled = defaultOptions.last.disabled;
|
|
}
|
|
|
|
//
|
|
if (!last.icon) {
|
|
preparedOptions.last.icon = defaultOptions.last.icon;
|
|
}
|
|
|
|
//
|
|
if (!last.title) {
|
|
preparedOptions.last.title = defaultOptions.last.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.next) {
|
|
preparedOptions.next = undefined;
|
|
} else {
|
|
//
|
|
const next = options.next;
|
|
|
|
//
|
|
if (next.disabled) {
|
|
const nextDisabled = await this.getValueAsync(next.disabled);
|
|
preparedOptions.next.disabled =
|
|
defaultOptions.next.disabled && nextDisabled;
|
|
} else {
|
|
preparedOptions.next.disabled = defaultOptions.next.disabled;
|
|
}
|
|
|
|
//
|
|
if (!next.icon) {
|
|
preparedOptions.next.icon = defaultOptions.next.icon;
|
|
}
|
|
|
|
//
|
|
if (!next.title) {
|
|
preparedOptions.next.title = defaultOptions.next.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.prev) {
|
|
preparedOptions.prev = undefined;
|
|
} else {
|
|
//
|
|
const prev = options.prev;
|
|
|
|
//
|
|
if (prev.disabled) {
|
|
const prevDisabled = await this.getValueAsync(prev.disabled);
|
|
preparedOptions.prev.disabled =
|
|
defaultOptions.prev.disabled && prevDisabled;
|
|
} else {
|
|
preparedOptions.prev.disabled = defaultOptions.prev.disabled;
|
|
}
|
|
|
|
//
|
|
if (!prev.icon) {
|
|
preparedOptions.prev.icon = defaultOptions.prev.icon;
|
|
}
|
|
|
|
//
|
|
if (!prev.title) {
|
|
preparedOptions.prev.title = defaultOptions.prev.title;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
this.PAGINATOR_OPTIONS = preparedOptions;
|
|
|
|
//
|
|
this.detectChanges();
|
|
//#endregion
|
|
}
|
|
|
|
private async registerPaginatorHandlers() {
|
|
//
|
|
//#region PageHandler Actions ...
|
|
//
|
|
if (!this.PAGINATOR) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Unsubscribe last ...
|
|
if (this.PAGINATOR_PAGE_SUBSCRIPTION) {
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION.unsubscribe();
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
// Subscribe New ...
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.paginator.page.asObservable()
|
|
).subscribe(async (res) => {
|
|
//
|
|
// Prepare New Query ...
|
|
const query: XBaseDataPagerQuery = {
|
|
...this.query,
|
|
//
|
|
pageNumber: res.pageIndex + 1,
|
|
rowsInPage: res.pageSize,
|
|
};
|
|
|
|
//
|
|
// Notify Query Changed ...
|
|
this.queryChange.emit(query);
|
|
});
|
|
//#endregion
|
|
}
|
|
|
|
private defaultPaginatorOptions() {
|
|
//
|
|
const options: XDataPagerPaginatorOptions = {
|
|
pageSizes: this.config.pageSizes,
|
|
pageSize: this.config.defaultPageSize,
|
|
first: {
|
|
title: 'first',
|
|
icon: XIconNames.first,
|
|
disabled: !this.paginator || !this.paginator.hasPreviousPage(),
|
|
},
|
|
last: {
|
|
title: 'last',
|
|
icon: XIconNames.last,
|
|
disabled: !this.paginator || !this.paginator.hasNextPage(),
|
|
},
|
|
prev: {
|
|
title: 'previous',
|
|
icon: XIconNames.previous,
|
|
disabled: !this.paginator || !this.paginator.hasPreviousPage(),
|
|
},
|
|
next: {
|
|
title: 'next',
|
|
icon: XIconNames.next,
|
|
disabled: !this.paginator || !this.paginator.hasNextPage(),
|
|
},
|
|
pageInfoProvider: (
|
|
locale: XLocale,
|
|
currentPage: number,
|
|
pageSize: number,
|
|
totalPages: number,
|
|
totalItems: number
|
|
) => {
|
|
//
|
|
const info = `${currentPage}/${totalPages}`;
|
|
return applyLocale(info, locale);
|
|
},
|
|
};
|
|
|
|
//
|
|
return options;
|
|
}
|
|
|
|
private calculatePageCount(itemsCount: number, pageSize: number) {
|
|
//
|
|
// Data Correction ...
|
|
pageSize = toNumber(pageSize);
|
|
itemsCount = toNumber(itemsCount);
|
|
|
|
//
|
|
// Result ...
|
|
return Math.floor((itemsCount + (pageSize - 1)) / pageSize);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XDataPagerComponent } from './x-data-pager.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XDataPagerComponent],
|
|
imports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
XEmptyModule,
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XEmptyModule,
|
|
CommonModule,
|
|
XDataPagerComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XDataPagerModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XBaseDataPagerQuery,
|
|
XColorWithBrightness,
|
|
XBaseDataPagerQueryResult,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardEmptyContainer,
|
|
XCardEmptyContainerComponent,
|
|
} from '../classes/i-x-card-empty.container';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XTablePaginatorOptions } from '../x-table/x-table.typings';
|
|
import { IXCardEmptyContainer } from '../classes/i-x-card-empty.container';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XDataPagerPaginatorPosition {
|
|
Above = 'above',
|
|
Below = 'below',
|
|
}
|
|
|
|
export type XDataPagerPaginatorPositionIdentifier =
|
|
| XDataPagerPaginatorPosition
|
|
| string;
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XDataPagerPaginatorOptions extends XTablePaginatorOptions {}
|
|
|
|
export enum XDataPagerPresentType {
|
|
Item = 'item',
|
|
Page = 'page',
|
|
}
|
|
|
|
export type XDataPagerPresentTypeIdentifier = XDataPagerPresentType | string;
|
|
|
|
export enum XDataPagerAction {
|
|
GoFirst = 'go_first',
|
|
GoLast = 'go_last',
|
|
GoNext = 'go_next',
|
|
GoPrev = 'go_prev',
|
|
ToPage = 'to_page',
|
|
ChangePageSize = 'change_page_size',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XDataPagerActionIdentifier = XDataPagerAction | string;
|
|
|
|
export interface XDataPagerActionModel
|
|
extends XBaseActionModel<XDataPagerActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card/Empty Container ...
|
|
export interface IXDataPagerContainer extends IXCardEmptyContainer {
|
|
//
|
|
actionProvider: Subject<XDataPagerActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
pageChanged: EventEmitter<number>;
|
|
type: XStandardType<XDataPagerPresentTypeIdentifier>;
|
|
itemTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
result: XBaseDataPagerQueryResult<any>;
|
|
task: (
|
|
query: XBaseDataPagerQuery
|
|
) => Observable<XBaseDataPagerQueryResult<any>>;
|
|
taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>>;
|
|
query: XBaseDataPagerQuery;
|
|
queryChange: EventEmitter<XBaseDataPagerQuery>;
|
|
|
|
//
|
|
showPaginator: XStandardType<boolean>;
|
|
paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier>;
|
|
paginatorColor: XStandardType<XColorIdentifier>;
|
|
paginatorOptions: XStandardType<XDataPagerPaginatorOptions>;
|
|
|
|
//
|
|
emptyListTemplate: TemplateRef<any>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XDataPagerContainer
|
|
extends XCardEmptyContainer
|
|
implements Readonly<IXDataPagerContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XDataPagerActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly pageChanged: EventEmitter<number> = new EventEmitter<number>();
|
|
readonly type: XStandardType<XDataPagerPresentTypeIdentifier> =
|
|
XDataPagerPresentType.Item;
|
|
readonly itemTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly result: XBaseDataPagerQueryResult<any>;
|
|
readonly task: (
|
|
query: XBaseDataPagerQuery
|
|
) => Observable<XBaseDataPagerQueryResult<any>>;
|
|
readonly taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>> =
|
|
new EventEmitter<Observable<XBaseDataPagerQueryResult<any>>>();
|
|
readonly query: XBaseDataPagerQuery;
|
|
readonly queryChange: EventEmitter<XBaseDataPagerQuery> =
|
|
new EventEmitter<XBaseDataPagerQuery>();
|
|
|
|
//
|
|
readonly showPaginator: XStandardType<boolean>;
|
|
readonly paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier> =
|
|
XDataPagerPaginatorPosition.Below;
|
|
readonly paginatorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly paginatorOptions: XStandardType<XDataPagerPaginatorOptions>;
|
|
|
|
//
|
|
readonly emptyListTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XDataPagerContainerComponent
|
|
extends XCardEmptyContainerComponent
|
|
implements IXDataPagerContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XDataPagerActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Output()
|
|
pageChanged: EventEmitter<number> = new EventEmitter();
|
|
|
|
@Input()
|
|
type: XStandardType<XDataPagerPresentTypeIdentifier> =
|
|
this.propertyProvider.type;
|
|
|
|
@Input()
|
|
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
|
|
|
|
//
|
|
@Input()
|
|
result: XBaseDataPagerQueryResult<any> = this.propertyProvider.result;
|
|
|
|
@Input()
|
|
task: (
|
|
query: XBaseDataPagerQuery
|
|
) => Observable<XBaseDataPagerQueryResult<any>> = this.propertyProvider.task;
|
|
|
|
@Output()
|
|
taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>> =
|
|
new EventEmitter();
|
|
|
|
@Input()
|
|
query: XBaseDataPagerQuery = this.propertyProvider.query;
|
|
|
|
@Output()
|
|
queryChange: EventEmitter<XBaseDataPagerQuery> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
showPaginator: XStandardType<boolean> = this.propertyProvider.showPaginator;
|
|
|
|
@Input()
|
|
paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier> =
|
|
this.propertyProvider.paginatorPosition;
|
|
|
|
@Input()
|
|
paginatorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.paginatorColor;
|
|
|
|
@Input()
|
|
paginatorOptions: XStandardType<XDataPagerPaginatorOptions> =
|
|
this.propertyProvider.paginatorOptions;
|
|
|
|
//
|
|
@Input()
|
|
emptyListTemplate: TemplateRef<any> = this.propertyProvider.emptyListTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XDataPagerContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXDataPagerContainer
|
|
): Observable<IXDataPagerContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
type: this.getValue(container ? container.type : this.type),
|
|
itemTemplate: this.getValue(
|
|
container ? container.itemTemplate : this.itemTemplate
|
|
),
|
|
result: this.getValue(container ? container.result : this.result),
|
|
task: this.getValue(container ? container.task : this.task),
|
|
query: this.getValue(container ? container.query : this.query),
|
|
showPaginator: this.getValue(
|
|
container ? container.showPaginator : this.showPaginator
|
|
),
|
|
paginatorPosition: this.getValue(
|
|
container ? container.paginatorPosition : this.paginatorPosition
|
|
),
|
|
paginatorColor: this.getValue(
|
|
container ? container.paginatorColor : this.paginatorColor
|
|
),
|
|
paginatorOptions: this.getValue(
|
|
container ? container.paginatorOptions : this.paginatorOptions
|
|
),
|
|
|
|
//
|
|
emptyListTemplate: this.getValue(
|
|
container ? container.emptyListTemplate : this.emptyListTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
pageChanged: this.pageChanged,
|
|
taskReady: this.taskReady,
|
|
queryChange: this.queryChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<div
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
class="x-data-scroller x-wrapper ion-no-padding"
|
|
>
|
|
<!-- Items or Empty -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
items && (hasChildValue(items) | async)
|
|
? contentsRef
|
|
: emptyListTemplate
|
|
? emptyListTemplate
|
|
: defaultEmptyListRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Default Empty Content -->
|
|
<ng-template #defaultEmptyListRef>
|
|
<!-- Empty Handler -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(showEmpty) | async) &&
|
|
(!result || !(hasChildValue(result.items) | async))
|
|
"
|
|
>
|
|
<x-empty
|
|
(refresh)="emptyRefresh.emit($event)"
|
|
[color]="getValue(emptyColor) | async"
|
|
[hasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[message]="getResourceValue(emptyMessage) | async"
|
|
[refreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
[messageColor]="getValue(emptyMessageColor) | async"
|
|
[foregroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[foregroundColor]="getValue(emptyForegroundColor) | async"
|
|
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
|
|
></x-empty> </ng-container
|
|
></ng-template>
|
|
|
|
<!-- Contents Template -->
|
|
<ng-template #contentsRef>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.ts
|
|
|
|
import {
|
|
XDataScrollerAction,
|
|
XDataScrollerActionModel,
|
|
XDataScrollerContainerComponent,
|
|
} from './x-data-scroller.typings';
|
|
import { Component } from '@angular/core';
|
|
import { of, Subject, Subscription } from 'rxjs';
|
|
import { ChangeDetectionStrategy } from '@angular/core';
|
|
import { nameof, hasChild, XBaseDataPagerQuery } from 'x-framework-core';
|
|
|
|
@Component({
|
|
selector: 'x-data-scroller',
|
|
templateUrl: './x-data-scroller.component.html',
|
|
styleUrls: ['./x-data-scroller.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XDataScrollerComponent extends XDataScrollerContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
canNext: boolean = true;
|
|
items: any[] = [];
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XDataScrollerComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Query Changed ...
|
|
const isTaskChanged = changeKeys.includes(
|
|
nameof<XDataScrollerComponent>('task')
|
|
);
|
|
const isQueryChanged = changeKeys.includes(
|
|
nameof<XDataScrollerComponent>('query')
|
|
);
|
|
if (isQueryChanged || isTaskChanged) {
|
|
await this.handleQueryChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Result Changed ...
|
|
const isResultChanged = changeKeys.includes(
|
|
nameof<XDataScrollerComponent>('result')
|
|
);
|
|
if (isResultChanged) {
|
|
await this.handleResultChanged();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async refreshItems() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.items = [];
|
|
this.result = null;
|
|
this.canNext = true;
|
|
this.notifyCanNext();
|
|
|
|
//
|
|
const query: XBaseDataPagerQuery = {
|
|
pageNumber: 1,
|
|
rowsInPage: this.query.rowsInPage,
|
|
};
|
|
|
|
//
|
|
// Notify Query Changed ...
|
|
this.queryChange.emit(query);
|
|
}
|
|
|
|
async loadMore() {
|
|
//
|
|
if (!this.canNext || this.uiDisabled || this.loading) {
|
|
this.notifyCanNext();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare New Query ...
|
|
const query: XBaseDataPagerQuery = {
|
|
...this.query,
|
|
//
|
|
pageNumber: this.query.pageNumber + 1,
|
|
rowsInPage: this.query.rowsInPage,
|
|
};
|
|
|
|
//
|
|
// Notify Query Changed ...
|
|
this.queryChange.emit(query);
|
|
}
|
|
|
|
async clearItems() {
|
|
//
|
|
this.items = [];
|
|
this.result = null;
|
|
this.canNext = true;
|
|
this.notifyCanNext();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XDataScrollerActionModel>();
|
|
}
|
|
|
|
//
|
|
this.notifyCanNext();
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XDataScrollerAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XDataScrollerAction.LoadMore:
|
|
await this.loadMore();
|
|
break;
|
|
|
|
//
|
|
case XDataScrollerAction.RefreshItems:
|
|
await this.refreshItems();
|
|
break;
|
|
|
|
//
|
|
case XDataScrollerAction.ClearItems:
|
|
await this.clearItems();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
private async handleQueryChanged() {
|
|
//
|
|
this.result = null;
|
|
|
|
//
|
|
if (!this.query || !this.task) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const mTask = this.task(this.query);
|
|
|
|
//
|
|
this.taskReady.emit(mTask);
|
|
}
|
|
|
|
private async handleResultChanged() {
|
|
//
|
|
if (!this.result || !hasChild(this.result.items)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
of(...this.result.items).subscribe({
|
|
next: item => {
|
|
setTimeout(() => {
|
|
//
|
|
this.items.push(item);
|
|
this.detectChanges();
|
|
}, 100);
|
|
},
|
|
error: (err) => {},
|
|
complete: () => {
|
|
this.canNext = this.items.length < this.result.count;
|
|
this.notifyCanNext();
|
|
}
|
|
})
|
|
}
|
|
|
|
private notifyCanNext() {
|
|
//
|
|
if (!this.actionProvider) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actionProvider.next({
|
|
action: XDataScrollerAction.CanNext,
|
|
payload: this.canNext,
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XDataScrollerComponent } from './x-data-scroller.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XDataScrollerComponent],
|
|
imports: [XCardModule, CommonModule, XEmptyModule, XBaseComponentModule],
|
|
exports: [
|
|
XCardModule,
|
|
CommonModule,
|
|
XEmptyModule,
|
|
XBaseComponentModule,
|
|
XDataScrollerComponent,
|
|
],
|
|
})
|
|
export class XDataScrollerModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XBaseDataPagerQuery,
|
|
XBaseDataPagerQueryResult,
|
|
} from 'x-framework-core';
|
|
import {
|
|
IXCardEmptyContainer,
|
|
XCardEmptyContainer,
|
|
XCardEmptyContainerComponent,
|
|
} from '../classes/i-x-card-empty.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XDataScrollerAction {
|
|
Refresh = 'refresh',
|
|
RefreshItems = 'refresh_items',
|
|
LoadMore = 'load_more',
|
|
ClearItems = 'clear_items',
|
|
CanNext = 'can_next',
|
|
}
|
|
|
|
export type XDataScrollerActionIdentifier = XDataScrollerAction | string;
|
|
|
|
export interface XDataScrollerActionModel
|
|
extends XBaseActionModel<XDataScrollerActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card/Empty Container ...
|
|
export interface IXDataScrollerContainer extends IXCardEmptyContainer {
|
|
//
|
|
actionProvider: Subject<XDataScrollerActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
result: XBaseDataPagerQueryResult<any>;
|
|
task: (query: XBaseDataPagerQuery) => Observable<any>;
|
|
taskReady: EventEmitter<Observable<any>>;
|
|
query: XBaseDataPagerQuery;
|
|
queryChange: EventEmitter<XBaseDataPagerQuery>;
|
|
|
|
//
|
|
emptyListTemplate: TemplateRef<any>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XDataScrollerContainer
|
|
extends XCardEmptyContainer
|
|
implements Readonly<IXDataScrollerContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XDataScrollerActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly result: XBaseDataPagerQueryResult<any>;
|
|
readonly task: (query: XBaseDataPagerQuery) => Observable<any>;
|
|
readonly taskReady = new EventEmitter<Observable<any>>();
|
|
readonly query: XBaseDataPagerQuery;
|
|
readonly queryChange = new EventEmitter<XBaseDataPagerQuery>();
|
|
|
|
//
|
|
readonly emptyListTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XDataScrollerContainerComponent
|
|
extends XCardEmptyContainerComponent
|
|
implements IXDataScrollerContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XDataScrollerActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
result: XBaseDataPagerQueryResult<any> = this.propertyProvider.result;
|
|
|
|
@Input()
|
|
task: (query: XBaseDataPagerQuery) => Observable<any> =
|
|
this.propertyProvider.task;
|
|
|
|
@Output()
|
|
taskReady: EventEmitter<Observable<any>> = new EventEmitter();
|
|
|
|
@Input()
|
|
query: XBaseDataPagerQuery = this.propertyProvider.query;
|
|
|
|
@Output()
|
|
queryChange: EventEmitter<XBaseDataPagerQuery> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
emptyListTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XDataScrollerContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXDataScrollerContainer
|
|
): Observable<IXDataScrollerContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
result: this.getValue(container ? container.result : this.result),
|
|
task: this.getValue(container ? container.task : this.task),
|
|
query: this.getValue(container ? container.query : this.query),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
emptyListTemplate: container
|
|
? container.emptyListTemplate
|
|
: this.emptyListTemplate,
|
|
|
|
//
|
|
taskReady: this.taskReady,
|
|
queryChange: this.queryChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<!-- Check Prepared Model Exists -->
|
|
<div
|
|
class="x-wrapper x-description-list"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[class.isLegacy]="getValue(isLegacy) | async"
|
|
[class.isNotLegacy]="!(getValue(isLegacy) | async)"
|
|
*ngIf="notNullOrUndefinedValue(preparedModel) | async"
|
|
>
|
|
<!-- New -->
|
|
<ng-container *ngIf="!(getValue(isLegacy) | async)">
|
|
<dl
|
|
class="x-description-list-innner"
|
|
[xColor]="getValue(color) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Loop of Model Keys -->
|
|
<ng-container *ngFor="let key of keys(preparedModel)">
|
|
<!-- Check Can Show Key -->
|
|
<section
|
|
class="x-description-list-item-container"
|
|
*ngIf="canShowKey(key) | async as canShowTheKey"
|
|
>
|
|
<!-- Title (Key) -->
|
|
<dt
|
|
[isForeground]="true"
|
|
class="x-description-list-title"
|
|
*ngIf="
|
|
canShowTheKey &&
|
|
(getValue(showLabels) | async) &&
|
|
(canShowLabelKey(key) | async)
|
|
"
|
|
[xColor]="getValue(labelColor) | async"
|
|
[ngClass]="getDescriptionTitleClasses(key)"
|
|
>
|
|
<span class="x-title-span text-truncate">
|
|
{{ getTitle(key) | async }}
|
|
</span>
|
|
</dt>
|
|
|
|
<!-- Content (Value) -->
|
|
<!-- if Has Not ContentItem and Descibeable -->
|
|
<dd
|
|
[isForeground]="true"
|
|
class="x-description-list-description"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getDescriptionContentClasses(key)"
|
|
*ngIf="
|
|
!(hasContentItem(key) | async) &&
|
|
(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
>
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasEndOrBottomSlot]="
|
|
notNullOrUndefinedValue(propertyActionTemplate) | async
|
|
"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
style="overflow: hidden"
|
|
[cssClass]="[
|
|
'ion-text-start',
|
|
'text-truncate',
|
|
'x-decription-span'
|
|
]"
|
|
>
|
|
{{ getContent(key, preparedModel[key]) | async }}
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END" [cssClass]="'ion-text-end'">
|
|
<!-- propertyActionTemplate -->
|
|
<ng-container
|
|
*ngIf="
|
|
notNullOrUndefinedValue(propertyActionTemplate) | async
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
propertyActionTemplate;
|
|
context: {
|
|
key: key,
|
|
prefix: prefix,
|
|
value: preparedModel[key]
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</dd>
|
|
|
|
<!-- if Has not ContentItem && not Describeable -->
|
|
<dd
|
|
[isForeground]="true"
|
|
class="x-description-list-description"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getDescriptionContentClasses(key)"
|
|
*ngIf="
|
|
!(hasContentItem(key) | async) &&
|
|
!(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
>
|
|
<section class="nested-container ion-margin-start">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nestedRef;
|
|
context: {
|
|
key: key,
|
|
value: preparedModel[key],
|
|
prefix: getKeyPrefix(key),
|
|
hiddenModelKeys: (getHiddenModelKeys(key) | async),
|
|
availableModelKeys: (getAvailableModelKeys(key) | async),
|
|
sortOrderModelKeys: (getSortOrderModelKeys(key) | async),
|
|
hiddenLabelModelKeys:
|
|
(getHiddenLabelModelKeys(key) | async)
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</section>
|
|
</dd>
|
|
|
|
<!-- if Has ContentItem -->
|
|
<dd
|
|
[isForeground]="true"
|
|
*ngIf="hasContentItem(key) | async"
|
|
class="x-description-list-description"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getDescriptionContentClasses(key)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getContentItem(key, preparedModel[key]) | async).content
|
|
"
|
|
></ng-container>
|
|
</dd>
|
|
</section>
|
|
</ng-container>
|
|
</dl>
|
|
</ng-container>
|
|
|
|
<!-- Legacy -->
|
|
<ng-container *ngIf="getValue(isLegacy) | async">
|
|
<dl
|
|
class="x-description-list"
|
|
[xColor]="getValue(color) | async"
|
|
[class.inline]="isNotMobileUi$ | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Loop of Model Keys -->
|
|
<ng-container *ngFor="let key of keys(preparedModel)">
|
|
<!-- Check Can Show Key -->
|
|
<ng-container *ngIf="canShowKey(key) | async">
|
|
<!-- Title -->
|
|
<dt
|
|
[isForeground]="true"
|
|
class="x-description-list-title"
|
|
[xColor]="getValue(labelColor) | async"
|
|
[ngClass]="getDescriptionTitleClasses(key)"
|
|
*ngIf="
|
|
(getValue(showLabels) | async) && (canShowLabelKey(key) | async)
|
|
"
|
|
>
|
|
{{ getTitle(key) | async }}
|
|
</dt>
|
|
|
|
<!-- Description -->
|
|
<dd
|
|
[isForeground]="true"
|
|
class="x-description-list-description"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getDescriptionContentClasses(key)"
|
|
[class.full-width]="hasContentItem(key) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(hasContentItem(key) | async) ? contentItemRef : contentRef;
|
|
context: {
|
|
$implicit: key,
|
|
value: getContent(key, preparedModel[key]) | async
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</dd>
|
|
</ng-container>
|
|
</ng-container>
|
|
</dl>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- NestedRef -->
|
|
<ng-template
|
|
#nestedRef
|
|
let-key="key"
|
|
let-value="value"
|
|
let-prefix="prefix"
|
|
let-hiddenModelKeys="hiddenModelKeys"
|
|
let-availableModelKeys="availableModelKeys"
|
|
let-sortOrderModelKeys="sortOrderModelKeys"
|
|
let-hiddenLabelModelKeys="hiddenLabelModelKeys"
|
|
>
|
|
<x-description-list
|
|
[model]="value"
|
|
[attr.keyPrefix]="prefix"
|
|
[actionProvider]="actionProvider"
|
|
[color]="getValue(color) | async"
|
|
[hiddenModelKeys]="hiddenModelKeys"
|
|
[modelKeyProvider]="modelKeyProvider"
|
|
[availableModelKeys]="availableModelKeys"
|
|
[sortOrderModelKeys]="sortOrderModelKeys"
|
|
[modelValueProvider]="modelValueProvider"
|
|
[showLabels]="getValue(showLabels) | async"
|
|
[labelColor]="getValue(labelColor) | async"
|
|
[valueColor]="getValue(valueColor) | async"
|
|
[cssClass]="getArrayValue(cssClass) | async"
|
|
[hiddenLabelModelKeys]="hiddenLabelModelKeys"
|
|
(onModelChanged)="onModelChanged.emit($event)"
|
|
[propertyActionTemplate]="propertyActionTemplate"
|
|
[foregroundColor]="getValue(foregroundColor) | async"
|
|
[hideOptionalValues]="getValue(hideOptionalValues) | async"
|
|
*ngIf="
|
|
(notEmptyValue(key) | async) && (notNullOrUndefinedValue(value) | async)
|
|
"
|
|
>
|
|
</x-description-list>
|
|
</ng-template>
|
|
|
|
<!-- XDescriptionListItemContent Template -->
|
|
<ng-template #contentItemRef let-key let-value="value">
|
|
<ng-container
|
|
*ngTemplateOutlet="(getContentItem(key, value) | async).content"
|
|
></ng-container>
|
|
</ng-template>
|
|
|
|
<!-- XDescriptionList Default Content Template -->
|
|
<ng-template #contentRef let-key let-value="value">
|
|
{{ value }}
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.scss
|
|
|
|
:host ::ng-deep .x-description-list {
|
|
&.isLegacy {
|
|
.x-card {
|
|
.x-description-list-title {
|
|
padding: {
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
}
|
|
|
|
.x-description-list-description:not(.full-width) {
|
|
padding: {
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.x-description-list-title {
|
|
padding: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.x-description-list-description:not(.full-width) {
|
|
padding: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
dl {
|
|
margin: {
|
|
top: 0;
|
|
bottom: 0;
|
|
}
|
|
}
|
|
|
|
dl.inline dd {
|
|
display: inline;
|
|
margin: 0;
|
|
}
|
|
|
|
dl.inline dd::after {
|
|
white-space: pre;
|
|
content: "\a";
|
|
}
|
|
|
|
dl.inline dt {
|
|
display: inline-block;
|
|
min-width: 100px;
|
|
}
|
|
|
|
dt {
|
|
margin-top: 8px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
dt::after {
|
|
content: ": ";
|
|
}
|
|
|
|
dd {
|
|
text-align: center;
|
|
|
|
//
|
|
&.full-width {
|
|
margin-inline-end: 0 !important;
|
|
margin-inline-start: 0 !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
&.isNotLegacy {
|
|
dd {
|
|
width: 100%;
|
|
display: inline;
|
|
margin-inline-start: 8px;
|
|
}
|
|
|
|
.x-description-list-item-container {
|
|
width: 100%;
|
|
}
|
|
|
|
.x-title-span::after {
|
|
content: ": ";
|
|
}
|
|
|
|
x-slotter {
|
|
width: 100%;
|
|
display: inline-block;
|
|
}
|
|
|
|
.x-title-span,
|
|
.x-decription-span {
|
|
max-width: calc(90%);
|
|
}
|
|
|
|
.x-slotter {
|
|
.x-start-top-slot {
|
|
flex: 1 1 auto !important;
|
|
}
|
|
|
|
.x-end-bottom-slot {
|
|
flex: 1 1 0% !important;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.ts
|
|
|
|
import {
|
|
Component,
|
|
QueryList,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
tap,
|
|
map,
|
|
filter,
|
|
mergeMap,
|
|
concatMap,
|
|
switchMap,
|
|
} from 'rxjs/operators';
|
|
import {
|
|
keys,
|
|
nameof,
|
|
isDate,
|
|
isArray,
|
|
toArray,
|
|
isObject,
|
|
isNumber,
|
|
isString,
|
|
toXString,
|
|
isFunction,
|
|
isSameObject,
|
|
XModelProperty,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
getPropertyValue,
|
|
setPropertyValue,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XDescriptionListAction,
|
|
XDescriptionListActionModel,
|
|
XDescriptionListContainerComponent,
|
|
} from './x-description-list.typings';
|
|
import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { of, from, Subject, forkJoin, Observable, Subscription } from 'rxjs';
|
|
import { XDescriptionListItemComponent } from './x-description-list-item/x-description-list-item.component';
|
|
|
|
@Component({
|
|
selector: 'x-description-list',
|
|
templateUrl: './x-description-list.component.html',
|
|
styleUrls: ['./x-description-list.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XDescriptionListComponent<
|
|
T = any
|
|
> extends XDescriptionListContainerComponent<T> {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private keyPrefix = '';
|
|
private MODEL: T;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
|
|
//
|
|
get prefix() {
|
|
return this.keyPrefix;
|
|
}
|
|
|
|
get preparedModel() {
|
|
return this.MODEL;
|
|
}
|
|
|
|
//
|
|
@ContentChildren(XDescriptionListItemComponent)
|
|
items: QueryList<XDescriptionListItemComponent>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareModel();
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// prepare KeyPrefix ...
|
|
const keyPrefix = this.element.nativeElement
|
|
? (this.element.nativeElement as HTMLElement).getAttribute('keyPrefix')
|
|
: '';
|
|
if (!isNullOrEmptyString(keyPrefix)) {
|
|
this.keyPrefix += `${keyPrefix}`;
|
|
}
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Model Changed ...
|
|
const isModelChanged = changeKeys.includes(
|
|
nameof<XDescriptionListComponent>('model')
|
|
);
|
|
|
|
//
|
|
if (isModelChanged) {
|
|
await this.prepareModel();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XDescriptionListComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
keys(model: T) {
|
|
//
|
|
let modelKeys = keys(model);
|
|
|
|
//
|
|
if (!this.hasChild(this.sortOrderModelKeys)) {
|
|
return modelKeys;
|
|
}
|
|
|
|
//
|
|
const sortOrderArray = toArray(this.sortOrderModelKeys) as string[];
|
|
const result: string[] = [
|
|
...sortOrderArray.filter((k) => modelKeys.includes(k)),
|
|
...modelKeys.filter((k) => !sortOrderArray.includes(k)),
|
|
];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
canShowKey(key: string) {
|
|
//
|
|
return forkJoin({
|
|
key: this.getValue(key),
|
|
model: this.getValue(this.model),
|
|
keyPrefix: this.getValue(this.keyPrefix),
|
|
hiddenModelKeys: this.getArrayValue(this.hiddenModelKeys),
|
|
hideOptionalValues: this.getValue(this.hideOptionalValues),
|
|
availableModelKeys: this.getArrayValue(this.availableModelKeys),
|
|
}).pipe(
|
|
map((provider) => {
|
|
//
|
|
const value = provider.model[provider.key];
|
|
|
|
//
|
|
const modelHasValue =
|
|
!isNullOrUndefined(provider.model) &&
|
|
!isNullOrUndefined(value) &&
|
|
!isNullOrEmptyString(toXString(provider.model[provider.key]));
|
|
const hasChildHiddens = this.hasChild(provider.hiddenModelKeys);
|
|
const hasChildAvailables = this.hasChild(provider.availableModelKeys);
|
|
|
|
//
|
|
if (!hasChildAvailables && !hasChildHiddens) {
|
|
//
|
|
if (!modelHasValue && provider.hideOptionalValues) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const isInHiddens = provider.hiddenModelKeys.includes(
|
|
provider.key as any
|
|
);
|
|
const isInAvailables = provider.availableModelKeys.includes(
|
|
provider.key as any
|
|
);
|
|
|
|
//
|
|
if (
|
|
(!hasChildAvailables && !isInHiddens) ||
|
|
(isInAvailables && !hasChildHiddens) ||
|
|
(isInAvailables && !isInHiddens) ||
|
|
(!isInAvailables &&
|
|
!isInHiddens &&
|
|
isNumber(provider.key) &&
|
|
!isNullOrEmptyString(provider.keyPrefix))
|
|
) {
|
|
//
|
|
if (!modelHasValue && provider.hideOptionalValues) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
//
|
|
return false;
|
|
})
|
|
);
|
|
}
|
|
|
|
canShowLabelKey(key: string) {
|
|
return this.getArrayValue(this.hiddenLabelModelKeys).pipe(
|
|
map((hiddenLabelsModelKeys) => {
|
|
//
|
|
const hasChildHiddenLabels = this.hasChild(hiddenLabelsModelKeys);
|
|
|
|
//
|
|
if (!hasChildHiddenLabels) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const isInHiddens = hiddenLabelsModelKeys.includes(key as any);
|
|
return hasChildHiddenLabels && !isInHiddens;
|
|
})
|
|
);
|
|
}
|
|
|
|
getTitle(key: string): Observable<string> {
|
|
return this.getValue(this.modelKeyProvider).pipe(
|
|
concatMap((provider) => {
|
|
return isNullOrUndefined(provider) || !isFunction(provider)
|
|
? this.getValue(key)
|
|
: this.getValue(provider(key as any));
|
|
})
|
|
);
|
|
}
|
|
|
|
hasContentItem(key: string) {
|
|
return of(this.items).pipe(
|
|
concatMap((items) => {
|
|
return isNullOrUndefined(items)
|
|
? of(false)
|
|
: this.getArrayValue(items.toArray()).pipe(
|
|
switchMap((items) =>
|
|
from(items).pipe(
|
|
mergeMap((item) =>
|
|
this.getValue(item.name).pipe(
|
|
map((name) => ({ name, item }))
|
|
)
|
|
),
|
|
filter(
|
|
(itemData) =>
|
|
toNormalString(itemData.name) === toNormalString(key)
|
|
),
|
|
map((dataObject) => !isNullOrUndefined(dataObject))
|
|
)
|
|
)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
getContentItem(
|
|
key: string,
|
|
value: any
|
|
): Observable<XDescriptionListItemComponent> {
|
|
return this.hasContentItem(key).pipe(
|
|
concatMap((isExists) => {
|
|
return !isExists
|
|
? of(null)
|
|
: of(this.items).pipe(
|
|
concatMap((items) => {
|
|
return isNullOrUndefined(items)
|
|
? of(null)
|
|
: this.getArrayValue(items.toArray()).pipe(
|
|
switchMap((items) =>
|
|
from(items).pipe(
|
|
mergeMap((item) =>
|
|
this.getValue(item.name).pipe(
|
|
map((name) => ({ name, item }))
|
|
)
|
|
),
|
|
filter(
|
|
(itemData) =>
|
|
toNormalString(itemData.name) ===
|
|
toNormalString(key)
|
|
),
|
|
tap((dataObject) => (dataObject.item.value = value)),
|
|
map((dataObject) => dataObject.item)
|
|
)
|
|
)
|
|
);
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
getContent(key: string, value: any): Observable<string> {
|
|
return this.getValue(this.modelValueProvider).pipe(
|
|
concatMap((provider) => {
|
|
return isNullOrUndefined(provider) || !isFunction(provider)
|
|
? this.getValue(value)
|
|
: this.getValue(provider(key as any, value));
|
|
})
|
|
);
|
|
}
|
|
|
|
canDescribe(key: string, value: any) {
|
|
return of(value).pipe(
|
|
map(
|
|
(eVal) =>
|
|
isDate(eVal) ||
|
|
isFunction(eVal) ||
|
|
(!isArray(eVal) && !isObject(eVal))
|
|
)
|
|
);
|
|
}
|
|
|
|
getDescriptionTitleClasses(key: string) {
|
|
return [`x-description-${key}-title`];
|
|
}
|
|
|
|
getDescriptionContentClasses(key: string) {
|
|
return [`x-description-${key}-title`];
|
|
}
|
|
|
|
//
|
|
//#region Neste ...
|
|
getKeyPrefix(key: string) {
|
|
//
|
|
const result = isNullOrEmptyString(this.keyPrefix)
|
|
? `${key}`
|
|
: `${this.keyPrefix}.${key}`;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getHiddenModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.hiddenModelKeys);
|
|
}
|
|
|
|
getSortOrderModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.sortOrderModelKeys);
|
|
}
|
|
|
|
getAvailableModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.availableModelKeys);
|
|
}
|
|
|
|
getHiddenLabelModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.hiddenLabelModelKeys);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async setModelProperty(property: XModelProperty) {
|
|
//
|
|
if (!property || isNullOrEmptyString(property.key)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const model = this.MODEL;
|
|
const nodeValue = getPropertyValue(model, property.prefix);
|
|
const modelKeys = isNullOrUndefined(nodeValue) ? [] : keys(nodeValue);
|
|
if (!this.hasChild(modelKeys)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(property.key as string);
|
|
if (!isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// normalize value ...
|
|
const normalValue = isString(property.value)
|
|
? !isNullOrEmptyString(property.value) &&
|
|
!isNullOrUndefined(property.value)
|
|
? property.value.toString().trim()
|
|
: undefined
|
|
: isNullOrUndefined(property.value)
|
|
? undefined
|
|
: property.value;
|
|
|
|
//
|
|
if (nodeValue[property.key] === normalValue) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const setterPropertyPath = isNullOrEmptyString(property.prefix)
|
|
? `${property.key as string}`
|
|
: `${property.prefix}.${property.key as string}`;
|
|
|
|
//
|
|
setPropertyValue(model, setterPropertyPath, normalValue);
|
|
|
|
//
|
|
this.MODEL = {
|
|
...model,
|
|
};
|
|
this.detectChanges();
|
|
this.onModelChanged.emit(model);
|
|
}
|
|
|
|
async getModelProperty(key: keyof T | string) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const model = await this.getValueAsync(this.model);
|
|
const modelKeys = await this.getValueAsync(this.keys(model));
|
|
if (!this.hasChild(modelKeys)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(key);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = model[key as any];
|
|
return result;
|
|
}
|
|
|
|
async getModelViewProperty(key: keyof T | string) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const model = await this.getValueAsync(this.model);
|
|
const modelKeys = await this.getValueAsync(this.keys(model));
|
|
if (!this.hasChild(modelKeys)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(key);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = await this.getValueAsync(
|
|
this.getContent(key, model[key as any])
|
|
);
|
|
return result;
|
|
}
|
|
|
|
async setModel(model: T) {
|
|
//
|
|
if (!model || isSameObject(model as any, this.MODEL as any)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.model = {
|
|
...model,
|
|
};
|
|
this.MODEL = {
|
|
...model,
|
|
};
|
|
|
|
//
|
|
await this.prepareModel();
|
|
this.onModelChanged.emit(model);
|
|
}
|
|
|
|
async getModel() {
|
|
//
|
|
const result = await this.getValueAsync(this.model);
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XDescriptionListActionModel>();
|
|
}
|
|
|
|
//
|
|
let modelProperty: XModelProperty = null;
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XDescriptionListAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XDescriptionListAction.ClearProperty:
|
|
//
|
|
modelProperty = model.payload as XModelProperty;
|
|
if (
|
|
!model.payload ||
|
|
isNullOrUndefined(model) ||
|
|
isNullOrUndefined(model.payload) ||
|
|
isNullOrEmptyString(model.action)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
modelProperty.value = null;
|
|
|
|
//
|
|
await this.setModelProperty(modelProperty);
|
|
break;
|
|
|
|
//
|
|
case XDescriptionListAction.SetProperty:
|
|
//
|
|
modelProperty = model.payload as XModelProperty;
|
|
if (
|
|
!model.payload ||
|
|
isNullOrUndefined(model) ||
|
|
isNullOrUndefined(model.payload) ||
|
|
isNullOrEmptyString(model.action)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setModelProperty(modelProperty);
|
|
break;
|
|
|
|
//
|
|
case XDescriptionListAction.SetModel:
|
|
//
|
|
const resetModel = model.payload as T;
|
|
if (!model || !model.payload || !resetModel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setModel(resetModel);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareModel() {
|
|
//
|
|
this.MODEL = null;
|
|
this.detectChanges();
|
|
|
|
//
|
|
if (!this.model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.MODEL = await this.getValueAsync(this.model);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private prepareNestedCollection(
|
|
key: string,
|
|
collection: XOneOrManyType<string>
|
|
) {
|
|
//
|
|
return forkJoin({
|
|
key: this.getValue(key),
|
|
keyPrefix: this.getValue(this.getKeyPrefix(key)),
|
|
model: this.getValue(this.preparedModel[key]),
|
|
collection: this.getArrayValue(collection),
|
|
}).pipe(
|
|
map((provider) => {
|
|
//
|
|
const allAvailableCollectionItems = provider.collection;
|
|
|
|
//
|
|
const keySelector = isNullOrUndefined(provider.keyPrefix)
|
|
? `${provider.key}.`
|
|
: `${provider.keyPrefix}.`;
|
|
|
|
//
|
|
const canFilter =
|
|
!isNumber(provider.key) &&
|
|
!provider.keyPrefix.includes(`${provider.key}.`);
|
|
const result = canFilter
|
|
? allAvailableCollectionItems
|
|
.filter((k) => k.includes(`${provider.key}.`))
|
|
.map((k) => k.replace(`${provider.key}.`, ''))
|
|
: allAvailableCollectionItems;
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XDescriptionListComponent } from './x-description-list.component';
|
|
import { XDescriptionListItemComponent } from './x-description-list-item/x-description-list-item.component';
|
|
|
|
@NgModule({
|
|
declarations: [XDescriptionListComponent, XDescriptionListItemComponent],
|
|
imports: [XCardModule, CommonModule, XSlotterModule, XBaseComponentModule],
|
|
exports: [
|
|
XCardModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XBaseComponentModule,
|
|
XDescriptionListComponent,
|
|
XDescriptionListItemComponent,
|
|
],
|
|
})
|
|
export class XDescriptionListModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XModelFieldsType,
|
|
XModelKeyProvider,
|
|
XModelValueProvider,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XDescriptionListAction {
|
|
//
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
|
|
//
|
|
ClearProperty = 'clear_property',
|
|
SetProperty = 'set_property',
|
|
|
|
//
|
|
SetModel = 'set_model',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XDescriptionListActionIdentifier = XDescriptionListAction | string;
|
|
|
|
export interface XDescriptionListActionModel
|
|
extends XBaseActionModel<XDescriptionListActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXDescriptionListContainer<T = any>
|
|
extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XDescriptionListActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
isLegacy: XStandardType<boolean>;
|
|
showLabels: XStandardType<boolean>;
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
labelColor: XStandardType<XColorIdentifier>;
|
|
valueColor: XStandardType<XColorIdentifier>;
|
|
propertyActionTemplate: TemplateRef<any>;
|
|
onModelChanged: EventEmitter<T>;
|
|
|
|
//
|
|
model: XStandardType<T>;
|
|
|
|
//
|
|
//#region Model Providers ...
|
|
hideOptionalValues: XStandardType<boolean>;
|
|
availableModelKeys: XModelFieldsType<T>;
|
|
hiddenModelKeys: XModelFieldsType<T>;
|
|
hiddenLabelModelKeys: XModelFieldsType<T>;
|
|
sortOrderModelKeys: XModelFieldsType<T>;
|
|
modelKeyProvider: XModelKeyProvider<T>;
|
|
modelValueProvider: XModelValueProvider<T>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XDescriptionListContainer<T = any>
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXDescriptionListContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XDescriptionListActionModel> =
|
|
new Subject<XDescriptionListActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly isLegacy: XStandardType<boolean> = true;
|
|
readonly showLabels: XStandardType<boolean> = false;
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
readonly labelColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryShade;
|
|
readonly valueColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly propertyActionTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly onModelChanged: EventEmitter<T>;
|
|
|
|
//
|
|
readonly model: XStandardType<T>;
|
|
|
|
//
|
|
//#region Model Providers ...
|
|
readonly hideOptionalValues: XStandardType<boolean>;
|
|
readonly availableModelKeys: XModelFieldsType<T>;
|
|
readonly hiddenModelKeys: XModelFieldsType<T>;
|
|
readonly hiddenLabelModelKeys: XModelFieldsType<T>;
|
|
readonly sortOrderModelKeys: XModelFieldsType<T>;
|
|
readonly modelKeyProvider: XModelKeyProvider<T>;
|
|
readonly modelValueProvider: XModelValueProvider<T>;
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XDescriptionListContainerComponent<T = any>
|
|
extends XComponentCardContainerComponent
|
|
implements IXDescriptionListContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XDescriptionListActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
isLegacy: XStandardType<boolean> = this.propertyProvider.isLegacy;
|
|
|
|
@Input()
|
|
showLabels: XStandardType<boolean> = this.propertyProvider.showLabels;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
labelColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.labelColor;
|
|
|
|
@Input()
|
|
valueColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.valueColor;
|
|
|
|
@Input()
|
|
propertyActionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.propertyActionTemplate;
|
|
|
|
@Output()
|
|
onModelChanged: EventEmitter<T> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
model: XStandardType<T> = this.propertyProvider.model;
|
|
|
|
//
|
|
//#region Model Providers ...
|
|
@Input()
|
|
hideOptionalValues: XStandardType<boolean> =
|
|
this.propertyProvider.hideOptionalValues;
|
|
|
|
@Input()
|
|
availableModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.availableModelKeys;
|
|
|
|
@Input()
|
|
hiddenModelKeys: XModelFieldsType<T> = this.propertyProvider.hiddenModelKeys;
|
|
|
|
@Input()
|
|
hiddenLabelModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.hiddenLabelModelKeys;
|
|
|
|
@Input()
|
|
sortOrderModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.sortOrderModelKeys;
|
|
|
|
@Input()
|
|
modelKeyProvider: XModelKeyProvider<T> =
|
|
this.propertyProvider.modelKeyProvider;
|
|
|
|
@Input()
|
|
modelValueProvider: XModelValueProvider<T> =
|
|
this.propertyProvider.modelValueProvider;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XDescriptionListContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXDescriptionListContainer
|
|
): Observable<IXDescriptionListContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
isLegacy: this.getValue(
|
|
container ? container.isLegacy : this.isLegacy
|
|
),
|
|
showLabels: this.getValue(
|
|
container ? container.showLabels : this.showLabels
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
labelColor: this.getValue(
|
|
container ? container.labelColor : this.labelColor
|
|
),
|
|
valueColor: this.getValue(
|
|
container ? container.valueColor : this.valueColor
|
|
),
|
|
propertyActionTemplate: this.getValue(
|
|
container
|
|
? container.propertyActionTemplate
|
|
: this.propertyActionTemplate
|
|
),
|
|
model: this.getValue(container ? container.model : this.model),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
//#region Model Providers ...
|
|
hideOptionalValues: container
|
|
? container.hideOptionalValues
|
|
: this.hideOptionalValues,
|
|
availableModelKeys: container
|
|
? container.availableModelKeys
|
|
: this.availableModelKeys,
|
|
hiddenModelKeys: container
|
|
? container.hiddenModelKeys
|
|
: this.hiddenModelKeys,
|
|
hiddenLabelModelKeys: container
|
|
? container.hiddenLabelModelKeys
|
|
: this.hiddenLabelModelKeys,
|
|
sortOrderModelKeys: container
|
|
? container.sortOrderModelKeys
|
|
: this.sortOrderModelKeys,
|
|
modelKeyProvider: container
|
|
? container.modelKeyProvider
|
|
: this.modelKeyProvider,
|
|
modelValueProvider: container
|
|
? container.modelValueProvider
|
|
: this.modelValueProvider,
|
|
//#endregion
|
|
|
|
//
|
|
onModelChanged: this.onModelChanged,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.html
|
|
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.ts
|
|
|
|
import { nameof } from 'x-framework-core';
|
|
import {
|
|
XDescriptionListItemAction,
|
|
XDescriptionListItemActionModel,
|
|
XDescriptionListItemContainerComponent,
|
|
} from './x-description-list-item.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ViewChild, TemplateRef } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-description-list-item',
|
|
templateUrl: './x-description-list-item.component.html',
|
|
styleUrls: ['./x-description-list-item.component.scss'],
|
|
})
|
|
export class XDescriptionListItemComponent extends XDescriptionListItemContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
content: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XDescriptionListItemComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XDescriptionListItemActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XDescriptionListItemAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XDescriptionListItemAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
export type XDescriptionListItemActionIdentifier =
|
|
| XDescriptionListItemAction
|
|
| string;
|
|
|
|
export interface XDescriptionListItemActionModel
|
|
extends XBaseActionModel<XDescriptionListItemActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXDescriptionListItemContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XDescriptionListItemActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
name: XStandardType<string>;
|
|
value: XStandardType<any>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XDescriptionListItemContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXDescriptionListItemContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XDescriptionListItemActionModel> =
|
|
new Subject<XDescriptionListItemActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly name: XStandardType<string>;
|
|
readonly value: XStandardType<any>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XDescriptionListItemContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXDescriptionListItemContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XDescriptionListItemActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
name: XStandardType<string> = this.propertyProvider.name;
|
|
|
|
@Input()
|
|
value: XStandardType<any> = this.propertyProvider.value;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XDescriptionListItemContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXDescriptionListItemContainer
|
|
): Observable<IXDescriptionListItemContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
name: this.getValue(container ? container.name : this.name),
|
|
value: this.getValue(container ? container.value : this.value),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.html
|
|
|
|
<div
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
class="x-empty x-wrapper ion-text-center"
|
|
[ngClass]="getArrayValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<h3
|
|
class="x-empty-title"
|
|
[xColor]="getValue(messageColor) | async"
|
|
[isForeground]="getValue(foregroundMessageColor) | async"
|
|
>
|
|
{{ getResourceValue(message) | async }}
|
|
</h3>
|
|
<x-button
|
|
class="x-refresh"
|
|
(clicked)="refresh.emit()"
|
|
[type]="ButtonTypes.Icon"
|
|
*ngIf="getValue(hasRefresh) | async"
|
|
[color]="getValue(refreshButtonColor) | async"
|
|
[foregroundColor]="getValue(foregroundRefreshButtonColor) | async"
|
|
>
|
|
<x-icon
|
|
[foregroundColor]="true"
|
|
[name]="getValue(refreshIcon) | async"
|
|
[color]="getValue(refreshButtonColor) | async"
|
|
></x-icon>
|
|
</x-button>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.scss
|
|
|
|
:host {
|
|
--padding: 6px;
|
|
}
|
|
|
|
.x-empty {
|
|
padding: var(--padding);
|
|
}
|
|
|
|
.x-empty-title {
|
|
padding-bottom: 6px;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.ts
|
|
|
|
import {
|
|
XEmptyAction,
|
|
XEmptyActionModel,
|
|
XEmptyContainerComponent,
|
|
} from './x-empty.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-empty',
|
|
templateUrl: './x-empty.component.html',
|
|
styleUrls: ['./x-empty.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XEmptyComponent extends XEmptyContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Provider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XEmptyComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XEmptyActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XEmptyAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XEmptyComponent } from './x-empty.component';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XEmptyComponent],
|
|
imports: [XIconModule, XButtonModule, CommonModule, XBaseComponentModule],
|
|
exports: [XIconModule, XButtonModule, XEmptyComponent, XBaseComponentModule],
|
|
})
|
|
export class XEmptyModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseComponentContainer,
|
|
XBaseContainerComponent,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XEmptyAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XEmptyActionIdentifier = XEmptyAction | string;
|
|
|
|
export interface XEmptyActionModel
|
|
extends XBaseActionModel<XEmptyActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXEmptyContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XEmptyActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
message: XStandardType<XResourceIdentifier>;
|
|
messageColor: XStandardType<XColorIdentifier>;
|
|
foregroundMessageColor: XStandardType<boolean>;
|
|
|
|
//
|
|
hasRefresh: XStandardType<boolean>;
|
|
|
|
//
|
|
refreshButtonColor: XStandardType<XColorIdentifier>;
|
|
foregroundRefreshButtonColor: XStandardType<boolean>;
|
|
|
|
//
|
|
refreshIcon: XStandardType<XIconIdentifier>;
|
|
|
|
//
|
|
refresh: EventEmitter<void>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XEmptyContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXEmptyContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XEmptyActionModel> =
|
|
new Subject<XEmptyActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly messageColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly foregroundMessageColor: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly hasRefresh: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly refreshButtonColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly foregroundRefreshButtonColor: XStandardType<boolean> = true;
|
|
readonly message: XStandardType<XResourceIdentifier> = XResourceIDs.no_item;
|
|
|
|
//
|
|
readonly refreshIcon: XStandardType<XIconIdentifier> = XIconNames.refresh;
|
|
|
|
//
|
|
readonly refresh: EventEmitter<void> = new EventEmitter<void>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XEmptyContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXEmptyContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
message: XStandardType<XResourceIdentifier> = this.propertyProvider.message;
|
|
|
|
@Input()
|
|
messageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.messageColor;
|
|
|
|
@Input()
|
|
foregroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundMessageColor;
|
|
|
|
//
|
|
@Input()
|
|
hasRefresh: XStandardType<boolean> = this.propertyProvider.hasRefresh;
|
|
|
|
//
|
|
@Input()
|
|
refreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.refreshButtonColor;
|
|
|
|
@Input()
|
|
foregroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundRefreshButtonColor;
|
|
|
|
//
|
|
@Input()
|
|
refreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.refreshIcon;
|
|
|
|
@Output()
|
|
refresh: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XEmptyContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXEmptyContainer
|
|
): Observable<IXEmptyContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
|
|
//
|
|
messageColor: this.getValue(
|
|
container ? container.messageColor : this.messageColor
|
|
),
|
|
foregroundMessageColor: this.getValue(
|
|
container
|
|
? container.foregroundMessageColor
|
|
: this.foregroundMessageColor
|
|
),
|
|
|
|
//
|
|
hasRefresh: this.getValue(
|
|
container ? container.hasRefresh : this.hasRefresh
|
|
),
|
|
refreshButtonColor: this.getValue(
|
|
container ? container.refreshButtonColor : this.refreshButtonColor
|
|
),
|
|
foregroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.foregroundRefreshButtonColor
|
|
: this.foregroundRefreshButtonColor
|
|
),
|
|
refreshIcon: this.getValue(
|
|
container ? container.refreshIcon : this.refreshIcon
|
|
),
|
|
|
|
//
|
|
message: this.getValue(container ? container.message : this.message),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
refresh: this.refresh,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentEmptyContainer = {
|
|
[TKey in keyof IXEmptyContainer as `empty${Capitalize<
|
|
string & TKey
|
|
>}`]: IXEmptyContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentEmptyContainer
|
|
extends TXComponentEmptyContainer,
|
|
IXBaseComponentContainer {
|
|
showEmpty: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentEmptyContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentEmptyContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showEmpty: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly emptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly emptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.message;
|
|
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.messageColor;
|
|
readonly emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundMessageColor;
|
|
|
|
//
|
|
readonly emptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.hasRefresh;
|
|
|
|
//
|
|
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.refreshButtonColor;
|
|
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundRefreshButtonColor;
|
|
|
|
//
|
|
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.refreshIcon;
|
|
|
|
//
|
|
readonly emptyRefresh: EventEmitter<void> = this.propertyProvider.refresh;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XEmptyContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XComponentEmptyContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentEmptyContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
showEmpty: XStandardType<boolean> = this.propertyProvider.showEmpty;
|
|
|
|
//
|
|
@Input()
|
|
emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.emptyActionProvider;
|
|
|
|
@Input()
|
|
emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.emptyCssClass;
|
|
|
|
//
|
|
@Input()
|
|
emptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyColor;
|
|
|
|
@Input()
|
|
emptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.emptyMessage;
|
|
|
|
@Input()
|
|
emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyMessageColor;
|
|
|
|
@Input()
|
|
emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundMessageColor;
|
|
|
|
//
|
|
@Input()
|
|
emptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.emptyHasRefresh;
|
|
|
|
//
|
|
@Input()
|
|
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyRefreshButtonColor;
|
|
|
|
@Input()
|
|
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundRefreshButtonColor;
|
|
|
|
//
|
|
@Input()
|
|
emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.emptyRefreshIcon;
|
|
|
|
//
|
|
@Output()
|
|
emptyRefresh: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentEmptyContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentEmptyContainer
|
|
): Observable<IXComponentEmptyContainer> {
|
|
return forkJoin({
|
|
//
|
|
showEmpty: this.getValue(
|
|
container ? container.showEmpty : this.showEmpty
|
|
),
|
|
emptyCssClass: this.getValue(
|
|
container ? container.emptyCssClass : this.emptyCssClass
|
|
),
|
|
emptyColor: this.getValue(
|
|
container ? container.emptyColor : this.emptyColor
|
|
),
|
|
emptyForegroundColor: this.getValue(
|
|
container ? container.emptyForegroundColor : this.emptyForegroundColor
|
|
),
|
|
emptyMessage: this.getValue(
|
|
container ? container.emptyMessage : this.emptyMessage
|
|
),
|
|
emptyMessageColor: this.getValue(
|
|
container ? container.emptyMessageColor : this.emptyMessageColor
|
|
),
|
|
emptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundMessageColor
|
|
: this.emptyForegroundMessageColor
|
|
),
|
|
emptyHasRefresh: this.getValue(
|
|
container ? container.emptyHasRefresh : this.emptyHasRefresh
|
|
),
|
|
emptyRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyRefreshButtonColor
|
|
: this.emptyRefreshButtonColor
|
|
),
|
|
emptyForegroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundRefreshButtonColor
|
|
: this.emptyForegroundRefreshButtonColor
|
|
),
|
|
emptyRefreshIcon: this.getValue(
|
|
container ? container.emptyRefreshIcon : this.emptyRefreshIcon
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
emptyActionProvider: container
|
|
? container.emptyActionProvider
|
|
: this.emptyActionProvider,
|
|
|
|
//
|
|
emptyRefresh: this.emptyRefresh,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else listRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="listRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- List Ref -->
|
|
<ng-template #listRef>
|
|
<ion-list
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
class="x-expandable-list x-wrapper ion-no-padding"
|
|
>
|
|
<ng-container *ngFor="let item of getArrayValue(items) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
parentPresenterRef;
|
|
context: { $implicit: item, siblings: getArrayValue(items) | async }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-list>
|
|
</ng-template>
|
|
|
|
<!-- Parent Ref -->
|
|
<ng-template #parentPresenterRef let-item let-siblings="siblings">
|
|
<ion-item-group
|
|
button="true"
|
|
xStopClickPropagation
|
|
class="expandable-item-parent"
|
|
[ngClass]="{ active: isExpanded(item) | async }"
|
|
>
|
|
<ion-item-divider
|
|
(click)="toggle(item, siblings)"
|
|
class="item-parent ion-activatable"
|
|
[class.active-parent]="isParentActivated(item) | async"
|
|
[matTooltip]="getResourceValue(item.description) | async"
|
|
>
|
|
<ion-ripple-effect></ion-ripple-effect>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
parentTemplate ? parentTemplate : defaultParentRef;
|
|
context: { $implicit: item }
|
|
"
|
|
></ng-container>
|
|
<x-icon
|
|
slot="end"
|
|
[color]="'cb-inherit'"
|
|
[name]="getIconName(item) | async"
|
|
[class.invisible]="
|
|
!(getValue(showParentDetailIcon) | async) ||
|
|
!(hasChildItems(item) | async)
|
|
"
|
|
></x-icon>
|
|
</ion-item-divider>
|
|
|
|
<!-- Childs -->
|
|
<ng-container
|
|
*ngTemplateOutlet="childsPresenterRef; context: { $implicit: item }"
|
|
>
|
|
</ng-container>
|
|
</ion-item-group>
|
|
</ng-template>
|
|
|
|
<!-- Children Ref -->
|
|
<ng-template #childsPresenterRef let-item>
|
|
<ng-container *ngFor="let child of getValue(item.childs) | async">
|
|
<ng-container *ngIf="!(hasChildItems(child) | async)">
|
|
<ion-item
|
|
button="true"
|
|
class="item-child"
|
|
xStopClickPropagation
|
|
[class.ion-hide]="isHidden(child) | async"
|
|
[ngClass]="getValue(itemCssClass) | async"
|
|
(click)="handleItemSelectedAction(child, item)"
|
|
[class.collapsed]="!(isExpanded(item) | async)"
|
|
[detail]="getValue(showChildDetailIcon) | async"
|
|
[class.active-child]="isChildActivated(child) | async"
|
|
[matTooltip]="getResourceValue(child.description) | async"
|
|
[disabled]="loading || uiDisabled || (isDisabled(child) | async)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
childTemplate ? childTemplate : defaultChildRef;
|
|
context: { $implicit: child }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ion-item>
|
|
</ng-container>
|
|
|
|
<ng-container *ngIf="hasChildItems(child) | async">
|
|
<ion-item
|
|
[class.ion-hide]="isHidden(child) | async"
|
|
[class.collapsed]="!(isExpanded(item) | async)"
|
|
class="item-child ion-no-padding ion-no-margin"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
parentPresenterRef;
|
|
context: {
|
|
$implicit: child,
|
|
siblings: getValue(item.childs) | async
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ion-item>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Default Parent Item -->
|
|
<ng-template #defaultParentRef let-item>
|
|
<h4>{{ getResourceValue(item.title) | async }}</h4>
|
|
</ng-template>
|
|
|
|
<!-- Default Child Item -->
|
|
<ng-template #defaultChildRef let-item>
|
|
<h5>{{ getResourceValue(item.title) | async }}</h5>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.scss
|
|
|
|
:host ::ng-deep {
|
|
//
|
|
--divider-color: var(--x-color-dark);
|
|
|
|
//
|
|
--child-color: var(--x-color-primary-shade-contrast);
|
|
--child-background-color: var(--x-color-primary-shade);
|
|
|
|
//
|
|
--child-active-color: var(--x-color-dark-tint-contrast);
|
|
--child-active-background-color: var(--x-color-dark-tint);
|
|
|
|
//
|
|
--highlight-color: var(--x-color-warning-contrast);
|
|
--highlight-background-color: var(--x-color-warning);
|
|
|
|
//
|
|
--parent-color: var(--x-color-tertiary-tint-contrast);
|
|
--parent-background-color: var(--x-color-tertiary-tint);
|
|
|
|
//
|
|
--parent-active-color: var(--x-color-dark-contrast);
|
|
--parent-active-background-color: var(--x-color-dark);
|
|
}
|
|
|
|
:host ::ng-deep .invisible {
|
|
display: none;
|
|
visibility: hidden;
|
|
}
|
|
|
|
ion-list,
|
|
ion-item,
|
|
ion-item-group {
|
|
width: 100%;
|
|
--background: transparent;
|
|
--inner-padding-end: 0px;
|
|
--inner-padding-start: 0px;
|
|
--color: var(--child-color);
|
|
--border-color: var(--divider-color);
|
|
}
|
|
|
|
ion-item-divider {
|
|
width: 100%;
|
|
position: relative;
|
|
--border-color: var(--divider-color);
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0;
|
|
}
|
|
|
|
.item-parent {
|
|
//
|
|
width: 100%;
|
|
padding-top: 0;
|
|
padding-bottom: 0;
|
|
position: relative;
|
|
|
|
//
|
|
color: var(--parent-color);
|
|
background-color: var(--parent-background-color);
|
|
|
|
//
|
|
*,
|
|
ion-icon,
|
|
x-icon {
|
|
color: var(--parent-color) !important;
|
|
}
|
|
}
|
|
|
|
.item-child {
|
|
padding-top: 0;
|
|
padding-bottom: 0;
|
|
display: block !important;
|
|
transition: opacity 0.2s ease-in;
|
|
color: var(--child-color) !important;
|
|
background-color: var(--child-background-color) !important;
|
|
|
|
//
|
|
*,
|
|
ion-icon,
|
|
x-icon {
|
|
color: var(--child-color) !important;
|
|
}
|
|
}
|
|
|
|
.item-child:hover,
|
|
.item-parent:hover {
|
|
color: var(--highlight-color) !important;
|
|
--color: var(--highlight-color) !important;
|
|
background-color: var(--highlight-background-color) !important;
|
|
|
|
//
|
|
*,
|
|
ion-icon,
|
|
x-icon {
|
|
color: var(--highlight-color) !important;
|
|
}
|
|
}
|
|
|
|
.item-parent.active-link,
|
|
.active-parent {
|
|
//
|
|
color: var(--parent-active-color) !important;
|
|
background-color: var(--parent-active-background-color) !important;
|
|
|
|
//
|
|
*,
|
|
ion-icon,
|
|
x-icon {
|
|
color: var(--parent-active-color) !important;
|
|
}
|
|
}
|
|
|
|
.item-child.active-link,
|
|
.active-child {
|
|
//
|
|
color: var(--child-active-color) !important;
|
|
background-color: var(--child-active-background-color) !important;
|
|
|
|
//
|
|
*,
|
|
ion-icon,
|
|
x-icon {
|
|
color: var(--child-active-color) !important;
|
|
}
|
|
}
|
|
|
|
ion-icon {
|
|
&.invisible {
|
|
visibility: hidden;
|
|
}
|
|
}
|
|
|
|
.collapsed {
|
|
opacity: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.ion-hide {
|
|
display: none !important;
|
|
}
|
|
|
|
x-card {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
.item-parent,
|
|
.expandable-item-parent {
|
|
//
|
|
cursor: pointer;
|
|
|
|
//
|
|
min-height: 48px;
|
|
|
|
//
|
|
&.active {
|
|
color: var(--parent-active-color);
|
|
background-color: var(--parent-active-background-color);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
toArray,
|
|
hasChild,
|
|
parseXColor,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
findItemById,
|
|
findItemByRoute,
|
|
parentItemsById,
|
|
parentItemsByRoute,
|
|
containsItemsByRoute,
|
|
} from './x-expandable-list.tools';
|
|
import {
|
|
XExpandableListItem,
|
|
XExpandableListAction,
|
|
XExpandableListCssVarKeys,
|
|
XExpandableListActionModel,
|
|
XExpandableListStartupState,
|
|
XExpandableListContainerComponent,
|
|
} from './x-expandable-list.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { forkJoin, of, Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-expandable-list',
|
|
templateUrl: './x-expandable-list.component.html',
|
|
styleUrls: ['./x-expandable-list.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XExpandableListComponent extends XExpandableListContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTIVATED_CHILD: XExpandableListItem<any>;
|
|
private ACTIVATED_PARENTS: XExpandableListItem<any>[];
|
|
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Item Changed ...
|
|
const isItemsChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('items')
|
|
);
|
|
if (isItemsChanged) {
|
|
await this.handleStartupState();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Color Change Detectors ...
|
|
const isChildColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('childColor')
|
|
);
|
|
if (isChildColorChanged) {
|
|
await this.applyChildColor();
|
|
}
|
|
|
|
const isChildActiveColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('childActiveColor')
|
|
);
|
|
if (isChildActiveColorChanged) {
|
|
await this.applyChildActiveColor();
|
|
}
|
|
|
|
const isParentColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('parentColor')
|
|
);
|
|
if (isParentColorChanged) {
|
|
await this.applyParentColor();
|
|
}
|
|
|
|
const isParentActiveColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('parentActiveColor')
|
|
);
|
|
if (isParentActiveColorChanged) {
|
|
await this.applyParentActiveColor();
|
|
}
|
|
|
|
const isHighlightColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('highlightColor')
|
|
);
|
|
if (isHighlightColorChanged) {
|
|
await this.applyHighlightColor();
|
|
}
|
|
|
|
const isDividerColorChanged = changeKeys.includes(
|
|
nameof<XExpandableListComponent>('dividerColor')
|
|
);
|
|
if (isDividerColorChanged) {
|
|
await this.applyDividerColor();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Provider Actions ...
|
|
hasChildItems(item: XExpandableListItem<any>) {
|
|
//
|
|
if (!item || !item.childs) {
|
|
return of(false);
|
|
}
|
|
|
|
return this.getValue(item.childs).pipe(map((childs) => hasChild(childs)));
|
|
}
|
|
|
|
getIconName(item: XExpandableListItem<any>) {
|
|
return this.isExpanded(item).pipe(
|
|
map((isExpanded) =>
|
|
isExpanded
|
|
? XIconNames.arrow_dropup.toString()
|
|
: XIconNames.arrow_dropdown.toString()
|
|
)
|
|
);
|
|
}
|
|
|
|
isParentActivated(item: XExpandableListItem<any>) {
|
|
//
|
|
return this.getValue(item).pipe(
|
|
concatMap((pItem) =>
|
|
this.getValue(this.supportRouting).pipe(
|
|
map((supportRouting) => {
|
|
return { item: pItem, supportRouting };
|
|
})
|
|
)
|
|
),
|
|
concatMap((dObject) => {
|
|
//
|
|
if (!dObject || !dObject.item) {
|
|
return this.getValue(false);
|
|
}
|
|
|
|
//
|
|
return this.getArrayValue(dObject.item.href).pipe(
|
|
map((hrefArray) => this.managerService.mergeRoutes(hrefArray)),
|
|
concatMap((route) => {
|
|
//
|
|
if (!this.ACTIVATED_PARENTS || !hasChild(this.ACTIVATED_PARENTS)) {
|
|
return this.getValue(false);
|
|
}
|
|
|
|
//
|
|
if (dObject.supportRouting) {
|
|
//
|
|
const routes$ = forkJoin(
|
|
this.ACTIVATED_PARENTS.map((i) =>
|
|
this.getArrayValue(i.href).pipe(
|
|
map((href) => this.managerService.mergeRoutes(href))
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
return routes$.pipe(
|
|
map(
|
|
(routes) =>
|
|
routes.findIndex(
|
|
(r) => toNormalString(r) === toNormalString(route)
|
|
) > -1
|
|
)
|
|
);
|
|
} else {
|
|
//
|
|
const ids$ = forkJoin(this.ACTIVATED_PARENTS.map((i) => i.id));
|
|
|
|
//
|
|
return ids$.pipe(
|
|
map(
|
|
(ids) =>
|
|
ids.findIndex(
|
|
(i) =>
|
|
toNormalString(i) === toNormalString(dObject.item.id)
|
|
) > -1
|
|
)
|
|
);
|
|
}
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
isChildActivated(item: XExpandableListItem<any>) {
|
|
//
|
|
return this.getValue(item).pipe(
|
|
concatMap((pItem) =>
|
|
this.getValue(this.supportRouting).pipe(
|
|
map((supportRouting) => {
|
|
return { item: pItem, supportRouting };
|
|
})
|
|
)
|
|
),
|
|
concatMap((dObject) => {
|
|
//
|
|
if (!dObject || !dObject.item || !this.ACTIVATED_CHILD) {
|
|
return this.getValue(false);
|
|
}
|
|
|
|
//
|
|
return this.getArrayValue(this.ACTIVATED_CHILD.href)
|
|
.pipe(map((hrefArray) => this.managerService.mergeRoutes(hrefArray)))
|
|
.pipe(
|
|
concatMap((activatedRoute) => {
|
|
return this.getArrayValue(dObject.item.href)
|
|
.pipe(
|
|
map((hrefArray) => this.managerService.mergeRoutes(hrefArray))
|
|
)
|
|
.pipe(
|
|
map((itemRoute) => {
|
|
return { itemRoute, activatedRoute };
|
|
}),
|
|
map((routeObject) => {
|
|
//
|
|
if (dObject.supportRouting) {
|
|
return (
|
|
toNormalString(routeObject.itemRoute) ===
|
|
toNormalString(routeObject.activatedRoute)
|
|
);
|
|
} else {
|
|
return (
|
|
toNormalString(this.ACTIVATED_CHILD.id) ===
|
|
toNormalString(dObject.item.id)
|
|
);
|
|
}
|
|
})
|
|
);
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
isHidden(item: XExpandableListItem<any>) {
|
|
return !item || !item.hidden ? of(false) : this.getValue(item.hidden);
|
|
}
|
|
|
|
isDisabled(item: XExpandableListItem<any>) {
|
|
return !item || !item.disabled ? of(false) : this.getValue(item.disabled);
|
|
}
|
|
|
|
isExpanded(item: XExpandableListItem<any>) {
|
|
return !item || !item.opened ? of(false) : this.getValue(item.opened);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleItemSelectedAction(
|
|
item: XExpandableListItem<any>,
|
|
parent: XExpandableListItem<any>
|
|
) {
|
|
//
|
|
// Check Component State ...
|
|
if (this.loading || this.uiDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Emit Event Handler ...
|
|
this.itemSelected.emit(item);
|
|
|
|
//
|
|
const isSupportRouting = await this.getValueAsync(this.supportRouting);
|
|
if (isSupportRouting) {
|
|
//
|
|
const currUrl: string = this.managerService.getRoute();
|
|
const itemHref = await this.getArrayValueAsync(item.href);
|
|
const itemUrl = this.managerService.mergeRoutes(itemHref);
|
|
|
|
//
|
|
if (currUrl === itemUrl) {
|
|
//
|
|
await this.setActivatedParent(parent);
|
|
await this.setActivatedChild(item);
|
|
} else {
|
|
await this.handleItemRoutingActions(item);
|
|
}
|
|
} else {
|
|
//
|
|
await this.setActivatedParent(parent);
|
|
await this.setActivatedChild(item);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async toggle(
|
|
item: XExpandableListItem<any>,
|
|
siblings: XExpandableListItem<any>[]
|
|
) {
|
|
//
|
|
const isExpanded = await this.toPromise(this.isExpanded(item));
|
|
item.opened = !isExpanded;
|
|
|
|
//
|
|
const isCloseSibling = await this.toPromise(
|
|
this.getValue(this.closeSiblings)
|
|
);
|
|
|
|
//
|
|
if (isCloseSibling) {
|
|
this.handleCloseSiblings(item, siblings);
|
|
}
|
|
|
|
//
|
|
if (this.loading || this.uiDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.itemSelected.emit(item);
|
|
|
|
//
|
|
await this.handleItemRoutingActions(item, true);
|
|
}
|
|
|
|
async expand(item: XExpandableListItem<any>) {
|
|
item.opened = true;
|
|
}
|
|
|
|
async expandAll() {
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
await this.handleChangeState(items, true);
|
|
}
|
|
|
|
async collapse(item: XExpandableListItem<any>) {
|
|
item.opened = false;
|
|
}
|
|
|
|
async collapseAll() {
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
await this.handleChangeState(items, false);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Privates ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XExpandableListActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XExpandableListAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XExpandableListAction.ExpandAll:
|
|
await this.expandAll();
|
|
break;
|
|
|
|
//
|
|
case XExpandableListAction.CollapseAll:
|
|
await this.collapseAll();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Parent and Child Avtivated ...
|
|
private async handleApplyCurrentItems() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
setTimeout(async () => await this.handleApplyCurrentItems(), 100);
|
|
}
|
|
|
|
//
|
|
const supportRouting = await this.getValueAsync(this.supportRouting);
|
|
if (supportRouting) {
|
|
await this.handleApplyCurrentItemsByRouting();
|
|
} else {
|
|
await this.handleApplyCurrentItemsById();
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async handleApplyCurrentItemsByRouting() {
|
|
//
|
|
const currentRoute = this.managerService.getRoute();
|
|
if (isNullOrEmptyString(currentRoute)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const foundedItem = await findItemByRoute(this.items, currentRoute);
|
|
const parentItems = await parentItemsByRoute(this.items, currentRoute);
|
|
|
|
//
|
|
if (!foundedItem || !hasChild(parentItems)) {
|
|
//
|
|
if (foundedItem) {
|
|
//
|
|
this.ACTIVATED_CHILD = foundedItem;
|
|
this.ACTIVATED_PARENTS = [foundedItem];
|
|
}
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTIVATED_PARENTS = parentItems;
|
|
this.ACTIVATED_CHILD = foundedItem;
|
|
}
|
|
|
|
private async handleApplyCurrentItemsById() {
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
const currentId = this.ACTIVATED_CHILD
|
|
? this.ACTIVATED_CHILD.id
|
|
: hasChild(items)
|
|
? items[0].id
|
|
: '';
|
|
if (isNullOrEmptyString(currentId)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const foundedItem = await findItemById(this.items, currentId);
|
|
const parentItems = await parentItemsById(this.items, currentId);
|
|
|
|
//
|
|
if (!foundedItem || !hasChild(parentItems)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTIVATED_PARENTS = parentItems;
|
|
this.ACTIVATED_CHILD = foundedItem;
|
|
}
|
|
//#endregion
|
|
|
|
private async handleItemRoutingActions(
|
|
item: XExpandableListItem<any>,
|
|
isParent = false
|
|
) {
|
|
//
|
|
if (!item || this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hidden = await this.getValueAsync(item.hidden);
|
|
const disabled = await this.getValueAsync(item.disabled);
|
|
if (hidden || disabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Handle Routing ...
|
|
//
|
|
const href = await this.getValueAsync(item.href);
|
|
const route = this.managerService.mergeRoutes(href);
|
|
const supportRouting = await this.getValueAsync(this.supportRouting);
|
|
const replaceUrl = await this.getOptionalValueAsync(item.replaceUrl);
|
|
const disableParentRouting = await this.getValueAsync(
|
|
this.disableParentRouting
|
|
);
|
|
|
|
//
|
|
// When just a not Child Parent with Href provided ...
|
|
const childsArr = !item.childs
|
|
? []
|
|
: await this.getArrayValueAsync(item.childs);
|
|
if (isParent && !hasChild(childsArr)) {
|
|
isParent = false;
|
|
}
|
|
|
|
//
|
|
if (isParent && disableParentRouting) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (supportRouting && hasChild(href) && !isNullOrEmptyString(route)) {
|
|
await this.managerService.navigateByUrlReplace(route, {}, replaceUrl);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
private handleCloseSiblings(
|
|
item: XExpandableListItem<any>,
|
|
siblings: XOneOrManyType<XExpandableListItem<any>>
|
|
) {
|
|
//
|
|
const pSiblings = toArray(siblings);
|
|
const others = pSiblings.filter((i) => item.id !== i.id);
|
|
others.forEach((i) => (i.opened = false));
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async handleChangeState(
|
|
items: XOneOrManyType<XExpandableListItem<any>>,
|
|
expand: boolean
|
|
) {
|
|
//
|
|
const pItems = toArray(items);
|
|
pItems.forEach((i) => {
|
|
//
|
|
i.opened = expand;
|
|
|
|
//
|
|
this.getValueAsync(i.childs).then((childs) => {
|
|
if (hasChild(childs)) {
|
|
this.handleChangeState(childs, expand);
|
|
}
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private async handleStartupState() {
|
|
//
|
|
const items = (await this.getValueAsync(
|
|
this.items
|
|
)) as XExpandableListItem<any>[];
|
|
|
|
//
|
|
await this.applyStartupState(items);
|
|
await this.handleApplyCurrentItems();
|
|
}
|
|
|
|
private async setActivatedParent(v: XExpandableListItem<any>) {
|
|
//
|
|
const isExists = hasChild(this.ACTIVATED_PARENTS)
|
|
? this.ACTIVATED_PARENTS.findIndex(
|
|
(p) => toNormalString(p.id) === toNormalString(v.id)
|
|
) > 1
|
|
: false;
|
|
|
|
//
|
|
if (isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTIVATED_PARENTS = await containsItemsByRoute(this.items, v.href);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async setActivatedChild(v: XExpandableListItem<any>) {
|
|
//
|
|
const isSamed = this.ACTIVATED_CHILD
|
|
? v.id === this.ACTIVATED_CHILD.id
|
|
: false;
|
|
|
|
//
|
|
if (isSamed) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTIVATED_CHILD = v;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyStartupState(
|
|
items: XOneOrManyType<XExpandableListItem<any>>
|
|
) {
|
|
//
|
|
if (!hasChild(items)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const startupState = await this.getValueAsync(this.startupState);
|
|
const pItems = await this.getArrayValueAsync(items);
|
|
|
|
//
|
|
pItems.forEach((i) => {
|
|
//
|
|
// Handle StartUp State for Items ...
|
|
i.opened =
|
|
startupState === XExpandableListStartupState.CollapseAll
|
|
? false
|
|
: startupState === XExpandableListStartupState.ExpandAll
|
|
? true
|
|
: false;
|
|
|
|
//
|
|
if (i.childs) {
|
|
this.getValueAsync(i.childs).then((childs) => {
|
|
this.applyStartupState(childs);
|
|
});
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyChildColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.childColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XExpandableListCssVarKeys.ChildColor, `var(${fgColor})`);
|
|
this.setCssVar(XExpandableListCssVarKeys.ChildBgColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyChildActiveColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.childActiveColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XExpandableListCssVarKeys.ChildActiveColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XExpandableListCssVarKeys.ChildActiveBgColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyParentColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.parentColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XExpandableListCssVarKeys.ParentColor, `var(${fgColor})`);
|
|
this.setCssVar(XExpandableListCssVarKeys.ParentBgColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyParentActiveColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.parentActiveColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XExpandableListCssVarKeys.ParentActiveColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XExpandableListCssVarKeys.ParentActiveBgColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyHighlightColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.highlightColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XExpandableListCssVarKeys.HighlightColor, `var(${fgColor})`);
|
|
this.setCssVar(
|
|
XExpandableListCssVarKeys.HighlightBgColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyDividerColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.dividerColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorVar = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(colorVar)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XExpandableListCssVarKeys.DividerColor, `var(${colorVar})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XExpandableListComponent } from './x-expandable-list.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XExpandableListComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XCardModule, XIconModule],
|
|
exports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
XBaseComponentModule,
|
|
XExpandableListComponent,
|
|
],
|
|
})
|
|
export class XExpandableListModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.tools.ts
|
|
|
|
import {
|
|
toArray,
|
|
hasChild,
|
|
toPromise,
|
|
mergeRoutes,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { XExpandableListItem } from './x-expandable-list.typings';
|
|
|
|
export async function toFlatItems(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>
|
|
) {
|
|
//
|
|
const result: XExpandableListItem<any>[] = [];
|
|
|
|
//
|
|
if (!items) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItemsArray = await toPromise(items);
|
|
if (!hasChild(pItemsArray)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItems = toArray(pItemsArray);
|
|
for (const item of pItems) {
|
|
//
|
|
const childsArray = await toPromise(item.childs);
|
|
const isParent = hasChild(childsArray);
|
|
|
|
//
|
|
result.push(item);
|
|
|
|
//
|
|
if (isParent) {
|
|
//
|
|
const childsRes = await toFlatItems(item.childs);
|
|
result.push(...childsRes);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//#region By Route ...
|
|
export async function findItemByRoute(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
route: XStandardType<XOneOrManyType<string>>
|
|
) {
|
|
//
|
|
let result: XExpandableListItem<any> = null;
|
|
|
|
//
|
|
if (!items || !route) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const routeArray = await toPromise(route);
|
|
if (!hasChild(routeArray)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pRoute = mergeRoutes(routeArray);
|
|
if (isNullOrEmptyString(pRoute)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItems = await toFlatItems(items);
|
|
if (!hasChild(pItems)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (const item of pItems) {
|
|
//
|
|
const itemRouteArray = await toPromise(item.href);
|
|
if (hasChild(itemRouteArray)) {
|
|
//
|
|
const itemRoute = mergeRoutes(itemRouteArray);
|
|
if (
|
|
!isNullOrEmptyString(itemRoute) &&
|
|
toNormalString(itemRoute) === toNormalString(pRoute)
|
|
) {
|
|
result = item;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export async function containsItemsByRoute(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
route: XStandardType<XOneOrManyType<string>>
|
|
) {
|
|
//
|
|
const result: XExpandableListItem<any>[] = [];
|
|
|
|
//
|
|
if (!items || !route) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const routeArray = await toPromise(route);
|
|
if (!hasChild(routeArray)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pRoute = mergeRoutes(routeArray);
|
|
if (isNullOrEmptyString(pRoute)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItems = await toFlatItems(items);
|
|
if (!hasChild(pItems)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (const item of pItems) {
|
|
//
|
|
const itemRouteArray = await toPromise(item.href);
|
|
if (hasChild(itemRouteArray)) {
|
|
//
|
|
const itemRoute = mergeRoutes(itemRouteArray);
|
|
if (
|
|
!isNullOrEmptyString(itemRoute) &&
|
|
toNormalString(pRoute).includes(toNormalString(itemRoute))
|
|
) {
|
|
result.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export async function parentItemsByRoute(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
route: XStandardType<XOneOrManyType<string>>
|
|
) {
|
|
//
|
|
let result: XExpandableListItem<any>[] = [];
|
|
|
|
//
|
|
if (!items || !route) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const parentItems = await containsItemsByRoute(items, route);
|
|
const foundedItem = await findItemByRoute(items, route);
|
|
if (!hasChild(parentItems) || isNullOrUndefined(foundedItem)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = parentItems.filter(
|
|
(i) => toNormalString(i.id) !== toNormalString(foundedItem.id)
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region By Id ...
|
|
export async function findItemById(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
id: XStandardType<string>
|
|
) {
|
|
//
|
|
let result: XExpandableListItem<any> = null;
|
|
|
|
//
|
|
if (!items || !id) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pId = await toPromise(id);
|
|
if (isNullOrEmptyString(pId)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItems = await toFlatItems(items);
|
|
if (!hasChild(pItems)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (const item of pItems) {
|
|
//
|
|
const itemRouteArray = await toPromise(item.href);
|
|
if (hasChild(itemRouteArray)) {
|
|
//
|
|
if (
|
|
!isNullOrEmptyString(item.id) &&
|
|
toNormalString(item.id) === toNormalString(pId)
|
|
) {
|
|
result = item;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export async function containsItemsById(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
id: XStandardType<string>
|
|
) {
|
|
//
|
|
const result: XExpandableListItem<any>[] = [];
|
|
|
|
//
|
|
if (!items || !id) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pId = await toPromise(id);
|
|
if (isNullOrEmptyString(pId)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const pItems = await toFlatItems(items);
|
|
if (!hasChild(pItems)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (const item of pItems) {
|
|
//
|
|
const isSameId = toNormalString(item.id) === toNormalString(pId);
|
|
if (isSameId) {
|
|
result.push(item);
|
|
} else {
|
|
//
|
|
const childsArr = await toPromise(item.childs);
|
|
const childs = toArray(childsArr);
|
|
const isParent = hasChild(childs);
|
|
|
|
//
|
|
if (isParent) {
|
|
const pChildsRes = await containsItemsById(childsArr, id);
|
|
result.push(...pChildsRes);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export async function parentItemsById(
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>,
|
|
id: XStandardType<string>
|
|
) {
|
|
//
|
|
let result: XExpandableListItem<any>[] = [];
|
|
|
|
//
|
|
if (!items || !id) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
const parentItems = await containsItemsById(items, id);
|
|
const foundedItem = await findItemById(items, id);
|
|
if (!hasChild(parentItems) || isNullOrUndefined(foundedItem)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = parentItems.filter(
|
|
(i) => toNormalString(i.id) !== toNormalString(foundedItem.id)
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export interface XExpandableListItem<T> {
|
|
id: string;
|
|
data: XStandardType<T>;
|
|
opened?: XStandardType<boolean>;
|
|
hidden?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
replaceUrl?: XStandardType<boolean>;
|
|
title: XStandardType<XResourceIdentifier>;
|
|
href?: XStandardType<XOneOrManyType<string>>;
|
|
description?: XStandardType<XResourceIdentifier>;
|
|
childs?: XStandardType<XOneOrManyType<XExpandableListItem<T>>>;
|
|
}
|
|
|
|
export enum XExpandableListStartupState {
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XExpandableListStartupStateIdentifier =
|
|
| XExpandableListStartupState
|
|
| string;
|
|
|
|
export enum XExpandableListAction {
|
|
//
|
|
Refresh = 'refresh',
|
|
|
|
//
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XExpandableListActionIdentifier = XExpandableListAction | string;
|
|
|
|
export interface XExpandableListActionModel
|
|
extends XBaseActionModel<XExpandableListActionIdentifier> {}
|
|
|
|
export enum XExpandableListCssVarKeys {
|
|
//
|
|
ChildColor = 'child-color',
|
|
ChildBgColor = 'child-background-color',
|
|
|
|
//
|
|
ChildActiveColor = 'child-active-color',
|
|
ChildActiveBgColor = 'child-active-background-color',
|
|
|
|
//
|
|
ParentColor = 'parent-color',
|
|
ParentBgColor = 'parent-background-color',
|
|
|
|
//
|
|
ParentActiveColor = 'parent-active-color',
|
|
ParentActiveBgColor = 'parent-active-background-color',
|
|
|
|
//
|
|
HighlightColor = 'highlight-color',
|
|
HighlightBgColor = 'highlight-background-color',
|
|
|
|
//
|
|
DividerColor = 'divider-color',
|
|
}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXExpandableListContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XExpandableListActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
itemCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
supportRouting: XStandardType<boolean>;
|
|
disableParentRouting: XStandardType<boolean>;
|
|
showParentDetailIcon: XStandardType<boolean>;
|
|
showChildDetailIcon: XStandardType<boolean>;
|
|
closeSiblings: XStandardType<boolean>;
|
|
startupState: XStandardType<XExpandableListStartupStateIdentifier>;
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>;
|
|
parentTemplate: TemplateRef<any>;
|
|
childTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
childColor: XStandardType<XColorIdentifier>;
|
|
childActiveColor: XStandardType<XColorIdentifier>;
|
|
parentColor: XStandardType<XColorIdentifier>;
|
|
parentActiveColor: XStandardType<XColorIdentifier>;
|
|
highlightColor: XStandardType<XColorIdentifier>;
|
|
dividerColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
itemSelected: EventEmitter<XExpandableListItem<any>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XExpandableListContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXExpandableListContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XExpandableListActionModel>;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly itemCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly supportRouting: XStandardType<boolean> = false;
|
|
readonly disableParentRouting: XStandardType<boolean> = true;
|
|
readonly showParentDetailIcon: XStandardType<boolean> = true;
|
|
readonly showChildDetailIcon: XStandardType<boolean> = true;
|
|
readonly closeSiblings: XStandardType<boolean> = false;
|
|
readonly startupState: XStandardType<XExpandableListStartupStateIdentifier> =
|
|
XExpandableListStartupState.CollapseAll;
|
|
readonly items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>;
|
|
readonly parentTemplate: TemplateRef<any>;
|
|
readonly childTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly childColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.PrimaryShade;
|
|
readonly childActiveColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly parentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryTint;
|
|
readonly parentActiveColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly highlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
readonly dividerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
//
|
|
readonly itemSelected: EventEmitter<XExpandableListItem<any>> =
|
|
new EventEmitter<XExpandableListItem<any>>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XExpandableListContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXExpandableListContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XExpandableListActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
itemCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.itemCssClass;
|
|
|
|
//
|
|
@Input()
|
|
supportRouting: XStandardType<boolean> = this.propertyProvider.supportRouting;
|
|
|
|
@Input()
|
|
disableParentRouting: XStandardType<boolean> =
|
|
this.propertyProvider.disableParentRouting;
|
|
|
|
@Input()
|
|
showParentDetailIcon: XStandardType<boolean> =
|
|
this.propertyProvider.showParentDetailIcon;
|
|
|
|
@Input()
|
|
showChildDetailIcon: XStandardType<boolean> =
|
|
this.propertyProvider.showChildDetailIcon;
|
|
|
|
@Input()
|
|
closeSiblings: XStandardType<boolean> = this.propertyProvider.closeSiblings;
|
|
|
|
@Input()
|
|
startupState: XStandardType<XExpandableListStartupStateIdentifier> =
|
|
this.propertyProvider.startupState;
|
|
|
|
@Input()
|
|
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>> =
|
|
this.propertyProvider.items;
|
|
|
|
@Input()
|
|
parentTemplate: TemplateRef<any> = this.propertyProvider.parentTemplate;
|
|
|
|
@Input()
|
|
childTemplate: TemplateRef<any> = this.propertyProvider.childTemplate;
|
|
|
|
//
|
|
@Input()
|
|
childColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.childColor;
|
|
|
|
@Input()
|
|
childActiveColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.childActiveColor;
|
|
|
|
@Input()
|
|
parentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.parentColor;
|
|
|
|
@Input()
|
|
parentActiveColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.parentActiveColor;
|
|
|
|
@Input()
|
|
highlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.highlightColor;
|
|
|
|
@Input()
|
|
dividerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.dividerColor;
|
|
|
|
//
|
|
@Output()
|
|
itemSelected: EventEmitter<XExpandableListItem<any>> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XExpandableListContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXExpandableListContainer
|
|
): Observable<IXExpandableListContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
itemCssClass: this.getValue(
|
|
container ? container.itemCssClass : this.itemCssClass
|
|
),
|
|
|
|
//
|
|
supportRouting: this.getValue(
|
|
container ? container.supportRouting : this.supportRouting
|
|
),
|
|
disableParentRouting: this.getValue(
|
|
container
|
|
? container.disableParentRouting
|
|
: this.disableParentRouting
|
|
),
|
|
showParentDetailIcon: this.getValue(
|
|
container
|
|
? container.showParentDetailIcon
|
|
: this.showParentDetailIcon
|
|
),
|
|
showChildDetailIcon: this.getValue(
|
|
container
|
|
? container.showChildDetailIcon
|
|
: this.showChildDetailIcon
|
|
),
|
|
closeSiblings: this.getValue(
|
|
container ? container.closeSiblings : this.closeSiblings
|
|
),
|
|
startupState: this.getValue(
|
|
container ? container.startupState : this.startupState
|
|
),
|
|
items: this.getValue(container ? container.items : this.items),
|
|
parentTemplate: this.getValue(
|
|
container ? container.parentTemplate : this.parentTemplate
|
|
),
|
|
childTemplate: this.getValue(
|
|
container ? container.childTemplate : this.childTemplate
|
|
),
|
|
|
|
//
|
|
childColor: this.getValue(
|
|
container ? container.childColor : this.childColor
|
|
),
|
|
childActiveColor: this.getValue(
|
|
container ? container.childActiveColor : this.childActiveColor
|
|
),
|
|
parentColor: this.getValue(
|
|
container ? container.parentColor : this.parentColor
|
|
),
|
|
parentActiveColor: this.getValue(
|
|
container ? container.parentActiveColor : this.parentActiveColor
|
|
),
|
|
highlightColor: this.getValue(
|
|
container ? container.highlightColor : this.highlightColor
|
|
),
|
|
dividerColor: this.getValue(
|
|
container ? container.dividerColor : this.dividerColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
itemSelected: this.itemSelected,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else wrapperRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="wrapperRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-card-actions" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Components itSelf Template -->
|
|
<ng-template #wrapperRef>
|
|
<!-- Wrapper Element -->
|
|
<div
|
|
class="x-expandable-panel x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[class.applyColors]="getValue(applyColors) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="getIsAccordion() ? accordionRef : panelRef"
|
|
></ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Accordion Template -->
|
|
<ng-template #accordionRef>
|
|
<mat-accordion
|
|
class="x-expandable-accordion"
|
|
[multi]="getValue(multiExpanded) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="panelRef"> </ng-container>
|
|
</mat-accordion>
|
|
</ng-template>
|
|
|
|
<!-- Non Accordion Template -->
|
|
<ng-template #panelRef>
|
|
<!-- Check Panels Exists -->
|
|
<ng-container *ngIf="hasPanels()">
|
|
<ng-container *ngFor="let panel of panels">
|
|
<!-- Panel -->
|
|
<mat-expansion-panel
|
|
[disabled]="panel.uiDisabled"
|
|
(opened)="handlePanelOpened(panel)"
|
|
[expanded]="getExpanded(panel) | async"
|
|
[ngClass]="getValue(panel.cssClass) | async"
|
|
[hideToggle]="getValue(panel.hideToggle) | async"
|
|
>
|
|
<!-- Header -->
|
|
<mat-expansion-panel-header
|
|
class="x-expandable-panel-header"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
>
|
|
<!-- Title -->
|
|
<mat-panel-title
|
|
*ngIf="panel.title"
|
|
class="x-expandable-panel-header-title"
|
|
>
|
|
<ng-container *ngTemplateOutlet="panel.title"></ng-container>
|
|
</mat-panel-title>
|
|
|
|
<!-- Description -->
|
|
<mat-panel-description
|
|
class="x-expandable-panel-header-description"
|
|
*ngIf="
|
|
panel.description &&
|
|
(!(getValue(hideDescriptionOnSmallScreens) | async) ||
|
|
((getValue(hideDescriptionOnSmallScreens) | async) &&
|
|
(isNotMobileUi$ | async)))
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="panel.description"></ng-container>
|
|
</mat-panel-description>
|
|
</mat-expansion-panel-header>
|
|
|
|
<!-- Conent -->
|
|
<ng-template matExpansionPanelContent>
|
|
<div class="x-expandable-panel-content">
|
|
<ng-container *ngTemplateOutlet="panel.content"></ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Actions -->
|
|
<mat-action-row
|
|
class="x-expandable-panel-actions"
|
|
*ngIf="
|
|
(hasActions(panel) | async) ||
|
|
(getValue(panel.hasCustomActions) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="panelActionsRef; context: { $implicit: panel }"
|
|
></ng-container>
|
|
</mat-action-row>
|
|
</mat-expansion-panel>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Panel Actions Template -->
|
|
<ng-template #panelActionsRef let-panel>
|
|
<!-- Step Buttons -->
|
|
<div class="x-panel-actions">
|
|
<!-- Defined Actions -->
|
|
<x-slotter *ngIf="hasActions(panel) | async">
|
|
<!-- Next -->
|
|
<x-slot
|
|
[name]="getValue(panel.nextPosition) | async"
|
|
[cssClass]="getValue(panel.nextCssClass) | async"
|
|
>
|
|
<ng-container *ngIf="hasStepAction(panel, NPRButtonTypes.Next) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
panel: panel,
|
|
type: NPRButtonTypes.Next
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Reset -->
|
|
<x-slot
|
|
[name]="getValue(panel.resetPosition) | async"
|
|
[cssClass]="getValue(panel.resetCssClass) | async"
|
|
>
|
|
<ng-container
|
|
*ngIf="hasStepAction(panel, NPRButtonTypes.Reset) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
panel: panel,
|
|
type: NPRButtonTypes.Reset
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Prev -->
|
|
<x-slot
|
|
[name]="getValue(panel.prevPosition) | async"
|
|
[cssClass]="getValue(panel.prevCssClass) | async"
|
|
>
|
|
<ng-container *ngIf="hasStepAction(panel, NPRButtonTypes.Prev) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
panel: panel,
|
|
type: NPRButtonTypes.Prev
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Specified Actions -->
|
|
<div
|
|
class="x-panel-custom-actions-wrapper"
|
|
*ngIf="getValue(panel.hasCustomActions) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="panel.actions"></ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Button Template -->
|
|
<ng-template #buttonRef let-panel="panel" let-type="type">
|
|
<x-button
|
|
(clicked)="handleNPRStep(panel, type)"
|
|
[icon]="getButtonIcon(panel, type) | async"
|
|
[type]="getButtonType(panel, type) | async"
|
|
[title]="getButtonTitle(panel, type) | async"
|
|
[color]="getButtonColor(panel, type) | async"
|
|
[cssClass]="getButtonCssClass(panel, type) | async"
|
|
[uiDisabled]="getButtonDisabled(panel, type) | async"
|
|
[class.disabled]="getButtonDisabled(panel, type) | async"
|
|
[iconPosition]="getButtonIconPosition(panel, type) | async"
|
|
[foregroundColor]="getButtonForegroundColor(panel, type) | async"
|
|
></x-button>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.scss
|
|
|
|
:host {
|
|
--panel-header-size: 48px;
|
|
}
|
|
|
|
.x-expandable-panel-header {
|
|
height: var(--panel-header-size);
|
|
}
|
|
|
|
.applyColors {
|
|
.mat-expansion-panel-header {
|
|
//
|
|
color: var(--header-foreground-color, var(--x-color-light-contrast));
|
|
background-color: var(--header-background-color, var(--x-color-light));
|
|
|
|
* {
|
|
color: var(--header-foreground-color, var(--x-color-light-contrast));
|
|
}
|
|
|
|
.mat-expansion-indicator {
|
|
&::after {
|
|
color: var(
|
|
--header-foreground-color,
|
|
var(--x-color-light-contrast)
|
|
) !important;
|
|
}
|
|
}
|
|
|
|
&:focus,
|
|
&:hover,
|
|
&.mat-expanded {
|
|
background: unset;
|
|
color: var(
|
|
--header-highlight-foreground-color,
|
|
var(--x-color-light-contrast)
|
|
);
|
|
background-color: var(
|
|
--header-highlight-background-color,
|
|
var(--x-color-light)
|
|
);
|
|
|
|
* {
|
|
color: var(
|
|
--header-highlight-foreground-color,
|
|
var(--x-color-light-contrast)
|
|
);
|
|
}
|
|
|
|
.mat-expansion-indicator {
|
|
&::after {
|
|
color: var(
|
|
--header-highlight-foreground-color,
|
|
var(--x-color-light-contrast)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep .mat-expansion-indicator {
|
|
&::after {
|
|
color: var(
|
|
--header-foreground-color,
|
|
var(--x-color-light-contrast)
|
|
) !important;
|
|
}
|
|
}
|
|
|
|
.x-panel-actions,
|
|
.x-panel-custom-actions-wrapper {
|
|
width: 100%;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.ts
|
|
|
|
import {
|
|
Component,
|
|
QueryList,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
XStandardType,
|
|
XModalButtonRole,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XExpandablePanelAction,
|
|
XExpandablePanelCssVars,
|
|
XExpandablePanelActionModel,
|
|
XExpandablePanelStartupState,
|
|
XExpandablePandelContainerComponent,
|
|
} from './x-expandable-panel.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { XPanelComponent } from './x-panel/x-panel.component';
|
|
import { XNPRButtonType } from '../classes/i-x-next-prev-reset.container';
|
|
|
|
@Component({
|
|
selector: 'x-expandable-panel',
|
|
templateUrl: './x-expandable-panel.component.html',
|
|
styleUrls: ['./x-expandable-panel.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XExpandablePanelComponent extends XExpandablePandelContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private IS_ACCORDION: boolean;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly NPRButtonTypes = Object.assign({}, XNPRButtonType);
|
|
|
|
//
|
|
//#region Panels Props ...
|
|
//
|
|
private PANELS: QueryList<XPanelComponent>;
|
|
|
|
//
|
|
@ContentChildren(XPanelComponent)
|
|
set panels(p: QueryList<XPanelComponent>) {
|
|
//
|
|
if (!p) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PANELS = p;
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
get panels() {
|
|
return this.PANELS;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
await this.handleStartupState();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isAccordionChanged = changeKeys.includes(
|
|
nameof<XExpandablePanelComponent>('isAccordion')
|
|
);
|
|
if (isAccordionChanged) {
|
|
this.IS_ACCORDION = await this.getValueAsync(this.isAccordion);
|
|
}
|
|
|
|
//
|
|
const isHeaderColorChanged = changeKeys.includes(
|
|
nameof<XExpandablePanelComponent>('headerColor')
|
|
);
|
|
if (isHeaderColorChanged) {
|
|
await this.applyHeaderColor();
|
|
}
|
|
|
|
//
|
|
const isHeaderHighlighColorChanged = changeKeys.includes(
|
|
nameof<XExpandablePanelComponent>('headerHighlightColor')
|
|
);
|
|
if (isHeaderHighlighColorChanged) {
|
|
await this.applyHeaderHighlightColor();
|
|
}
|
|
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XExpandablePanelComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerInstanceHandlers() {
|
|
super.registerInstanceHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Provider ...
|
|
hasStepAction(panel: XPanelComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getOptionalValue(panel.hasNext);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getOptionalValue(panel.hasPrev);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getOptionalValue(panel.hasReset);
|
|
}
|
|
}
|
|
|
|
hasPanels() {
|
|
return this.panels && this.panels.length > 0;
|
|
}
|
|
|
|
hasActions(panel: XPanelComponent) {
|
|
return this.getValue(panel.hasNext).pipe(
|
|
concatMap((hasNext) =>
|
|
this.getValue(panel.hasPrev).pipe(
|
|
map((hasPrev) => {
|
|
return {
|
|
hasNext,
|
|
hasPrev,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
concatMap((hasNextPrev) =>
|
|
this.getValue(panel.hasReset).pipe(
|
|
map((hasReset) => {
|
|
return {
|
|
...hasNextPrev,
|
|
hasReset,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((info) => info.hasNext || info.hasPrev || info.hasReset)
|
|
);
|
|
}
|
|
|
|
getIsAccordion() {
|
|
return this.IS_ACCORDION;
|
|
}
|
|
|
|
getExpanded(panel: XPanelComponent) {
|
|
return this.getValue(panel.id).pipe(
|
|
concatMap((panelId) =>
|
|
this.getValue(panel.expanded).pipe(
|
|
map((panelExpanded) => {
|
|
return {
|
|
panelId,
|
|
panelExpanded,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((panelInfo) => {
|
|
return {
|
|
...panelInfo,
|
|
isAccordion: this.IS_ACCORDION,
|
|
};
|
|
}),
|
|
map((info) =>
|
|
info.isAccordion ? this.selected === info.panelId : info.panelExpanded
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Button Providers ...
|
|
getButtonIcon(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getValue(actionButton.icon))
|
|
);
|
|
}
|
|
|
|
getButtonType(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getValue(actionButton.type)),
|
|
map((btnType) =>
|
|
!isNullOrEmptyString(btnType) ? btnType : XButtonType.Raised
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonTitle(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getResourceValue(actionButton.title))
|
|
);
|
|
}
|
|
|
|
getButtonColor(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getValue(actionButton.color)),
|
|
map((btnColor) =>
|
|
!isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonDisabled(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButtonDisabled(panel, type);
|
|
}
|
|
|
|
getButtonCssClass(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getArrayValue(actionButton.cssClass))
|
|
);
|
|
}
|
|
|
|
getButtonIconPosition(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) => this.getValue(actionButton.iconPosition))
|
|
);
|
|
}
|
|
|
|
getButtonForegroundColor(panel: XPanelComponent, type: XNPRButtonType) {
|
|
return this.getActionButton(panel, type).pipe(
|
|
concatMap((actionButton) =>
|
|
this.getOptionalValue(actionButton.foregroundColor)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleNPRStep(panel: XPanelComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
await this.handleNextStep(panel);
|
|
break;
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
await this.handlePrevStep(panel);
|
|
break;
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
await this.handleReset(panel);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleNextStep(panel: XPanelComponent, force?: boolean) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!panel ||
|
|
panel.loading ||
|
|
panel.uiDisabled ||
|
|
!this.hasPanels()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let nextId: string;
|
|
const panelId = await this.getValueAsync(panel.id);
|
|
const panelIndex = await this.getPanelIndex(panelId);
|
|
if (panelIndex === -1) {
|
|
return;
|
|
}
|
|
if (panelIndex < this.panels.length - 1) {
|
|
nextId = await this.getValueAsync(
|
|
this.panels.toArray()[panelIndex + 1].id
|
|
);
|
|
}
|
|
if (isNullOrEmptyString(nextId)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!force) {
|
|
//
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canNextStep = await this.getValueAsync(this.canNext);
|
|
const disableNextStep = await this.getValueAsync(panel.disableNext);
|
|
|
|
//
|
|
if (isUiBusy || disableNextStep || !canNextStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepNextConfitmedType = panel.nextConfirmer
|
|
? panel.nextConfirmer()
|
|
: this.getValue(true);
|
|
const isStepNextConfirmed = await this.getValueAsync(
|
|
isStepNextConfitmedType
|
|
);
|
|
if (!isStepNextConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = nextId;
|
|
this.detectChanges();
|
|
this.selectedChange.emit(nextId);
|
|
this.onNext.emit(panelId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handlePrevStep(panel: XPanelComponent, force?: boolean) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!panel ||
|
|
panel.loading ||
|
|
panel.uiDisabled ||
|
|
!this.hasPanels()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let prevId: string;
|
|
const panelId = await this.getValueAsync(panel.id);
|
|
const panelIndex = await this.getPanelIndex(panelId);
|
|
if (panelIndex === -1) {
|
|
return;
|
|
}
|
|
if (panelIndex > 0) {
|
|
prevId = await this.getValueAsync(
|
|
this.panels.toArray()[panelIndex - 1].id
|
|
);
|
|
}
|
|
if (isNullOrEmptyString(prevId)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canPrevStep = await this.getValueAsync(this.canPrev);
|
|
const disablePrevStep = await this.getValueAsync(panel.disablePrev);
|
|
if (isUiBusy || disablePrevStep || !canPrevStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepPrevConfitmedType = panel.prevConfirmer
|
|
? panel.prevConfirmer()
|
|
: this.getValue(true);
|
|
const isStepPrevConfirmed = await this.getValueAsync(
|
|
isStepPrevConfitmedType
|
|
);
|
|
if (!isStepPrevConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = prevId;
|
|
this.detectChanges();
|
|
this.selectedChange.emit(prevId);
|
|
this.onPrev.emit(panelId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleReset(panel: XPanelComponent, force?: boolean) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!panel ||
|
|
panel.loading ||
|
|
panel.uiDisabled ||
|
|
!this.hasPanels()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(panel.id);
|
|
const firstId = await this.getValueAsync(this.panels.toArray()[0].id);
|
|
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canResetStep = await this.getValueAsync(this.canReset);
|
|
const disableResetStep = await this.getValueAsync(panel.disableReset);
|
|
if (isUiBusy || disableResetStep || !canResetStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isConfirmedType = await this.resetConfirmer();
|
|
const isConfirmed = await this.getValueAsync(isConfirmedType);
|
|
|
|
//
|
|
if (!isConfirmed) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepResetConfitmedType = panel.resetConfirmer
|
|
? panel.resetConfirmer()
|
|
: this.getValue(true);
|
|
const isStepResetConfirmed = await this.getValueAsync(
|
|
isStepResetConfitmedType
|
|
);
|
|
if (!isStepResetConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = firstId;
|
|
this.detectChanges();
|
|
this.selectedChange.emit(firstId);
|
|
this.onReset.emit(stepId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleToStep(panel: XPanelComponent) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!panel ||
|
|
panel.loading ||
|
|
panel.uiDisabled ||
|
|
!this.hasPanels() ||
|
|
this.selected === (await this.getValueAsync(panel.id))
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const panelId = await this.getValueAsync(panel.id);
|
|
|
|
//
|
|
this.selected = panelId;
|
|
this.detectChanges();
|
|
this.selectedChange.emit(panelId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handlePanelOpened(panel: XPanelComponent) {
|
|
//
|
|
const panelId = await this.getValueAsync(panel.id);
|
|
this.selected = panelId;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async next(force?: boolean) {
|
|
//
|
|
const panel = await this.getPanel(this.selected);
|
|
if (!panel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleNextStep(panel, force);
|
|
}
|
|
|
|
async prev(force?: boolean) {
|
|
//
|
|
const panel = await this.getPanel(this.selected);
|
|
if (!panel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handlePrevStep(panel, force);
|
|
}
|
|
|
|
async reset(force?: boolean) {
|
|
//
|
|
const panel = await this.getPanel(this.selected);
|
|
if (!panel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleReset(panel, force);
|
|
}
|
|
|
|
async to(id: XStandardType<string>, force?: boolean) {
|
|
//
|
|
if (!id || !this.hasPanels()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const panelId = await this.getValueAsync(id);
|
|
if (!panelId) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const panelIndex = await this.getPanelIndex(panelId);
|
|
if (panelIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const panel = await this.getPanel(panelId);
|
|
if (!panel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const selectedIndex = await this.getPanelIndex(this.selected);
|
|
if (selectedIndex === -1 || selectedIndex === panelIndex) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (panelIndex > selectedIndex) {
|
|
//
|
|
// next confirm ...
|
|
//
|
|
if (!force) {
|
|
//
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canNextStep = await this.getValueAsync(this.canNext);
|
|
const disableNextStep = await this.getValueAsync(panel.disableNext);
|
|
|
|
//
|
|
if (isUiBusy || disableNextStep || !canNextStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepNextConfitmedType = panel.nextConfirmer
|
|
? panel.nextConfirmer()
|
|
: this.getValue(true);
|
|
const isStepNextConfirmed = await this.getValueAsync(
|
|
isStepNextConfitmedType
|
|
);
|
|
if (!isStepNextConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = panelId;
|
|
this.selectedChange.emit(panelId);
|
|
} else if (panelIndex < selectedIndex) {
|
|
//
|
|
// prev Confirm ...
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canPrevStep = await this.getValueAsync(this.canPrev);
|
|
const disablePrevStep = await this.getValueAsync(panel.disablePrev);
|
|
if (isUiBusy || disablePrevStep || !canPrevStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepPrevConfitmedType = panel.prevConfirmer
|
|
? panel.prevConfirmer()
|
|
: this.getValue(true);
|
|
const isStepPrevConfirmed = await this.getValueAsync(
|
|
isStepPrevConfitmedType
|
|
);
|
|
if (!isStepPrevConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = panelId;
|
|
this.selectedChange.emit(panelId);
|
|
}
|
|
}
|
|
|
|
async expandAll() {
|
|
//
|
|
if (!this.hasChild(this.PANELS)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PANELS.toArray().forEach((panel) => {
|
|
//
|
|
if (panel) {
|
|
//
|
|
panel.expanded = true;
|
|
panel.detectChanges();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async collapseAll() {
|
|
//
|
|
if (!this.hasChild(this.PANELS)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PANELS.toArray().forEach((panel) => {
|
|
//
|
|
if (panel) {
|
|
//
|
|
panel.expanded = false;
|
|
panel.detectChanges();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async handleStartupState() {
|
|
//
|
|
const state = await this.getValueAsync(this.startupState);
|
|
if (isNullOrEmptyString(state)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (state) {
|
|
//
|
|
case XExpandablePanelStartupState.CollapseAll:
|
|
await this.collapseAll();
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.ExpandAll:
|
|
await this.expandAll();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private defaultStepperResetConfirmer() {
|
|
//
|
|
return new Promise<boolean>((resolver) => {
|
|
//
|
|
this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
() => resolver(true),
|
|
XModalButtonRole.Destructive,
|
|
() => resolver(false)
|
|
);
|
|
});
|
|
}
|
|
|
|
private getActionButton(panel: XPanelComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getValue(panel.nextButton);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getValue(panel.prevButton);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getValue(panel.resetButton);
|
|
}
|
|
}
|
|
|
|
private getActionButtonDisabled(
|
|
panel: XPanelComponent,
|
|
type: XNPRButtonType
|
|
) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getOptionalValue(panel.disableNext).pipe(
|
|
map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getOptionalValue(panel.disablePrev).pipe(
|
|
map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getOptionalValue(panel.disableReset).pipe(
|
|
map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable)
|
|
);
|
|
}
|
|
}
|
|
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XExpandablePanelActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XExpandablePanelAction.NEXT:
|
|
await this.next(model.force);
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.PREV:
|
|
await this.prev(model.force);
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.RESET:
|
|
await this.reset(model.force);
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.TO:
|
|
if (model.payload) {
|
|
await this.to(model.payload, model.force);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.ExpandAll:
|
|
await this.expandAll();
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.CollapseAll:
|
|
await this.collapseAll();
|
|
break;
|
|
|
|
//
|
|
case XExpandablePanelAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
|
|
private async getPanel(id: string) {
|
|
//
|
|
if (!id || !this.hasPanels()) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.panels.toArray().find(async (p) => {
|
|
const pId = await this.getValueAsync(p.id);
|
|
return pId === id;
|
|
});
|
|
}
|
|
|
|
private async getPanelIndex(id: string) {
|
|
//
|
|
if (!id || !this.hasPanels()) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
let result = -1;
|
|
const panels = this.panels.toArray();
|
|
if (!this.hasChild(panels)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (let i = 0; i < panels.length; i++) {
|
|
//
|
|
const panel = panels[i];
|
|
const pId = await this.getValueAsync(panel.id);
|
|
if (pId === id) {
|
|
result = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyHeaderColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XExpandablePanelCssVars.HeaderForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XExpandablePanelCssVars.HeaderBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyHeaderHighlightColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerHighlightColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XExpandablePanelCssVars.HeaderHighlightForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XExpandablePanelCssVars.HeaderHighlightBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XPanelComponent } from './x-panel/x-panel.component';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XExpandablePanelComponent } from './x-expandable-panel.component';
|
|
|
|
@NgModule({
|
|
declarations: [XPanelComponent, XExpandablePanelComponent],
|
|
imports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XSlotterModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XSlotterModule,
|
|
XPanelComponent,
|
|
XBaseComponentModule,
|
|
XExpandablePanelComponent,
|
|
],
|
|
})
|
|
export class XExpandablePanelModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XModalButtonRole,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XNextPrevResetHostContainer,
|
|
XCardNextPrevResetHostContainer,
|
|
IXCardNextPrevResetHostContainer,
|
|
XCardNextPrevResetHostContainerComponent,
|
|
} from '../classes/i-x-next-prev-reset.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XComponentCardContainer } from '../x-card/x-card.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XExpandablePanelStartupState {
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XExpandablePanelStartupStateIdentifier =
|
|
| XExpandablePanelStartupState
|
|
| string;
|
|
|
|
export enum XExpandablePanelAction {
|
|
NEXT = 'next',
|
|
PREV = 'prev',
|
|
RESET = 'reset',
|
|
TO = 'to',
|
|
|
|
//
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XExpandablePanelActionIdentifier = XExpandablePanelAction | string;
|
|
|
|
export interface XExpandablePanelActionModel
|
|
extends XBaseActionModel<XExpandablePanelActionIdentifier> {
|
|
force?: boolean;
|
|
}
|
|
|
|
export enum XExpandablePanelCssVars {
|
|
//
|
|
HeaderForegroundColor = 'header-foreground-color',
|
|
HeaderBackgroundColor = 'header-background-color',
|
|
|
|
//
|
|
HeaderHighlightForegroundColor = 'header-highlight-foreground-color',
|
|
HeaderHighlightBackgroundColor = 'header-highlight-background-color',
|
|
}
|
|
|
|
export type XExpandablePandelCssVarsIdentifier =
|
|
| XExpandablePanelCssVars
|
|
| string;
|
|
|
|
//
|
|
//#region Inside Host Container ...
|
|
export interface IXExpandablePandelContainer
|
|
extends IXCardNextPrevResetHostContainer {
|
|
//
|
|
actionProvider: Subject<XExpandablePanelActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
startupState: XStandardType<XExpandablePanelStartupStateIdentifier>;
|
|
isAccordion: XStandardType<boolean>;
|
|
multiExpanded: XStandardType<boolean>;
|
|
hideDescriptionOnSmallScreens: XStandardType<boolean>;
|
|
|
|
//
|
|
applyColors: XStandardType<boolean>;
|
|
headerColor: XStandardType<XColorIdentifier>;
|
|
headerHighlightColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
resetConfirmer: () => XStandardType<boolean>;
|
|
selected: string;
|
|
|
|
//
|
|
selectedChange: EventEmitter<string>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XExpandablePandelContainer
|
|
extends XCardNextPrevResetHostContainer
|
|
implements Readonly<IXExpandablePandelContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XExpandablePanelActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly startupState: XStandardType<XExpandablePanelStartupStateIdentifier> =
|
|
XExpandablePanelStartupState.ExpandAll;
|
|
readonly isAccordion: XStandardType<boolean>;
|
|
readonly multiExpanded: XStandardType<boolean>;
|
|
readonly hideDescriptionOnSmallScreens: XStandardType<boolean>;
|
|
|
|
//
|
|
readonly applyColors: XStandardType<boolean> = true;
|
|
readonly headerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Primary;
|
|
readonly headerHighlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
|
|
//
|
|
readonly resetConfirmer: () => XStandardType<boolean> = () => {
|
|
return new Promise<boolean>((resolver) => {
|
|
//
|
|
this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
() => resolver(true),
|
|
XModalButtonRole.Destructive,
|
|
() => resolver(false)
|
|
);
|
|
});
|
|
};
|
|
readonly selected: string;
|
|
|
|
//
|
|
readonly selectedChange: EventEmitter<string>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
public managerService: XManagerService,
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected nextPrevResetHostPropertyProvider: XNextPrevResetHostContainer
|
|
) {
|
|
super(cardPropertyProvider, nextPrevResetHostPropertyProvider);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XExpandablePandelContainerComponent
|
|
extends XCardNextPrevResetHostContainerComponent
|
|
implements IXExpandablePandelContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XExpandablePanelActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
startupState: XStandardType<XExpandablePanelStartupStateIdentifier> =
|
|
this.propertyProvider.startupState;
|
|
|
|
@Input()
|
|
isAccordion: XStandardType<boolean> = this.propertyProvider.isAccordion;
|
|
|
|
@Input()
|
|
multiExpanded: XStandardType<boolean> = this.propertyProvider.multiExpanded;
|
|
|
|
@Input()
|
|
hideDescriptionOnSmallScreens: XStandardType<boolean> =
|
|
this.propertyProvider.hideDescriptionOnSmallScreens;
|
|
|
|
//
|
|
@Input()
|
|
applyColors: XStandardType<boolean> = this.propertyProvider.applyColors;
|
|
|
|
@Input()
|
|
headerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerColor;
|
|
|
|
@Input()
|
|
headerHighlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerHighlightColor;
|
|
|
|
//
|
|
@Input()
|
|
resetConfirmer: () => XStandardType<boolean> =
|
|
this.propertyProvider.resetConfirmer;
|
|
|
|
@Input()
|
|
selected: string = this.propertyProvider.selected;
|
|
|
|
//
|
|
@Output()
|
|
selectedChange: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XExpandablePandelContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXExpandablePandelContainer
|
|
): Observable<IXExpandablePandelContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
startupState: this.getValue(
|
|
container ? container.startupState : this.startupState
|
|
),
|
|
isAccordion: this.getValue(
|
|
container ? container.isAccordion : this.isAccordion
|
|
),
|
|
multiExpanded: this.getValue(
|
|
container ? container.multiExpanded : this.multiExpanded
|
|
),
|
|
hideDescriptionOnSmallScreens: this.getValue(
|
|
container
|
|
? container.hideDescriptionOnSmallScreens
|
|
: this.hideDescriptionOnSmallScreens
|
|
),
|
|
applyColors: this.getValue(
|
|
container ? container.applyColors : this.applyColors
|
|
),
|
|
headerColor: this.getValue(
|
|
container ? container.headerColor : this.headerColor
|
|
),
|
|
headerHighlightColor: this.getValue(
|
|
container
|
|
? container.headerHighlightColor
|
|
: this.headerHighlightColor
|
|
),
|
|
resetConfirmer: this.getValue(
|
|
container ? container.resetConfirmer : this.resetConfirmer
|
|
),
|
|
selected: this.getValue(
|
|
container ? container.selected : this.selected
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
selectedChange: this.selectedChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.html
|
|
|
|
<!-- Title -->
|
|
<ng-template #title>
|
|
<ng-content select="[x-panel-title]"></ng-content>
|
|
</ng-template>
|
|
|
|
<!-- Description -->
|
|
<ng-template #description>
|
|
<ng-content select="[x-panel-description]"></ng-content>
|
|
</ng-template>
|
|
|
|
<!-- Content -->
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
<!-- Actions -->
|
|
<ng-template #actions>
|
|
<ng-content select="[x-panel-actions]"></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
TemplateRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XPanelAction,
|
|
XPanelActionModel,
|
|
XPanelContainerComponent,
|
|
} from './x-panel.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
|
|
@Component({
|
|
selector: 'x-panel',
|
|
templateUrl: './x-panel.component.html',
|
|
styleUrls: ['./x-panel.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XPanelComponent extends XPanelContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
//#region ViewChilds ...
|
|
@ViewChild('title', { static: false })
|
|
title!: TemplateRef<any>;
|
|
|
|
@ViewChild('description', { static: false })
|
|
description!: TemplateRef<any>;
|
|
|
|
@ViewChild('content', { static: false })
|
|
content!: TemplateRef<any>;
|
|
|
|
@ViewChild('actions', { static: false })
|
|
actions!: TemplateRef<any>;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XPanelComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Privates ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XPanelActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XPanelAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import {
|
|
IXNextPrevResetContainer,
|
|
XNextPrevResetContainer,
|
|
XNextPrevResetContainerComponent,
|
|
} from '../../classes/i-x-next-prev-reset.container';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { XStandardType, XOneOrManyType, generateUuid } from 'x-framework-core';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XPanelAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XPanelActionIdentifier = XPanelAction | string;
|
|
|
|
export interface XPanelActionModel
|
|
extends XBaseActionModel<XPanelActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXPanelContainer extends IXNextPrevResetContainer {
|
|
//
|
|
actionProvider: Subject<XPanelActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
id: XStandardType<string>;
|
|
|
|
//
|
|
hideToggle: XStandardType<boolean>;
|
|
expanded: XStandardType<boolean>;
|
|
hasCustomActions: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XPanelContainer
|
|
extends XNextPrevResetContainer
|
|
implements Readonly<IXPanelContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider = new Subject<XPanelActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly id: XStandardType<string> = generateUuid('XPanelComponent');
|
|
|
|
//
|
|
readonly hideToggle: XStandardType<boolean> = false;
|
|
readonly expanded: XStandardType<boolean>;
|
|
readonly hasCustomActions: XStandardType<boolean>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<x-panel
|
|
[id]="props.id"
|
|
[hasNext]="props.hasNext"
|
|
[hasPrev]="props.hasPrev"
|
|
[cssClass]="props.cssClass"
|
|
[expanded]="props.expanded"
|
|
[hasReset]="props.hasReset"
|
|
[hideToggle]="props.hideToggle"
|
|
[nextButton]="props.nextButton"
|
|
[prevButton]="props.prevButton"
|
|
[disablePrev]="props.disablePrev"
|
|
[disableNext]="props.disableNext"
|
|
[resetButton]="props.resetButton"
|
|
[nextPosition]="props.nextPosition"
|
|
[nextCssClass]="props.nextCssClass"
|
|
[prevPosition]="props.prevPosition"
|
|
[prevCssClass]="props.prevCssClass"
|
|
[disableReset]="props.disableReset"
|
|
[prevConfirmer]="props.prevConfirmer"
|
|
[nextConfirmer]="props.nextConfirmer"
|
|
[resetPosition]="props.resetPosition"
|
|
[resetCssClass]="props.resetCssClass"
|
|
[actionProvider]="props.actionProvider"
|
|
[resetConfirmer]="props.resetConfirmer"
|
|
[hasCustomActions]="props.hasCustomActions"
|
|
>
|
|
</x-panel>
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XPanelContainerComponent
|
|
extends XNextPrevResetContainerComponent
|
|
implements IXPanelContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XPanelActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
id: XStandardType<string> = this.propertyProvider.id;
|
|
|
|
@Input()
|
|
hideToggle: XStandardType<boolean> = this.propertyProvider.hideToggle;
|
|
|
|
@Input()
|
|
expanded: XStandardType<boolean> = this.propertyProvider.expanded;
|
|
|
|
@Input()
|
|
hasCustomActions: XStandardType<boolean> =
|
|
this.propertyProvider.hasCustomActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XPanelContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXPanelContainer
|
|
): Observable<IXPanelContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
id: this.getValue(container ? container.id : this.id),
|
|
hideToggle: this.getValue(
|
|
container ? container.hideToggle : this.hideToggle
|
|
),
|
|
expanded: this.getValue(
|
|
container ? container.expanded : this.expanded
|
|
),
|
|
hasCustomActions: this.getValue(
|
|
container ? container.hasCustomActions : this.hasCustomActions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.html
|
|
|
|
<section
|
|
class="x-fab x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
*ngIf="parsedItem && (notNullOrUndefinedValue(item) | async)"
|
|
>
|
|
<!-- Fab Main Button -->
|
|
<ion-fab
|
|
#fab
|
|
[slot]="getFixedValue(parsedItem) | async"
|
|
[edge]="getOptionalValue(parsedItem.edged) | async"
|
|
[vertical]="getValue(parsedItem.vertical) | async"
|
|
[horizontal]="getValue(parsedItem.horizontal) | async"
|
|
[activated]="getOptionalValue(parsedItem.activated) | async"
|
|
>
|
|
<!-- Fab Main Button -->
|
|
<ng-container
|
|
*ngTemplateOutlet="fabButtonRef; context: { $implicit: parsedItem }"
|
|
></ng-container>
|
|
|
|
<!-- Fab List Buttons -->
|
|
<section
|
|
class="x-fab-childs-container"
|
|
[ngClass]="getValue(childsCssClass) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="fabChildsRef"></ng-container>
|
|
</section>
|
|
</ion-fab>
|
|
</section>
|
|
|
|
<!-- Fab Childs -->
|
|
<ng-template #fabChildsRef>
|
|
<!-- Fab Lists -->
|
|
<ng-container *ngIf="hasChildValue(parsedChilds) | async">
|
|
<!-- Top Side -->
|
|
<ion-fab-list side="top" *ngIf="hasTopSideChilds">
|
|
<ng-container *ngFor="let child of parsedChilds">
|
|
<ng-container *ngIf="isTopSideFab(child) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-fab-list>
|
|
|
|
<!-- End Side -->
|
|
<ion-fab-list side="end" *ngIf="hasEndSideChilds">
|
|
<ng-container *ngFor="let child of parsedChilds">
|
|
<ng-container *ngIf="isEndSideFab(child) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-fab-list>
|
|
|
|
<!-- Start Side -->
|
|
<ion-fab-list side="start" *ngIf="hasStartSideChilds">
|
|
<ng-container *ngFor="let child of parsedChilds">
|
|
<ng-container *ngIf="isStartSideFab(child) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-fab-list>
|
|
|
|
<!-- Bottom Side -->
|
|
<ion-fab-list side="bottom" *ngIf="hasBottomSideChilds">
|
|
<ng-container *ngFor="let child of parsedChilds">
|
|
<ng-container *ngIf="isBottomSideFab(child) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-fab-list>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Represent Single Fab -->
|
|
<ng-template #fabButtonRef let-item>
|
|
<ion-fab-button
|
|
[color]="getValue(item.color) | async"
|
|
(click)="handleFabButtonClicked(item)"
|
|
[size]="getOptionalValue(item.size) | async"
|
|
[href]="getOptionalValue(item.href) | async"
|
|
[hidden]="getOptionalValue(item.hidden) | async"
|
|
[download]="getOptionalValue(item.download) | async"
|
|
[matTooltip]="getResourceValue(item.tooltip) | async"
|
|
[target]="getOptionalValue(item.routerTarget) | async"
|
|
[routerDirection]="getOptionalValue(item.routerDirection) | async"
|
|
[disabled]="
|
|
uiDisabled ||
|
|
loading ||
|
|
(applyTakeUntilWrapper(getOptionalValue(item.disabled)) | async)
|
|
"
|
|
>
|
|
<x-icon
|
|
[foregroundColor]="false"
|
|
[name]="getValue(item.icon) | async"
|
|
[color]="getValue(item.color) | async"
|
|
></x-icon>
|
|
</ion-fab-button>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.scss
|
|
|
|
:host ::ng-deep .x-icon {
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.ts
|
|
|
|
import {
|
|
XFabItem,
|
|
XFabButton,
|
|
XFabAction,
|
|
XFabButtonSide,
|
|
XFabActionModel,
|
|
XFabContainerComponent,
|
|
} from './x-fab.typings';
|
|
import {
|
|
nameof,
|
|
hasChild,
|
|
isFunction,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import { IonFab } from '@ionic/angular';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { of, Observable, Subject, Subscription } from 'rxjs';
|
|
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-fab',
|
|
templateUrl: './x-fab.component.html',
|
|
styleUrls: ['./x-fab.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFabComponent extends XFabContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
private FAB: IonFab;
|
|
private PARSED_ITEM: XFabItem;
|
|
private PARSED_CHILDS: XFabButton[] = [];
|
|
private HAS_TOP_SIDE_CHILDS: boolean;
|
|
private HAS_END_SIDE_CHILDS: boolean;
|
|
private HAS_START_SIDE_CHILDS: boolean;
|
|
private HAS_BOTTOM_SIDE_CHILDS: boolean;
|
|
|
|
//
|
|
@ViewChild('fab', { static: false })
|
|
set fab(v: IonFab) {
|
|
//
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.FAB = v;
|
|
this.detectChanges();
|
|
}
|
|
|
|
get fab() {
|
|
return this.FAB;
|
|
}
|
|
|
|
get parsedItem() {
|
|
return this.PARSED_ITEM;
|
|
}
|
|
|
|
get parsedChilds() {
|
|
return this.PARSED_CHILDS;
|
|
}
|
|
|
|
get hasTopSideChilds() {
|
|
return this.HAS_TOP_SIDE_CHILDS;
|
|
}
|
|
|
|
get hasEndSideChilds() {
|
|
return this.HAS_END_SIDE_CHILDS;
|
|
}
|
|
|
|
get hasStartSideChilds() {
|
|
return this.HAS_START_SIDE_CHILDS;
|
|
}
|
|
|
|
get hasBottomSideChilds() {
|
|
return this.HAS_BOTTOM_SIDE_CHILDS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFabComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Items Changes ...
|
|
//
|
|
const isItemsChanged = changeKeys.includes(nameof<XFabComponent>('item'));
|
|
if (isItemsChanged) {
|
|
//
|
|
const item = await this.getValueAsync(this.item);
|
|
this.detectChanges();
|
|
if (!isNullOrUndefined(item)) {
|
|
//
|
|
this.PARSED_ITEM = item;
|
|
this.detectChanges();
|
|
|
|
//
|
|
if (item.childs) {
|
|
//
|
|
const childs = await this.getValueAsync(item.childs);
|
|
if (!hasChild(childs)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sorting Childs ...
|
|
this.PARSED_CHILDS = childs.sort((a, b) => a.index - b.index);
|
|
this.detectChanges();
|
|
|
|
//
|
|
// Determine Sides ...
|
|
this.PARSED_CHILDS.forEach(async (ch) => {
|
|
//
|
|
const side = await this.getValueAsync(ch.side);
|
|
switch (side) {
|
|
case XFabButtonSide.TOP:
|
|
if (!this.HAS_TOP_SIDE_CHILDS) {
|
|
this.HAS_TOP_SIDE_CHILDS = true;
|
|
}
|
|
break;
|
|
|
|
case XFabButtonSide.END:
|
|
if (!this.HAS_END_SIDE_CHILDS) {
|
|
this.HAS_END_SIDE_CHILDS = true;
|
|
}
|
|
break;
|
|
|
|
case XFabButtonSide.START:
|
|
if (!this.HAS_START_SIDE_CHILDS) {
|
|
this.HAS_START_SIDE_CHILDS = true;
|
|
}
|
|
break;
|
|
|
|
case XFabButtonSide.BOTTOM:
|
|
if (!this.HAS_BOTTOM_SIDE_CHILDS) {
|
|
this.HAS_BOTTOM_SIDE_CHILDS = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Provider ...
|
|
getFixedValue(items: XFabItem) {
|
|
return of(items).pipe(
|
|
concatMap((rItems) => {
|
|
//
|
|
if (!rItems) {
|
|
return of('');
|
|
}
|
|
|
|
//
|
|
const obs = this.getOptionalValue(rItems.fixed) as Observable<boolean>;
|
|
return obs.pipe(map((res) => (res === true ? 'fixed' : '')));
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Fab Button Side Providers ...
|
|
isTopSideFab(child: XFabButton) {
|
|
return this.getValue(child.side).pipe(
|
|
map((side) => side === XFabButtonSide.TOP.toString())
|
|
);
|
|
}
|
|
|
|
isEndSideFab(child: XFabButton) {
|
|
return this.getValue(child.side).pipe(
|
|
map((side) => side === XFabButtonSide.END.toString())
|
|
);
|
|
}
|
|
|
|
isStartSideFab(child: XFabButton) {
|
|
return this.getValue(child.side).pipe(
|
|
map((side) => side === XFabButtonSide.START.toString())
|
|
);
|
|
}
|
|
|
|
isBottomSideFab(child: XFabButton) {
|
|
return this.getValue(child.side).pipe(
|
|
map((side) => side === XFabButtonSide.BOTTOM.toString())
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleFabButtonClicked(item: XFabButton | XFabButton) {
|
|
//
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (item.handler && isFunction(item.handler)) {
|
|
await this.getValueAsync(item.handler(item.id));
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async close() {
|
|
//
|
|
if (!this.fab) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.fab.close();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFabActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFabAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XFabAction.CLOSE:
|
|
await this.close();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XFabComponent } from './x-fab.component';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XFabComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XIconModule],
|
|
exports: [XBaseComponentModule, XIconModule, XFabComponent],
|
|
})
|
|
export class XFabModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XRouterDirection,
|
|
XResourceIdentifier,
|
|
XRouterTargetIdentifier,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XFabVerticalSlot {
|
|
TOP = 'top',
|
|
CENTER = 'center',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XFabVerticalSlotIdentifier = XFabVerticalSlot | string;
|
|
|
|
export enum XFabHorizontalSlot {
|
|
START = 'start',
|
|
CENTER = 'center',
|
|
END = 'end',
|
|
}
|
|
|
|
export type XFabHorizontalSlotIdentifier = XFabHorizontalSlot | string;
|
|
|
|
export enum XFabButtonSide {
|
|
TOP = 'top',
|
|
END = 'end',
|
|
START = 'start',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XFabButtonSideIdentifier = XFabButtonSide | string;
|
|
|
|
export enum XFabButtonSize {
|
|
REGULAR = '',
|
|
MINI = 'small',
|
|
}
|
|
|
|
export type XFabButtonSizeIdentifier = XFabButtonSize | string;
|
|
|
|
export interface XFabButton {
|
|
//
|
|
id: string;
|
|
index: number;
|
|
|
|
//
|
|
icon: XStandardType<XIconIdentifier>;
|
|
side: XStandardType<XFabButtonSideIdentifier>;
|
|
size?: XStandardType<XFabButtonSizeIdentifier>;
|
|
|
|
//
|
|
disabled?: XStandardType<boolean>;
|
|
hidden?: XStandardType<boolean>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
|
|
//
|
|
href?: XStandardType<string>;
|
|
download?: XStandardType<string>;
|
|
routerDirection?: XStandardType<XRouterDirection>;
|
|
routerTarget?: XStandardType<XRouterTargetIdentifier>;
|
|
|
|
//
|
|
handler?: (id?: string) => XStandardType<void>;
|
|
}
|
|
|
|
type FAB_MAIN_BUTTON = Pick<
|
|
XFabButton,
|
|
| 'id'
|
|
| 'icon'
|
|
| 'size'
|
|
| 'color'
|
|
| 'hidden'
|
|
| 'handler'
|
|
| 'tooltip'
|
|
| 'disabled'
|
|
| 'href'
|
|
| 'download'
|
|
| 'routerDirection'
|
|
| 'routerTarget'
|
|
>;
|
|
|
|
export interface XFabItem extends FAB_MAIN_BUTTON {
|
|
//
|
|
vertical: XStandardType<XFabVerticalSlotIdentifier>;
|
|
horizontal: XStandardType<XFabHorizontalSlotIdentifier>;
|
|
|
|
//
|
|
fixed?: XStandardType<boolean>;
|
|
edged?: XStandardType<boolean>;
|
|
|
|
//
|
|
activated?: XStandardType<boolean>;
|
|
|
|
//
|
|
childs?: XStandardType<XFabButton[]>;
|
|
}
|
|
|
|
export enum XFabAction {
|
|
CLOSE = 'close',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XFabActionIdentifier = XFabAction | string;
|
|
|
|
export interface XFabActionModel
|
|
extends XBaseActionModel<XFabActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXFabContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XFabActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
childsCssClass: XStandardType<XOneOrManyType<string>>;
|
|
item: XStandardType<XFabItem>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XFabContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXFabContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XFabActionModel> =
|
|
new Subject<XFabActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly childsCssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly item: XStandardType<XFabItem> = null;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFabContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXFabContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XFabActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
childsCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.childsCssClass;
|
|
|
|
@Input()
|
|
item: XStandardType<XFabItem> = this.propertyProvider.item;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFabContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(container?: IXFabContainer): Observable<IXFabContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
childsCssClass: this.getValue(
|
|
container ? container.childsCssClass : this.childsCssClass
|
|
),
|
|
item: this.getValue(container ? container.item : this.item),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.html
|
|
|
|
<!-- Card Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Template -->
|
|
<ng-template #componentRef>
|
|
<div
|
|
class="x-file-drop-area x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
[class.no-drag]="
|
|
uiDisabled || loading || (getValue(dragDisabled) | async)
|
|
"
|
|
>
|
|
<section
|
|
xDroppable
|
|
class="x-droppable-container"
|
|
[errorColor]="getValue(errorColor) | async"
|
|
[accentColor]="getValue(accentColor) | async"
|
|
[successColor]="getValue(successColor) | async"
|
|
[error]="notNullOrUndefinedValue(error) | async"
|
|
(filesChangeEmiter)="filesChangeEmiter.emit($event)"
|
|
[disableFileCheck]="getValue(disableFileCheck) | async"
|
|
[allowedExtensions]="getValue(allowedExtensions) | async"
|
|
[dragDisabled]="
|
|
uiDisabled || loading || (getValue(dragDisabled) | async)
|
|
"
|
|
[supportsMultipleFiles]="getValue(supportsMultipleFiles) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
contentTemplate ? contentTemplate : defaultContentTemplateRef
|
|
"
|
|
></ng-container>
|
|
</section>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Default Content Template -->
|
|
<ng-template #defaultContentTemplateRef>
|
|
<div class="x-drop-area">
|
|
<div class="x-icon">
|
|
<x-icon
|
|
[foregroundColor]="false"
|
|
[cssClass]="'transparent'"
|
|
[name]="getValue(icon) | async"
|
|
[color]="getValue(color) | async"
|
|
></x-icon>
|
|
</div>
|
|
<ion-text class="x-drag-drop-title">
|
|
{{ getResourceValue(message) | async }}
|
|
</ion-text>
|
|
</div>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.scss
|
|
|
|
:host {
|
|
width: inherit;
|
|
height: inherit;
|
|
|
|
--label-color: var(--x-color-light-contrast);
|
|
}
|
|
|
|
.x-wrapper {
|
|
cursor: grab;
|
|
}
|
|
|
|
.x-wrapper:active {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.no-drag {
|
|
cursor: unset;
|
|
}
|
|
|
|
.x-droppable-container {
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.x-drop-area {
|
|
width: 100%;
|
|
height: auto;
|
|
|
|
box-sizing: border-box;
|
|
|
|
border-radius: 10px;
|
|
border: 2px dashed var(--label-color);
|
|
|
|
text-align: center;
|
|
|
|
padding: {
|
|
top: 16px;
|
|
bottom: 16px;
|
|
}
|
|
}
|
|
|
|
.x-drag-drop-title {
|
|
color: var(--label-color);
|
|
}
|
|
|
|
.x-icon {
|
|
margin: {
|
|
left: auto;
|
|
right: auto;
|
|
}
|
|
|
|
margin-bottom: 16px;
|
|
|
|
font-size: 8px;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XFileDropAreaAction,
|
|
XFileDropAreaCssVars,
|
|
XFileDropAreaActionModel,
|
|
XFileDropAreaContainerComponent,
|
|
} from './x-file-drop-area.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-file-drop-area',
|
|
templateUrl: './x-file-drop-area.component.html',
|
|
styleUrls: ['./x-file-drop-area.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFileDropAreaComponent extends XFileDropAreaContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Color Changed ...
|
|
const isColorChanged = changeKeys.includes(
|
|
nameof<XFileDropAreaComponent>('color')
|
|
);
|
|
if (isColorChanged) {
|
|
await this.applyColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFileDropAreaComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Provider ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFileDropAreaActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe((model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFileDropAreaAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async applyColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.color);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFileDropAreaCssVars.LabelColor, `var(${fgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XFileDropAreaComponent } from './x-file-drop-area.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XFileDropAreaComponent],
|
|
imports: [
|
|
XListModule,
|
|
XCardModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
XListModule,
|
|
XBaseComponentModule,
|
|
XFileDropAreaComponent,
|
|
],
|
|
})
|
|
export class XFileDropAreaModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import {
|
|
XBaseComponentContainer,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XFileDropAreaAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XFileDropAreaActionIdentifier = XFileDropAreaAction | string;
|
|
|
|
export interface XFileDropAreaActionModel
|
|
extends XBaseActionModel<XFileDropAreaActionIdentifier> {}
|
|
|
|
export enum XFileDropAreaCssVars {
|
|
LabelColor = 'label-color',
|
|
}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXFileDropAreaContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XFileDropAreaActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
icon: XStandardType<XIconIdentifier>;
|
|
message: XStandardType<XResourceIdentifier>;
|
|
|
|
//
|
|
disableFileCheck: XStandardType<boolean>;
|
|
|
|
//
|
|
supportsMultipleFiles: XStandardType<boolean>;
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
dragDisabled: XStandardType<boolean>;
|
|
contentTemplate: TemplateRef<any>;
|
|
filesChangeEmiter: EventEmitter<XOneOrManyType<File>>;
|
|
|
|
//
|
|
successColor: XStandardType<XColorIdentifier>;
|
|
errorColor: XStandardType<XColorIdentifier>;
|
|
accentColor: XStandardType<XColorIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFileDropAreaContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXFileDropAreaContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XFileDropAreaActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
readonly icon: XStandardType<XIconIdentifier> = XIconNames.arrow_down;
|
|
readonly message: XStandardType<XResourceIdentifier> =
|
|
XResourceIDs.drag_drop_here;
|
|
|
|
//
|
|
readonly disableFileCheck: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
|
|
readonly supportsMultipleFiles: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly dragDisabled: XStandardType<boolean> = false;
|
|
readonly contentTemplate: TemplateRef<any>;
|
|
readonly filesChangeEmiter = new EventEmitter<XOneOrManyType<File>>();
|
|
|
|
//
|
|
readonly successColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Success;
|
|
readonly errorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
readonly accentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Secondary;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFileDropAreaContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXFileDropAreaContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
icon: XStandardType<XIconIdentifier> = this.propertyProvider.icon;
|
|
|
|
@Input()
|
|
message: XStandardType<XResourceIdentifier> = this.propertyProvider.message;
|
|
|
|
//
|
|
@Input()
|
|
disableFileCheck: XStandardType<boolean> =
|
|
this.propertyProvider.disableFileCheck;
|
|
|
|
//
|
|
@Input()
|
|
supportsMultipleFiles: XStandardType<boolean> =
|
|
this.propertyProvider.supportsMultipleFiles;
|
|
|
|
@Input()
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.allowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
dragDisabled: XStandardType<boolean> = this.propertyProvider.dragDisabled;
|
|
|
|
@Input()
|
|
contentTemplate: TemplateRef<any> = this.propertyProvider.contentTemplate;
|
|
|
|
@Output()
|
|
filesChangeEmiter: EventEmitter<XOneOrManyType<File>> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
successColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.successColor;
|
|
|
|
@Input()
|
|
errorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.errorColor;
|
|
|
|
@Input()
|
|
accentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.accentColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFileDropAreaContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFileDropAreaContainer
|
|
): Observable<IXFileDropAreaContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
icon: this.getValue(container ? container.icon : this.icon),
|
|
message: this.getValue(
|
|
container ? container.message : this.message
|
|
),
|
|
disableFileCheck: this.getValue(
|
|
container ? container.disableFileCheck : this.disableFileCheck
|
|
),
|
|
supportsMultipleFiles: this.getValue(
|
|
container
|
|
? container.supportsMultipleFiles
|
|
: this.supportsMultipleFiles
|
|
),
|
|
allowedExtensions: this.getValue(
|
|
container ? container.allowedExtensions : this.allowedExtensions
|
|
),
|
|
dragDisabled: this.getValue(
|
|
container ? container.dragDisabled : this.dragDisabled
|
|
),
|
|
successColor: this.getValue(
|
|
container ? container.successColor : this.successColor
|
|
),
|
|
errorColor: this.getValue(
|
|
container ? container.errorColor : this.errorColor
|
|
),
|
|
accentColor: this.getValue(
|
|
container ? container.accentColor : this.accentColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
contentTemplate: container
|
|
? container.contentTemplate
|
|
: this.contentTemplate,
|
|
|
|
//
|
|
filesChangeEmiter: this.filesChangeEmiter,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentFileDropAreaContainer = {
|
|
[TKey in keyof IXFileDropAreaContainer as `fileDropArea${Capitalize<
|
|
string & TKey
|
|
>}`]: IXFileDropAreaContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentFileDropAreaContainer
|
|
extends TXComponentFileDropAreaContainer,
|
|
IXBaseComponentContainer {
|
|
showFileDropArea: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentFileDropAreaContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentFileDropAreaContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showFileDropArea: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
|
|
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.icon;
|
|
|
|
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.message;
|
|
|
|
//
|
|
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.propertyProvider.disableFileCheck;
|
|
|
|
//
|
|
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.propertyProvider.supportsMultipleFiles;
|
|
|
|
readonly fileDropAreaAllowedExtensions: XStandardType<
|
|
XOneOrManyType<string>
|
|
> = this.propertyProvider.allowedExtensions;
|
|
|
|
//
|
|
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.propertyProvider.dragDisabled;
|
|
|
|
readonly fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.contentTemplate;
|
|
|
|
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
this.propertyProvider.filesChangeEmiter;
|
|
|
|
//
|
|
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.successColor;
|
|
|
|
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.errorColor;
|
|
|
|
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.accentColor;
|
|
|
|
//
|
|
//#region ComponentsCard ...
|
|
readonly fileDropAreaIsInPage: XStandardType<boolean> = false;
|
|
readonly fileDropAreaWrapWithCard: XStandardType<boolean> = false;
|
|
readonly fileDropAreaCardShowFooter: XStandardType<boolean> = false;
|
|
readonly fileDropAreaCardShowActions: XStandardType<boolean> = false;
|
|
readonly fileDropAreaCardColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly fileDropAreaCardForegroundColor: XStandardType<boolean> = false;
|
|
readonly fileDropAreaCardTitle: XStandardType<XResourceIdentifier>;
|
|
readonly fileDropAreaCardActionProvider: Subject<XCardActionModel> =
|
|
new Subject<XCardActionModel>();
|
|
readonly fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier>;
|
|
readonly fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>>;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XFileDropAreaContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showFileDropArea">
|
|
<x-file-drop-area
|
|
[icon]="props.fileDropAreaIcon"
|
|
[color]="props.fileDropAreaColor"
|
|
[message]="props.fileDropAreaMessage"
|
|
[cssClass]="props.fileDropAreaCssClass"
|
|
[isInPage]="props.fileDropAreaIsInPage"
|
|
[cardTitle]="props.fileDropAreaCardTitle"
|
|
[cardColor]="props.fileDropAreaCardColor"
|
|
[errorColor]="props.fileDropAreaErrorColor"
|
|
[accentColor]="props.fileDropAreaAccentColor"
|
|
[dragDisabled]="props.fileDropAreaDragDisabled"
|
|
[successColor]="props.fileDropAreaSuccessColor"
|
|
[cardCssClass]="props.fileDropAreaCardCssClass"
|
|
[wrapWithCard]="props.fileDropAreaWrapWithCard"
|
|
[cardSubTitle]="props.fileDropAreaCardSubTitle"
|
|
[actionProvider]="props.fileDropAreaActionProvider"
|
|
[cardShowFooter]="props.fileDropAreaCardShowFooter"
|
|
[foregroundColor]="props.fileDropAreaForegroundColor"
|
|
[contentTemplate]="props.fileDropAreaContentTemplate"
|
|
[foregroundColor]="props.fileDropAreaForegroundColor"
|
|
[disableFileCheck]="props.fileDropAreaDisableFileCheck"
|
|
[allowedExtensions]="props.fileDropAreaAllowedExtensions"
|
|
(filesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
|
|
[cardActionProvider]="props.fileDropAreaCardActionProvider"
|
|
[cardForegroundColor]="props.fileDropAreaCardForegroundColor"
|
|
[supportsMultipleFiles]="props.fileDropAreaSupportsMultipleFiles"
|
|
></x-file-drop-area>
|
|
</ng-container>
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XComponentFileDropAreaContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentFileDropAreaContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.propertyProvider.fileDropAreaActionProvider;
|
|
|
|
@Input()
|
|
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaCssClass;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaColor;
|
|
|
|
@Input()
|
|
fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.fileDropAreaIcon;
|
|
|
|
@Input()
|
|
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaMessage;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDisableFileCheck;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
|
|
@Input()
|
|
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaAllowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDragDisabled;
|
|
|
|
@Input()
|
|
fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.fileDropAreaContentTemplate;
|
|
|
|
@Output()
|
|
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaSuccessColor;
|
|
|
|
@Input()
|
|
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaErrorColor;
|
|
|
|
@Input()
|
|
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaAccentColor;
|
|
|
|
//
|
|
@Input()
|
|
showFileDropArea: XStandardType<boolean> =
|
|
this.propertyProvider.showFileDropArea;
|
|
|
|
//
|
|
//#region ComponentsCard ...
|
|
@Input()
|
|
fileDropAreaIsInPage: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaIsInPage;
|
|
|
|
@Input()
|
|
fileDropAreaWrapWithCard: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaWrapWithCard;
|
|
|
|
@Input()
|
|
fileDropAreaCardShowFooter: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardShowFooter;
|
|
|
|
@Input()
|
|
fileDropAreaCardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardShowActions;
|
|
|
|
@Input()
|
|
fileDropAreaCardColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardColor;
|
|
|
|
@Input()
|
|
fileDropAreaCardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaCardForegroundColor;
|
|
|
|
@Input()
|
|
fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardTitle;
|
|
|
|
@Input()
|
|
fileDropAreaCardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.fileDropAreaCardActionProvider;
|
|
|
|
@Input()
|
|
fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaCardSubTitle;
|
|
|
|
@Input()
|
|
fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaCardCssClass;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentFileDropAreaContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentFileDropAreaContainer
|
|
): Observable<IXComponentFileDropAreaContainer> {
|
|
return forkJoin({
|
|
//
|
|
fileDropAreaCssClass: this.getValue(
|
|
container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass
|
|
),
|
|
fileDropAreaColor: this.getValue(
|
|
container ? container.fileDropAreaColor : this.fileDropAreaColor
|
|
),
|
|
fileDropAreaForegroundColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaForegroundColor
|
|
: this.fileDropAreaForegroundColor
|
|
),
|
|
fileDropAreaIcon: this.getValue(
|
|
container ? container.fileDropAreaIcon : this.fileDropAreaIcon
|
|
),
|
|
fileDropAreaMessage: this.getValue(
|
|
container ? container.fileDropAreaMessage : this.fileDropAreaMessage
|
|
),
|
|
fileDropAreaDisableFileCheck: this.getValue(
|
|
container
|
|
? container.fileDropAreaDisableFileCheck
|
|
: this.fileDropAreaDisableFileCheck
|
|
),
|
|
fileDropAreaSupportsMultipleFiles: this.getValue(
|
|
container
|
|
? container.fileDropAreaSupportsMultipleFiles
|
|
: this.fileDropAreaSupportsMultipleFiles
|
|
),
|
|
fileDropAreaAllowedExtensions: this.getValue(
|
|
container
|
|
? container.fileDropAreaAllowedExtensions
|
|
: this.fileDropAreaAllowedExtensions
|
|
),
|
|
fileDropAreaDragDisabled: this.getValue(
|
|
container
|
|
? container.fileDropAreaDragDisabled
|
|
: this.fileDropAreaDragDisabled
|
|
),
|
|
fileDropAreaContentTemplate: this.getValue(
|
|
container
|
|
? container.fileDropAreaContentTemplate
|
|
: this.fileDropAreaContentTemplate
|
|
),
|
|
fileDropAreaSuccessColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaSuccessColor
|
|
: this.fileDropAreaSuccessColor
|
|
),
|
|
fileDropAreaErrorColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaErrorColor
|
|
: this.fileDropAreaErrorColor
|
|
),
|
|
fileDropAreaAccentColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaAccentColor
|
|
: this.fileDropAreaAccentColor
|
|
),
|
|
showFileDropArea: this.getValue(
|
|
container ? container.showFileDropArea : this.showFileDropArea
|
|
),
|
|
fileDropAreaIsInPage: this.getValue(
|
|
container ? container.fileDropAreaIsInPage : this.fileDropAreaIsInPage
|
|
),
|
|
fileDropAreaWrapWithCard: this.getValue(
|
|
container
|
|
? container.fileDropAreaWrapWithCard
|
|
: this.fileDropAreaWrapWithCard
|
|
),
|
|
fileDropAreaCardShowFooter: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardShowFooter
|
|
: this.fileDropAreaCardShowFooter
|
|
),
|
|
fileDropAreaCardShowActions: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardShowActions
|
|
: this.fileDropAreaCardShowActions
|
|
),
|
|
fileDropAreaCardColor: this.getValue(
|
|
container ? container.fileDropAreaCardColor : this.fileDropAreaCardColor
|
|
),
|
|
fileDropAreaCardForegroundColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardForegroundColor
|
|
: this.fileDropAreaCardForegroundColor
|
|
),
|
|
fileDropAreaCardTitle: this.getValue(
|
|
container ? container.fileDropAreaCardTitle : this.fileDropAreaCardTitle
|
|
),
|
|
fileDropAreaCardSubTitle: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardSubTitle
|
|
: this.fileDropAreaCardSubTitle
|
|
),
|
|
fileDropAreaCardCssClass: this.getValue(
|
|
container
|
|
? container.fileDropAreaCardCssClass
|
|
: this.fileDropAreaCardCssClass
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
fileDropAreaActionProvider: container
|
|
? container.fileDropAreaActionProvider
|
|
: this.fileDropAreaActionProvider,
|
|
|
|
//
|
|
fileDropAreaCardActionProvider: container
|
|
? container.fileDropAreaCardActionProvider
|
|
: this.fileDropAreaCardActionProvider,
|
|
|
|
//
|
|
fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Template -->
|
|
<ng-template #componentRef>
|
|
<div
|
|
class="x-file-upload x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- File Upload Input -->
|
|
<input
|
|
hidden
|
|
#fileInput
|
|
type="file"
|
|
multiple="true"
|
|
(change)="handleFilesSelected()"
|
|
/>
|
|
|
|
<!-- File Drop -->
|
|
<ng-container *ngIf="getValue(showFileDropArea) | async">
|
|
<ng-container *ngTemplateOutlet="fileDragAreaRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- File List -->
|
|
<ng-container *ngIf="getValue(showList) | async">
|
|
<ng-container *ngTemplateOutlet="filesListRef"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- File Drop Area Template -->
|
|
<ng-template #fileDragAreaRef>
|
|
<div class="x-file-upload-file-drag-drop-wrapper">
|
|
<x-file-drop-area
|
|
[cardTitle]=""
|
|
[cardSubTitle]=""
|
|
[isInPage]="false"
|
|
[loading]="loading"
|
|
[wrapWithCard]="false"
|
|
[cardShowFooter]="false"
|
|
[uiDisabled]="uiDisabled"
|
|
[cardForegroundColor]="false"
|
|
[supportsMultipleFiles]="true"
|
|
[icon]="getValue(fileDropAreaIcon) | async"
|
|
[color]="getValue(fileDropAreaColor) | async"
|
|
[actionProvider]="fileDropAreaActionProvider"
|
|
(filesChangeEmiter)="handleFileDropped($event)"
|
|
[cssClass]="getValue(fileDropAreaCssClass) | async"
|
|
[cardColor]="getValue(cardColor) | async"
|
|
[errorColor]="getValue(fileDropAreaErrorColor) | async"
|
|
[accentColor]="getValue(fileDropAreaAccentColor) | async"
|
|
[message]="getResourceValue(fileDropAreaMessage) | async"
|
|
[successColor]="getValue(fileDropAreaSuccessColor) | async"
|
|
[dragDisabled]="getValue(fileDropAreaDragDisabled) | async"
|
|
[allowedExtensions]="getArrayValue(allowedExtensions) | async"
|
|
[foregroundColor]="getValue(fileDropAreaForegroundColor) | async"
|
|
[contentTemplate]="getValue(fileDropAreaContentTemplate) | async"
|
|
[disableFileCheck]="getValue(fileDropAreaDisableFileCheck) | async"
|
|
></x-file-drop-area>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Files List Template -->
|
|
<ng-template #filesListRef>
|
|
<x-list
|
|
#listPresenter
|
|
[loading]="loading"
|
|
[selectableItems]="true"
|
|
[foregroundColor]="false"
|
|
[uiDisabled]="uiDisabled"
|
|
[itemTemplate]="fileItemRef"
|
|
[color]="getValue(color) | async"
|
|
[actionProvider]="listActionProvider"
|
|
[showEmpty]="getValue(showEmpty) | async"
|
|
[filteringHandler]="listFilteringHandler"
|
|
(orderChanged)="handleListOrderChanged()"
|
|
(removeItems)="handleRemoveItems($event)"
|
|
(emptyRefresh)="emptyRefresh.emit($event)"
|
|
[emptyColor]="getValue(emptyColor) | async"
|
|
[cssClass]="getValue(listCssClass) | async"
|
|
[emptyForegroundMessageColor]="
|
|
getValue(emptyForegroundMessageColor) | async
|
|
"
|
|
[showSearchBar]="
|
|
(getValue(showSearchBar) | async) &&
|
|
(countChildsValue(fileListItems) | async) > 1
|
|
"
|
|
[emptyMessage]="getValue(emptyMessage) | async"
|
|
[showToolbar]="getValue(listShowToolbar) | async"
|
|
[showDivider]="getValue(listShowDivider) | async"
|
|
[showActionBar]="getValue(showActionBar) | async"
|
|
[searchBarColor]="getValue(searchBarColor) | async"
|
|
[actionBarColor]="getValue(actionBarColor) | async"
|
|
[confirmRemove]="getValue(listConfirmRemove) | async"
|
|
[items]="fileListItemsSubject.asObservable() | async"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[stickyToolbar]="getValue(listStickyToolbar) | async"
|
|
[emptyHasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[actionBarActions]="getValue(actionBarActions) | async"
|
|
[emptyRefreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
(selectionChanged)="handleFilesSelectionChanged($event)"
|
|
[actionBarCssClass]="getValue(actionBarCssClass) | async"
|
|
[searchBarCssClass]="getValue(searchBarCssClass) | async"
|
|
[emptyMessageColor]="getValue(emptyMessageColor) | async"
|
|
(actionBarActionFired)="actionBarActionFired.emit($event)"
|
|
[enableReordering]="getValue(listEnableReordering) | async"
|
|
[emptyForegroundColor]="getValue(emptyForegroundColor) | async"
|
|
[actionBarHideActions]="getArrayValue(actionBarHideActions) | async"
|
|
[emptyRefreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[searchBarSearchInputColor]="getValue(searchBarSearchInputColor) | async"
|
|
>
|
|
</x-list>
|
|
</ng-template>
|
|
|
|
<!-- File Item Template -->
|
|
<ng-template #fileItemRef let-item="item" let-index="index">
|
|
<div fxLayout="row" class="x-file-item" [matTooltip]="item.data.name">
|
|
<x-thumbnail
|
|
fxFlex="nogrow"
|
|
[loading]="loading"
|
|
class="x-file-thumbnail"
|
|
[uiDisabled]="uiDisabled"
|
|
[type]="getThumbnailType(item.data) | async"
|
|
[identifier]="getThumbnailIdentifier(item.data) | async"
|
|
></x-thumbnail>
|
|
<div class="x-file-title text-truncate">
|
|
{{ item.data.name }}
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.scss
|
|
|
|
:host {
|
|
--top-radius: 5px;
|
|
--padding: 6px;
|
|
--host-bg-color: var(--x-color-light);
|
|
}
|
|
|
|
:host ::ng-deep .x-card {
|
|
box-shadow: unset !important;
|
|
}
|
|
|
|
:host ::ng-deep .x-thumbnail,
|
|
:host ::ng-deep .x-item {
|
|
width: 32px !important;
|
|
height: 32px !important;
|
|
object-fit: contain !important;
|
|
object-position: center !important;
|
|
}
|
|
|
|
:host ::ng-deep ion-searchbar {
|
|
padding-left: unset;
|
|
padding-right: unset;
|
|
padding-inline-end: 0 !important;
|
|
padding-inline-start: 0 !important;
|
|
}
|
|
|
|
.x-file-item {
|
|
width: 100%;
|
|
text-align: start;
|
|
}
|
|
|
|
.x-file-item,
|
|
.x-file-thumbnail {
|
|
height: 32px;
|
|
}
|
|
|
|
.x-file-thumbnail {
|
|
width: 32px;
|
|
}
|
|
|
|
.x-file-title,
|
|
.x-file-thumbnail {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.x-file-title {
|
|
text-align: start;
|
|
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
}
|
|
|
|
.x-file-upload-file-drag-drop-wrapper {
|
|
padding: var(--padding);
|
|
background-color: var(--host-bg-color);
|
|
border-top-left-radius: var(--top-radius);
|
|
border-top-right-radius: var(--top-radius);
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.ts
|
|
|
|
import {
|
|
ViewChild,
|
|
Component,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XColor,
|
|
nameof,
|
|
isFile,
|
|
isArray,
|
|
toArray,
|
|
isString,
|
|
hasChild,
|
|
XFileType,
|
|
XFileBlob,
|
|
getArrayOf,
|
|
isXFileBlob,
|
|
parseXColor,
|
|
getFileInfo,
|
|
isExtensionOk,
|
|
XOneOrManyType,
|
|
getErrorException,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XExceptionIdentifier,
|
|
XBaseRangeRequestDto,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XFileStatus,
|
|
XFileUploadAction,
|
|
XFileUploadCssVars,
|
|
XFileUploadActionModel,
|
|
XFileUploadContainerComponent,
|
|
} from './x-file-upload.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XActionBarItem,
|
|
defaultActionBarAddItem,
|
|
DefaultActionBarItemIds,
|
|
defaultActionBarUploadItem,
|
|
defaultActionBarRemoveItem,
|
|
defaultActionBarSelectAllItem,
|
|
defaultActionBarDeSelectAllItem,
|
|
defaultActionBarInverseSelectionItem,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
|
|
import { XListItem, XListAction } from '../x-list/x-list.typings';
|
|
import { XThumbnailType } from '../x-thumbnail/x-thumbnail.typings';
|
|
import { XFileDropAreaAction } from '../x-file-drop-area/x-file-drop-area.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-file-upload',
|
|
templateUrl: './x-file-upload.component.html',
|
|
styleUrls: ['./x-file-upload.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFileUploadComponent extends XFileUploadContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
private addDisablerSubject = new BehaviorSubject<boolean>(false);
|
|
private uploadDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
private removeDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
private selectAllDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
private deSelectAllDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
private inverseSelectionDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
|
|
//
|
|
@ViewChild('fileInput', { static: false })
|
|
private fileInputRef!: ElementRef;
|
|
|
|
//
|
|
private inputFiles: File[] = [];
|
|
fileListItems: XListItem<File>[] = [];
|
|
fileListItemsSubject: BehaviorSubject<XListItem<File>[]> =
|
|
new BehaviorSubject([]);
|
|
|
|
//
|
|
get files() {
|
|
return this.inputFiles;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareActionBarActions();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isColorChanged = changeKeys.includes(
|
|
nameof<XFileUploadComponent>('color')
|
|
);
|
|
if (isColorChanged) {
|
|
await this.applyColor();
|
|
}
|
|
|
|
//
|
|
//#region ActionBar Actions ...
|
|
const isActionBarActionsChanged = changeKeys.includes(
|
|
nameof<XFileUploadComponent>('actionBarActions')
|
|
);
|
|
const isActionBarHideActionsChanged = changeKeys.includes(
|
|
nameof<XFileUploadComponent>('actionBarHideActions')
|
|
);
|
|
if (isActionBarActionsChanged || isActionBarHideActionsChanged) {
|
|
await this.prepareActionBarActions();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFileUploadComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Providers ...
|
|
async canAddFile() {
|
|
//
|
|
const isMaxFilesOk = await this.isMaxAllowedFilesOk(
|
|
this.inputFiles.length + 1
|
|
);
|
|
const isMaxSizeOk = await this.isMaxAllowedSizeOk();
|
|
|
|
//
|
|
const result = isMaxFilesOk && isMaxSizeOk;
|
|
if (result) {
|
|
this.addDisablerSubject.next(false);
|
|
} else {
|
|
this.addDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getThumbnailType(item: any) {
|
|
return this.getValue(item).pipe(
|
|
map((it) => {
|
|
//
|
|
let result = XThumbnailType.GENERAL;
|
|
|
|
//
|
|
let fileInfo;
|
|
if (isString(it)) {
|
|
fileInfo = getFileInfo(it);
|
|
} else if (!isFile(it) && isXFileBlob(fileInfo)) {
|
|
fileInfo = getFileInfo((it as XFileBlob).name);
|
|
} else {
|
|
fileInfo = getFileInfo((it as File).name);
|
|
}
|
|
|
|
//
|
|
switch (fileInfo.type) {
|
|
case XFileType.Image:
|
|
case XFileType.CoverImage:
|
|
case XFileType.ProfileImage:
|
|
result = XThumbnailType.CUSTOM;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
|
|
getThumbnailIdentifier(item: any) {
|
|
return this.getValue(item).pipe(
|
|
map((it) => {
|
|
//
|
|
let result = '';
|
|
if (!isFile(it)) {
|
|
result = !isNullOrUndefined(it.name) ? it.name : it;
|
|
} else {
|
|
result = it;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Handlers ...
|
|
async handleFileDropped(files: File | File[]) {
|
|
//
|
|
if (!files) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.loading = true;
|
|
|
|
//
|
|
if (!isArray(files) && files instanceof File) {
|
|
await this.handleAddNewFile(files as File);
|
|
} else {
|
|
//
|
|
const filesArr = files as File[];
|
|
for (const file of filesArr) {
|
|
await this.handleAddNewFile(file);
|
|
}
|
|
}
|
|
|
|
//
|
|
this.loading = false;
|
|
this.fileChange.emit(this.inputFiles);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async handleAddNewFile(file: File) {
|
|
//
|
|
if (this.isExists(file)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const status = await this.getFileStatusForAdd(file);
|
|
|
|
//
|
|
await this.prepareActionBarActionsSubjects(this.getSelectedFiles());
|
|
if (status !== XFileStatus.OK) {
|
|
this.loading = false;
|
|
await this.handleFileStatusForAdd(status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.inputFiles.push(file);
|
|
const fileListItem = await this.getListItem(file);
|
|
this.fileListItems.push(fileListItem);
|
|
this.fileListItemsSubject.next(this.fileListItems);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async handleRemoveItems(request: XBaseRangeRequestDto<File>) {
|
|
//
|
|
if (!request || !hasChild(request.items)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.loading = true;
|
|
|
|
//
|
|
const filteredFiles = this.inputFiles.filter(
|
|
(f) => !request.items.includes(f)
|
|
);
|
|
this.inputFiles = [];
|
|
this.fileListItems = [];
|
|
|
|
//
|
|
if (!hasChild(filteredFiles)) {
|
|
//
|
|
this.inputFiles = [];
|
|
this.fileListItems = [];
|
|
this.fileListItemsSubject.next([]);
|
|
} else {
|
|
await this.handleFileDropped(filteredFiles);
|
|
}
|
|
|
|
//
|
|
this.loading = false;
|
|
this.fileChange.emit(this.inputFiles);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async handleFilesSelectionChanged(items: XListItem<File>[]) {
|
|
await this.prepareActionBarActionsSubjects(items);
|
|
}
|
|
|
|
async handleListOrderChanged() {
|
|
//
|
|
const listItems = await this.getArrayValueAsync(this.fileListItems);
|
|
this.inputFiles = [...listItems.map((li) => li.data)];
|
|
|
|
//
|
|
this.loading = false;
|
|
this.fileChange.emit(this.inputFiles);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
handleFilesSelected() {
|
|
//
|
|
if (!this.fileInputRef) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fileInput = this.fileInputRef.nativeElement;
|
|
if (!fileInput || !fileInput.files) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const files = getArrayOf<File>(fileInput.files);
|
|
|
|
//
|
|
if (!files || files.length === 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const file = files[0];
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
fileInput.value = null;
|
|
|
|
//
|
|
this.handleFileDropped(files);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
selectFiles() {
|
|
//
|
|
const isBussy = this.uiDisabled || this.loading;
|
|
if (isBussy) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.fileInputRef) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fileInput = this.fileInputRef.nativeElement;
|
|
if (!fileInput) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
fileInput.click();
|
|
}
|
|
|
|
isExists(file: File) {
|
|
//
|
|
const result =
|
|
file && hasChild(this.inputFiles)
|
|
? this.inputFiles.findIndex(
|
|
(f) =>
|
|
f.name === file.name &&
|
|
f.size === file.size &&
|
|
f.type === file.type &&
|
|
f.lastModified === file.lastModified
|
|
) > -1
|
|
: false;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getSelectedFiles() {
|
|
return this.fileListItems.filter((i) => i.isSelected === true);
|
|
}
|
|
|
|
/**
|
|
* sync files with list ...
|
|
* @param files
|
|
*/
|
|
async handleSyncFiles(files: Array<File>) {
|
|
//
|
|
// first Remove List and Files ...
|
|
await this.handleRemoveItems({
|
|
items: this.files,
|
|
});
|
|
|
|
//
|
|
// Drop New Files ...
|
|
await this.handleFileDropped(files);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
/**
|
|
* retrieve all exists files in list current size ...
|
|
*/
|
|
private currentFilesSize() {
|
|
//
|
|
let result = 0;
|
|
this.inputFiles.forEach((i) => (result += i.size));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Extension ...
|
|
*/
|
|
private async isExtensionOk(file: File) {
|
|
//
|
|
if (!file) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const allowedExtensionsType = await this.getValueAsync(
|
|
this.allowedExtensions
|
|
);
|
|
if (!allowedExtensionsType) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const allowedExtensions = toArray(allowedExtensionsType);
|
|
if (!hasChild(allowedExtensions)) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const result = isExtensionOk(file, allowedExtensions);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Number of Files is Ok after and before Upload ...
|
|
*/
|
|
private async isMaxAllowedFilesOk(num?: number) {
|
|
//
|
|
if (!num && !hasChild(this.inputFiles)) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
if (!num) {
|
|
num = this.inputFiles.length;
|
|
}
|
|
|
|
//
|
|
const maxAllowedFiles = await this.getValueAsync(this.maxAllowedFiles);
|
|
const result =
|
|
maxAllowedFiles && maxAllowedFiles > 0 ? num <= maxAllowedFiles : true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check all File Sizes after and before Upload ...
|
|
*/
|
|
private async isMaxAllowedSizeOk(file?: File) {
|
|
//
|
|
let currentSize = this.currentFilesSize();
|
|
|
|
//
|
|
if (file) {
|
|
currentSize += file.size;
|
|
}
|
|
|
|
//
|
|
const maxAllowedSize = await this.getValueAsync(this.maxAllowedSize);
|
|
|
|
//
|
|
const result =
|
|
maxAllowedSize && maxAllowedSize > 0
|
|
? currentSize <= maxAllowedSize
|
|
: true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Size satisfied Min Required Size ...
|
|
*/
|
|
private async isMinAllowedFileSizeOk(file: File) {
|
|
//
|
|
const minAllowedFileSize = await this.getValueAsync(
|
|
this.minAllowedFileSize
|
|
);
|
|
|
|
//
|
|
const result =
|
|
minAllowedFileSize && minAllowedFileSize > 0
|
|
? file.size >= minAllowedFileSize
|
|
: true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Size less than or Equals Max Required Size ...
|
|
*/
|
|
private async isMaxAllowedFileSizeOk(file: File) {
|
|
//
|
|
const maxAllowedFileSize = await this.getValueAsync(
|
|
this.maxAllowedFileSize
|
|
);
|
|
|
|
//
|
|
const result =
|
|
maxAllowedFileSize && maxAllowedFileSize > 0
|
|
? file.size <= maxAllowedFileSize
|
|
: true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check File Status for Add a File to List ...
|
|
*/
|
|
private async getFileStatusForAdd(file: File) {
|
|
//
|
|
// Check Not Empty File ...
|
|
if (!file || file.size === 0) {
|
|
return XFileStatus.EMPTY;
|
|
}
|
|
|
|
//
|
|
// Check File Extension Validation ...
|
|
const isExtensionIsOk = await this.isExtensionOk(file);
|
|
if (!isExtensionIsOk) {
|
|
return XFileStatus.NOT_ALLOWED_TYPE;
|
|
}
|
|
|
|
//
|
|
// Check File Min Size Ok ...
|
|
const isMinAllowedFileSizeOk = await this.isMinAllowedFileSizeOk(file);
|
|
if (!isMinAllowedFileSizeOk) {
|
|
return XFileStatus.MIN_SIZE_NOT_REACHED;
|
|
}
|
|
|
|
//
|
|
// Check File Max Size Ok ...
|
|
const isMaxAllowedFileSizeOk = await this.isMaxAllowedFileSizeOk(file);
|
|
if (!isMaxAllowedFileSizeOk) {
|
|
return XFileStatus.SIZE_EXCEEDED;
|
|
}
|
|
|
|
//
|
|
// Check Max Files Size Ok ...
|
|
const isMaxAllowedSizeOk = await this.isMaxAllowedSizeOk(file);
|
|
if (!isMaxAllowedSizeOk) {
|
|
return XFileStatus.MAX_ALLOWED_SIZE_REACHED;
|
|
}
|
|
|
|
//
|
|
// Check Max Files Ok ...
|
|
const isMaxAllowedFilesOk = await this.isMaxAllowedFilesOk(
|
|
this.inputFiles.length + 1
|
|
);
|
|
if (!isMaxAllowedFilesOk) {
|
|
return XFileStatus.MAX_ALLOWED_FILES_REACHED;
|
|
}
|
|
|
|
//
|
|
// Everythings Ok ...
|
|
return XFileStatus.OK;
|
|
}
|
|
|
|
/**
|
|
* recieve file status and act based of it (notifiy when exception) ...
|
|
*
|
|
* @param status File Status for Add ...
|
|
*/
|
|
private async handleFileStatusForAdd(status: XFileStatus) {
|
|
//
|
|
let identifier: XExceptionIdentifier = null;
|
|
switch (status) {
|
|
//
|
|
case XFileStatus.EMPTY:
|
|
identifier = await this.getValueAsync(this.emptyFileException);
|
|
break;
|
|
|
|
//
|
|
case XFileStatus.NOT_ALLOWED_TYPE:
|
|
identifier = await this.getValueAsync(this.notAllowedFileException);
|
|
break;
|
|
|
|
//
|
|
case XFileStatus.SIZE_EXCEEDED:
|
|
identifier = await this.getValueAsync(this.maxAllowedFileSizeException);
|
|
break;
|
|
|
|
//
|
|
case XFileStatus.MAX_ALLOWED_SIZE_REACHED:
|
|
identifier = await this.getValueAsync(this.maxAllowedSizeException);
|
|
break;
|
|
|
|
//
|
|
case XFileStatus.MAX_ALLOWED_FILES_REACHED:
|
|
identifier = await this.getValueAsync(this.maxAllowedFilesException);
|
|
break;
|
|
|
|
//
|
|
case XFileStatus.MIN_SIZE_NOT_REACHED:
|
|
identifier = await this.getValueAsync(this.minAllowedFileSizeException);
|
|
break;
|
|
}
|
|
|
|
//
|
|
const exception = getErrorException(identifier);
|
|
if (exception) {
|
|
this.managerService.notificationService.presentErrorNotification({
|
|
exception,
|
|
dissmissable: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
private handleChangeDetection() {
|
|
//
|
|
if (this.listActionProvider) {
|
|
this.listActionProvider.next({
|
|
action: XListAction.Refresh,
|
|
});
|
|
}
|
|
|
|
//
|
|
if (this.fileDropAreaActionProvider) {
|
|
this.fileDropAreaActionProvider.next({
|
|
action: XFileDropAreaAction.Refresh,
|
|
});
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
//#region ActionBar Preparations ...
|
|
private async prepareActionBarActions() {
|
|
//
|
|
//#region Prepare Default Actions ...
|
|
const hideActions = await this.getArrayValueAsync(
|
|
this.actionBarHideActions
|
|
);
|
|
|
|
//
|
|
const defaultActions: XOneOrManyType<XActionBarItem> = [];
|
|
|
|
//
|
|
// Add ...
|
|
const addId = DefaultActionBarItemIds.Add.toString();
|
|
if (!hideActions.includes(addId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarAddItem,
|
|
|
|
//
|
|
index: 1,
|
|
disabled: this.addDisablerSubject.asObservable(),
|
|
|
|
//
|
|
handler: () => {
|
|
this.selectFiles();
|
|
},
|
|
});
|
|
}
|
|
|
|
//
|
|
// Upload ...
|
|
const uploadId = DefaultActionBarItemIds.Upload.toString();
|
|
if (!hideActions.includes(uploadId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarUploadItem,
|
|
|
|
//
|
|
index: 2,
|
|
disabled: this.uploadDisablerSubject.asObservable(),
|
|
});
|
|
}
|
|
|
|
//
|
|
// Remove ...
|
|
const removeId = DefaultActionBarItemIds.Remove.toString();
|
|
if (!hideActions.includes(removeId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarRemoveItem,
|
|
|
|
//
|
|
index: 3,
|
|
disabled: this.removeDisablerSubject.asObservable(),
|
|
});
|
|
}
|
|
|
|
//
|
|
// Select All ...
|
|
const selectAllId = DefaultActionBarItemIds.SelectAll.toString();
|
|
if (!hideActions.includes(selectAllId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarSelectAllItem,
|
|
|
|
//
|
|
index: 4,
|
|
disabled: this.selectAllDisablerSubject.asObservable(),
|
|
});
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
const inverseSelectionId =
|
|
DefaultActionBarItemIds.InverseSelection.toString();
|
|
if (!hideActions.includes(inverseSelectionId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarInverseSelectionItem,
|
|
|
|
//
|
|
index: 5,
|
|
disabled: this.inverseSelectionDisablerSubject.asObservable(),
|
|
});
|
|
}
|
|
|
|
//
|
|
// De Select All ...
|
|
const deselectAllId = DefaultActionBarItemIds.DeSelectAll.toString();
|
|
if (!hideActions.includes(deselectAllId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarDeSelectAllItem,
|
|
|
|
//
|
|
index: 6,
|
|
disabled: this.deSelectAllDisablerSubject.asObservable(),
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
if (!this.actionBarActions) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
this.handleChangeDetection();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const actions = await this.getArrayValueAsync(this.actionBarActions);
|
|
if (!hasChild(actions)) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
this.handleChangeDetection();
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actionBarActions = actions;
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
private async prepareActionBarActionsSubjects(items: XListItem<File>[]) {
|
|
//
|
|
// Check Can Add ...
|
|
const canAdd = await this.canAddFile();
|
|
if (canAdd) {
|
|
this.addDisablerSubject.next(false);
|
|
} else {
|
|
this.addDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Check Select All ...
|
|
if (!hasChild(this.fileListItems)) {
|
|
//
|
|
this.addDisablerSubject.next(false);
|
|
this.uploadDisablerSubject.next(true);
|
|
this.removeDisablerSubject.next(true);
|
|
this.selectAllDisablerSubject.next(true);
|
|
this.deSelectAllDisablerSubject.next(true);
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
} else {
|
|
//
|
|
this.uploadDisablerSubject.next(false);
|
|
|
|
//
|
|
// DeSelectAll ...
|
|
if (!hasChild(items)) {
|
|
//
|
|
this.removeDisablerSubject.next(true);
|
|
this.deSelectAllDisablerSubject.next(true);
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
} else {
|
|
//
|
|
this.removeDisablerSubject.next(false);
|
|
this.deSelectAllDisablerSubject.next(false);
|
|
this.inverseSelectionDisablerSubject.next(false);
|
|
}
|
|
|
|
//
|
|
if (this.fileListItems.length === items.length) {
|
|
//
|
|
this.selectAllDisablerSubject.next(true);
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
} else {
|
|
this.selectAllDisablerSubject.next(false);
|
|
}
|
|
}
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handler Registerrers ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFileUploadActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFileUploadAction.SELECT_FILES:
|
|
this.selectFiles();
|
|
break;
|
|
|
|
//
|
|
case XFileUploadAction.CLEAR_LIST:
|
|
await this.handleRemoveItems({
|
|
items: this.files,
|
|
});
|
|
break;
|
|
|
|
//
|
|
case XFileUploadAction.SYNC_LIST:
|
|
await this.handleSyncFiles(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFileUploadAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Handlers ...
|
|
private async getListItem(item: any) {
|
|
//
|
|
if (!item) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result: XListItem<any> = {
|
|
data: item,
|
|
disabled: this.uiDisabled,
|
|
slideOptions: [
|
|
{
|
|
id: 'delete_file',
|
|
icon: XIconNames.remove,
|
|
title: this.ResourceIDs.delete,
|
|
color: XColor.Danger,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
slot: 'end',
|
|
handler: async () => {
|
|
await this.confirmAndRemove(item);
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private isValidDataSource() {
|
|
return hasChild(this.inputFiles);
|
|
}
|
|
|
|
private addToDataSource(item: XListItem<any>) {
|
|
this.fileListItems.push(item);
|
|
}
|
|
|
|
private changeDataSourceItem(item: XListItem<any>) {
|
|
//
|
|
const index = this.fileListItems.findIndex((i) => i.data === item.data);
|
|
if (index === -1) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.fileListItems[index] = item;
|
|
}
|
|
|
|
private async clearListItems() {
|
|
this.fileListItems = null;
|
|
this.fileListItems = [];
|
|
}
|
|
|
|
private async refreshListItems(forceClean = false) {
|
|
//
|
|
if (forceClean) {
|
|
await this.clearListItems();
|
|
}
|
|
|
|
//
|
|
if (!this.isValidDataSource()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (const f of this.inputFiles) {
|
|
//
|
|
const fListItem = await this.getListItem(f);
|
|
|
|
//
|
|
if (forceClean) {
|
|
this.addToDataSource(fListItem);
|
|
} else {
|
|
this.changeDataSourceItem(fListItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async confirmAndRemove(items: XOneOrManyType<File>) {
|
|
//
|
|
if (!items) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const extractedItems: File[] = !items
|
|
? []
|
|
: isArray(items)
|
|
? (items as File[])
|
|
: [items as File];
|
|
const removeRequest: XBaseRangeRequestDto<File> = {
|
|
items: [...extractedItems],
|
|
};
|
|
|
|
//
|
|
const confirmRemove = await this.getValueAsync(this.listConfirmRemove);
|
|
if (confirmRemove) {
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
() => {
|
|
this.handleRemoveItems(removeRequest);
|
|
}
|
|
);
|
|
} else {
|
|
this.handleRemoveItems(removeRequest);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.color);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFileUploadCssVars.HostBgColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XFileUploadComponent } from './x-file-upload.component';
|
|
import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module';
|
|
|
|
@NgModule({
|
|
declarations: [XFileUploadComponent],
|
|
imports: [
|
|
XCardModule,
|
|
XListModule,
|
|
CommonModule,
|
|
XThumbnailModule,
|
|
XFileDropAreaModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XCardModule,
|
|
XListModule,
|
|
XThumbnailModule,
|
|
XFileDropAreaModule,
|
|
XBaseComponentModule,
|
|
XFileUploadComponent,
|
|
],
|
|
})
|
|
export class XFileUploadModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
Injectable,
|
|
ElementRef,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
hasChild,
|
|
XFileBlob,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
XColorIdentifier,
|
|
fileToJsonString,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
XExceptionIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XListItem,
|
|
XListFilteringHandler,
|
|
XComponentListContainer,
|
|
IXComponentListContainer,
|
|
} from '../x-list/x-list.typings';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
} from '../x-card/x-card.typings';
|
|
import {
|
|
XEmptyActionModel,
|
|
XComponentEmptyContainer,
|
|
IXComponentEmptyContainer,
|
|
} from '../x-empty/x-empty.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarActionModel,
|
|
XActionBarActionIdentifier,
|
|
XActionBarActionFiredModel,
|
|
XComponentActionBarContainer,
|
|
IXComponentActionBarContainer,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import {
|
|
XSearchBarActionModel,
|
|
XSearchBarTypeIdentifier,
|
|
XComponentSearchBarContainer,
|
|
IXComponentSearchBarContainer,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import {
|
|
XFileDropAreaActionModel,
|
|
XComponentFileDropAreaContainer,
|
|
IXComponentFileDropAreaContainer,
|
|
} from '../x-file-drop-area/x-file-drop-area.typings';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { IXFileContainer, XFileContainer } from '../classes/i-x-file.container';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XFileStatus {
|
|
OK = 'ok',
|
|
EMPTY = 'empty',
|
|
SIZE_EXCEEDED = 'size_exceeded',
|
|
NOT_ALLOWED_TYPE = 'not_allowed_type',
|
|
MIN_SIZE_NOT_REACHED = 'min_size_not_reached',
|
|
MAX_ALLOWED_FILES_REACHED = 'max_allowed_files_reached',
|
|
MAX_ALLOWED_SIZE_REACHED = 'max_allowed_size_reached',
|
|
}
|
|
|
|
export type XFileStatusIdentifier = XFileStatus | string;
|
|
|
|
export enum XFileUploadAction {
|
|
SELECT_FILES = 'select_files',
|
|
CLEAR_LIST = 'clear_list',
|
|
SYNC_LIST = 'sync_list',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XFileUploadActionIdentifier = XFileUploadAction | string;
|
|
|
|
export interface XFileUploadActionModel
|
|
extends XBaseActionModel<XFileUploadActionIdentifier> {}
|
|
|
|
export const defaultFileUploadListFilteringHandler: XListFilteringHandler = (
|
|
query: string,
|
|
items: XListItem<File>[]
|
|
) => {
|
|
//
|
|
if (!query || !hasChild(items)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return items.filter((i) =>
|
|
toNormalString(fileToJsonString(i.data)).includes(toNormalString(query))
|
|
);
|
|
};
|
|
|
|
export enum XFileUploadCssVars {
|
|
HostBgColor = 'host-bg-color',
|
|
}
|
|
|
|
//
|
|
//#region Container ...
|
|
//
|
|
type TXFileUploadContainer = IXComponentCardContainer &
|
|
Partial<IXComponentFileDropAreaContainer> &
|
|
Partial<IXComponentListContainer> &
|
|
IXComponentActionBarContainer &
|
|
IXComponentSearchBarContainer &
|
|
IXComponentEmptyContainer &
|
|
IXFileContainer;
|
|
|
|
export interface IXFileUploadContainer
|
|
extends IXBaseContainer,
|
|
TXFileUploadContainer {
|
|
//
|
|
actionProvider: Subject<XFileUploadActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>>;
|
|
|
|
//
|
|
actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFileUploadContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXFileUploadContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
//
|
|
readonly actionProvider: Subject<XFileUploadActionModel> =
|
|
new Subject<XFileUploadActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>> = new EventEmitter<
|
|
XOneOrManyType<File | XFileBlob>
|
|
>();
|
|
|
|
readonly actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Drop Props ...
|
|
//
|
|
readonly showFileDropArea: XStandardType<boolean> =
|
|
this.fileDropAreaPropertyProvider.showFileDropArea;
|
|
|
|
//
|
|
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaActionProvider;
|
|
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaCssClass;
|
|
|
|
//
|
|
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaColor;
|
|
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaForegroundColor;
|
|
|
|
//
|
|
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaIcon;
|
|
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaMessage;
|
|
|
|
//
|
|
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaDisableFileCheck;
|
|
|
|
//
|
|
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
readonly fileDropAreaAllowedExtensions: XStandardType<
|
|
XOneOrManyType<string>
|
|
> = this.fileDropAreaPropertyProvider.fileDropAreaAllowedExtensions;
|
|
|
|
//
|
|
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaDragDisabled;
|
|
readonly fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaContentTemplate;
|
|
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaFilesChangeEmiter;
|
|
|
|
//
|
|
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaSuccessColor;
|
|
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaErrorColor;
|
|
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.fileDropAreaPropertyProvider.fileDropAreaAccentColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Card Props ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Props ...
|
|
readonly showList: XStandardType<boolean> =
|
|
this.listPropertyProvider.showList;
|
|
readonly listConfirmRemove: XStandardType<boolean> =
|
|
this.listPropertyProvider.listConfirmRemove;
|
|
readonly listActionProvider = this.listPropertyProvider.listActionProvider;
|
|
readonly listCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.listPropertyProvider.listCssClass;
|
|
readonly listShowToolbar: XStandardType<boolean> = true;
|
|
readonly listStickyToolbar: XStandardType<boolean> =
|
|
this.listPropertyProvider.listStickyToolbar;
|
|
readonly listEnableReordering: XStandardType<boolean> =
|
|
this.listPropertyProvider.listEnableReordering;
|
|
readonly listShowDivider: XStandardType<boolean> =
|
|
this.listPropertyProvider.listShowDivider;
|
|
readonly listFilteringHandler: XListFilteringHandler =
|
|
this.listPropertyProvider.listFilteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
readonly showActionBar: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.actionBarPropertyProvider.actionBarActionProvider;
|
|
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.actionBarPropertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.actionBarPropertyProvider.actionBarColor;
|
|
readonly actionBarForegroundColor: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.actionBarPropertyProvider.actionBarActions;
|
|
|
|
//
|
|
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.actionBarPropertyProvider.actionBarActionFired;
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
readonly showSearchBar: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.showSearchBar;
|
|
|
|
//
|
|
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.searchBarPropertyProvider.searchBarActionProvider;
|
|
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.searchBarPropertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
readonly searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarColor;
|
|
readonly searchBarForegroundColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchInputColor;
|
|
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarType;
|
|
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarTitle;
|
|
readonly searchBarValue: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarValue;
|
|
readonly searchBarEnterKeyHint: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarEnterKeyHint;
|
|
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarKeyboardType;
|
|
readonly searchBarSpellcheck: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarSpellcheck;
|
|
readonly searchBarDebounce: XStandardType<number> =
|
|
this.searchBarPropertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
readonly searchBarShowCancelButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowCancelButton;
|
|
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
|
|
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
|
|
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarShowClearButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowClearButton;
|
|
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIcon;
|
|
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
|
|
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarQueryChange: EventEmitter<string> =
|
|
this.searchBarPropertyProvider.searchBarQueryChange;
|
|
readonly searchBarOnEvent: EventEmitter<string> =
|
|
this.searchBarPropertyProvider.searchBarOnEvent;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Empty Props ...
|
|
readonly showEmpty: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.showEmpty;
|
|
readonly emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.emptyPropertyProvider.emptyActionProvider;
|
|
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.emptyPropertyProvider.emptyCssClass;
|
|
readonly emptyColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.emptyColor;
|
|
readonly emptyForegroundColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.emptyForegroundColor;
|
|
readonly emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.emptyPropertyProvider.emptyMessage;
|
|
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.emptyMessageColor;
|
|
readonly emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.emptyForegroundMessageColor;
|
|
readonly emptyHasRefresh: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.emptyHasRefresh;
|
|
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.emptyPropertyProvider.emptyRefreshButtonColor;
|
|
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.emptyPropertyProvider.emptyForegroundRefreshButtonColor;
|
|
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.emptyPropertyProvider.emptyRefreshIcon;
|
|
readonly emptyRefresh: EventEmitter<void> =
|
|
this.emptyPropertyProvider.emptyRefresh;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Props ...
|
|
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.emptyFileException;
|
|
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.notAllowedFileException;
|
|
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.filePropertyProvider.allowedExtensions;
|
|
readonly maxAllowedFiles: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFiles;
|
|
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFilesException;
|
|
readonly maxAllowedSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedSize;
|
|
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedSizeException;
|
|
readonly minAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.minAllowedFileSize;
|
|
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.minAllowedFileSizeException;
|
|
readonly maxAllowedFileSize: XStandardType<number> =
|
|
this.filePropertyProvider.maxAllowedFileSize;
|
|
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.filePropertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected filePropertyProvider: XFileContainer,
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected listPropertyProvider: XComponentListContainer,
|
|
protected emptyPropertyProvider: XComponentEmptyContainer,
|
|
protected actionBarPropertyProvider: XComponentActionBarContainer,
|
|
protected searchBarPropertyProvider: XComponentSearchBarContainer,
|
|
protected fileDropAreaPropertyProvider: XComponentFileDropAreaContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFileUploadContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXFileUploadContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XFileUploadActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Output()
|
|
fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>> = new EventEmitter();
|
|
|
|
@Input()
|
|
actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
> = this.propertyProvider.actionBarHideActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Drop Props ...
|
|
//
|
|
@Input()
|
|
showFileDropArea: XStandardType<boolean> =
|
|
this.propertyProvider.showFileDropArea;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
|
|
this.propertyProvider.fileDropAreaActionProvider;
|
|
|
|
@Input()
|
|
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaCssClass;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaColor;
|
|
|
|
@Input()
|
|
fileDropAreaForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.fileDropAreaIcon;
|
|
|
|
@Input()
|
|
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.fileDropAreaMessage;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDisableFileCheck: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDisableFileCheck;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
|
|
@Input()
|
|
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.fileDropAreaAllowedExtensions;
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaDragDisabled: XStandardType<boolean> =
|
|
this.propertyProvider.fileDropAreaDragDisabled;
|
|
|
|
@Input()
|
|
fileDropAreaContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.fileDropAreaContentTemplate;
|
|
|
|
@Output()
|
|
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
|
|
new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaSuccessColor;
|
|
|
|
@Input()
|
|
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaErrorColor;
|
|
|
|
@Input()
|
|
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.fileDropAreaAccentColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Card Props ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Props ...
|
|
@Input()
|
|
showList: XStandardType<boolean> = this.propertyProvider.showList;
|
|
|
|
@Input()
|
|
listConfirmRemove: XStandardType<boolean> =
|
|
this.propertyProvider.listConfirmRemove;
|
|
|
|
@Input()
|
|
listActionProvider = this.propertyProvider.listActionProvider;
|
|
|
|
@Input()
|
|
listCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listCssClass;
|
|
|
|
@Input()
|
|
listShowToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.listShowToolbar;
|
|
|
|
@Input()
|
|
listStickyToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.listStickyToolbar;
|
|
|
|
@Input()
|
|
listEnableReordering: XStandardType<boolean> =
|
|
this.propertyProvider.listEnableReordering;
|
|
|
|
@Input()
|
|
listShowDivider: XStandardType<boolean> =
|
|
this.propertyProvider.listShowDivider;
|
|
|
|
@Input()
|
|
listFilteringHandler: XListFilteringHandler =
|
|
this.propertyProvider.listFilteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
|
|
//
|
|
@Output()
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
@Input()
|
|
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
|
|
|
|
//
|
|
@Input()
|
|
searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.searchBarActionProvider;
|
|
|
|
@Input()
|
|
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
|
|
@Input()
|
|
searchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchInputColor;
|
|
|
|
@Input()
|
|
searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarType;
|
|
|
|
@Input()
|
|
searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarTitle;
|
|
|
|
@Input()
|
|
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
|
|
|
|
@Input()
|
|
searchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.searchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarKeyboardType;
|
|
|
|
@Input()
|
|
searchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarSpellcheck;
|
|
|
|
@Input()
|
|
searchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowCancelButton;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowClearButton;
|
|
|
|
@Input()
|
|
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
searchBarOnEvent: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Empty Props ...
|
|
@Input()
|
|
showEmpty: XStandardType<boolean> = this.propertyProvider.showEmpty;
|
|
|
|
@Input()
|
|
emptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.emptyActionProvider;
|
|
|
|
@Input()
|
|
emptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.emptyCssClass;
|
|
|
|
@Input()
|
|
emptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyColor;
|
|
|
|
@Input()
|
|
emptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundColor;
|
|
|
|
@Input()
|
|
emptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.emptyMessage;
|
|
|
|
@Input()
|
|
emptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyMessageColor;
|
|
|
|
@Input()
|
|
emptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundMessageColor;
|
|
|
|
@Input()
|
|
emptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.emptyHasRefresh;
|
|
|
|
@Input()
|
|
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyRefreshButtonColor;
|
|
|
|
@Input()
|
|
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundRefreshButtonColor;
|
|
|
|
@Input()
|
|
emptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.emptyRefreshIcon;
|
|
|
|
@Output()
|
|
emptyRefresh: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Props ...
|
|
@Input()
|
|
emptyFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.emptyFileException;
|
|
|
|
@Input()
|
|
notAllowedFileException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.notAllowedFileException;
|
|
|
|
@Input()
|
|
allowedExtensions: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.allowedExtensions;
|
|
|
|
@Input()
|
|
maxAllowedFiles: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFiles;
|
|
|
|
@Input()
|
|
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFilesException;
|
|
|
|
@Input()
|
|
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
|
|
|
|
@Input()
|
|
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedSizeException;
|
|
|
|
@Input()
|
|
minAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.minAllowedFileSize;
|
|
|
|
@Input()
|
|
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.minAllowedFileSizeException;
|
|
|
|
@Input()
|
|
maxAllowedFileSize: XStandardType<number> =
|
|
this.propertyProvider.maxAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
|
|
this.propertyProvider.maxAllowedFileSizeException;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFileUploadContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFileUploadContainer
|
|
): Observable<IXFileUploadContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
actionBarHideActions: this.getValue(
|
|
container ? container.actionBarHideActions : this.actionBarHideActions
|
|
),
|
|
showFileDropArea: this.getValue(
|
|
container ? container.showFileDropArea : this.showFileDropArea
|
|
),
|
|
fileDropAreaCssClass: this.getValue(
|
|
container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass
|
|
),
|
|
fileDropAreaColor: this.getValue(
|
|
container ? container.fileDropAreaColor : this.fileDropAreaColor
|
|
),
|
|
fileDropAreaForegroundColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaForegroundColor
|
|
: this.fileDropAreaForegroundColor
|
|
),
|
|
fileDropAreaIcon: this.getValue(
|
|
container ? container.fileDropAreaIcon : this.fileDropAreaIcon
|
|
),
|
|
fileDropAreaMessage: this.getValue(
|
|
container ? container.fileDropAreaMessage : this.fileDropAreaMessage
|
|
),
|
|
fileDropAreaDisableFileCheck: this.getValue(
|
|
container
|
|
? container.fileDropAreaDisableFileCheck
|
|
: this.fileDropAreaDisableFileCheck
|
|
),
|
|
fileDropAreaSupportsMultipleFiles: this.getValue(
|
|
container
|
|
? container.fileDropAreaSupportsMultipleFiles
|
|
: this.fileDropAreaSupportsMultipleFiles
|
|
),
|
|
fileDropAreaAllowedExtensions: this.getValue(
|
|
container
|
|
? container.fileDropAreaAllowedExtensions
|
|
: this.fileDropAreaAllowedExtensions
|
|
),
|
|
fileDropAreaDragDisabled: this.getValue(
|
|
container
|
|
? container.fileDropAreaDragDisabled
|
|
: this.fileDropAreaDragDisabled
|
|
),
|
|
fileDropAreaContentTemplate: this.getValue(
|
|
container
|
|
? container.fileDropAreaContentTemplate
|
|
: this.fileDropAreaContentTemplate
|
|
),
|
|
fileDropAreaSuccessColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaSuccessColor
|
|
: this.fileDropAreaSuccessColor
|
|
),
|
|
fileDropAreaErrorColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaErrorColor
|
|
: this.fileDropAreaErrorColor
|
|
),
|
|
fileDropAreaAccentColor: this.getValue(
|
|
container
|
|
? container.fileDropAreaAccentColor
|
|
: this.fileDropAreaAccentColor
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardCssClass: this.getValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
showList: this.getValue(container ? container.showList : this.showList),
|
|
listConfirmRemove: this.getValue(
|
|
container ? container.listConfirmRemove : this.listConfirmRemove
|
|
),
|
|
listCssClass: this.getValue(
|
|
container ? container.listCssClass : this.listCssClass
|
|
),
|
|
listShowToolbar: this.getValue(
|
|
container ? container.listShowToolbar : this.listShowToolbar
|
|
),
|
|
listStickyToolbar: this.getValue(
|
|
container ? container.listStickyToolbar : this.listStickyToolbar
|
|
),
|
|
listEnableReordering: this.getValue(
|
|
container ? container.listEnableReordering : this.listEnableReordering
|
|
),
|
|
listShowDivider: this.getValue(
|
|
container ? container.listShowDivider : this.listShowDivider
|
|
),
|
|
listFilteringHandler: this.getValue(
|
|
container ? container.listFilteringHandler : this.listFilteringHandler
|
|
),
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
actionBarActions: this.getValue(
|
|
container ? container.actionBarActions : this.actionBarActions
|
|
),
|
|
showSearchBar: this.getValue(
|
|
container ? container.showSearchBar : this.showSearchBar
|
|
),
|
|
searchBarCssClass: this.getValue(
|
|
container ? container.searchBarCssClass : this.searchBarCssClass
|
|
),
|
|
searchBarColor: this.getValue(
|
|
container ? container.searchBarColor : this.searchBarColor
|
|
),
|
|
searchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundColor
|
|
: this.searchBarForegroundColor
|
|
),
|
|
searchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchInputColor
|
|
: this.searchBarSearchInputColor
|
|
),
|
|
searchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundSearchInputColor
|
|
: this.searchBarForegroundSearchInputColor
|
|
),
|
|
searchBarType: this.getValue(
|
|
container ? container.searchBarType : this.searchBarType
|
|
),
|
|
searchBarTitle: this.getValue(
|
|
container ? container.searchBarTitle : this.searchBarTitle
|
|
),
|
|
searchBarValue: this.getValue(
|
|
container ? container.searchBarValue : this.searchBarValue
|
|
),
|
|
searchBarEnterKeyHint: this.getValue(
|
|
container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint
|
|
),
|
|
searchBarKeyboardType: this.getValue(
|
|
container ? container.searchBarKeyboardType : this.searchBarKeyboardType
|
|
),
|
|
searchBarSpellcheck: this.getValue(
|
|
container ? container.searchBarSpellcheck : this.searchBarSpellcheck
|
|
),
|
|
searchBarDebounce: this.getValue(
|
|
container ? container.searchBarDebounce : this.searchBarDebounce
|
|
),
|
|
searchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.searchBarShowCancelButton
|
|
: this.searchBarShowCancelButton
|
|
),
|
|
searchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIcon
|
|
: this.searchBarCancelButtonIcon
|
|
),
|
|
searchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonTitle
|
|
: this.searchBarCancelButtonTitle
|
|
),
|
|
searchBarCancelButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIconColor
|
|
: this.searchBarCancelButtonIconColor
|
|
),
|
|
searchBarShowClearButton: this.getValue(
|
|
container
|
|
? container.searchBarShowClearButton
|
|
: this.searchBarShowClearButton
|
|
),
|
|
searchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIcon
|
|
: this.searchBarClearButtonIcon
|
|
),
|
|
searchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIconColor
|
|
: this.searchBarClearButtonIconColor
|
|
),
|
|
searchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIcon
|
|
: this.searchBarSearchButtonIcon
|
|
),
|
|
searchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIconColor
|
|
: this.searchBarSearchButtonIconColor
|
|
),
|
|
showEmpty: this.getValue(
|
|
container ? container.showEmpty : this.showEmpty
|
|
),
|
|
emptyCssClass: this.getValue(
|
|
container ? container.emptyCssClass : this.emptyCssClass
|
|
),
|
|
emptyColor: this.getValue(
|
|
container ? container.emptyColor : this.emptyColor
|
|
),
|
|
emptyForegroundColor: this.getValue(
|
|
container ? container.emptyForegroundColor : this.emptyForegroundColor
|
|
),
|
|
emptyMessage: this.getValue(
|
|
container ? container.emptyMessage : this.emptyMessage
|
|
),
|
|
emptyMessageColor: this.getValue(
|
|
container ? container.emptyMessageColor : this.emptyMessageColor
|
|
),
|
|
emptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundMessageColor
|
|
: this.emptyForegroundMessageColor
|
|
),
|
|
emptyHasRefresh: this.getValue(
|
|
container ? container.emptyHasRefresh : this.emptyHasRefresh
|
|
),
|
|
emptyRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyRefreshButtonColor
|
|
: this.emptyRefreshButtonColor
|
|
),
|
|
emptyForegroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.emptyForegroundRefreshButtonColor
|
|
: this.emptyForegroundRefreshButtonColor
|
|
),
|
|
emptyRefreshIcon: this.getValue(
|
|
container ? container.emptyRefreshIcon : this.emptyRefreshIcon
|
|
),
|
|
emptyFileException: this.getValue(
|
|
container ? container.emptyFileException : this.emptyFileException
|
|
),
|
|
notAllowedFileException: this.getValue(
|
|
container
|
|
? container.notAllowedFileException
|
|
: this.notAllowedFileException
|
|
),
|
|
allowedExtensions: this.getValue(
|
|
container ? container.allowedExtensions : this.allowedExtensions
|
|
),
|
|
maxAllowedFiles: this.getValue(
|
|
container ? container.maxAllowedFiles : this.maxAllowedFiles
|
|
),
|
|
maxAllowedFilesException: this.getValue(
|
|
container
|
|
? container.maxAllowedFilesException
|
|
: this.maxAllowedFilesException
|
|
),
|
|
maxAllowedSize: this.getValue(
|
|
container ? container.maxAllowedSize : this.maxAllowedSize
|
|
),
|
|
maxAllowedSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedSizeException
|
|
: this.maxAllowedSizeException
|
|
),
|
|
minAllowedFileSize: this.getValue(
|
|
container ? container.minAllowedFileSize : this.minAllowedFileSize
|
|
),
|
|
minAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.minAllowedFileSizeException
|
|
: this.minAllowedFileSizeException
|
|
),
|
|
maxAllowedFileSize: this.getValue(
|
|
container ? container.maxAllowedFileSize : this.maxAllowedFileSize
|
|
),
|
|
maxAllowedFileSizeException: this.getValue(
|
|
container
|
|
? container.maxAllowedFileSizeException
|
|
: this.maxAllowedFileSizeException
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
fileChange: this.fileChange,
|
|
|
|
//
|
|
fileDropAreaActionProvider: container
|
|
? container.fileDropAreaActionProvider
|
|
: this.fileDropAreaActionProvider,
|
|
|
|
//
|
|
fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
listActionProvider: container
|
|
? container.listActionProvider
|
|
: this.listActionProvider,
|
|
|
|
//
|
|
actionBarActionProvider: container
|
|
? container.actionBarActionProvider
|
|
: this.actionBarActionProvider,
|
|
|
|
//
|
|
actionBarActionFired: this.actionBarActionFired,
|
|
|
|
//
|
|
searchBarActionProvider: container
|
|
? container.searchBarActionProvider
|
|
: this.searchBarActionProvider,
|
|
|
|
//
|
|
searchBarQueryChange: this.searchBarQueryChange,
|
|
searchBarOnEvent: this.searchBarOnEvent,
|
|
|
|
//
|
|
emptyActionProvider: container
|
|
? container.emptyActionProvider
|
|
: this.emptyActionProvider,
|
|
|
|
//
|
|
emptyRefresh: this.emptyRefresh,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else formRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="formRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div [ngClass]="getFormCardActionsCssClass() | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div
|
|
footer
|
|
*ngIf="getValue(cardShowFooter) | async"
|
|
[ngClass]="getFormCardFooterCssClass() | async"
|
|
>
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Form itSelf Template -->
|
|
<ng-template #formRef>
|
|
<!-- Form Wrapper -->
|
|
<div
|
|
*ngIf="form"
|
|
class="x-form x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
>
|
|
<!-- Form Element -->
|
|
<form
|
|
*ngIf="form"
|
|
[formGroup]="form"
|
|
[ngClass]="getFormCssClass() | async"
|
|
style="width: 100%"
|
|
>
|
|
<ng-container *ngIf="hasChildValue(getFormControls()) | async">
|
|
<!-- Presenting Props -->
|
|
<ng-container
|
|
*ngFor="
|
|
let control of getFormControls() | async;
|
|
index as controlIndex
|
|
"
|
|
>
|
|
<!-- Check Control Exists -->
|
|
<ng-container *ngIf="control">
|
|
<ng-container
|
|
*ngIf="getControlType(control) | async as controlType"
|
|
>
|
|
<!-- 1- Input Type (Text/Number/Password/Email/Url/Color/Tel) Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
controlType === ControlTypes.Text ||
|
|
controlType === ControlTypes.Number ||
|
|
controlType === ControlTypes.Password ||
|
|
controlType === ControlTypes.Color ||
|
|
controlType === ControlTypes.Email ||
|
|
controlType === ControlTypes.Url ||
|
|
controlType === ControlTypes.Tel
|
|
"
|
|
>
|
|
<!-- Auto Complete Wrapper -->
|
|
<div
|
|
class="x-auto-complete-wrapper"
|
|
(xOnOutsideClicked)="
|
|
handleAutoCompleteOutsideClicked(control)
|
|
"
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div>
|
|
<!-- Not None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) !==
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- Mat Form Field -->
|
|
<mat-form-field
|
|
class="x-mat-form-field"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[appearance]="getControlAppearance(control) | async"
|
|
>
|
|
<!-- label -->
|
|
<mat-label
|
|
class="x-field-label"
|
|
*ngIf="
|
|
notEmptyValue(getControlLabel(control)) | async
|
|
"
|
|
>{{ getControlLabel(control) | async }}</mat-label
|
|
>
|
|
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="controlHasFormatter(control) | async"
|
|
>
|
|
<input
|
|
matInput
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[inputFormatterType]="
|
|
getFormatterType(control) | async
|
|
"
|
|
[formControlName]="control.propName.toString()"
|
|
[enabledInputFormatter]="
|
|
controlHasFormatter(control) | async
|
|
"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[stringInputFormatterType]="
|
|
getFormatterInputType(control) | async
|
|
"
|
|
[currencyLable]="
|
|
getFormatterCurrencyLabel(control) | async
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
[stringFormatter]="
|
|
getFormatterStringFormatter(control) | async
|
|
"
|
|
(xOnEscape)="handleAutoCompleteEscaped(control)"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[readonly]="isInputControlReadOnly(control) | async"
|
|
[seperator]="getFormatterSeperator(control) | async"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="!(controlHasFormatter(control) | async)"
|
|
>
|
|
<input
|
|
matInput
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(xOnEscape)="handleAutoCompleteEscaped(control)"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[readonly]="isInputControlReadOnly(control) | async"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Prefix Icon -->
|
|
<span
|
|
matPrefix
|
|
*ngIf="controlHasPrefixIcon(control) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</span>
|
|
|
|
<!-- Suffix Icon -->
|
|
<span
|
|
matSuffix
|
|
*ngIf="controlHasSuffixIcon(control) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</span>
|
|
</mat-form-field>
|
|
</ng-container>
|
|
|
|
<!-- None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) ===
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
byIconLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="controlHasFormatter(control) | async"
|
|
>
|
|
<input
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[inputFormatterType]="
|
|
getFormatterType(control) | async
|
|
"
|
|
[formControlName]="control.propName.toString()"
|
|
[enabledInputFormatter]="
|
|
controlHasFormatter(control) | async
|
|
"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
[stringInputFormatterType]="
|
|
getFormatterInputType(control) | async
|
|
"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
[currencyLable]="
|
|
getFormatterCurrencyLabel(control) | async
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
[stringFormatter]="
|
|
getFormatterStringFormatter(control) | async
|
|
"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[seperator]="getFormatterSeperator(control) | async"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="!(controlHasFormatter(control) | async)"
|
|
>
|
|
<input
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
hintRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Auto Complete -->
|
|
<div
|
|
[id]="getAutoCompleteId(control)"
|
|
[ngClass]="getAutoCompleteCssClass(control) | async"
|
|
[class.open]="getAutoCompleteOpened(control) | async"
|
|
*ngIf="
|
|
(controlHasAutoComplete(control) | async) &&
|
|
(hasChildValue(getAutoCompleteItems(control)) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngIf="
|
|
getControlAutoCompleteConfig(control)
|
|
| async as autoComplete
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngIf="getAutoCompleteItems(control) as items"
|
|
>
|
|
<x-list
|
|
[items]="items"
|
|
[showEmpty]="false"
|
|
[showToolbar]="false"
|
|
[wrapWithCard]="false"
|
|
[clickableItems]="true"
|
|
[uiDisabled]="uiDisabled"
|
|
[color]="getAutoCompleteColor(control) | async"
|
|
(itemSelected)="
|
|
handleAutoCompleteResultSelected(
|
|
control,
|
|
autoComplete,
|
|
$event
|
|
)
|
|
"
|
|
[itemTemplate]="
|
|
getAutoCompleteItemTemplate(control) | async
|
|
"
|
|
></x-list>
|
|
</ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 2- Select -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasSelectConfig(control) | async) &&
|
|
controlType === ControlTypes.Select
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- Not None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) !==
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- Mat Form Field -->
|
|
<mat-form-field
|
|
class="x-mat-form-field"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[appearance]="getControlAppearance(control) | async"
|
|
>
|
|
<!-- label -->
|
|
<mat-label
|
|
class="x-field-label"
|
|
*ngIf="notEmptyValue(getControlLabel(control)) | async"
|
|
>{{ getControlLabel(control) | async }}</mat-label
|
|
>
|
|
|
|
<!-- Select -->
|
|
<mat-select
|
|
[formControlName]="control.propName.toString()"
|
|
[multiple]="getSelectMultiple(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[class.multiple]="getSelectMultiple(control) | async"
|
|
[panelClass]="getSelectPanelClasses(control) | async"
|
|
[placeholder]="getControlPlaceHolder(control) | async"
|
|
>
|
|
<mat-option
|
|
[value]="getValue(option.value) | async"
|
|
[ngClass]="getOptionClassName(option) | async"
|
|
*ngFor="
|
|
let option of getSelectOptions(control) | async
|
|
"
|
|
>
|
|
{{ getResourceValue(option.viewValue) | async }}
|
|
</mat-option>
|
|
</mat-select>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Prefix Icon -->
|
|
<span
|
|
matPrefix
|
|
*ngIf="controlHasPrefixIcon(control) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</span>
|
|
|
|
<!-- Suffix Icon -->
|
|
<span
|
|
matSuffix
|
|
*ngIf="controlHasSuffixIcon(control) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</span>
|
|
</mat-form-field>
|
|
</ng-container>
|
|
|
|
<!-- None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) ===
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
byIconLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Select -->
|
|
<mat-select
|
|
[formControlName]="control.propName.toString()"
|
|
[multiple]="getSelectMultiple(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[class.multiple]="getSelectMultiple(control) | async"
|
|
[panelClass]="getSelectPanelClasses(control) | async"
|
|
[placeholder]="getControlPlaceHolder(control) | async"
|
|
>
|
|
<mat-option
|
|
[value]="getValue(option.value) | async"
|
|
[ngClass]="getOptionClassName(option) | async"
|
|
*ngFor="
|
|
let option of getSelectOptions(control) | async
|
|
"
|
|
>
|
|
{{ getResourceValue(option.viewValue) | async }}
|
|
</mat-option>
|
|
</mat-select>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 3- Radio Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasRadioConfig(control) | async) &&
|
|
controlType === ControlTypes.Radio
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
byIconLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Content -->
|
|
<mat-radio-group
|
|
[formControlName]="control.propName.toString()"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[labelPosition]="getRadioLabelPosition(control) | async"
|
|
>
|
|
<mat-radio-button
|
|
#radioButton
|
|
class="x-radio-button"
|
|
[class.active]="radioButton.checked"
|
|
[value]="getValue(option.value) | async"
|
|
[ngClass]="getOptionClassName(option) | async"
|
|
*ngFor="let option of getRadioOptions(control) | async"
|
|
>
|
|
{{ getResourceValue(option.viewValue) | async }}
|
|
</mat-radio-button>
|
|
</mat-radio-group>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 4- Checkbox Type -->
|
|
<ng-container *ngIf="controlType === ControlTypes.CheckBox">
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
>
|
|
<!-- Content -->
|
|
<x-slotter
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasStartOrTopSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasPrefixIcon(control) | async)
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasSuffixIcon(control) | async)
|
|
"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<mat-checkbox
|
|
[formControlName]="control.propName.toString()"
|
|
[labelPosition]="
|
|
getCheckboxLabelPosition(control) | async
|
|
"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[class.has-icon]="controlHasIcons(control) | async"
|
|
(change)="
|
|
handleCheckboxCheckedChange(control, $event.checked)
|
|
"
|
|
>
|
|
<!-- label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultFieldLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</mat-checkbox>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 5- Toggle Type -->
|
|
<ng-container *ngIf="controlType === ControlTypes.Toggle">
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
>
|
|
<!-- Content -->
|
|
<x-slotter
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasStartOrTopSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasPrefixIcon(control) | async)
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasSuffixIcon(control) | async)
|
|
"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<!-- Content -->
|
|
<mat-slide-toggle
|
|
[formControlName]="control.propName.toString()"
|
|
[labelPosition]="
|
|
getToggleLabelPosition(control) | async
|
|
"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[class.has-icon]="controlHasIcons(control) | async"
|
|
>
|
|
<!-- label -->
|
|
<mat-label
|
|
class="x-field-label"
|
|
*ngIf="
|
|
notEmptyValue(getControlLabel(control)) | async
|
|
"
|
|
>
|
|
{{ getControlLabel(control) | async }}
|
|
</mat-label>
|
|
</mat-slide-toggle>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 6- Slider Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasSliderConfig(control) | async) &&
|
|
controlType === ControlTypes.Slider
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
byIconLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Content -->
|
|
<!-- [disabled]="getControlDisabled(control) | async" -->
|
|
<mat-slider
|
|
[formControlName]="control.propName.toString()"
|
|
[min]="getSliderMin(control) | async"
|
|
[max]="getSliderMax(control) | async"
|
|
[step]="getSliderStep(control) | async"
|
|
[invert]="getSliderInvert(control) | async"
|
|
[vertical]="isSliderVertical(control) | async"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[displayWith]="getSliderFormatter(control) | async"
|
|
[thumbLabel]="showSliderThumbLabel(control) | async"
|
|
[class.vertical]="isSliderVertical(control) | async"
|
|
>
|
|
</mat-slider>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 7- Date Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasDateConfig(control) | async) &&
|
|
controlType === ControlTypes.Date
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- Not None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) !==
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- Form Field -->
|
|
<mat-form-field
|
|
class="x-mat-form-field"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[appearance]="getControlAppearance(control) | async"
|
|
>
|
|
<!-- label -->
|
|
<mat-label
|
|
class="x-field-label"
|
|
*ngIf="notEmptyValue(getControlLabel(control)) | async"
|
|
>{{ getControlLabel(control) | async }}</mat-label
|
|
>
|
|
|
|
<!-- Date Input -->
|
|
<input
|
|
matInput
|
|
autocomplete="off"
|
|
[matDatepicker]="dp"
|
|
[formControlName]="control.propName.toString()"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerInputDisabled(control) | async)
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[matDatepickerFilter]="getDateFilter(control) | async"
|
|
[placeholder]="getControlPlaceHolder(control) | async"
|
|
(dateInput)="
|
|
handleDatePickerDateInput(control.propName.toString(), $event)
|
|
"
|
|
(dateChange)="
|
|
handleDatePickerDateChange(control.propName.toString(), $event)
|
|
"
|
|
/>
|
|
|
|
<!-- Date Toggler Icon -->
|
|
<!-- Prefix -->
|
|
<mat-datepicker-toggle
|
|
[for]="dp"
|
|
matPrefix
|
|
[disabled]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerToggleDisabled(control) | async)
|
|
"
|
|
*ngIf="isDatePickerHasPrefixIcon(control) | async"
|
|
>
|
|
<x-icon
|
|
[selectable]="true"
|
|
matDatepickerToggleIcon
|
|
class="x-date-picker-icon"
|
|
[name]="getDatePickerIcon(control) | async"
|
|
[color]="getDatePickerIconColor(control) | async"
|
|
[matTooltip]="
|
|
getDatePickerIconTooltip(control) | async
|
|
"
|
|
[class.x-status-handler]="
|
|
getDatePickerIconApplyStateColor(control) | async
|
|
"
|
|
>
|
|
</x-icon>
|
|
</mat-datepicker-toggle>
|
|
|
|
<!-- Suffix -->
|
|
<mat-datepicker-toggle
|
|
[for]="dp"
|
|
matSuffix
|
|
[disabled]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerToggleDisabled(control) | async)
|
|
"
|
|
*ngIf="isDatePickerHasSuffixIcon(control) | async"
|
|
>
|
|
<x-icon
|
|
[selectable]="true"
|
|
[color]="'cb-inherit'"
|
|
matDatepickerToggleIcon
|
|
class="x-date-picker-icon"
|
|
[name]="getDatePickerIcon(control) | async"
|
|
[color]="getDatePickerIconColor(control) | async"
|
|
[matTooltip]="
|
|
getDatePickerIconTooltip(control) | async
|
|
"
|
|
[class.x-status-handler]="
|
|
getDatePickerIconApplyStateColor(control) | async
|
|
"
|
|
>
|
|
</x-icon>
|
|
</mat-datepicker-toggle>
|
|
|
|
<!-- Date Picker Component -->
|
|
<mat-datepicker
|
|
#dp
|
|
[touchUi]="isMobileUi$ | async"
|
|
[startAt]="getDateStartAt(control) | async"
|
|
[disabled]="getControlDisabled(control) | async"
|
|
[ngClass]="getDatePickerClasses(control) | async"
|
|
[panelClass]="getDatePickerClasses(control) | async"
|
|
></mat-datepicker>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</mat-form-field>
|
|
</ng-container>
|
|
|
|
<!-- None Appearance -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlAppearanceObject(control) | async) ===
|
|
FormControlAppearances.None
|
|
"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
byIconLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Content -->
|
|
<x-slotter
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[centerSlotCssClass]="'full-heigh'"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
[hasStartOrTopSlot]="
|
|
isDatePickerHasPrefixIcon(control) | async
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
isDatePickerHasSuffixIcon(control) | async
|
|
"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Date Toggler Icon -->
|
|
<!-- Prefix -->
|
|
<mat-datepicker-toggle
|
|
[for]="dp"
|
|
matPrefix
|
|
[disabled]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerToggleDisabled(control) | async)
|
|
"
|
|
*ngIf="isDatePickerHasPrefixIcon(control) | async"
|
|
>
|
|
<x-icon
|
|
[selectable]="true"
|
|
matDatepickerToggleIcon
|
|
class="x-date-picker-icon"
|
|
[name]="getDatePickerIcon(control) | async"
|
|
[color]="getDatePickerIconColor(control) | async"
|
|
[matTooltip]="
|
|
getDatePickerIconTooltip(control) | async
|
|
"
|
|
[class.x-status-handler]="
|
|
getDatePickerIconApplyStateColor(control)
|
|
| async
|
|
"
|
|
>
|
|
</x-icon>
|
|
</mat-datepicker-toggle>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<!-- Date Input -->
|
|
<input
|
|
matInput
|
|
autocomplete="off"
|
|
[matDatepicker]="dp"
|
|
(dateInput)="
|
|
handleDatePickerDateInput(
|
|
control.propName.toString(),
|
|
$event
|
|
)
|
|
"
|
|
(dateChange)="
|
|
handleDatePickerDateChange(
|
|
control.propName.toString(),
|
|
$event
|
|
)
|
|
"
|
|
[matDatepickerFilter]="
|
|
getDateFilter(control) | async
|
|
"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerInputDisabled(control) | async)
|
|
"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
/>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Date Toggler Icon -->
|
|
<!-- Suffix -->
|
|
<mat-datepicker-toggle
|
|
[for]="dp"
|
|
matSuffix
|
|
[disabled]="
|
|
(getControlDisabled(control) | async) ||
|
|
(isDatePickerToggleDisabled(control) | async)
|
|
"
|
|
*ngIf="isDatePickerHasSuffixIcon(control) | async"
|
|
>
|
|
<x-icon
|
|
[selectable]="true"
|
|
[color]="'cb-inherit'"
|
|
matDatepickerToggleIcon
|
|
class="x-date-picker-icon"
|
|
[name]="getDatePickerIcon(control) | async"
|
|
[color]="getDatePickerIconColor(control) | async"
|
|
[matTooltip]="
|
|
getDatePickerIconTooltip(control) | async
|
|
"
|
|
[class.x-status-handler]="
|
|
getDatePickerIconApplyStateColor(control)
|
|
| async
|
|
"
|
|
>
|
|
</x-icon>
|
|
</mat-datepicker-toggle>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Date Picker Component -->
|
|
<mat-datepicker
|
|
#dp
|
|
[touchUi]="isMobileUi$ | async"
|
|
[startAt]="getDateStartAt(control) | async"
|
|
[disabled]="getControlDisabled(control) | async"
|
|
[ngClass]="getDatePickerClasses(control) | async"
|
|
[panelClass]="getDatePickerClasses(control) | async"
|
|
></mat-datepicker>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 8- Hidden Type -->
|
|
<ng-container *ngIf="controlType === ControlTypes.Hidden">
|
|
<input
|
|
type="hidden"
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- 9- Markdown Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasMarkdownConfig(control) | async) &&
|
|
controlType === ControlTypes.MarkDown
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
markdownRef;
|
|
context: {
|
|
$implicit: control,
|
|
controlIndex: controlIndex
|
|
}
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 10- Avatar Upload -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasAvatarConfig(control) | async) &&
|
|
controlType === ControlTypes.AvatarUpload
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
avatarRef;
|
|
context: {
|
|
$implicit: control,
|
|
controlIndex: controlIndex
|
|
}
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 11- Map Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasMapConfig(control) | async) &&
|
|
controlType === ControlTypes.Map
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultFieldLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Control Input Element -->
|
|
<x-slotter
|
|
[hasStartOrTopSlot]="true"
|
|
[hasEndOrBottomSlot]="true"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Prefix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Prefix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="controlHasFormatter(control) | async"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[seperator]="getFormatterSeperator(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisableInput(control) | async) ||
|
|
(getControlDisabled(control) | async)
|
|
"
|
|
[inputFormatterType]="
|
|
getFormatterType(control) | async
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[currencyLable]="
|
|
getFormatterCurrencyLabel(control) | async
|
|
"
|
|
[enabledInputFormatter]="
|
|
controlHasFormatter(control) | async
|
|
"
|
|
[stringFormatter]="
|
|
getFormatterStringFormatter(control) | async
|
|
"
|
|
[stringInputFormatterType]="
|
|
getFormatterInputType(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="!(controlHasFormatter(control) | async)"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisableInput(control) | async) ||
|
|
(getControlDisabled(control) | async)
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Suffix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Suffix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Content -->
|
|
<ng-container
|
|
*ngIf="!(isMapPresentWithDialog(control) | async)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
mapContentRef;
|
|
context: { $implicit: control }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 12- ColorPicker Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasColorPickerConfig(control) | async) &&
|
|
controlType === ControlTypes.ColorPicker
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultFieldLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Control Input Element -->
|
|
<x-slotter
|
|
[hasStartOrTopSlot]="true"
|
|
[hasEndOrBottomSlot]="true"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Prefix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Prefix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<div fxLayout="row" fxLayoutAlign="none">
|
|
<!-- Input Box -->
|
|
<div fxFlex>
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="controlHasFormatter(control) | async"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[xFocus]="
|
|
getControlFocusHandler(control) | async
|
|
"
|
|
[matTooltip]="
|
|
getControlTooltip(control) | async
|
|
"
|
|
[seperator]="
|
|
getFormatterSeperator(control) | async
|
|
"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisableInput(control) | async) ||
|
|
(getControlDisabled(control) | async)
|
|
"
|
|
[inputFormatterType]="
|
|
getFormatterType(control) | async
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[currencyLable]="
|
|
getFormatterCurrencyLabel(control) | async
|
|
"
|
|
[enabledInputFormatter]="
|
|
controlHasFormatter(control) | async
|
|
"
|
|
[stringFormatter]="
|
|
getFormatterStringFormatter(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(getControlDisableInput(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
[stringInputFormatterType]="
|
|
getFormatterInputType(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="!(controlHasFormatter(control) | async)"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[xFocus]="
|
|
getControlFocusHandler(control) | async
|
|
"
|
|
[matTooltip]="
|
|
getControlTooltip(control) | async
|
|
"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisableInput(control) | async) ||
|
|
(getControlDisabled(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Color Preview -->
|
|
<div
|
|
*ngIf="
|
|
isColorPickerPresentWithDialog(control) | async
|
|
"
|
|
>
|
|
<x-color
|
|
[size]="22"
|
|
[showLabel]="false"
|
|
[value]="{
|
|
key: 'color',
|
|
value: getControl(control.propName.toString()).value
|
|
}"
|
|
[borderWidth]="
|
|
getColorPickerColorViewBorderWidth(control)
|
|
| async
|
|
"
|
|
[borderStyle]="
|
|
getColorPickerColorViewBorderStyle(control)
|
|
| async
|
|
"
|
|
[borderColor]="
|
|
getColorPickerColorViewBorderColor(control)
|
|
| async
|
|
"
|
|
></x-color>
|
|
</div>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Suffix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Suffix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Content -->
|
|
<ng-container
|
|
*ngIf="!(isColorPickerPresentWithDialog(control) | async)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
colorPickerContentRef;
|
|
context: { $implicit: control }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- 13- Selector Type -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasSelectorConfig(control) | async) &&
|
|
controlType === ControlTypes.Selector
|
|
"
|
|
>
|
|
<!-- Form Control Wrapper -->
|
|
<div
|
|
[hidden]="getControlHidden(control) | async"
|
|
[class.show]="!(getControlHidden(control) | async)"
|
|
[ngClass]="getFormControlWrapperClasses(control) | async"
|
|
[class.readonly]="isInputControlReadOnly(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[enableHandler]="
|
|
!uiDisabled &&
|
|
!loading &&
|
|
!(getControlDisabled(control) | async)
|
|
"
|
|
[class.apply-status]="
|
|
getValue(applyStatusOnControls) | async
|
|
"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultFieldLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Control Input Element -->
|
|
<x-slotter
|
|
[hasStartOrTopSlot]="true"
|
|
[hasEndOrBottomSlot]="true"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
prefixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Prefix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Prefix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="controlHasFormatter(control) | async"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[seperator]="getFormatterSeperator(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(getControlDisableInput(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
[inputFormatterType]="
|
|
getFormatterType(control) | async
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
[currencyLable]="
|
|
getFormatterCurrencyLabel(control) | async
|
|
"
|
|
[enabledInputFormatter]="
|
|
controlHasFormatter(control) | async
|
|
"
|
|
[stringFormatter]="
|
|
getFormatterStringFormatter(control) | async
|
|
"
|
|
[stringInputFormatterType]="
|
|
getFormatterInputType(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container
|
|
*ngIf="!(controlHasFormatter(control) | async)"
|
|
>
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[placeholder]="
|
|
getControlPlaceHolder(control) | async
|
|
"
|
|
[readonly]="
|
|
(getControlDisabled(control) | async) ||
|
|
(getControlDisableInput(control) | async) ||
|
|
(isInputControlReadOnly(control) | async)
|
|
"
|
|
[ngClass]="
|
|
getControlInputElementClasses(control) | async
|
|
"
|
|
/>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
suffixIconRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Action Suffix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Suffix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
loadingRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
errorsRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</form>
|
|
|
|
<!-- Custom Content -->
|
|
<ng-content select="[contents]"></ng-content>
|
|
|
|
<!-- Form Error Handlers -->
|
|
<div
|
|
[ngClass]="getFormErrorsClasses() | async"
|
|
*ngIf="errors && (formHasErrorHandlers() | async)"
|
|
>
|
|
<!-- Errors -->
|
|
<ng-container *ngIf="getFormErrorHandlers() | async as errorHandlers">
|
|
<mat-error
|
|
*ngFor="let handler of errorHandlers"
|
|
[class.show]="formHasError(handler) | async"
|
|
[ngClass]="getFormErrorClasses(handler) | async"
|
|
>
|
|
<span class="x-error-message">
|
|
{{ getErrorHandlerErrorMessage(handler) | async }}
|
|
</span>
|
|
</mat-error>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- 9- MarkDown Template -->
|
|
<ng-template #markdownRef let-control let-controlIndex="controlIndex">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
xFormFieldRef;
|
|
context: {
|
|
$implicit: control,
|
|
controlIndex: controlIndex,
|
|
fieldLabelRef: byIconLabelRef,
|
|
fieldContentRef: markdownContentRef
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- 10 -Avatar Template -->
|
|
<ng-template #avatarRef let-control let-controlIndex="controlIndex">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
xFormFieldRef;
|
|
context: {
|
|
$implicit: control,
|
|
controlIndex: controlIndex,
|
|
fieldLabelRef: defaultFieldLabelRef,
|
|
fieldContentRef: avatarContentRef
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- //#region Templates -->
|
|
<!-- MarkDown Content Template -->
|
|
<ng-template #markdownContentRef let-control>
|
|
<!-- Markdown Component -->
|
|
<x-markdown
|
|
[mode]="getMarkdownMode(control) | async"
|
|
[isInPage]="isMarkdownInPage(control) | async"
|
|
[content]="getMarkDownContent(control) | async"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
[cssClass]="getMarkdownCssClass(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[cardTitle]="getMarkdownCardTitle(control) | async"
|
|
[cardColor]="getMarkdownCardColor(control) | async"
|
|
[toolbarForegroundColor]="
|
|
getMarkDownToolbarForegroundColor(control) | async
|
|
"
|
|
[hasToolbar]="getMarkDownHasToolbar(control) | async"
|
|
[wrapWithCard]="isMarkdownWrapWithCard(control) | async"
|
|
[cardSubTitle]="getMarkdownCardSubTitle(control) | async"
|
|
[toolbarColor]="getMarkDownToolbarColor(control) | async"
|
|
[toolbarConfig]="getMarkdownToolbarConfig(control) | async"
|
|
[actionProvider]="getMarkdownActionProvider(control) | async"
|
|
[editorBoxColor]="getMarkdownEditorBoxColor(control) | async"
|
|
[previewBoxColor]="getMarkdownPreviewBoxColor(control) | async"
|
|
[toolbarCssClass]="getMarkdownToolbarCssClass(control) | async"
|
|
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
|
|
[cardForegroundColor]="getMarkdownCardForegroundColor(control) | async"
|
|
(contentChange)="handleMarkDownContentChanged(control.propName.toString(), $event)"
|
|
></x-markdown>
|
|
</ng-template>
|
|
|
|
<!-- Avatar Content Template -->
|
|
<ng-template #avatarContentRef let-control>
|
|
<!-- Avatar Upload -->
|
|
<x-avatar-upload
|
|
[color]="getAvatarColor(control) | async"
|
|
[isInPage]="isAvatarInPage(control) | async"
|
|
[actions]="getAvatarActions(control) | async"
|
|
[cssClass]="getAvatarCssClass(control) | async"
|
|
[cardColor]="getAvatarCardColor(control) | async"
|
|
[cardTitle]="getAvatarCardTitle(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[fileDropAreaForegroundColor]="
|
|
isAvatarDropAreaForegroundColor(control) | async
|
|
"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[fileDropAreaActionProvider]="
|
|
getAvatarDropAreaActionProvider(control) | async
|
|
"
|
|
[fileDropAreaDisableFileCheck]="
|
|
isAvatarDropAreaDisableFileCheck(control) | async
|
|
"
|
|
[fileDropAreaContentTemplate]="
|
|
getAvatarDropAreaContentTemplate(control) | async
|
|
"
|
|
[notAllowedFileException]="
|
|
getAvatarNotAllowedFileException(control) | async
|
|
"
|
|
[fileDropAreaAllowedExtensions]="
|
|
getAvatarDropAreaAllowedExtensions(control) | async
|
|
"
|
|
[wrapWithCard]="isAvatarWrapWithCard(control) | async"
|
|
[fileDropAreaCardForegroundColor]="
|
|
isAvatarDropAreaCardForegroundColor(control) | async
|
|
"
|
|
[cardSubTitle]="getAvatarCardSubTitle(control) | async"
|
|
[minAllowedFileSizeException]="
|
|
getAvatarMinAllowedFileSizeException(control) | async
|
|
"
|
|
[cardShowFooter]="avatarCardShowFooter(control) | async"
|
|
[maxAllowedFileSizeException]="
|
|
getAvatarMaxAllowedFileSizeException(control) | async
|
|
"
|
|
[fileDropAreaSupportsMultipleFiles]="
|
|
isAvatarDropAreaSupportsMultipleFiles(control) | async
|
|
"
|
|
(avatarChange)="handleAvatarAvatarChange(control, $event)"
|
|
[actionProvider]="getAvatarActionProvider(control) | async"
|
|
[fileDropAreaIcon]="getAvatarDropAreaIcon(control) | async"
|
|
[foregroundColor]="isAvatarForegroundColor(control) | async"
|
|
(fileDropAreaFilesChangeEmiter)="
|
|
handleAvatarFileDropAreaFilesChangeEmitter(control, $event)
|
|
"
|
|
[fileDropAreaColor]="getAvatarDropAreaColor(control) | async"
|
|
[fileDropAreaIsInPage]="isAvatarDropAreaInPage(control) | async"
|
|
[fileDropAreaMessage]="getAvatarDropAreaMessage(control) | async"
|
|
[allowedExtensions]="getAvatarAllowedExtensions(control) | async"
|
|
[placeHolderAvatar]="getAvatarPlaceHolderAvatar(control) | async"
|
|
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
|
|
[fileDropAreaCssClass]="getAvatarDropAreaCssClass(control) | async"
|
|
[emptyFileException]="getAvatarEmptyFileException(control) | async"
|
|
[minAllowedFileSize]="getAvatarMinAllowedFileSize(control) | async"
|
|
[maxAllowedFileSize]="getAvatarMaxAllowedFileSize(control) | async"
|
|
[cardForegroundColor]="isAvatarCardForegroundColor(control) | async"
|
|
[fileDropAreaCardColor]="getAvatarDropAreaCardColor(control) | async"
|
|
[fileDropAreaCardTitle]="getAvatarDropAreaCardTitle(control) | async"
|
|
[fileDropAreaErrorColor]="getAvatarDropAreaErrorColor(control) | async"
|
|
[fileDropAreaWrapWithCard]="isAvatarDropAreaWrapWithCard(control) | async"
|
|
[fileDropAreaDragDisabled]="isAvatarDropAreaDragDisabled(control) | async"
|
|
[fileDropAreaAccentColor]="getAvatarDropAreaAccesntColor(control) | async"
|
|
[fileDropAreaSuccessColor]="getAvatarDropAreaSuccessColor(control) | async"
|
|
[fileDropAreaCardSubTitle]="getAvatarDropAreaCardSubTitle(control) | async"
|
|
[fileDropAreaCardShowFooter]="avatarDropAreaCardShowFooter(control) | async"
|
|
[showFileDropArea]="
|
|
!(isMobileUi$ | async) && (avatarCanDrop(control) | async)
|
|
"
|
|
>
|
|
</x-avatar-upload>
|
|
</ng-template>
|
|
|
|
<!-- Map Content Template -->
|
|
<ng-template #mapContentRef let-control>
|
|
<!-- Map Component -->
|
|
<x-map
|
|
[zoom]="getMapZoom(control) | async"
|
|
[loading]="getValue(loading) | async"
|
|
(isReady)="handleMapIsReady(control)"
|
|
[isInPage]="isMapInPage(control) | async"
|
|
[showZoom]="mapShowZoom(control) | async"
|
|
[canSelect]="mapCanSelect(control) | async"
|
|
[cssClass]="getMapCssClass(control) | async"
|
|
[latitude]="getMapLatitude(control) | async"
|
|
[showRotate]="mapShowRotate(control) | async"
|
|
[showLocator]="mapShowLocator(control) | async"
|
|
[cardTitle]="getMapCardTitle(control) | async"
|
|
[longitude]="getMapLongitude(control) | async"
|
|
[cardColor]="getMapCardColor(control) | async"
|
|
[searchBarCancelButtonIcon]="
|
|
getMapSearchBarCancelButtonIcon(control) | async
|
|
"
|
|
*ngIf="!(isMapPresentWithDialog(control) | async)"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[markerStyle]="getMapMarkerStyle(control) | async"
|
|
[wrapWithCard]="isMapWrapWithCard(control) | async"
|
|
[showSearchBar]="mapShowSearchBar(control) | async"
|
|
[searchBarCancelButtonTitle]="
|
|
getMapSearchBarCancelButtonTitle(control) | async
|
|
"
|
|
[cardSubTitle]="getMapCardSubTitle(control) | async"
|
|
[cardShowFooter]="mapCardShowFooter(control) | async"
|
|
[showZoomSlider]="mapShowZoomSlider(control) | async"
|
|
[searchBarType]="getMapSearchBarType(control) | async"
|
|
[showClearMarker]="mapShowClearMarker(control) | async"
|
|
[showProgressBar]="mapShowProgressBar(control) | async"
|
|
[actionProvider]="getMapActionProvider(control) | async"
|
|
[searchBarColor]="getMapSearchBarColor(control) | async"
|
|
[searchBarValue]="getMapSearchBarValue(control) | async"
|
|
[searchBarTitle]="getMapSearchBarTitle(control) | async"
|
|
[locatorPosition]="getMapLocatorPosition(control) | async"
|
|
[showGoMarkedPlace]="mapShowGoMarkedPlace(control) | async"
|
|
[progressBarColor]="getMapProgressBarColor(control) | async"
|
|
[searchBarForegroundSearchInputColor]="
|
|
getMapSearchBarForegroundSearchInputColor(control) | async
|
|
"
|
|
[searchBarDebounce]="getMapSearchBarDebounce(control) | async"
|
|
[searchBarCssClass]="getMapSearchBarCssClass(control) | async"
|
|
[searchBarPosition]="getMapSearchBarPosition(control) | async"
|
|
(locationSelected)="handleMapLocationSelected(control, $event)"
|
|
[cardForegroundColor]="isMapCardForegroundColor(control) | async"
|
|
[showSelectedLocation]="mapShowSelectedLocation(control) | async"
|
|
[searchPlaceProvider]="getMapSearchPlaceProvider(control) | async"
|
|
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
|
|
[clearMarkerPosition]="getMapClearMarkerPosition(control) | async"
|
|
[searchPlaceProvider]="getMapSearchPlaceProvider(control) | async"
|
|
[searchBarSpellcheck]="getMapSearchBarSpellcheck(control) | async"
|
|
[searchBarSearchInputColor]="
|
|
getMapSearchBarSearchInputColor(control) | async
|
|
"
|
|
[progressBarPosition]="getMapProgressBarPosition(control) | async"
|
|
[searchResultListColor]="getMapSearchResultListColor(control) | async"
|
|
(searchBarQueryChange)="handleMapSearchBarQueryChange(control, $event)"
|
|
[searchBarActionProvider]="getMapSearchBarActionProvider(control) | async"
|
|
[searchBarShowCancelButton]="mapShowSearchBarCancelButton(control) | async"
|
|
[searchBarClearButtonIcon]="getMapSearchBarClearButtonIcon(control) | async"
|
|
[searchBarForegroundColor]="getMapSearchBarForegroundColor(control) | async"
|
|
[selectedLocationPosition]="getMapSelectedLocationPosition(control) | async"
|
|
[searchBarClearButtonIconColor]="
|
|
getMapSearchBarClearButtonIconColor(control) | async
|
|
"
|
|
[searchBarSearchButtonIconColor]="
|
|
getMapSearchBarSearchButtonIconColor(control) | async
|
|
"
|
|
>
|
|
</x-map>
|
|
<!-- (zoomChanged)="handleMapZoomChanged(control, $event)" -->
|
|
</ng-template>
|
|
|
|
<!-- ColorPicker Content Template -->
|
|
<ng-template #colorPickerContentRef let-control>
|
|
<!-- ColorPicker Component -->
|
|
<x-color-picker
|
|
[color]="getColorPickerColor(control) | async"
|
|
[isInPage]="isColorPickerInPage(control) | async"
|
|
[ngClass]="getFormControlClasses(control) | async"
|
|
[cssClass]="getColorPickerCssClass(control) | async"
|
|
[cardColor]="getColorPickerCardColor(control) | async"
|
|
[showSelectedColorPreview]="
|
|
colorPickerShowSelectedColorPreview(control) | async
|
|
"
|
|
[cardTitle]="getColorPickerCardTitle(control) | async"
|
|
[representColorFormats]="
|
|
getColorPickerRepresentColorFormats(control) | async
|
|
"
|
|
[presetColorsLableColor]="
|
|
getColorPickerPresetColorsLableColor(control) | async
|
|
"
|
|
[copyToClipboardIconColor]="
|
|
getColorPickerCopyToClipboardIconColor(control) | async
|
|
"
|
|
[copyToClipboardIconLabel]="
|
|
getColorPickerCopyToClipboardIconLabel(control) | async
|
|
"
|
|
[cursorColor]="getColorPickerCursorColor(control) | async"
|
|
*ngIf="!(isColorPickerPresentWithDialog(control) | async)"
|
|
[wrapWithCard]="isColorPickerWrapWithCard(control) | async"
|
|
[cardSubTitle]="getColorPickerCardSubTitle(control) | async"
|
|
[presetColors]="getColorPickerPresetColors(control) | async"
|
|
[outputFormat]="getColorPickerOutputFormat(control) | async"
|
|
[cardShowFooter]="colorPickercardShowFooter(control) | async"
|
|
[showHueChannel]="colorPickerShowHueChannel(control) | async"
|
|
[showColorValue]="colorPickerShowColorValue(control) | async"
|
|
[showColorInput]="colorPickerShowColorInput(control) | async"
|
|
[selectedColor]="getColorPickerSelectedColor(control) | async"
|
|
[actionProvider]="getColorPickerActionProvider(control) | async"
|
|
[colorTextColor]="getColorPickerColorTextColor(control) | async"
|
|
[foregroundColor]="isColorPickerForegroundColor(control) | async"
|
|
[showPresetColors]="colorPickerShowPresetColors(control) | async"
|
|
[showAlphaChannel]="colorPickerShowAlphaChannel(control) | async"
|
|
(colorSelected)="handleColorPickerColorSelected(control, $event)"
|
|
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
|
|
[showPaletteChannel]="colorPickerShowPaletteChannel(control) | async"
|
|
[presetColorsLable]="getColorPickerPresetColorsLable(control) | async"
|
|
[showCopyToClipboard]="colorPickerShowCopyToClipboard(control) | async"
|
|
[cardForegroundColor]="isColorPickerCardForegroundColor(control) | async"
|
|
[clearColorIconColor]="getColorPickerClearColorIconColor(control) | async"
|
|
[clearColorIconLabel]="getColorPickerClearColorIconLabel(control) | async"
|
|
[colorInputIconColor]="getColorPickerColorInputIconColor(control) | async"
|
|
[colorInputIconLabel]="getColorPickerColorInputIconLabel(control) | async"
|
|
>
|
|
</x-color-picker>
|
|
</ng-template>
|
|
<!-- //#endregion -->
|
|
|
|
<!-- By Icon Label Template -->
|
|
<ng-template #byIconLabelRef let-control>
|
|
<!-- Label and Icons -->
|
|
<x-slotter
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasStartOrTopSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasPrefixIcon(control) | async)
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasSuffixIcon(control) | async)
|
|
"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<!-- label -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultFieldLabelRef;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</ng-template>
|
|
|
|
<!-- By Icon Label Template -->
|
|
<ng-template #byIconContentRef let-control let-contentRef="contentRef">
|
|
<!-- Label and Icons -->
|
|
<x-slotter
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasStartOrTopSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasPrefixIcon(control) | async)
|
|
"
|
|
[hasEndOrBottomSlot]="
|
|
(controlHasIcons(control) | async) &&
|
|
(controlHasSuffixIcon(control) | async)
|
|
"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<ng-container *ngIf="contentRef">
|
|
<ng-container
|
|
*ngTemplateOutlet="contentRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</ng-template>
|
|
|
|
<!-- Prefix Icon Template -->
|
|
<ng-template #prefixIconRef let-control>
|
|
<!-- Prefix Icon -->
|
|
<x-icon
|
|
matPrefix
|
|
[name]="getControlIconName(icon) | async"
|
|
(clicked)="handleControlIconClicked(icon)"
|
|
[color]="getControlIconColor(icon) | async"
|
|
[matTooltip]="getControlIconTooltip(icon) | async"
|
|
*ngIf="getControlPrefixIcon(control) | async as icon"
|
|
[clickable]="notNullOrUndefinedValue(icon.handler) | async"
|
|
[uiDisabled]="(getValue(uiDisabled) | async) && !icon.handler"
|
|
[class.x-status-handler]="getControlIconApplyStateColor(icon) | async"
|
|
>
|
|
</x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Suffix Icon Template -->
|
|
<ng-template #suffixIconRef let-control>
|
|
<!-- Suffix Icon -->
|
|
<x-icon
|
|
matSuffix
|
|
[name]="getControlIconName(icon) | async"
|
|
(clicked)="handleControlIconClicked(icon)"
|
|
[color]="getControlIconColor(icon) | async"
|
|
[matTooltip]="getControlIconTooltip(icon) | async"
|
|
*ngIf="getControlSuffixIcon(control) | async as icon"
|
|
[clickable]="notNullOrUndefinedValue(icon.handler) | async"
|
|
[uiDisabled]="(getValue(uiDisabled) | async) && !icon.handler"
|
|
[class.x-status-handler]="getControlIconApplyStateColor(icon) | async"
|
|
>
|
|
</x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Loading Ref Template -->
|
|
<ng-template #loadingRef let-control>
|
|
<ion-progress-bar
|
|
type="indeterminate"
|
|
[color]="getProgressBarColor(control) | async"
|
|
*ngIf="
|
|
(controlHasProgressBar(control) | async) &&
|
|
getControlStatus(control) === FormStatuses.Pending
|
|
"
|
|
></ion-progress-bar>
|
|
</ng-template>
|
|
|
|
<!-- Hint Template -->
|
|
<ng-template #hintRef let-control>
|
|
<mat-hint
|
|
[ngClass]="getFormControlHintClasses(control) | async"
|
|
*ngIf="notEmptyValue(getControlHint(control) | async) | async"
|
|
>{{ getControlHint(control) | async }}</mat-hint
|
|
>
|
|
</ng-template>
|
|
|
|
<!-- Errors Ref Template -->
|
|
<ng-template #errorsRef let-control>
|
|
<div
|
|
*ngIf="
|
|
(controlHasErrors(control) | async) &&
|
|
(controlHasErrorHandlers(control) | async)
|
|
"
|
|
[ngClass]="getControlErrorsClasses(control) | async"
|
|
>
|
|
<ng-container
|
|
*ngIf="getControlErrorHandlers(control) | async as errorHandlers"
|
|
>
|
|
<mat-error
|
|
*ngFor="let handler of errorHandlers"
|
|
[class.show]="controlHasError(control, handler) | async"
|
|
[ngClass]="getControlErrorClasses(control, handler) | async"
|
|
>
|
|
<span class="x-error-message">
|
|
{{ getErrorHandlerErrorMessage(handler, control) | async }}
|
|
</span>
|
|
</mat-error>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- XFormField Template -->
|
|
<ng-template
|
|
#xFormFieldRef
|
|
let-control
|
|
let-controlIndex="controlIndex"
|
|
let-fieldLabelRef="fieldLabelRef"
|
|
let-fieldInputRef="fieldInputRef"
|
|
let-fieldContentRef="fieldContentRef"
|
|
>
|
|
<!-- XForm Field -->
|
|
<div
|
|
xFocusHandler
|
|
[tabIndex]="controlIndex"
|
|
[ngClass]="getFormFieldClasses(control) | async"
|
|
[class.apply-status]="getValue(applyStatusOnControls) | async"
|
|
[enableHandler]="
|
|
!uiDisabled && !loading && !(getControlDisabled(control) | async)
|
|
"
|
|
>
|
|
<!-- Label -->
|
|
<ng-container *ngIf="fieldLabelRef">
|
|
<div [ngClass]="getFormControlFieldLabelClasses(control) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="fieldLabelRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
|
|
<!-- Input -->
|
|
<ng-container *ngIf="fieldInputRef">
|
|
<ng-container
|
|
*ngTemplateOutlet="fieldInputRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Show hint in below of input if exists -->
|
|
<ng-container *ngIf="fieldInputRef">
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="loadingRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Content -->
|
|
<ng-container
|
|
*ngTemplateOutlet="fieldContentRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Show hint in below of content when input not exists -->
|
|
<ng-container *ngIf="!fieldInputRef">
|
|
<!-- Progressbar for Loading -->
|
|
<ng-container
|
|
*ngTemplateOutlet="loadingRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Hint -->
|
|
<ng-container
|
|
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Errors -->
|
|
<ng-container
|
|
*ngTemplateOutlet="errorsRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
</ng-template>
|
|
|
|
<!-- XField Label Template -->
|
|
<ng-template #defaultFieldLabelRef let-control>
|
|
<!-- label -->
|
|
<mat-label
|
|
class="x-field-label"
|
|
*ngIf="notEmptyValue(getControlLabel(control)) | async"
|
|
>{{ getControlLabel(control) | async }}</mat-label
|
|
>
|
|
</ng-template>
|
|
|
|
<!-- byIcon Input Element Template -->
|
|
<ng-template #byIconInputElemntRef let-control>
|
|
<!-- Control Input Element -->
|
|
<x-slotter
|
|
[hasStartOrTopSlot]="true"
|
|
[hasEndOrBottomSlot]="true"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[startTopSlotCssClass]="'auto-size-flex'"
|
|
[endBottomSlotCssClass]="'auto-size-flex'"
|
|
*ngIf="notNullOrUndefinedValue(control) | async"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START">
|
|
<!-- Prefix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Action Prefix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Prefix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
defaultXInputElement;
|
|
context: { $implicit: control }
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END">
|
|
<!-- Suffix Icon -->
|
|
<ng-container
|
|
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
|
|
></ng-container>
|
|
|
|
<!-- Action Suffix Icons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconsRef;
|
|
context: {
|
|
$implicit: control,
|
|
position: ControlIconPositions.Suffix
|
|
}
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</ng-template>
|
|
|
|
<!-- Default X Input Element Template -->
|
|
<ng-template #defaultXInputElement let-control>
|
|
<!-- Has Formatter Input Control -->
|
|
<ng-container *ngIf="controlHasFormatter(control) | async">
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
xFromInputFormatter
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
[locale]="getFormatterLocale(control) | async"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[seperator]="getFormatterSeperator(control) | async"
|
|
[placeholder]="getControlPlaceHolder(control) | async"
|
|
[inputFormatterType]="getFormatterType(control) | async"
|
|
[ngClass]="getControlInputElementClasses(control) | async"
|
|
[currencyLable]="getFormatterCurrencyLabel(control) | async"
|
|
[enabledInputFormatter]="controlHasFormatter(control) | async"
|
|
[stringFormatter]="getFormatterStringFormatter(control) | async"
|
|
[stringInputFormatterType]="getFormatterInputType(control) | async"
|
|
/>
|
|
</ng-container>
|
|
|
|
<!-- Has not Formatter Input Control -->
|
|
<ng-container *ngIf="!(controlHasFormatter(control) | async)">
|
|
<input
|
|
class="x-input"
|
|
autocomplete="off"
|
|
[formControlName]="control.propName.toString()"
|
|
[id]="getControlInputElementId(control)"
|
|
[type]="getControlType(control) | async"
|
|
(blur)="handleControlBlured(control.propName.toString())"
|
|
(focus)="handleControlFocused(control.propName.toString())"
|
|
[matTooltip]="getControlTooltip(control) | async"
|
|
[xFocus]="getControlFocusHandler(control) | async"
|
|
[placeholder]="getControlPlaceHolder(control) | async"
|
|
[ngClass]="getControlInputElementClasses(control) | async"
|
|
/>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Action Icons Template -->
|
|
<ng-template #actionIconsRef let-control let-position="position">
|
|
<!-- Clear -->
|
|
<ng-container
|
|
*ngIf="
|
|
controlHasValue(control.propName.toString()) &&
|
|
(hasControlClearIcon(control) | async) &&
|
|
(notNullOrUndefinedValue(control) | async)
|
|
"
|
|
>
|
|
<ng-container *ngIf="getControlClearIcon(control) | async as descriptor">
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlIconDescriptorPosition(descriptor) | async) === position
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconRef;
|
|
context: {
|
|
$implicit: descriptor,
|
|
role: ControlIconRoles.Clear,
|
|
control: control
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Select -->
|
|
<ng-container *ngIf="getControlType(control) | async as controlType">
|
|
<!-- Recieve Control Type for Handling Without Dialog Actions -->
|
|
<ng-container
|
|
*ngIf="
|
|
(controlType !== ControlTypes.Map &&
|
|
controlType !== ControlTypes.ColorPicker) ||
|
|
(controlType === ControlTypes.Map &&
|
|
(isMapPresentWithDialog(control) | async)) ||
|
|
(controlType === ControlTypes.ColorPicker &&
|
|
(isColorPickerPresentWithDialog(control) | async))
|
|
"
|
|
>
|
|
<!-- if Map/ColorPicker Control Presented Without Dialog, there is no need to has Select icon ... -->
|
|
<ng-container *ngIf="getControlSelectIcon(control) | async as descriptor">
|
|
<ng-container
|
|
*ngIf="
|
|
(getControlIconDescriptorPosition(descriptor) | async) === position
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
actionIconRef;
|
|
context: {
|
|
control: control,
|
|
$implicit: descriptor,
|
|
role: ControlIconRoles.Select
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Action Icon Template -->
|
|
<ng-template
|
|
#actionIconRef
|
|
let-descriptor
|
|
let-role="role"
|
|
let-control="control"
|
|
>
|
|
<x-icon
|
|
[clickable]="true"
|
|
class="x-action-icon"
|
|
[uiDisabled]="getValue(uiDisabled) | async"
|
|
[uiDisabled]="
|
|
(getControlDisabled(control) | async) ||
|
|
(getControlDisableIcon(control) | async)
|
|
"
|
|
[class.x-status-handler]="
|
|
getControlIconDescriptorApplyStateColor(descriptor) | async
|
|
"
|
|
[name]="getControlIconDescriptorName(role, descriptor) | async"
|
|
[color]="getControlIconDescriptorColor(role, descriptor) | async"
|
|
(clicked)="handleControlActionIconClicked(role, descriptor, control)"
|
|
[matTooltip]="getControlIconDescriptorTooltip(role, descriptor) | async"
|
|
>
|
|
</x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Nothing Template -->
|
|
<ng-template #nothingRef></ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.scss
|
|
|
|
//
|
|
:host {
|
|
//
|
|
--regular-color: var(--x-color-dark);
|
|
--valid-color: var(--x-color-success);
|
|
--hint-color: var(--x-color-tertiary);
|
|
--invalid-color: var(--x-color-danger);
|
|
--active-color: var(--x-color-tertiary);
|
|
--pending-color: var(--x-color-warning);
|
|
--disabled-color: var(--x-color-medium);
|
|
--accent-color: var(--x-color-secondary);
|
|
--fill-color: var(--x-color-secondary-tint);
|
|
--disabled-fill-color: var(--x-color-light-shade);
|
|
|
|
//
|
|
--hint-text-size: 7pt;
|
|
--error-text-size: 7pt;
|
|
|
|
//
|
|
--form-fields-vertical-margin: 16px;
|
|
}
|
|
|
|
//
|
|
//#region Mixins ...
|
|
//
|
|
@mixin formFieldRegularProps {
|
|
//
|
|
x-icon {
|
|
--size: 20px;
|
|
}
|
|
|
|
//
|
|
.x-field-label {
|
|
}
|
|
|
|
//
|
|
.auto-size-flex {
|
|
flex: 0 0 auto !important;
|
|
}
|
|
|
|
//
|
|
.full-heigh {
|
|
* {
|
|
height: 100%;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formInputElementProps {
|
|
//
|
|
.mat-input-element {
|
|
@include colorHandler(var(--regular-color), false);
|
|
}
|
|
|
|
//
|
|
.x-form-input-element {
|
|
width: 100%;
|
|
border: unset;
|
|
outline: unset;
|
|
border-color: transparent;
|
|
|
|
//
|
|
&:focus {
|
|
// outline: var(--active-color) auto 1px;
|
|
}
|
|
|
|
//
|
|
@include colorHandler(var(--regular-color), false);
|
|
@include backgroundColorHandler(transparent, false);
|
|
}
|
|
|
|
//
|
|
.x-form-date-input-element,
|
|
.x-form-input-element:not(.mat-input-element) {
|
|
height: 100% !important;
|
|
}
|
|
}
|
|
|
|
@mixin formFieldHintProps(
|
|
$color: var(--hint-color),
|
|
$size: var(--hint-text-size)
|
|
) {
|
|
.x-form-control-hint {
|
|
//
|
|
color: $color;
|
|
font-size: $size;
|
|
}
|
|
}
|
|
|
|
@mixin formFieldErrorProps(
|
|
$color: var(--invalid-color),
|
|
$size: var(--error-text-size)
|
|
) {
|
|
//
|
|
//
|
|
$duration: 250ms;
|
|
$transform-show: scaleY(1);
|
|
$transform-hide: scaleY(0);
|
|
.x-form-error,
|
|
.x-form-field-error {
|
|
//
|
|
color: $color;
|
|
font-size: $size;
|
|
|
|
//
|
|
height: 0;
|
|
|
|
//
|
|
transform: $transform-hide;
|
|
-ms-transform: $transform-hide;
|
|
-webkit-transform: $transform-hide;
|
|
//
|
|
transition: transform;
|
|
-webkit-transition: transform;
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
|
|
//
|
|
&.show {
|
|
//
|
|
height: auto !important;
|
|
//
|
|
transform: $transform-show;
|
|
-ms-transform: $transform-show;
|
|
-webkit-transform: $transform-show;
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formFieldProps {
|
|
//
|
|
.x-form-field {
|
|
//
|
|
@include dateProps;
|
|
@include sliderProps;
|
|
@include radioButtonProps;
|
|
@include selectOptionProps;
|
|
@include toogleColorHandler;
|
|
@include checkBoxColorHandler;
|
|
@include formFieldRegularProps;
|
|
@include formInputElementProps;
|
|
@include formFieldAppearanceHandler;
|
|
@include colorHandler(var(--regular-color), false);
|
|
@include backgroundColorHandler(transparent !important);
|
|
|
|
//
|
|
&.x-mat-form-field {
|
|
//
|
|
width: 100%;
|
|
|
|
//
|
|
&.mat-focused {
|
|
@include formFieldFocusHandler;
|
|
}
|
|
}
|
|
|
|
//
|
|
&.x-form-radio-field {
|
|
//
|
|
outline: unset;
|
|
|
|
//
|
|
&.x-focused {
|
|
//
|
|
@include formFieldFocusHandler;
|
|
@include iconStatusColorHandler(var(--active-color));
|
|
}
|
|
}
|
|
|
|
//
|
|
&:not(.x-mat-form-field):not(.x-form-radio-field) {
|
|
//
|
|
outline: unset;
|
|
|
|
//
|
|
&.x-focused {
|
|
//
|
|
@include formFieldFocusHandler;
|
|
border-color: var(--active-color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin autoCompleteProps {
|
|
/* Auto Complete Styling */
|
|
//
|
|
$duration: 250ms;
|
|
$transform-show: scaleY(1);
|
|
$transform-hide: scaleY(0);
|
|
|
|
.x-auto-complete-wrapper {
|
|
position: unset;
|
|
display: unset;
|
|
}
|
|
|
|
.x-auto-complete {
|
|
//
|
|
position: content;
|
|
|
|
//
|
|
&.x-auto-complete-margin {
|
|
margin-top: 0;
|
|
}
|
|
|
|
//
|
|
height: calc(50%);
|
|
max-height: 300px;
|
|
|
|
//
|
|
left: 8px;
|
|
right: 8px;
|
|
overflow-y: scroll;
|
|
|
|
//
|
|
z-index: 113;
|
|
|
|
//
|
|
transform: $transform-hide;
|
|
-ms-transform: $transform-hide;
|
|
-webkit-transform: $transform-hide;
|
|
|
|
//
|
|
transition: transform;
|
|
-webkit-transition: transform;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
|
|
//
|
|
&.open {
|
|
//
|
|
transform: $transform-show;
|
|
-ms-transform: $transform-show;
|
|
-webkit-transform: $transform-show;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
}
|
|
/* END Auto Complete Styling */
|
|
}
|
|
|
|
@mixin selectOptionProps {
|
|
//
|
|
.x-select-option {
|
|
width: 100%;
|
|
margin-bottom: 4px;
|
|
|
|
&:last-child {
|
|
margin-bottom: 8px;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin dateProps {
|
|
//
|
|
.mat-icon-button {
|
|
display: table-cell;
|
|
vertical-align: bottom;
|
|
}
|
|
}
|
|
|
|
@mixin radioButtonProps($disabled: false) {
|
|
//
|
|
.x-radio-button {
|
|
//
|
|
@include radioColorHandler(var(--regular-color), true, false);
|
|
|
|
//
|
|
&.active {
|
|
//
|
|
@include radioColorHandler(var(--active-color) !important, true, true);
|
|
}
|
|
}
|
|
|
|
&.x-form-radio-field {
|
|
//
|
|
outline: unset;
|
|
|
|
//
|
|
&.x-focused {
|
|
//
|
|
.x-field-label {
|
|
color: var(--active-color) !important;
|
|
}
|
|
border-color: var(--active-color) !important;
|
|
|
|
//
|
|
@include iconStatusColorHandler(var(--active-color));
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formFieldFocusHandler {
|
|
//
|
|
.mat-form-field-ripple {
|
|
@include backgroundColorHandler(var(--active-color) !important, false);
|
|
}
|
|
|
|
//
|
|
@include iconStatusColorHandler(var(--active-color));
|
|
@include formFieldLabelColorHandler(var(--active-color));
|
|
@include formFieldWrapperColorHandler(var(--active-color));
|
|
@include matFormFieldOutlineColorHandler(var(--active-color) !important);
|
|
}
|
|
|
|
@mixin formFieldAppearanceHandler($disabled: false) {
|
|
//
|
|
// Label Colors ...
|
|
@if $disabled {
|
|
//
|
|
@include formFieldLabelColorHandler(var(--disabled-color));
|
|
|
|
//
|
|
.x-form-field-appearance-fill:not(.x-mat-form-field) {
|
|
border-color: var(--disabled-fill-color);
|
|
}
|
|
|
|
//
|
|
.mat-select-value-text {
|
|
color: var(--disabled-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-select-value-text {
|
|
color: var(--regular-color);
|
|
}
|
|
|
|
//
|
|
// None ...
|
|
.x-form-field-appearance-none {
|
|
//
|
|
@if $disabled {
|
|
@include formFieldLabelColorHandler(var(--disabled-color));
|
|
} @else {
|
|
}
|
|
}
|
|
|
|
//
|
|
// Legacy ...
|
|
// Standard ...
|
|
.x-form-field-appearance-legacy,
|
|
.x-form-field-appearance-standard {
|
|
//
|
|
@if $disabled {
|
|
@include matFormFieldUnderlineColorHandler(
|
|
var(--disabled-fill-color) !important,
|
|
true
|
|
);
|
|
} @else {
|
|
@include matFormFieldUnderlineColorHandler(var(--fill-color) !important);
|
|
}
|
|
|
|
//
|
|
&:not(.x-mat-form-field) {
|
|
@if $disabled {
|
|
} @else {
|
|
//
|
|
padding: 8px;
|
|
border-radius: 0;
|
|
border-bottom-width: 1px;
|
|
border-bottom-style: solid;
|
|
border-color: var(--fill-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Outline ...
|
|
.x-form-field-appearance-outline {
|
|
//
|
|
@if $disabled {
|
|
@include matFormFieldOutlineColorHandler(var(--disabled-fill-color));
|
|
} @else {
|
|
@include formFieldLabelColorHandler(var(--regular-color));
|
|
@include matFormFieldOutlineColorHandler(var(--fill-color));
|
|
}
|
|
|
|
//
|
|
&:not(.x-mat-form-field) {
|
|
@if $disabled {
|
|
@include backgroundColorHandler(transaprent!important, false);
|
|
} @else {
|
|
//
|
|
padding: 8px;
|
|
border-radius: 3px;
|
|
border-width: 1px;
|
|
border-style: solid;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill ...
|
|
.x-form-field-appearance-fill {
|
|
//
|
|
&.x-mat-form-field:not(.x-form-field-disabled) {
|
|
//
|
|
@if $disabled {
|
|
//
|
|
.mat-form-field-flex {
|
|
@include colorHandler(var(--disabled-fill-color) !important, false);
|
|
@include backgroundColorHandler(
|
|
var(--disabled-fill-color) !important,
|
|
false
|
|
);
|
|
}
|
|
|
|
//
|
|
@include matFormFieldUnderlineColorHandler(var(--disabled-color));
|
|
} @else {
|
|
//
|
|
@include backgroundColorHandler(var(--fill-color) !important, false);
|
|
|
|
//
|
|
.mat-form-field-flex {
|
|
@include colorHandler(var(--regular-color), false);
|
|
@include backgroundColorHandler(var(--fill-color) !important, false);
|
|
}
|
|
|
|
//
|
|
@include matFormFieldUnderlineColorHandler(var(--accent-color));
|
|
}
|
|
}
|
|
|
|
//
|
|
@if $disabled {
|
|
//
|
|
&.x-form-field-disabled {
|
|
background-color: var(--disabled-fill-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-form-field-flex {
|
|
@include colorHandler(var(--disabled-color) !important, false);
|
|
@include backgroundColorHandler(
|
|
var(--disabled-fill-color) !important,
|
|
false
|
|
);
|
|
}
|
|
|
|
//
|
|
.x-form-slider-control {
|
|
//
|
|
.mat-slider-thumb {
|
|
background-color: var(--disabled-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-slider-wrapper,
|
|
.mat-slider-track-wrapper {
|
|
background-color: var(--disabled-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
@include matFormFieldUnderlineColorHandler(var(--disabled-color));
|
|
} @else {
|
|
//
|
|
.x-form-slider-control {
|
|
.mat-slider-wrapper,
|
|
.mat-slider-track-wrapper {
|
|
background-color: var(--regular-color) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
&:not(.x-mat-form-field) {
|
|
@if $disabled {
|
|
@include backgroundColorHandler(
|
|
var(--disabled-fill-color) !important,
|
|
false
|
|
);
|
|
} @else {
|
|
//
|
|
padding: 8px;
|
|
border-radius: 3px;
|
|
border-bottom-width: 1px;
|
|
border-bottom-style: solid;
|
|
border-bottom-left-radius: 0;
|
|
border-bottom-right-radius: 0;
|
|
border-color: var(--regular-color);
|
|
|
|
//
|
|
@include backgroundColorHandler(var(--fill-color) !important, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formFieldStatusHandler {
|
|
//
|
|
// Global ...
|
|
@include formFieldAppearanceHandler(false);
|
|
|
|
//
|
|
// Disabled ...
|
|
&.x-form-field-wrapper-disabled {
|
|
//
|
|
* {
|
|
cursor: default;
|
|
pointer-events: none;
|
|
}
|
|
|
|
//
|
|
x-icon.x-action-icon > * {
|
|
color: var(--disabled-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-form-field-disabled {
|
|
color: var(--disabled-color) !important;
|
|
}
|
|
|
|
//
|
|
.x-form-input-element {
|
|
//
|
|
opacity: 1 !important;
|
|
border-color: var(--disabled-fill-color) !important;
|
|
|
|
//
|
|
@include colorHandler(var(--disabled-color) !important, false);
|
|
}
|
|
|
|
//
|
|
.x-form-control {
|
|
opacity: 1 !important;
|
|
@include colorHandler(var(--disabled-color) !important, false);
|
|
}
|
|
|
|
//
|
|
.mat-slide-toggle-bar {
|
|
background-color: var(--disabled-fill-color) !important;
|
|
}
|
|
|
|
//
|
|
@include sliderProps(true);
|
|
@include formFieldAppearanceHandler(true);
|
|
@include formFieldHintProps(var(--disabled-color));
|
|
@include formFieldErrorProps(var(--disabled-color));
|
|
@include checkBoxColorHandler(--disabled-color, true);
|
|
@include iconStatusColorHandler(var(--disabled-color), true);
|
|
@include formFieldWrapperColorHandler(var(--disabled-color) !important);
|
|
@include radioColorHandler(var(--disabled-color) !important, true, true);
|
|
}
|
|
|
|
//
|
|
// Valid ...
|
|
&.x-form-field-wrapper-valid {
|
|
//
|
|
@include iconStatusColorHandler(var(--valid-color), true);
|
|
|
|
//
|
|
&.apply-status {
|
|
@include formFieldWrapperColorHandler(var(--valid-color));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Invalid ...
|
|
&.x-form-field-wrapper-invalid {
|
|
//
|
|
@include iconStatusColorHandler(var(--invalid-color), true);
|
|
|
|
//
|
|
&.apply-status {
|
|
@include formFieldWrapperColorHandler(var(--invalid-color));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pending ...
|
|
&.x-form-field-wrapper-pending {
|
|
//
|
|
@include iconStatusColorHandler(var(--pending-color), true);
|
|
|
|
//
|
|
&.apply-status {
|
|
@include formFieldWrapperColorHandler(var(--pending-color));
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin colorHandler($color: var(--regular-color), $applyToChilds: true) {
|
|
color: $color;
|
|
|
|
//
|
|
@if $applyToChilds {
|
|
* {
|
|
:not(x-icon):not(x-icon > *) {
|
|
color: $color;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
@include matFormFieldOutlineColorHandler($color);
|
|
}
|
|
|
|
@mixin backgroundColorHandler($color: transaprent, $applyToChilds: true) {
|
|
//
|
|
background-color: $color;
|
|
|
|
//
|
|
@if $applyToChilds {
|
|
*:not(.x-field-label):not(.x-field-label
|
|
*):not(.mat-form-field-ripple):not(.mat-slide-toggle-thumb):not(.mat-slide-toggle-bar):not(.mat-checkbox-frame):not(.mat-radio-inner-circle):not(.mat-form-field-underline):not(.mat-slide):not(.mat-slider
|
|
*):not(.x-markdown *):not(.x-color *):not(.x-map
|
|
*):not(.x-selected-color):not(.x-color-palette):not(.x-color-alpha) {
|
|
background-color: $color;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formFieldWrapperColorHandler($color: var(--regular-color)) {
|
|
//
|
|
.x-form-input-element {
|
|
// outline: $color auto 1px;
|
|
}
|
|
|
|
//
|
|
.x-form-field:not(.x-mat-form-field) {
|
|
border-color: $color;
|
|
}
|
|
|
|
//
|
|
@include sliderProps;
|
|
@include toogleColorHandler($color);
|
|
@include checkBoxColorHandler($color);
|
|
@include formFieldLabelColorHandler($color);
|
|
@include matFormFieldOutlineColorHandler($color);
|
|
@include iconStatusColorHandler($color !important);
|
|
@include matFormFieldUnderlineColorHandler($color !important);
|
|
}
|
|
|
|
@mixin radioColorHandler(
|
|
$color: var(--regular-color),
|
|
$applyOnOuterCircle: false,
|
|
$applyOnInnerCircle: false
|
|
) {
|
|
//
|
|
.mat-radio-label {
|
|
//
|
|
color: $color;
|
|
|
|
//
|
|
@if $applyOnOuterCircle {
|
|
.mat-radio-outer-circle {
|
|
border-color: $color;
|
|
}
|
|
}
|
|
|
|
//
|
|
@if $applyOnInnerCircle {
|
|
.mat-radio-inner-circle {
|
|
background-color: $color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin checkBoxColorHandler($color: var(--regular-color), $disabled: false) {
|
|
//
|
|
.mat-checkbox-frame {
|
|
@if $disabled {
|
|
border-color: var(--disabled-color) !important;
|
|
} @else {
|
|
border-color: var(--regular-color);
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-checkbox-checked {
|
|
.mat-checkbox-frame,
|
|
.mat-checkbox-background {
|
|
background-color: var(--active-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-checkbox-label {
|
|
.x-field-label {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
//
|
|
.x-form-control {
|
|
&.has-icon {
|
|
.mat-checkbox-layout {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin toogleColorHandler($color: var(--regular-color)) {
|
|
//
|
|
:not(.x-form-field-disabled) {
|
|
.mat-slide-toggle-bar {
|
|
background-color: var(--active-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
.x-form-field-disabled {
|
|
.mat-slide-toggle-bar {
|
|
background-color: var(--disabled-color) !important;
|
|
}
|
|
.mat-slide-toggle-thumb {
|
|
background-color: var(--disabled-fill-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-slide-toggle-thumb {
|
|
background-color: $color !important;
|
|
}
|
|
|
|
//
|
|
.x-form-control {
|
|
&.has-icon {
|
|
.mat-slide-toggle-label {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin sliderProps($disabled: false) {
|
|
//
|
|
.x-form-slider-control {
|
|
//
|
|
@if $disabled {
|
|
//
|
|
cursor: default;
|
|
pointer-events: none;
|
|
}
|
|
|
|
//
|
|
&:not(.vertical) {
|
|
width: 100%;
|
|
}
|
|
|
|
//
|
|
&.vertical {
|
|
display: block;
|
|
margin: {
|
|
left: auto;
|
|
right: auto;
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-slider-wrapper,
|
|
.mat-slider-track-wrapper {
|
|
//
|
|
@if $disabled {
|
|
background-color: var(--disabled-fill-color) !important;
|
|
} @else {
|
|
background-color: var(--fill-color);
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-slider-thumb,
|
|
.mat-slider-thumb-label,
|
|
.mat-slider-thumb-label-text {
|
|
//
|
|
@if $disabled {
|
|
color: var(--disabled-color) !important;
|
|
background-color: var(--disabled-fill-color) !important;
|
|
} @else {
|
|
color: var(--accent-color);
|
|
background-color: var(--active-color);
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-slider-track-fill {
|
|
//
|
|
@if $disabled {
|
|
background-color: var(--disabled-color) !important;
|
|
} @else {
|
|
background-color: var(--active-color);
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-slider-vertical {
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin formFieldLabelColorHandler($color: var(--regular-color)) {
|
|
//
|
|
.mat-form-field-label {
|
|
color: $color;
|
|
}
|
|
|
|
//
|
|
.x-field-label {
|
|
color: $color;
|
|
}
|
|
|
|
//
|
|
.mat-select-placeholder {
|
|
color: $color;
|
|
}
|
|
}
|
|
|
|
@mixin iconStatusColorHandler($color: var(--regular-color), $important: false) {
|
|
//
|
|
x-icon.x-status-handler > * {
|
|
//
|
|
@if $important {
|
|
color: $color !important;
|
|
} @else {
|
|
color: $color;
|
|
}
|
|
}
|
|
}
|
|
|
|
@mixin matFormFieldUnderlineColorHandler(
|
|
$color: var(--fill-color),
|
|
$clearBackground: false
|
|
) {
|
|
//
|
|
.mat-form-field-underline {
|
|
//
|
|
border-color: $color;
|
|
background-color: $color;
|
|
|
|
//
|
|
&::before {
|
|
background-color: $color;
|
|
}
|
|
|
|
//
|
|
@if $clearBackground {
|
|
background-image: none;
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-select-arrow {
|
|
color: $color;
|
|
}
|
|
}
|
|
|
|
@mixin matFormFieldOutlineColorHandler($color: var(--regular-color)) {
|
|
//
|
|
color: $color;
|
|
|
|
//
|
|
.mat-form-field-outline-start,
|
|
.mat-form-field-outline-end,
|
|
.mat-form-field-outline-gap {
|
|
border-width: 1px !important;
|
|
}
|
|
|
|
//
|
|
.mat-form-field-outline,
|
|
.mat-form-field-outline-thick {
|
|
color: $color;
|
|
border-width: 1px !important;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
::ng-deep.cdk-overlay-pane {
|
|
//
|
|
transform: translateY(0px) !important;
|
|
|
|
//
|
|
.mat-datepicker-content-container {
|
|
height: auto !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
::ng-deep.x-form-select-control {
|
|
//
|
|
min-width: 100% !important;
|
|
|
|
//
|
|
&:not(.x-form-select-control-panel) {
|
|
max-width: 100% !important;
|
|
}
|
|
|
|
//
|
|
&.x-form-select-control-panel {
|
|
}
|
|
|
|
// //
|
|
// .mat-select-value-text {
|
|
// color: var(--regular-color) !important;
|
|
// }
|
|
|
|
//
|
|
.x-select-option {
|
|
//
|
|
color: var(--regular-color) !important;
|
|
background-color: var(--fill-color) !important;
|
|
|
|
//
|
|
&.mat-active {
|
|
color: var(--active-color) !important;
|
|
}
|
|
|
|
//
|
|
&.mat-selected {
|
|
//
|
|
color: var(--active-color) !important;
|
|
|
|
//
|
|
.mat-pseudo-checkbox-checked {
|
|
background: var(--active-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-pseudo-checkbox::after {
|
|
color: var(--accent-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
&:hover {
|
|
$level: 0.5;
|
|
filter: brightness($level);
|
|
-webkit-filter: brightness($level);
|
|
color: var(--active-color) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
::ng-deep.x-form-control-date-picker {
|
|
//
|
|
&.mat-calendar {
|
|
//
|
|
color: var(--regular-color) !important;
|
|
background-color: var(--fill-color) !important;
|
|
|
|
//
|
|
.mat-calendar-arrow {
|
|
border-top-color: unset;
|
|
}
|
|
|
|
//
|
|
.mat-calendar-body-today {
|
|
color: var(--active-color);
|
|
border-color: var(--acttive-color);
|
|
}
|
|
|
|
//
|
|
.mat-calendar-table-header {
|
|
color: var(--accent-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-calendar-body-selected {
|
|
//
|
|
color: var(--accent-color);
|
|
background-color: var(--active-color);
|
|
border-color: var(--accent-color);
|
|
}
|
|
|
|
//
|
|
.mat-calendar-next-button,
|
|
.mat-calendar-previous-button,
|
|
.mat-calendar-period-button {
|
|
color: var(--active-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-calendar-body-label {
|
|
color: var(--active-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-calendar-body-cell-content {
|
|
color: var(--regular-color) !important;
|
|
}
|
|
|
|
//
|
|
.mat-calendar-body-disabled {
|
|
color: var(--disabled-color) !important;
|
|
filter: contrast(0.5) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
:host ::ng-deep .x-form {
|
|
//
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
flex-direction: row;
|
|
|
|
//
|
|
.x-form-field-wrapper {
|
|
//
|
|
width: 100%;
|
|
margin-bottom: var(--form-fields-vertical-margin);
|
|
|
|
//
|
|
.mat-form-field-wrapper {
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
//
|
|
.mat-form-field-underline {
|
|
position: initial;
|
|
}
|
|
|
|
//
|
|
.ng-invalid,
|
|
.mat-form-field-invalid {
|
|
//
|
|
*:not(.x-field-label):not(ion-icon):not(.mat-form-field-outline):not(.mat-form-field-outline-thick):not(.mat-form-field-outline-end):not(.mat-form-field-outline-gap):not(.mat-form-field-outline-start) {
|
|
color: var(--regular-color);
|
|
}
|
|
|
|
//
|
|
&.apply-status {
|
|
* {
|
|
color: var(--invalid-color) !important;
|
|
}
|
|
}
|
|
|
|
*:not(.x-field-label) {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
|
|
//
|
|
&.readonly {
|
|
//
|
|
.x-field-label {
|
|
color: var(--disabled-color) !important;
|
|
}
|
|
|
|
//
|
|
.x-form-control {
|
|
color: var(--disabled-color) !important;
|
|
}
|
|
}
|
|
|
|
//
|
|
@include formFieldProps;
|
|
@include autoCompleteProps;
|
|
@include formFieldStatusHandler;
|
|
@include formFieldAppearanceHandler(false);
|
|
@include formFieldHintProps(var(--hint-color), var(--hint-text-size));
|
|
@include formFieldErrorProps(var(--invalid-color), var(--error-text-size));
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.ts
|
|
|
|
import {
|
|
FormGroup,
|
|
FormControl,
|
|
AbstractControl,
|
|
ValidationErrors,
|
|
} from '@angular/forms';
|
|
import {
|
|
defaultFormControlClearIcon,
|
|
defaultFormControlSelectIcon,
|
|
} from './x-form.tools';
|
|
import {
|
|
keys,
|
|
sort,
|
|
nameof,
|
|
XColor,
|
|
isDate,
|
|
assign,
|
|
entries,
|
|
XUiEvent,
|
|
hasChild,
|
|
isFunction,
|
|
parseXColor,
|
|
momentToDate,
|
|
XResourceIDs,
|
|
XBorderStyle,
|
|
XExceptionIDs,
|
|
XDialogResult,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XFormCssVar,
|
|
XFormStatus,
|
|
XFormUpdateOn,
|
|
XFormBaseAction,
|
|
XFormControlType,
|
|
XFormActionModel,
|
|
XControlIconRole,
|
|
XFormErrorHandler,
|
|
XFormControlConfig,
|
|
XFormControlAction,
|
|
XFormIconDescriptor,
|
|
XControlIconPosition,
|
|
XFormStatusIdentifier,
|
|
XFormMapControlConfig,
|
|
XControlIconDescriptor,
|
|
XFormControlAppearance,
|
|
XFormInputControlConfig,
|
|
XFormRadioControlConfig,
|
|
XFormContainerComponent,
|
|
XFormSelectControlConfig,
|
|
XFormSliderControlConfig,
|
|
XFormSelectControlOption,
|
|
XFormControlLabelPosition,
|
|
XControlIconRoleIdentifier,
|
|
XFormMarkdownControlConfig,
|
|
XFormControlNameIdentifier,
|
|
XFormMapControlPresentType,
|
|
XFormCheckBoxControlConfig,
|
|
XFormSelectorControlConfig,
|
|
XBaseFormControlActionModel,
|
|
XFormDatePickerControlConfig,
|
|
XFormColorPickerControlConfig,
|
|
XFormControlAutoCompleteConfig,
|
|
XFormAvatarUploadControlConfig,
|
|
XFormControlAppearanceDescriptor,
|
|
XFormControlValueChangeEventModel,
|
|
XFormControlStatusChangeEventModel,
|
|
XFormColorPickerControlPresentType,
|
|
XFormDatePickerControlPickerPosition,
|
|
} from './x-form.typings';
|
|
import {
|
|
XMapAction,
|
|
XMapLocation,
|
|
XMapActionModel,
|
|
XMapItemPosition,
|
|
defaultMarkerStyle,
|
|
defaultMapSearchPlaceProvider,
|
|
} from '../x-map/x-map.typings';
|
|
import { isMoment } from 'moment';
|
|
import {
|
|
XMarkdownMode,
|
|
XMarkdownActionModel,
|
|
} from '../x-markdown/x-markdown.typings';
|
|
import {
|
|
XSearchBarType,
|
|
XSearchBarActionModel,
|
|
XSearchBarEnterKeyHint,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import {
|
|
XColorPickerActionModel,
|
|
XColorPickerOutputFormat,
|
|
} from '../x-color-picker/x-color-picker.typings';
|
|
import {
|
|
XAvatarUploadActionModel,
|
|
defaultAvatarUploadActionButtons,
|
|
} from '../x-avatar-upload/x-avatar-upload.typings';
|
|
import { map, concatMap, tap } from 'rxjs/operators';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { toLongLat, fromLongLat } from '../x-map/x-map.tools';
|
|
import { XStringInputFormatType } from 'x-framework-services';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { MatFormFieldAppearance } from '@angular/material/form-field';
|
|
import { of, Subject, Subscription, Observable, forkJoin } from 'rxjs';
|
|
import { MatDatepickerInputEvent } from '@angular/material/datepicker';
|
|
import { XSlotName, XSlotLayout } from '../x-slotter/x-slotter.typings';
|
|
import { XMapDialogConfig } from '../x-map/x-map-dialog/x-map-dialog.typings';
|
|
import { XFileDropAreaActionModel } from '../x-file-drop-area/x-file-drop-area.typings';
|
|
import { XColorPickerDialogConfig } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-form',
|
|
templateUrl: './x-form.component.html',
|
|
styleUrls: ['./x-form.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFormComponent extends XFormContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private VALUE: any;
|
|
private FORM: FormGroup;
|
|
private FORM_CONFIG: any;
|
|
private ERRORS: ValidationErrors;
|
|
private actionProviders: any = {};
|
|
private STATUS: XFormStatusIdentifier;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
readonly FormStatuses = Object.assign({}, XFormStatus);
|
|
readonly ControlTypes = Object.assign({}, XFormControlType);
|
|
readonly ControlIconRoles = Object.assign({}, XControlIconRole);
|
|
readonly ControlIconPositions = Object.assign({}, XControlIconPosition);
|
|
readonly FormControlAppearances = Object.assign({}, XFormControlAppearance);
|
|
|
|
//
|
|
currentInputFocus: string;
|
|
|
|
//
|
|
get value() {
|
|
return this.VALUE;
|
|
}
|
|
|
|
get status() {
|
|
return this.STATUS;
|
|
}
|
|
|
|
get errors() {
|
|
return this.ERRORS;
|
|
}
|
|
|
|
get isStatusValid() {
|
|
return this.status === XFormStatus.Valid;
|
|
}
|
|
|
|
get form() {
|
|
return this.FORM;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.applyColors();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
// Form Config ...
|
|
const isFormConfigChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('formConfig')
|
|
);
|
|
if (isFormConfigChanged) {
|
|
await this.prepareFormGroup();
|
|
}
|
|
|
|
//
|
|
// Action Provider ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
await this.registerActionProvider();
|
|
}
|
|
|
|
//
|
|
//#region UI Disabled or Loading ...
|
|
const isUiDisabledChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('uiDisabled')
|
|
);
|
|
if (isUiDisabledChanged) {
|
|
await this.handleUiDisabledChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Color Change Detecotrs ...
|
|
//
|
|
const isRegularColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('regularColor')
|
|
);
|
|
if (isRegularColorChanged) {
|
|
await this.applyRegularColor();
|
|
}
|
|
|
|
//
|
|
const isAccentColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('accentColor')
|
|
);
|
|
if (isAccentColorChanged) {
|
|
await this.applyAccentColor();
|
|
}
|
|
|
|
//
|
|
const isHintColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('hintColor')
|
|
);
|
|
if (isHintColorChanged) {
|
|
await this.applyHintColor();
|
|
}
|
|
|
|
//
|
|
const isPendingColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('pendingColor')
|
|
);
|
|
if (isPendingColorChanged) {
|
|
await this.applyPendingColor();
|
|
}
|
|
|
|
//
|
|
const isActiveColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('activeColor')
|
|
);
|
|
if (isActiveColorChanged) {
|
|
await this.applyActiveColor();
|
|
}
|
|
|
|
//
|
|
const isValidColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('validColor')
|
|
);
|
|
if (isValidColorChanged) {
|
|
await this.applyValidColor();
|
|
}
|
|
|
|
//
|
|
const isInvalidColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('invalidColor')
|
|
);
|
|
if (isInvalidColorChanged) {
|
|
await this.applyInvalidColor();
|
|
}
|
|
|
|
//
|
|
const isFillColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('fillColor')
|
|
);
|
|
if (isFillColorChanged) {
|
|
await this.applyFillColor();
|
|
}
|
|
|
|
//
|
|
const isDisabledColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('disabledColor')
|
|
);
|
|
if (isDisabledColorChanged) {
|
|
await this.applyDisabledColor();
|
|
}
|
|
|
|
//
|
|
const isDisabledFillColorChanged = changeKeys.includes(
|
|
nameof<XFormComponent>('disabledFillColor')
|
|
);
|
|
if (isDisabledFillColorChanged) {
|
|
await this.applyDisabledFillColor();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
this.managerService.dispatchResizeEvent();
|
|
setTimeout(() => this.managerService.dispatchResizeEvent(), 500);
|
|
this.detectChanges();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
//#region Form Providers ...
|
|
//
|
|
//#region Form Config ...
|
|
/**
|
|
* prepare form config object
|
|
*/
|
|
getFormConfig() {
|
|
return this.getValue(this.formConfig);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Model ...
|
|
/**
|
|
* get form name ...
|
|
*/
|
|
getFormName() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) => this.getValue(formConfig.name))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Css Class Lists...
|
|
/**
|
|
* retrieve form cssClasses ...
|
|
*/
|
|
getFormCssClass() {
|
|
return this.getArrayValue(this.cssClass).pipe(
|
|
concatMap((cssClasses) =>
|
|
this.getFormName().pipe(
|
|
map((formName) => {
|
|
return {
|
|
name: formName,
|
|
cssClasses,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((descriptor) => {
|
|
return descriptor.cssClasses.concat(
|
|
'x-form',
|
|
`x-status-${this.STATUS}`,
|
|
`x-form-${descriptor.name}`
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form control wrapper classes list ...
|
|
*
|
|
* @param control form control config ...
|
|
*/
|
|
getFormControlWrapperClasses(control: XFormControlConfig) {
|
|
return this.getControlInfo(control).pipe(
|
|
map((cInfo) => {
|
|
//
|
|
const fControl = this.getControl(control.propName);
|
|
const isFocused =
|
|
this.getControlInputElementId(control) === this.currentInputFocus;
|
|
|
|
//
|
|
return [
|
|
'x-form-field-wrapper',
|
|
`x-form-${cInfo.type}-field-wrapper`,
|
|
`x-form-field-${control.index.toString()}-wrapper`,
|
|
`x-form-field-${control.propName.toString()}-wrapper`,
|
|
`x-form-field-appearance-${cInfo.appearance
|
|
.toString()
|
|
.toLowerCase()}-wrapper`,
|
|
//
|
|
// Focused ...
|
|
...(isFocused ? ['x-focused'] : []),
|
|
//
|
|
// Disabled ...
|
|
...(cInfo.disabled || fControl.disabled
|
|
? ['x-form-field-wrapper-disabled']
|
|
: []),
|
|
//
|
|
// Valid ...
|
|
...(fControl.valid ? ['x-form-field-wrapper-valid'] : []),
|
|
//
|
|
// Invalid ...
|
|
...(fControl.invalid ? ['x-form-field-wrapper-invalid'] : []),
|
|
//
|
|
// Pending ...
|
|
...(fControl.pending ? ['x-form-field-wrapper-pending'] : []),
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form errors classes ...
|
|
*/
|
|
getFormErrorsClasses() {
|
|
return this.getFormName().pipe(
|
|
map((formName) => {
|
|
return ['x-form-errors', `x-form-${formName}-errors`];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form specific error's class lists ...
|
|
*
|
|
* @param handler form error handler ...
|
|
*/
|
|
getFormErrorClasses(handler: XFormErrorHandler) {
|
|
return this.getFormName().pipe(
|
|
concatMap((formName) =>
|
|
this.getErrorHandlerErrorName(handler).pipe(
|
|
map((errorName) => {
|
|
return {
|
|
formName,
|
|
errorName,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((descriptor) => {
|
|
return [
|
|
'x-form-error',
|
|
`x-form-${descriptor.formName}-error`,
|
|
`x-form-${descriptor.errorName}-error`,
|
|
`x-form-${descriptor.formName}-${descriptor.errorName}-error`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form card footer css classes ...
|
|
*/
|
|
getFormCardFooterCssClass() {
|
|
return this.getFormName().pipe(
|
|
map((formName) => {
|
|
return ['x-form-footer', `x-form-${formName}-footer`];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form card actions css classes ...
|
|
*/
|
|
getFormCardActionsCssClass() {
|
|
return this.getFormName().pipe(
|
|
map((formName) => {
|
|
return ['x-form-actions', `x-form-${formName}-actions`];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form field classes list ...
|
|
*
|
|
* @param control form control config ...
|
|
*/
|
|
getFormFieldClasses(control: XFormControlConfig) {
|
|
return this.getControlInfo(control).pipe(
|
|
map((cInfo) => {
|
|
//
|
|
const fControl = this.getControl(control.propName);
|
|
const isFocused =
|
|
this.getControlInputElementId(control) === this.currentInputFocus;
|
|
|
|
//
|
|
return [
|
|
'x-form-field',
|
|
`x-form-${cInfo.type}-field`,
|
|
`x-form-field-${control.index.toString()}`,
|
|
`x-form-field-${control.propName.toString()}`,
|
|
`x-form-field-appearance-${cInfo.appearance
|
|
.toString()
|
|
.toLowerCase()}`,
|
|
//
|
|
// Focused ...
|
|
...(isFocused ? ['x-focused'] : []),
|
|
//
|
|
// Disabled ...
|
|
...(cInfo.disabled || fControl.disabled
|
|
? ['x-form-field-disabled']
|
|
: []),
|
|
//
|
|
// Valid ...
|
|
...(fControl.valid ? ['x-form-field-valid'] : []),
|
|
//
|
|
// Invalid ...
|
|
...(fControl.invalid ? ['x-form-field-invalid'] : []),
|
|
//
|
|
// Pending ...
|
|
...(fControl.pending ? ['x-form-field-pending'] : []),
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form control classes list ...
|
|
*
|
|
* @param control form control config ...
|
|
*/
|
|
getFormControlClasses(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
map((type) => {
|
|
return [
|
|
'x-form-control',
|
|
`x-form-${type}-control`,
|
|
`x-form-control-${control.index.toString()}`,
|
|
`x-form-control-${control.propName.toString()}`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve focusHandler of a form control ...
|
|
*
|
|
* @param control form control config ...
|
|
*/
|
|
getControlFocusHandler(control: XFormControlConfig) {
|
|
return this.getValue(control).pipe(map((config) => config.focusHandler));
|
|
}
|
|
|
|
/**
|
|
* retriev a form control label classes ...
|
|
*/
|
|
getFormControlFieldLabelClasses(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
map((type) => {
|
|
return [
|
|
'x-form-field-label',
|
|
`x-form-${type}-field-label`,
|
|
`x-form-field-label-${control.index.toString()}`,
|
|
`x-form-field-label-${control.propName.toString()}`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve form control hint class list
|
|
*/
|
|
getFormControlHintClasses(control: XFormControlConfig) {
|
|
return this.getControlInfo(control).pipe(
|
|
map((cInfo) => {
|
|
return [
|
|
'x-form-control-hint',
|
|
`x-form-${cInfo.type}-control-hint`,
|
|
`x-form-control-${control.index.toString()}-hint`,
|
|
`x-form-control-${control.propName.toString()}-hint`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Model ...
|
|
/**
|
|
* retrieve for model which provide's initial input for each field.
|
|
* if the form model is <T> this type is Partial<T> ...
|
|
*/
|
|
getFormModel() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) => this.getOptionalValue(formConfig.model))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines the form has intial value provider or not ...
|
|
*/
|
|
formHasModel() {
|
|
return this.getFormModel().pipe(
|
|
map((formModel) => !isNullOrUndefined(formModel))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Updte On ...
|
|
/**
|
|
* retrieve form update strategy identifier ...
|
|
*/
|
|
getFormUpdateOn() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) =>
|
|
this.getOptionalValue(formConfig.updateOn).pipe(
|
|
map((updateOn) => (updateOn ? updateOn : XFormUpdateOn.CHANGE))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Validators ...
|
|
/**
|
|
* retrieve form Validators object ...
|
|
*/
|
|
getFormValidators() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) => this.getOptionalValue(formConfig.validators))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines form has Validators or not ...
|
|
*/
|
|
formHasValidators() {
|
|
return this.getFormValidators().pipe(
|
|
map((formValidators) => !isNullOrUndefined(formValidators))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Controls ...
|
|
/**
|
|
* retrieve form Controls Configs ...
|
|
*/
|
|
getFormControls() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) =>
|
|
this.getArrayValue(formConfig.controls).pipe(
|
|
map((arrVal) => sort(arrVal, (v1, v2) => v1.index - v2.index))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Error Handlers ...
|
|
/**
|
|
* retrieve form Error Handlers Descriptor object ...
|
|
*/
|
|
getFormErrorHandlers() {
|
|
return this.getFormConfig().pipe(
|
|
concatMap((formConfig) => this.getArrayValue(formConfig.errorHandlers))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines form has Error Handlers or not ...
|
|
*/
|
|
formHasErrorHandlers() {
|
|
return this.hasChildValue(this.getFormErrorHandlers());
|
|
}
|
|
|
|
/**
|
|
* determines for has specific error or not ...
|
|
*
|
|
* @param handler form error handler ...
|
|
*/
|
|
formHasError(handler: XFormErrorHandler) {
|
|
return this.getValue(handler.errorName).pipe(
|
|
map((errorName) => {
|
|
return (
|
|
!isNullOrUndefined(this.ERRORS) &&
|
|
keys(this.ERRORS).includes(errorName) &&
|
|
!isNullOrUndefined(this.ERRORS[errorName])
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determine form has specific error by name ...
|
|
*
|
|
* @param name error name ...
|
|
*/
|
|
formHasErrorByName(name: string) {
|
|
return (
|
|
!isNullOrUndefined(this.ERRORS) &&
|
|
keys(this.ERRORS).includes(name) &&
|
|
!isNullOrUndefined(this.ERRORS[name])
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve specific error from form ...
|
|
*
|
|
* @param handler form error handler ...
|
|
*/
|
|
getFormError(handler: XFormErrorHandler) {
|
|
return this.getErrorHandlerErrorName(handler).pipe(
|
|
concatMap((errorName) =>
|
|
this.formHasError(handler).pipe(
|
|
map((hasError) => {
|
|
return {
|
|
errorName,
|
|
hasError,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((descriptor) =>
|
|
descriptor.hasError ? this.ERRORS[descriptor.errorName] : null
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve specific form error by name ...
|
|
*
|
|
* @param name error name ...
|
|
*/
|
|
getFormErrorByName(name: string) {
|
|
return this.formHasErrorByName(name) ? this.ERRORS[name] : null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Control Providers ...
|
|
/**
|
|
* retrieve specific control config ...
|
|
*
|
|
* @param name control name
|
|
*/
|
|
getFormControl(name: XFormControlNameIdentifier) {
|
|
return this.getFormControls().pipe(
|
|
map((controls) => controls.find((c) => c.propName === name))
|
|
);
|
|
}
|
|
|
|
//
|
|
getControlInputElementId(control: XFormControlConfig) {
|
|
return `x-form-${control.propName.toString()}-input-element`;
|
|
}
|
|
|
|
//
|
|
getControlInputElementIdByName(name: XFormControlNameIdentifier) {
|
|
return `x-form-${name.toString()}-input-element`;
|
|
}
|
|
|
|
//
|
|
getControlInputElementClasses(control: XFormControlConfig) {
|
|
return this.getControlInputElementCssClasses(control).pipe(
|
|
concatMap((inpCss) =>
|
|
this.getControlType(control).pipe(
|
|
map((type) => {
|
|
//
|
|
return [
|
|
'x-form-input-element',
|
|
`x-form-${type}-input-element`,
|
|
`x-form-${control.index.toString()}-input-element`,
|
|
`x-form-${control.propName.toString()}-input-element`,
|
|
//
|
|
...inpCss.map((i) => i.toString()),
|
|
];
|
|
})
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
getControlInputElementCssClasses(control: XFormControlConfig) {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getArrayValue(
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.inputCssClass)
|
|
? config.inputCssClass
|
|
: []
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
getControlDisableInput(control: XFormControlConfig) {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.disableInput)
|
|
? config.disableInput
|
|
: false
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
isInputControlReadOnly(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
concatMap((type) => {
|
|
//
|
|
if (type === XFormControlType.Text) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config && (config as XFormInputControlConfig)
|
|
? this.getOptionalValue(
|
|
(config as XFormInputControlConfig).readonly
|
|
)
|
|
: of(false)
|
|
)
|
|
);
|
|
} else {
|
|
return this.getValue(false);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
getControlDisableIcon(control: XFormControlConfig) {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.disableIcon)
|
|
? config.disableIcon
|
|
: false
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Control Type Providers ...
|
|
//
|
|
//#region Type Descriptor ...
|
|
/**
|
|
* retrieve a control type descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlTypeDescriptor(control: XFormControlConfig) {
|
|
return this.getValue(control.type);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Type ...
|
|
/**
|
|
* retrieve a control type ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlType(control: XFormControlConfig) {
|
|
return this.getControlTypeDescriptor(control).pipe(
|
|
concatMap((typeDesc) =>
|
|
this.getValue(
|
|
typeDesc && typeDesc.type ? typeDesc.type : XFormControlType.Hidden
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Type Config ...
|
|
/**
|
|
* retrieve a control type specific config object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlTypeConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeDescriptor(control).pipe(
|
|
concatMap((typeDesc) => this.getOptionalValue(typeDesc.config))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Action Icon Configs ...
|
|
/**
|
|
* determines a custom control has clear icon or not ...
|
|
*/
|
|
hasControlClearIcon(control: XFormControlConfig): Observable<boolean> {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
map((config) => {
|
|
return (
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.clearIcon)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve custom control clear icon
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlClearIcon(
|
|
control: XFormControlConfig
|
|
): Observable<XControlIconDescriptor> {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return !isNullOrUndefined(config)
|
|
? this.getValue(config.clearIcon)
|
|
: of(null);
|
|
}),
|
|
map((iconSelector) => {
|
|
return !isNullOrUndefined(iconSelector)
|
|
? iconSelector
|
|
: defaultFormControlClearIcon;
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a custom control has select icon or not ...
|
|
*/
|
|
hasControlSelectIcon(control: XFormControlConfig): Observable<boolean> {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
map((config) => {
|
|
return (
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.selectIcon)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve custom control select icon
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlSelectIcon(
|
|
control: XFormControlConfig
|
|
): Observable<XControlIconDescriptor> {
|
|
return this.getCustomControlConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return !isNullOrUndefined(config)
|
|
? this.getValue(config.selectIcon)
|
|
: of(null);
|
|
}),
|
|
map((iconSelector) => {
|
|
return !isNullOrUndefined(iconSelector)
|
|
? iconSelector
|
|
: defaultFormControlSelectIcon;
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region XForm Custom Control IconDescriptor Providers ...
|
|
/**
|
|
* retrieve Custom Control Action Icon's Name ...
|
|
*
|
|
* @param role Icon Action Descriptor...
|
|
* @param descriptor Selector icon descriptor ...
|
|
*/
|
|
getControlIconDescriptorName(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor
|
|
) {
|
|
return this.getValue(descriptor.name).pipe(
|
|
map((name) => {
|
|
return !isNullOrUndefined(name) && !isNullOrEmptyString(name.toString())
|
|
? name
|
|
: role === this.ControlIconRoles.Select
|
|
? XIconNames.touch
|
|
: XIconNames.clear;
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve Custom Control Action Icon's color ...
|
|
*
|
|
* @param role Icon Action Descriptor...
|
|
* @param descriptor Selector icon descriptor ...
|
|
*/
|
|
getControlIconDescriptorColor(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor
|
|
) {
|
|
return this.getValue(descriptor.color).pipe(
|
|
map((color) => {
|
|
return !isNullOrEmptyString(color)
|
|
? color
|
|
: role === this.ControlIconRoles.Select
|
|
? XColorWithBrightness.Success
|
|
: XColorWithBrightness.Danger;
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve Custom Control Action Icon's applyStateColor ...
|
|
*
|
|
* @param descriptor Selector icon descriptor ...
|
|
*/
|
|
getControlIconDescriptorApplyStateColor(descriptor: XControlIconDescriptor) {
|
|
return this.getOptionalValue(descriptor.applyStateColor);
|
|
}
|
|
|
|
/**
|
|
* retrieve Custom Control Action Icon's tooltip ...
|
|
*
|
|
* @param role Icon Action Descriptor...
|
|
* @param descriptor Selector icon descriptor ...
|
|
*/
|
|
getControlIconDescriptorTooltip(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor
|
|
) {
|
|
return this.getResourceValue(descriptor.tooltip).pipe(
|
|
map((tooltip) => {
|
|
return !isNullOrEmptyString(tooltip)
|
|
? tooltip
|
|
: role === this.ControlIconRoles.Select
|
|
? this.resourceProvider(this.ResourceIDs.select)
|
|
: this.resourceProvider(this.ResourceIDs.clear);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve Custom Control Action Icon's position ...
|
|
*
|
|
* @param descriptor Selector icon descriptor ...
|
|
*/
|
|
getControlIconDescriptorPosition(descriptor: XControlIconDescriptor) {
|
|
return this.getValue(descriptor.position).pipe(
|
|
map((position) => {
|
|
return !isNullOrEmptyString(position)
|
|
? position
|
|
: XControlIconPosition.Suffix;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Type Configs
|
|
//
|
|
//#region Markdown Config ...
|
|
/**
|
|
* retrieve Markdown Control Config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormMarkdownControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines control has Markdown Config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasMarkdownConfig(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines markdown Card is In Page or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMarkdownInPage(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.isInPage);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown has toolbar ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkDownHasToolbar(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.hasToolbar);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown wrap with card ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMarkdownWrapWithCard(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.wrapWithCard);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown card color ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownCardColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getValue(
|
|
config && config.cardColor ? config.cardColor : XColor.Light
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown editorBoxColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownEditorBoxColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getValue(
|
|
config && config.editorBoxColor ? config.editorBoxColor : XColor.Light
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown previewBoxColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownPreviewBoxColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getValue(
|
|
config && config.previewBoxColor
|
|
? config.previewBoxColor
|
|
: XColorWithBrightness.MediumTint
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines markdown toolbar color is foreground color or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownCardForegroundColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.cardForegroundColor);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown mode ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownMode(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.mode || null)),
|
|
map((mode) => (mode ? mode : XMarkdownMode.PREVIEW))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown Toolbar Color ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkDownToolbarColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getValue(
|
|
config && config.toolbarColor ? config.toolbarColor : XColor.Light
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown Card Title ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownCardTitle(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.cardTitle);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown action provider ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownActionProvider(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
if (!config.actionProvider) {
|
|
//
|
|
if (!this.actionProviders[control.propName]) {
|
|
this.actionProviders[control.propName] =
|
|
new Subject<XMarkdownActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[
|
|
control.propName
|
|
] as Subject<XMarkdownActionModel>;
|
|
} else {
|
|
return config.actionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines markdown toolbar color is foreground color or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkDownToolbarForegroundColor(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.toolbarForegroundColor);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown cssClass ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownCssClass(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getArrayValue(config.cssClass);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown content ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkDownContent(control: XFormControlConfig) {
|
|
return this.getValue(control).pipe(
|
|
map((ctrl) => {
|
|
//
|
|
if (!this.hasControl(ctrl.propName)) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const xFormControl = this.getControl(ctrl.propName);
|
|
if (!xFormControl) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
return (xFormControl.value || '') as string;
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown Card SubTitle ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownCardSubTitle(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getResourceValue(config.cardSubTitle);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown toolbar css class ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownToolbarCssClass(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getArrayValue(config.toolbarCssClass);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve markdown toolbar config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMarkdownToolbarConfig(control: XFormControlConfig) {
|
|
return this.getMarkdownConfig(control).pipe(
|
|
concatMap((config) => {
|
|
return this.getOptionalValue(config.toolbarConfig);
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Select/Radio Config ...
|
|
/**
|
|
* retrieve select control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSelectConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormSelectControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines select control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasSelectConfig(control: XFormControlConfig) {
|
|
return this.getSelectConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve select control options ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSelectOptions(control: XFormControlConfig) {
|
|
return this.getSelectConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.options))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines select control can select multiple or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSelectMultiple(control: XFormControlConfig) {
|
|
return this.getSelectConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.multiple))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve Select Control Panel Calsses ...
|
|
*/
|
|
getSelectPanelClasses(control: XFormControlConfig) {
|
|
return this.getFormControlClasses(control).pipe(
|
|
concatMap((classes) =>
|
|
this.getSelectMultiple(control).pipe(
|
|
map((isMultiple) => ({ classes, isMultiple }))
|
|
)
|
|
),
|
|
map((selectInfo) => {
|
|
return [
|
|
...selectInfo.classes,
|
|
'x-form-select-control-panel',
|
|
...(selectInfo.isMultiple ? ['multiple'] : []),
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve select control option css classes ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getOptionClassName(option: XFormSelectControlOption) {
|
|
return this.getValue(option).pipe(
|
|
map((opt) => ['x-select-option', `x-select-${opt.value}-option`])
|
|
);
|
|
}
|
|
|
|
//
|
|
// Radio ...
|
|
/**
|
|
* retrieve radio control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getRadioConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormRadioControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines radio control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasRadioConfig(control: XFormControlConfig) {
|
|
return this.getRadioConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve radio control options ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getRadioOptions(control: XFormControlConfig) {
|
|
return this.getRadioConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.options))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a radio control options label position ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getRadioLabelPosition(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.labelPosition
|
|
: XFormControlLabelPosition.After
|
|
).pipe(map((result) => result as 'before' | 'after'))
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region CheckBox Config ...
|
|
/**
|
|
* retrieve checkbox control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getCheckboxConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormCheckBoxControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines checkbox control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasCheckboxConfig(control: XFormControlConfig) {
|
|
return this.getCheckboxConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a checkbox control label position ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getCheckboxLabelPosition(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.labelPosition
|
|
: XFormControlLabelPosition.After
|
|
).pipe(map((result) => result as 'before' | 'after'))
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Date Picker Config ...
|
|
/**
|
|
* retrieve date control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDateConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormDatePickerControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines date control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasDateConfig(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve date control start at ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDateStartAt(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.startAt))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve date control picker position ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerPosition(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.datePickerPosition))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve date control filter ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDateFilter(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.dateFilter))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve date control input handler ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDateInputHandler(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.dateInput))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve date control change handler ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDateChangeHandler(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.dateChange))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines date control input field disabled or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isDatePickerInputDisabled(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.disableInput))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines date control input field disabled or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isDatePickerToggleDisabled(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.disablePicker))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retriece date control classes ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerClasses(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
map((type) => {
|
|
return [
|
|
'x-date-picker',
|
|
`x-form-control-${type}-picker`,
|
|
`x-form-control-${control.propName.toString()}-date-picker`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retriece date control toggle icon name ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerIcon(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.toggleIcon)),
|
|
map((icon) => (icon ? icon : XIconNames.calendar))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retriece date control toggle icon color ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerIconColor(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.iconColor)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retriece date control toggle icon tooltip ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerIconTooltip(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.iconTooltip))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retriece date control toggle apply color state ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getDatePickerIconApplyStateColor(control: XFormControlConfig) {
|
|
return this.getDateConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.applyStateColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines date control icon position is suffix or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isDatePickerHasSuffixIcon(control: XFormControlConfig) {
|
|
return this.getDatePickerPosition(control).pipe(
|
|
map(
|
|
(position) => position === XFormDatePickerControlPickerPosition.Suffix
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines date control icon position is prefix or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isDatePickerHasPrefixIcon(control: XFormControlConfig) {
|
|
return this.getDatePickerPosition(control).pipe(
|
|
map(
|
|
(position) => position === XFormDatePickerControlPickerPosition.Prefix
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Slider Config ...
|
|
/**
|
|
* retrieve slider control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSliderConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormSliderControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines slider control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasSliderConfig(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve slider control min value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSliderMin(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.min)),
|
|
map((min) => (min ? min : 0))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve slider control max value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSliderMax(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.max)),
|
|
map((max) => (max ? max : 99))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve slider control step value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSliderStep(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.step)),
|
|
map((step) => (step ? step : 1))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve slider control invert value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSliderInvert(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.invert))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines slider control is vertical or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isSliderVertical(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.vertical))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines slider control show thumb label or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
showSliderThumbLabel(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.thumbLabel))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve slider formatter function ...
|
|
*/
|
|
getSliderFormatter(control: XFormControlConfig) {
|
|
return this.getSliderConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.formatter))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Toggle Config ...
|
|
/**
|
|
* retrieve a checkbox control label position ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getToggleLabelPosition(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.labelPosition
|
|
: XFormControlLabelPosition.After
|
|
).pipe(map((result) => result as 'before' | 'after'))
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Map Config ...
|
|
/**
|
|
* retrieve map control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormMapControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasMapConfig(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map component's selected point value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSelectedPoint(control: XFormControlConfig): Observable<XMapLocation> {
|
|
//
|
|
const fControl = this.getControl(control.propName);
|
|
if (!fControl || !fControl.value) {
|
|
return of(null);
|
|
}
|
|
|
|
//
|
|
const fValue = fControl.value as string;
|
|
if (isNullOrEmptyString(fValue)) {
|
|
return of(null);
|
|
}
|
|
|
|
//
|
|
const result = fromLongLat(fValue);
|
|
this.getMapActionProvider(control).pipe(
|
|
tap((actionProvider) => {
|
|
//
|
|
if (actionProvider) {
|
|
//
|
|
actionProvider.next({
|
|
action: XMapAction.SetCenter,
|
|
payload: result,
|
|
});
|
|
}
|
|
})
|
|
);
|
|
|
|
//
|
|
return of(result);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control zoom value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapLatitude(control: XFormControlConfig) {
|
|
return this.getMapSelectedPoint(control).pipe(
|
|
map((point) => (point && point.latitude ? +point.latitude : 0))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control zoom value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapLongitude(control: XFormControlConfig) {
|
|
return this.getMapSelectedPoint(control).pipe(
|
|
map((point) => (point && point.longitude ? +point.longitude : 0))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control zoom value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapZoom(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => (config.zoom ? this.getValue(config.zoom) : of(0)))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control markerStyle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapMarkerStyle(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.markerStyle)),
|
|
map((markerStyle) => (markerStyle ? markerStyle : defaultMarkerStyle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control cssClass value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapCssClass(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.cssClass))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control canSelect or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapCanSelect(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.canSelect))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showProgressBar or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowProgressBar(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showProgressBar)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control progressBarColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapProgressBarColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.progressBarColor)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control progressBarPosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapProgressBarPosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.progressBarPosition)),
|
|
map((position) =>
|
|
isNullOrEmptyString(position) ? XMapItemPosition.TOP : position
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Map Search Bar ...
|
|
/**
|
|
* determines map control showSearchBar or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowSearchBar(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showSearchBar)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarType value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarType(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarType)),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XSearchBarType.Search : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarValue value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarValue(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.searchBarValue))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarDebounce value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarDebounce(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarDebounce)),
|
|
map((result) =>
|
|
isNullOrUndefined(result)
|
|
? this.config.defaultSearchDebounceTime
|
|
: result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarSpellcheck value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarSpellcheck(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.searchBarSpellcheck)),
|
|
map((result) => (isNullOrUndefined(result) ? false : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchPlaceProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchPlaceProvider(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.searchPlaceProvider)),
|
|
map((result) =>
|
|
isNullOrUndefined(result) ? defaultMapSearchPlaceProvider : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarColor)),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XColorWithBrightness.Primary : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarForegroundColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarForegroundColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarForegroundColor)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarClearIcon value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarClearButtonIcon(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarClearButtonIcon)
|
|
),
|
|
map((result) => (isNullOrUndefined(result) ? XIconNames.clear : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarTitle(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.searchBarTitle)),
|
|
map((result) =>
|
|
isNullOrUndefined(result) ? XResourceIDs.search : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarSearchIcon value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarSearchButtonIcon(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchButtonIcon)
|
|
),
|
|
map((result) => (isNullOrUndefined(result) ? XIconNames.search : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarInputColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarSearchInputColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchInputColor)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XColorWithBrightness.Primary : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarForegroundInputColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarForegroundSearchInputColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarForegroundSearchInputColor)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchResultListColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchResultListColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchResultListColor)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XColorWithBrightness.Light : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarActionProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarActionProvider(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
const key = `${control.propName.toString()}_SearchBar`;
|
|
if (!config.searchBarActionProvider) {
|
|
//
|
|
if (!this.actionProviders[key]) {
|
|
this.actionProviders[key] = new Subject<XSearchBarActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[key] as Subject<XSearchBarActionModel>;
|
|
} else {
|
|
return config.searchBarActionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarClearIconColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarClearButtonIconColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarClearButtonIconColor)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XColorWithBrightness.Light : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarCssClass value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarCssClass(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.searchBarCssClass))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarSearchIconColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarSearchButtonIconColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchButtonIconColor)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XColorWithBrightness.Light : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarCancelButtonIcon value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarCancelButtonIcon(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarCancelButtonIcon)
|
|
),
|
|
map((result) => (isNullOrUndefined(result) ? XIconNames.cancel : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarPosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarPosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarPosition)),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarKeyboardType value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarKeyboardType(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarKeyboardType)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XSearchBarType.Search : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarCancelButtonTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarCancelButtonTitle(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.searchBarCancelButtonTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control searchBarEnterKeyHint value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSearchBarEnterKeyHint(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarEnterKeyHint)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XSearchBarEnterKeyHint.Search : result
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control searchBarShowCancelButton or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowSearchBarCancelButton(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarShowCancelButton)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
/**
|
|
* determines map control showSelectedLocation or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowSelectedLocation(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showSelectedLocation)),
|
|
map((result) => (isNullOrUndefined(result) ? false : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control selectedLocationPosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapSelectedLocationPosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.selectedLocationPosition)
|
|
),
|
|
map((position) =>
|
|
isNullOrEmptyString(position) ? XMapItemPosition.TOP : position
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showGoMarkedPlace or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowGoMarkedPlace(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showGoMarkedPlace)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control goMarkedPlacePosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapGoMarkedPlacePosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.goMarkedPlacePosition)
|
|
),
|
|
map((position) =>
|
|
isNullOrEmptyString(position) ? XMapItemPosition.TOP : position
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showClearMarker or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowClearMarker(control: XFormControlConfig) {
|
|
//
|
|
// Clear Marker in Form Components only must shown when user decide to it and the present Type is with dialog
|
|
// since the clear value handle clear marker actions in without dialog mode ...
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) =>
|
|
forkJoin({
|
|
showClearMarker: this.getOptionalValue(config.showClearMarker),
|
|
withDialog: this.isMapPresentWithDialog(control),
|
|
})
|
|
),
|
|
map(
|
|
(info) =>
|
|
(isNullOrUndefined(info.showClearMarker)
|
|
? true
|
|
: info.showClearMarker) && info.withDialog
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control clearMarkerPosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapClearMarkerPosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.clearMarkerPosition)),
|
|
map((position) =>
|
|
isNullOrEmptyString(position) ? XMapItemPosition.TOP : position
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showLocator or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowLocator(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showLocator)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control locatorPosition value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapLocatorPosition(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.locatorPosition)),
|
|
map((position) =>
|
|
isNullOrEmptyString(position) ? XMapItemPosition.TOP : position
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showZoom or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowZoom(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showZoom)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showRotate or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowRotate(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showRotate)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showZoomSlider or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapShowZoomSlider(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showZoomSlider)),
|
|
map((result) => (isNullOrUndefined(result) ? false : result))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control isInPage or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMapInPage(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.isInPage))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control wrapWithCard or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMapWrapWithCard(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.wrapWithCard))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control cardColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapCardColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardColor)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control cardForegroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMapCardForegroundColor(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardForegroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control cardTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapCardTitle(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control cardSubTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapCardSubTitle(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardSubTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showCardFooter or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
mapCardShowFooter(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardShowFooter))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve map control actionProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapActionProvider(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
if (!config.actionProvider) {
|
|
//
|
|
if (!this.actionProviders[control.propName]) {
|
|
this.actionProviders[control.propName] =
|
|
new Subject<XMapActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[
|
|
control.propName
|
|
] as Subject<XMapActionModel>;
|
|
} else {
|
|
return config.actionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Map Present Types ...
|
|
/**
|
|
* retrieve map control presentType value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getMapPresentType(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.presentType)),
|
|
map((presentType) =>
|
|
!isNullOrEmptyString(presentType)
|
|
? presentType
|
|
: XFormMapControlPresentType.WithoutDialog
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control present WithoutDialog or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMapPresentWithoutDialog(control: XFormControlConfig) {
|
|
return this.getMapPresentType(control).pipe(
|
|
map(
|
|
(presentType) =>
|
|
presentType === XFormMapControlPresentType.WithoutDialog
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control present WithDialog or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isMapPresentWithDialog(control: XFormControlConfig) {
|
|
return this.getMapPresentType(control).pipe(
|
|
map(
|
|
(presentType) => presentType === XFormMapControlPresentType.WithDialog
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region ColorPicker Config ...
|
|
/**
|
|
* retrieve color picker control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormColorPickerControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasColorPickerConfig(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control color value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.color)),
|
|
map((color) => (isNullOrEmptyString(color) ? XColor.Light : color))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control colorViewBorderColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorViewBorderColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.colorViewBorderColor)),
|
|
map((color) => (isNullOrEmptyString(color) ? XColor.Light : color))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control colorViewBorderStyle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorViewBorderStyle(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.colorViewBorderStyle)),
|
|
map((style) => (isNullOrEmptyString(style) ? XBorderStyle.Solid : style))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control colorViewBorderWidth value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorViewBorderWidth(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.colorViewBorderWidth))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control cssClass value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCssClass(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.cssClass))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control cardColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCardColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control cardTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCardTitle(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control cursorColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCursorColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.cursorColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control presetColors value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerPresetColors(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.presetColors))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control outputFormat value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerOutputFormat(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.outputFormat)),
|
|
map((format) =>
|
|
!isNullOrEmptyString(format) ? format : XColorPickerOutputFormat.XHEX
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control cardSubTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCardSubTitle(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardSubTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control colorTextColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorTextColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.colorTextColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showColorValue or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowColorValue(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showColorValue ? this.getValue(config.showColorValue) : of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showHueChannel or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowHueChannel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showHueChannel ? this.getValue(config.showHueChannel) : of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control foregroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerForegroundColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.foregroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showPresetColors or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowPresetColors(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showPresetColors
|
|
? this.getValue(config.showPresetColors)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showAlphaChannel or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowAlphaChannel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showAlphaChannel
|
|
? this.getValue(config.showAlphaChannel)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control presetColorsLable value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerPresetColorsLable(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.presetColorsLable)),
|
|
map((value) =>
|
|
isNullOrEmptyString(value) ? XResourceIDs.preset_colors : value
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control copyToClipboardIconLabel value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCopyToClipboardIconLabel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getResourceValue(config.copyToClipboardIconLabel)
|
|
),
|
|
map((value) =>
|
|
isNullOrEmptyString(value) ? XResourceIDs.copy_to_clipboard : value
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control colorInputIconLabel value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorInputIconLabel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.colorInputIconLabel)),
|
|
map((value) => (isNullOrEmptyString(value) ? XResourceIDs.input : value))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control clearColorIconLabel value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerClearColorIconLabel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.clearColorIconLabel)),
|
|
map((value) => (isNullOrEmptyString(value) ? XResourceIDs.clear : value))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showPaletteChannel or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowPaletteChannel(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showPaletteChannel
|
|
? this.getValue(config.showPaletteChannel)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control cardForegroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerCardForegroundColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardForegroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showCopyToClipboard or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowCopyToClipboard(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showCopyToClipboard
|
|
? this.getValue(config.showCopyToClipboard)
|
|
: of(false)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showColorInput or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowColorInput(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showCopyToClipboard
|
|
? this.getValue(config.showColorInput)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control representColorFormats value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerRepresentColorFormats(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.representColorFormats)),
|
|
map((formats) =>
|
|
hasChild(formats) ? formats : [XColorPickerOutputFormat.XHEX]
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control presetColorsLableColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerPresetColorsLableColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.presetColorsLableColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control copyToClipboardIconColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerCopyToClipboardIconColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.copyToClipboardIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Tertiary))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control copyToClipboardIconColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerColorInputIconColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.colorInputIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Secondary))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control clearColorIconColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerClearColorIconColor(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.clearColorIconColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Danger))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showSelectedColorPreview or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickerShowSelectedColorPreview(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
config.showSelectedColorPreview
|
|
? this.getValue(config.showSelectedColorPreview)
|
|
: of(true)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control isInPage or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerInPage(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.isInPage))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control wrapWithCard or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerWrapWithCard(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.wrapWithCard))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control showCardFooter or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
colorPickercardShowFooter(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showCardFooter))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker component's selected value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerSelectedColor(control: XFormControlConfig) {
|
|
//
|
|
const fControl = this.getControl(control.propName);
|
|
if (!fControl) {
|
|
return of('');
|
|
}
|
|
|
|
//
|
|
const fValue = fControl.value as string;
|
|
if (isNullOrEmptyString(fValue)) {
|
|
return of('');
|
|
}
|
|
|
|
//
|
|
return of(fValue);
|
|
}
|
|
|
|
/**
|
|
* retrieve color picker control actionProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerActionProvider(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
if (!config.actionProvider) {
|
|
//
|
|
if (!this.actionProviders[control.propName]) {
|
|
this.actionProviders[control.propName] =
|
|
new Subject<XMapActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[
|
|
control.propName
|
|
] as Subject<XColorPickerActionModel>;
|
|
} else {
|
|
return config.actionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region ColorPicker Present Types ...
|
|
/**
|
|
* retrieve color picker control presentType value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getColorPickerPresentType(control: XFormControlConfig) {
|
|
return this.getColorPickerConfig(control).pipe(
|
|
concatMap((config) =>
|
|
!isNullOrUndefined(config) && !isNullOrUndefined(config.presentType)
|
|
? this.getOptionalValue(config.presentType)
|
|
: of(null)
|
|
),
|
|
map((presentType) =>
|
|
!isNullOrEmptyString(presentType)
|
|
? presentType
|
|
: XFormColorPickerControlPresentType.WithoutDialog
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control present WithoutDialog or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerPresentWithoutDialog(control: XFormControlConfig) {
|
|
return this.getColorPickerPresentType(control).pipe(
|
|
map(
|
|
(presentType) =>
|
|
presentType === XFormColorPickerControlPresentType.WithoutDialog
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines color picker control present WithDialog or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isColorPickerPresentWithDialog(control: XFormControlConfig) {
|
|
return this.getColorPickerPresentType(control).pipe(
|
|
map(
|
|
(presentType) =>
|
|
presentType === XFormColorPickerControlPresentType.WithDialog
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Avatar Config ...
|
|
/**
|
|
* retrieve avatar upload control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormAvatarUploadControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasAvatarConfig(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control canDrop or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
avatarCanDrop(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.canDrop))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control isInPage or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarInPage(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.isInPage))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control wrapWithCard or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarWrapWithCard(control: XFormControlConfig) {
|
|
return this.getMapConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.wrapWithCard))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control color value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.color)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control showCardFooter or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
avatarCardShowFooter(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showCardFooter))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control foregroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarForegroundColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.foregroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control placeHolderAvatar value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarPlaceHolderAvatar(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.placeHolderAvatar))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control minAllowedFileSize value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarMinAllowedFileSize(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.minAllowedFileSize)),
|
|
map((minAllowedFileSize) =>
|
|
minAllowedFileSize ? minAllowedFileSize : this.config.minAllowedFileSize
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control maxAllowedFileSize value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarMaxAllowedFileSize(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.maxAllowedFileSize)),
|
|
map((maxAllowedFileSize) =>
|
|
maxAllowedFileSize
|
|
? maxAllowedFileSize
|
|
: this.config.maxProfileImageSize
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control cardColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarCardColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardColor)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control cardForegroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarCardForegroundColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.cardForegroundColor))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaIsInPage or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaInPage(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.fileDropAreaIsInPage))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control cardTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarCardTitle(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control cssClass value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarCssClass(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.cssClass))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaWrapWithCard or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaWrapWithCard(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaWrapWithCard)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaIcon value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaIcon(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getValue(config.fileDropAreaIcon)),
|
|
map((icon) => (icon ? icon : XIconNames.arrow_down))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaDragDisabled or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaDragDisabled(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaDragDisabled)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control cardSubTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarCardSubTitle(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.cardSubTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar control actionProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarActionProvider(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
if (!config.actionProvider) {
|
|
//
|
|
if (!this.actionProviders[control.propName]) {
|
|
this.actionProviders[control.propName] =
|
|
new Subject<XAvatarUploadActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[
|
|
control.propName
|
|
] as Subject<XAvatarUploadActionModel>;
|
|
} else {
|
|
return config.actionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines map control fileDropAreaShowCardFooter or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
avatarDropAreaCardShowFooter(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaShowCardFooter)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.fileDropAreaColor)),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaForegroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaForegroundColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaForegroundColor)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaDisableFileCheck or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaDisableFileCheck(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaDisableFileCheck)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaCardColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaCardColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaCardColor)
|
|
),
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaCardForegroundColor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaCardForegroundColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaCardForegroundColor)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control emptyFileException value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarEmptyFileException(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.emptyFileException)),
|
|
map((exception) => (exception ? exception : XExceptionIDs.EmptyFile))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaErrorColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaErrorColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaErrorColor)
|
|
),
|
|
map((color) => (color ? color : XColor.Danger))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaMessage value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaMessage(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getOptionalValue(config.fileDropAreaMessage)),
|
|
map((message) => (message ? message : XResourceIDs.drag_drop_here)),
|
|
concatMap((resource) => this.getResourceValue(resource))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaAccentColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaAccesntColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaAccentColor)
|
|
),
|
|
map((color) => (color ? color : XColor.Secondary))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control allowedExtensions value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarAllowedExtensions(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.allowedExtensions)),
|
|
map((allowedExtensions) =>
|
|
hasChild(allowedExtensions)
|
|
? allowedExtensions
|
|
: this.config.allowedImageExtensions
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaCardTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaCardTitle(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getResourceValue(config.fileDropAreaCardTitle))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaSuccessColor value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaSuccessColor(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaSuccessColor)
|
|
),
|
|
map((color) => (color ? color : XColor.Success))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines avatar upload control fileDropAreaSupportsMultipleFiles or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
isAvatarDropAreaSupportsMultipleFiles(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaSupportsMultipleFiles)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaCssClass value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaCssClass(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.fileDropAreaCssClass))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaCardSubTitle value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaCardSubTitle(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getResourceValue(config.fileDropAreaCardSubTitle)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control emptyFileException value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarNotAllowedFileException(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.notAllowedFileException)
|
|
),
|
|
map((exception) => (exception ? exception : XExceptionIDs.InavlidFile))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control fileDropAreaContentTemplate value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaContentTemplate(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.fileDropAreaContentTemplate)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control minAllowedFileSizeException value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarMinAllowedFileSizeException(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.minAllowedFileSizeException)
|
|
),
|
|
map((exception) =>
|
|
exception ? exception : XExceptionIDs.MinFilesSizeExceeded
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control maxAllowedFileSizeException value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarMaxAllowedFileSizeException(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.maxAllowedFileSizeException)
|
|
),
|
|
map((exception) =>
|
|
exception ? exception : XExceptionIDs.MaxFilesSizeExceeded
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar control actions value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarActions(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) => this.getArrayValue(config.actions)),
|
|
concatMap((actions) =>
|
|
hasChild(actions)
|
|
? of(actions)
|
|
: this.getArrayValue(defaultAvatarUploadActionButtons)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar control fileDropAreaActionProvider value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaActionProvider(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
map((config) => {
|
|
//
|
|
const key = `${control.propName.toString()}_drop_area`;
|
|
|
|
//
|
|
if (!config.fileDropAreaActionProvider) {
|
|
//
|
|
if (!this.actionProviders[key]) {
|
|
this.actionProviders[key] = new Subject<XFileDropAreaActionModel>();
|
|
}
|
|
|
|
//
|
|
return this.actionProviders[key] as Subject<XFileDropAreaActionModel>;
|
|
} else {
|
|
return config.fileDropAreaActionProvider;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve avatar upload control allowedExtensions value ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAvatarDropAreaAllowedExtensions(control: XFormControlConfig) {
|
|
return this.getAvatarConfig(control).pipe(
|
|
concatMap((config) =>
|
|
this.getArrayValue(config.fileDropAreaAllowedExtensions)
|
|
),
|
|
map((allowedExtensions) =>
|
|
hasChild(allowedExtensions)
|
|
? allowedExtensions
|
|
: this.config.allowedImageExtensions
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selector Config ...
|
|
/**
|
|
* retrieve selector control config ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getSelectorConfig(control: XFormControlConfig) {
|
|
return this.getControlTypeConfig(control).pipe(
|
|
map((config) => config as XFormSelectorControlConfig)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines selector control has config or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
hasSelectorConfig(control: XFormControlConfig) {
|
|
return this.getSelectorConfig(control).pipe(
|
|
map((config) => !isNullOrUndefined(config))
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Update On ...
|
|
/**
|
|
* retrieve a control UpdateOn strategy ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlUpdateOn(control: XFormControlConfig) {
|
|
return this.getOptionalValue(control.updateOn).pipe(
|
|
map((updateOn) => (updateOn ? updateOn : XFormUpdateOn.CHANGE))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Validators ...
|
|
/**
|
|
* retrieve a control validators descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlValidators(control: XFormControlConfig) {
|
|
return this.getOptionalValue(control.validators);
|
|
}
|
|
|
|
/**
|
|
* determines a control has Validators or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasValidators(control: XFormControlConfig) {
|
|
return this.getControlValidators(control).pipe(
|
|
map((controlValidators) => !isNullOrUndefined(controlValidators))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Event Handlers ...
|
|
/**
|
|
* retrieve a control event handlers descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlEventHandlers(control: XFormControlConfig) {
|
|
return this.getOptionalValue(control.eventHandlers);
|
|
}
|
|
|
|
/**
|
|
* determines a control has validators or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasEventHandlers(control: XFormControlConfig) {
|
|
return this.getControlEventHandlers(control).pipe(
|
|
map((eventHandlers) => !isNullOrUndefined(eventHandlers))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Appearance Descriptor ...
|
|
/**
|
|
* retrieve a control appearance descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlAppearanceDesc(
|
|
control: XFormControlConfig
|
|
): Observable<XFormControlAppearanceDescriptor> {
|
|
return !isNullOrUndefined(control)
|
|
? this.getValue(control.appearance)
|
|
: of(null);
|
|
}
|
|
|
|
//
|
|
//#region Appearance Parts ...
|
|
//
|
|
//#region Control Hidden ...
|
|
/**
|
|
* determines a control hidden or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlHidden(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.hidden : true
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Disabled ...
|
|
/**
|
|
* determines a control is disabled or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlDisabled(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.disabled
|
|
: true
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Hint ...
|
|
/**
|
|
* retrieve a control hint ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlHint(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getResourceValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.hint : ''
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Label ...
|
|
/**
|
|
* retrieve a control label ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlLabel(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getResourceValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.label : ''
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Tooltip ...
|
|
/**
|
|
* retrieve a control tooltip ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlTooltip(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getResourceValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.tooltip : ''
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control PlaceHolder ...
|
|
/**
|
|
* retrieve a control placeholder ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlPlaceHolder(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getResourceValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.placeholder
|
|
: ''
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control CssClass ...
|
|
/**
|
|
* retrieve a control cssClaases ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlCssClass(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getArrayValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.cssClass : []
|
|
)
|
|
),
|
|
concatMap((cssClasses) =>
|
|
this.getControlType(control).pipe(
|
|
map((type) => {
|
|
return {
|
|
type,
|
|
cssClasses,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((descriptor) => {
|
|
return descriptor.cssClasses.concat(
|
|
'x-form-control',
|
|
`x-form-control-${control.index}`,
|
|
`x-form-control-${descriptor.type}`
|
|
);
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Icons Descriptor ...
|
|
/**
|
|
* retrieve a control icons descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlIconDesc(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig) ? appearanceConfig.icons : null
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a control has icons descriptor object or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasIcons(control: XFormControlConfig) {
|
|
return this.getControlIconDesc(control).pipe(
|
|
map((iconDesc) => !isNullOrUndefined(iconDesc))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a control has suffix icon or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasSuffixIcon(control: XFormControlConfig) {
|
|
return this.getControlIconDesc(control).pipe(
|
|
concatMap((iconDesc) =>
|
|
this.getOptionalValue(iconDesc ? iconDesc.suffix : null).pipe(
|
|
map((iconSuffix) => !isNullOrUndefined(iconSuffix))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control suffix icon object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlSuffixIcon(control: XFormControlConfig) {
|
|
return this.getControlIconDesc(control).pipe(
|
|
concatMap((iconDesc) =>
|
|
this.getOptionalValue(iconDesc ? iconDesc.suffix : null)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a control has prefix icon or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasPrefixIcon(control: XFormControlConfig) {
|
|
return this.getControlIconDesc(control).pipe(
|
|
concatMap((iconDesc) =>
|
|
this.getOptionalValue(iconDesc ? iconDesc.prefix : null).pipe(
|
|
map((iconPrefix) => !isNullOrUndefined(iconPrefix))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control prefix icon ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlPrefixIcon(control: XFormControlConfig) {
|
|
return this.getControlIconDesc(control).pipe(
|
|
concatMap((iconDesc) =>
|
|
this.getOptionalValue(iconDesc ? iconDesc.prefix : null)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve an icon descriptor's icon name ...
|
|
*
|
|
* @param icon form control icon descriptor ...
|
|
*/
|
|
getControlIconName(icon: XFormIconDescriptor) {
|
|
return this.getValue(icon.name);
|
|
}
|
|
|
|
/**
|
|
* retrieve an icon descriptor's icon color ...
|
|
*
|
|
* @param icon form control icon descriptor ...
|
|
*/
|
|
getControlIconColor(icon: XFormIconDescriptor) {
|
|
return this.getOptionalValue(icon.color).pipe(
|
|
map((color) => (color ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve an icon descriptor's icon tooltip ...
|
|
*
|
|
* @param icon form control icon descriptor ...
|
|
*/
|
|
getControlIconTooltip(icon: XFormIconDescriptor) {
|
|
return this.getResourceValue(icon.tooltip);
|
|
}
|
|
|
|
/**
|
|
* retrieve an icon descriptor's apply state color ...
|
|
*
|
|
* @param icon form control icon descriptor ...
|
|
*/
|
|
getControlIconApplyStateColor(icon: XFormIconDescriptor) {
|
|
return this.getOptionalValue(icon.applyStateColor);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Formatter Config ...
|
|
/**
|
|
* retrieve a control formatter config descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlFormatterConfig(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.formatter
|
|
: null
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a control has formatter config descriptor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasFormatter(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
map((formatterConfig) => !isNullOrUndefined(formatterConfig))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter locale ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterLocale(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) => this.getValue(formatterConfig.locale))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter seperator ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterSeperator(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) =>
|
|
this.getOptionalValue(formatterConfig.seperator)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter type ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterType(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) => this.getValue(formatterConfig.type))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter currency label ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterCurrencyLabel(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) =>
|
|
isNullOrUndefined(formatterConfig.currencyLable)
|
|
? of('')
|
|
: this.getResourceValue(formatterConfig.currencyLable)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter string formatter ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterStringFormatter(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) =>
|
|
this.getArrayValue(formatterConfig.stringFormatter)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control formatter string formatter ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getFormatterInputType(control: XFormControlConfig) {
|
|
return this.getControlFormatterConfig(control).pipe(
|
|
concatMap((formatterConfig) =>
|
|
isNullOrUndefined(formatterConfig.inputType)
|
|
? of(XStringInputFormatType.None)
|
|
: this.getValue(formatterConfig.inputType)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Progressbar ...
|
|
/**
|
|
* retrieve a control progress bar config descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlProgressBarConfig(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.progressBar
|
|
: null
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control has progress bar object descriptor or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasProgressBar(control: XFormControlConfig) {
|
|
return this.getControlProgressBarConfig(control).pipe(
|
|
map((progressBarConfig) => !isNullOrUndefined(progressBarConfig))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control progressbar color ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getProgressBarColor(control: XFormControlConfig) {
|
|
return this.getControlProgressBarConfig(control).pipe(
|
|
concatMap((progressBarConfig) => this.getValue(progressBarConfig.color))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control AutoComplete ...
|
|
/**
|
|
* retrieve an id number for form control auto complete view ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteId(control: XFormControlConfig) {
|
|
return `x-${control.propName.toString()}-auto-complete`;
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete config object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlAutoCompleteConfig(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.autoComplete
|
|
: null
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control has autocomplete or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasAutoComplete(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
map((autoConpleteConfig) => !isNullOrUndefined(autoConpleteConfig))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete opened ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteOpened(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) =>
|
|
this.getOptionalValue(autoCompleteConfig.opened)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete item template ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteItemTemplate(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) =>
|
|
this.getValue(autoCompleteConfig.itemTemplate)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete color ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteColor(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) =>
|
|
this.getOptionalValue(autoCompleteConfig.color).pipe(
|
|
map((color) => (color ? color : XColor.Light))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete onSelect ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteOnSelect(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) =>
|
|
this.getValue(autoCompleteConfig.onSelect)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control autocomplete Items ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteItems(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) => {
|
|
return !isNullOrUndefined(autoCompleteConfig.items) &&
|
|
isFunction(autoCompleteConfig.items)
|
|
? this.getArrayValue(autoCompleteConfig.items())
|
|
: this.getValue([]);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve autocomplete CssClass ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getAutoCompleteCssClass(control: XFormControlConfig) {
|
|
return this.getControlAutoCompleteConfig(control).pipe(
|
|
concatMap((autoCompleteConfig) =>
|
|
this.getArrayValue(autoCompleteConfig.cssClass).pipe(
|
|
map((cssClasses) =>
|
|
cssClasses.concat(
|
|
'x-auto-complete',
|
|
`x-${control.propName.toString()}-auto-complete`
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve control errors classes ...
|
|
*
|
|
* @param control form control config ...
|
|
*/
|
|
getControlErrorsClasses(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
map((type) => {
|
|
return [
|
|
'x-form-control-errors',
|
|
`x-form-${type}-control-errors`,
|
|
`x-form-control-${control.index.toString()}-errors`,
|
|
`x-form-control-${control.propName.toString()}-errors`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve special control's special error's class list ...
|
|
*
|
|
* @param control form control config ...
|
|
* @param handler form error handler instance ...
|
|
*/
|
|
getControlErrorClasses(
|
|
control: XFormControlConfig,
|
|
handler: XFormErrorHandler
|
|
) {
|
|
return this.getControlType(control).pipe(
|
|
concatMap((type) =>
|
|
this.getErrorHandlerErrorName(handler).pipe(
|
|
map((errorName) => {
|
|
return {
|
|
type,
|
|
errorName,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((descriptor) => {
|
|
return [
|
|
'x-form-field-error',
|
|
`x-form-field-${descriptor.type}-error`,
|
|
`x-form-field-${descriptor.errorName}-error`,
|
|
`x-form-field-${control.propName.toString()}-error`,
|
|
`x-form-field-${descriptor.type}-${descriptor.errorName}-error`,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Appearance ...
|
|
/**
|
|
* retrieve a control appearance ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlAppearance(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig) &&
|
|
!isNullOrUndefined(appearanceConfig.appearance)
|
|
? appearanceConfig.appearance
|
|
: XFormControlAppearance.Fill
|
|
).pipe(map((result) => result as MatFormFieldAppearance))
|
|
)
|
|
);
|
|
}
|
|
getControlAppearanceObject(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig) &&
|
|
!isNullOrUndefined(appearanceConfig.appearance)
|
|
? appearanceConfig.appearance
|
|
: XFormControlAppearance.Fill
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Label Position ...
|
|
/**
|
|
* retrieve a control label position ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlLabelPosition(control: XFormControlConfig) {
|
|
return this.getControlAppearanceDesc(control).pipe(
|
|
concatMap((appearanceConfig) =>
|
|
this.getOptionalValue(
|
|
!isNullOrUndefined(appearanceConfig)
|
|
? appearanceConfig.labelPosition
|
|
: XFormControlLabelPosition.Before
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Error Handlers ...
|
|
/**
|
|
* retrieve a control error handlers descriptor object ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
getControlErrorHandlers(control: XFormControlConfig) {
|
|
return this.getArrayValue(control.errorHandlers);
|
|
}
|
|
|
|
/**
|
|
* determines a control has error handlers descriptors object or not ...
|
|
*
|
|
* @param control form control config object ...
|
|
*/
|
|
controlHasErrorHandlers(control: XFormControlConfig) {
|
|
return this.hasChildValue(this.getControlErrorHandlers(control));
|
|
}
|
|
|
|
controlHasErrors(control: XFormControlConfig) {
|
|
return this.getValue(control).pipe(
|
|
concatMap((ctrl) =>
|
|
this.getValue(this.getControl(ctrl.propName)).pipe(
|
|
map((fControl) => ({ ctrl, fControl }))
|
|
)
|
|
),
|
|
map((ctrlInfo) => {
|
|
return isNullOrUndefined(ctrlInfo.ctrl) ||
|
|
isNullOrUndefined(ctrlInfo.fControl)
|
|
? false
|
|
: !isNullOrUndefined(ctrlInfo.fControl.errors);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* determines a control has specific error or not ...
|
|
*
|
|
* @param controlName control name ...
|
|
* @param errorName error name ...
|
|
*/
|
|
controlHasErrorByName(
|
|
controlName: XFormControlNameIdentifier,
|
|
errorName: string
|
|
) {
|
|
//
|
|
const control = this.getControl(controlName);
|
|
if (!control) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const result =
|
|
!isNullOrUndefined(control.errors) &&
|
|
keys(control.errors).includes(errorName) &&
|
|
!isNullOrUndefined(control.errors[errorName]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determine a control has specific error or not ...
|
|
*
|
|
* @param control form control config ...
|
|
* @param handler form error handler instance ...
|
|
*/
|
|
controlHasError(control: XFormControlConfig, handler: XFormErrorHandler) {
|
|
return this.getErrorHandlerErrorName(handler).pipe(
|
|
map((errorName) => {
|
|
return this.controlHasErrorByName(control.propName, errorName);
|
|
})
|
|
);
|
|
}
|
|
|
|
controlGetError(control: XFormControlConfig, handler: XFormErrorHandler) {
|
|
return this.getErrorHandlerErrorName(handler).pipe(
|
|
map((errorName) => {
|
|
return this.controlHasErrorByName(control.propName, errorName);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve specific error of a control ...
|
|
*
|
|
* @param controlName control name ...
|
|
* @param errorName error name ...
|
|
*/
|
|
getControlErrorByName(
|
|
controlName: XFormControlNameIdentifier,
|
|
errorName: string
|
|
) {
|
|
//
|
|
const control = this.getControl(controlName);
|
|
if (!this.controlHasErrorByName(controlName, errorName)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return control.errors[errorName] || null;
|
|
}
|
|
|
|
/**
|
|
* retrieve specific error of a control ...
|
|
*
|
|
* @param control form control config ...
|
|
* @param handler form error handler instance ...
|
|
*/
|
|
getControlError(control: XFormControlConfig, handler: XFormErrorHandler) {
|
|
return this.getErrorHandlerErrorName(handler).pipe(
|
|
map((errorName) => {
|
|
if (!isNullOrUndefined(control)) {
|
|
return this.getControlErrorByName(control.propName, errorName);
|
|
} else {
|
|
return this.getFormErrorByName(errorName);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Error Handler Providers ...
|
|
/**
|
|
* retrieve an error handler error name ...
|
|
*
|
|
* @param errorHandler an error handler descriptor object ...
|
|
*/
|
|
getErrorHandlerErrorName(errorHandler: XFormErrorHandler) {
|
|
return this.getValue(errorHandler.errorName);
|
|
}
|
|
|
|
/**
|
|
* retrieve an error handler error message ...
|
|
*
|
|
* @param errorHandler an error handler descriptor object ...
|
|
*/
|
|
getErrorHandlerErrorMessage(
|
|
errorHandler: XFormErrorHandler,
|
|
control?: XFormControlConfig
|
|
) {
|
|
//
|
|
if (
|
|
errorHandler.errorDataProvider &&
|
|
isFunction(errorHandler.errorDataProvider)
|
|
) {
|
|
//
|
|
return this.getControlError(control, errorHandler).pipe(
|
|
concatMap((controlError) =>
|
|
this.getResourceValue(errorHandler.errorDataProvider(controlError))
|
|
)
|
|
);
|
|
} else {
|
|
return this.getResourceValue(errorHandler.errorMessage);
|
|
}
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//
|
|
//#region Common Controls UI Handlers ...
|
|
async handleControlBlured(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM_CONFIG || !this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(name));
|
|
if (!control) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const eventModel: XBaseFormControlActionModel = {
|
|
name: control.propName,
|
|
};
|
|
|
|
//
|
|
this.controlBlured.emit(eventModel);
|
|
|
|
//
|
|
const eventHandlers = await this.getValueAsync(
|
|
this.getControlEventHandlers(control)
|
|
);
|
|
if (!eventHandlers || !eventHandlers.onBlured) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(eventHandlers.onBlured(eventModel));
|
|
}
|
|
|
|
async handleControlFocused(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM_CONFIG || !this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(name));
|
|
if (!control) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const inputId = await this.getValueAsync(
|
|
this.getControlInputElementId(control)
|
|
);
|
|
this.currentInputFocus = inputId;
|
|
|
|
//
|
|
const eventModel: XBaseFormControlActionModel = {
|
|
name: control.propName,
|
|
};
|
|
|
|
//
|
|
this.controlFocused.emit(eventModel);
|
|
|
|
//
|
|
const eventHandlers = await this.getValueAsync(
|
|
this.getControlEventHandlers(control)
|
|
);
|
|
if (!eventHandlers || !eventHandlers.onFocused) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(eventHandlers.onFocused(eventModel));
|
|
}
|
|
|
|
async handleControlValueChanged(event: XFormControlValueChangeEventModel) {
|
|
//
|
|
if (
|
|
!this.FORM ||
|
|
this.uiDisabled ||
|
|
!this.FORM_CONFIG ||
|
|
!this.hasControl(event.name)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(event.name));
|
|
if (control) {
|
|
//
|
|
const isDisabled = await this.getValueAsync(
|
|
this.getControlDisabled(control)
|
|
);
|
|
if (isDisabled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.controlValueChanged.emit(event);
|
|
}
|
|
|
|
async handleControlStatusChanged(event: XFormControlStatusChangeEventModel) {
|
|
//
|
|
if (
|
|
!this.FORM ||
|
|
this.uiDisabled ||
|
|
!this.FORM_CONFIG ||
|
|
!this.hasControl(event.name)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(event.name));
|
|
if (control) {
|
|
//
|
|
const isDisabled = await this.getValueAsync(
|
|
this.getControlDisabled(control)
|
|
);
|
|
if (isDisabled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.controlStatusChanged.emit(event);
|
|
}
|
|
|
|
async handleControlIconClicked(icon: XFormIconDescriptor) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG || !icon.handler) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(icon.handler());
|
|
}
|
|
|
|
async handleControlActionIconClicked(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor,
|
|
control: XFormControlConfig
|
|
) {
|
|
//
|
|
const type = await this.getValueAsync(this.getControlType(control));
|
|
|
|
//
|
|
switch (type) {
|
|
//
|
|
case XFormControlType.Map:
|
|
//
|
|
await this.handleMapIconClicked(role, descriptor, control);
|
|
break;
|
|
|
|
//
|
|
case XFormControlType.Selector:
|
|
await this.handleItemSelectorIconClicked(role, descriptor, control);
|
|
break;
|
|
|
|
//
|
|
case XFormControlType.ColorPicker:
|
|
//
|
|
await this.handleColorPickerIconClicked(role, descriptor, control);
|
|
break;
|
|
|
|
//
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region DatePicker UI Handlers ...
|
|
async handleDatePickerDateInput(
|
|
name: XFormControlNameIdentifier,
|
|
event: MatDatepickerInputEvent<any>
|
|
) {
|
|
//
|
|
let result: Date = null;
|
|
const isDateInput = isDate(event.value);
|
|
const isMomentInput = isMoment(event.value);
|
|
if (isMomentInput) {
|
|
result = momentToDate(event.value);
|
|
} else if (isDateInput) {
|
|
result = event.value as Date;
|
|
}
|
|
|
|
//
|
|
await this.setValue(name, result);
|
|
|
|
//
|
|
if (!this.FORM_CONFIG || !this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(name));
|
|
if (!control) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const handler = await this.getValueAsync(this.getDateInputHandler(control));
|
|
if (!handler) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fire Hanlder ...
|
|
await this.getValueAsync(handler(result));
|
|
}
|
|
|
|
async handleDatePickerDateChange(
|
|
name: XFormControlNameIdentifier,
|
|
event: MatDatepickerInputEvent<any>
|
|
) {
|
|
//
|
|
let result: Date = null;
|
|
const isDateInput = isDate(event.value);
|
|
const isMomentInput = isMoment(event.value);
|
|
if (isMomentInput) {
|
|
result = momentToDate(event.value);
|
|
} else if (isDateInput) {
|
|
result = event.value as Date;
|
|
}
|
|
|
|
//
|
|
await this.setValue(name, result);
|
|
|
|
//
|
|
if (!this.FORM_CONFIG || !this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = await this.getValueAsync(this.getFormControl(name));
|
|
if (!control) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const handler = await this.getValueAsync(
|
|
this.getDateChangeHandler(control)
|
|
);
|
|
if (!handler) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fire Hanlder ...
|
|
await this.getValueAsync(handler(result));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Auto Complete Controls UI Handlers ...
|
|
async handleAutoCompleteResultSelected(
|
|
control: XFormControlConfig,
|
|
autoComplete: XFormControlAutoCompleteConfig,
|
|
event: any
|
|
) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const formCtrl = this.getControl(control.propName);
|
|
if (!formCtrl) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
formCtrl.setValue(event.data);
|
|
const formInputControl = this.getElementById(
|
|
this.getControlInputElementId(control)
|
|
);
|
|
if (formInputControl) {
|
|
(formInputControl as HTMLInputElement).select();
|
|
}
|
|
|
|
//
|
|
if (autoComplete.onSelect && isFunction(autoComplete.onSelect)) {
|
|
await this.getValueAsync(autoComplete.onSelect(event));
|
|
}
|
|
|
|
//
|
|
this.focusOnControl(control.propName);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleAutoCompleteEscaped(control: XFormControlConfig) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const autoComplete = await this.getValueAsync(
|
|
this.getControlAutoCompleteConfig(control)
|
|
);
|
|
if (
|
|
autoComplete &&
|
|
autoComplete.onEscape &&
|
|
isFunction(autoComplete.onEscape)
|
|
) {
|
|
await this.getValueAsync(autoComplete.onEscape());
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleAutoCompleteOutsideClicked(control: XFormControlConfig) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const autoComplete = await this.getValueAsync(
|
|
this.getControlAutoCompleteConfig(control)
|
|
);
|
|
if (
|
|
autoComplete &&
|
|
autoComplete.onOutsideClicked &&
|
|
isFunction(autoComplete.onOutsideClicked)
|
|
) {
|
|
await this.getValueAsync(autoComplete.onOutsideClicked());
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Markdown Control UI Handlers ...
|
|
async handleMarkDownContentChanged(
|
|
name: XFormControlNameIdentifier,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setValue(name, event);
|
|
|
|
//
|
|
const controlConfig = await this.getValueAsync(this.getFormControl(name));
|
|
if (!controlConfig) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const markDownConfig = await this.getValueAsync(
|
|
this.getMarkdownConfig(controlConfig)
|
|
);
|
|
if (!markDownConfig || !markDownConfig.contentChanged) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(markDownConfig.contentChanged(event));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Checkbox Control UI Handlers ...
|
|
async handleCheckboxCheckedChange(
|
|
control: XFormControlConfig,
|
|
checked: boolean
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getCheckboxConfig(control));
|
|
if (!config || !config.checkedChanged) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.checkedChanged(checked));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Map UI Handlers ...
|
|
async handleMapIsReady(control: XFormControlConfig) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getMapConfig(control));
|
|
if (!config || !config.isReady) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.isReady.emit();
|
|
}
|
|
|
|
async handleMapZoomChanged(control: XFormControlConfig, zoom: number) {
|
|
}
|
|
|
|
async handleMapLocationSelected(
|
|
control: XFormControlConfig,
|
|
event: XMapLocation
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const longLat = event ? toLongLat(event) : null;
|
|
await this.setValue(control.propName, longLat);
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getMapConfig(control));
|
|
if (!config || !config.locationSelected) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.locationSelected.emit(event);
|
|
}
|
|
|
|
async handleMapIconClicked(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor,
|
|
control: XFormControlConfig
|
|
) {
|
|
//
|
|
const presentType = await this.getValueAsync(
|
|
this.getMapPresentType(control)
|
|
);
|
|
|
|
//
|
|
switch (role) {
|
|
//
|
|
case this.ControlIconRoles.Clear:
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
async () => {
|
|
//
|
|
await this.setValue(control.propName, undefined);
|
|
|
|
//
|
|
const mapControlActionPtovider = await this.getValueAsync(
|
|
this.getMapActionProvider(control)
|
|
);
|
|
if (
|
|
mapControlActionPtovider &&
|
|
presentType === XFormMapControlPresentType.WithoutDialog
|
|
) {
|
|
//
|
|
// Clear Marker ...
|
|
mapControlActionPtovider.next({
|
|
action: XMapAction.ClearMarker,
|
|
});
|
|
}
|
|
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
}
|
|
);
|
|
break;
|
|
|
|
//
|
|
case this.ControlIconRoles.Select:
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
|
|
//
|
|
let center: XMapLocation = null;
|
|
const longLatControl = this.getControl(control.propName);
|
|
if (longLatControl) {
|
|
//
|
|
const longLat = longLatControl.value as string;
|
|
if (!isNullOrEmptyString(longLat)) {
|
|
center = fromLongLat(longLat);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prevent go forward if map control present type does't support map dialog ...
|
|
if (presentType === XFormMapControlPresentType.WithoutDialog) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare Selector Dialog Config ...
|
|
const controlConfig = await this.getValueAsync(
|
|
this.getMapConfig(control)
|
|
);
|
|
const dialogConfig: XMapDialogConfig = {
|
|
...controlConfig,
|
|
//
|
|
latitude: center && center.latitude ? +center.latitude : 0,
|
|
longitude: center && center.longitude ? +center.longitude : 0,
|
|
|
|
//
|
|
showSelectedLocation: true,
|
|
};
|
|
|
|
//
|
|
// Open Dialog ...
|
|
await this.mapDialogService.openDialog(dialogConfig);
|
|
|
|
//
|
|
// Wait for Handle Dialog Result ...
|
|
const s = this.mapDialogService.onResult
|
|
.asObservable()
|
|
.subscribe(async (result) => {
|
|
//
|
|
let value: any;
|
|
|
|
//
|
|
if (
|
|
!isNullOrUndefined(result) &&
|
|
!isNullOrUndefined(result.payload) &&
|
|
result.result === XDialogResult.Ok
|
|
) {
|
|
value = toLongLat(result.payload);
|
|
}
|
|
|
|
//
|
|
if (!isNullOrUndefined(value)) {
|
|
await this.setValue(control.propName, value);
|
|
}
|
|
|
|
//
|
|
s.unsubscribe();
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleMapControlInputValueChanged(
|
|
control: XFormControlConfig,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getMapConfig(control));
|
|
if (
|
|
!config ||
|
|
!config.inputValueChanged ||
|
|
!isFunction(config.inputValueChanged)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.inputValueChanged(event));
|
|
}
|
|
|
|
async handleMapSearchBarQueryChange(
|
|
control: XFormControlConfig,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getMapConfig(control));
|
|
if (!config || !config.searchBarQueryChange) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.searchBarQueryChange.emit(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ColorPicker UI Handlers ...
|
|
async handleColorPickerIconClicked(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor,
|
|
control: XFormControlConfig
|
|
) {
|
|
//
|
|
switch (role) {
|
|
//
|
|
case this.ControlIconRoles.Clear:
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
async () => {
|
|
//
|
|
await this.setValue(control.propName, undefined);
|
|
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
}
|
|
);
|
|
break;
|
|
|
|
//
|
|
case this.ControlIconRoles.Select:
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
|
|
//
|
|
const presentType = await this.getValueAsync(
|
|
this.getColorPickerPresentType(control)
|
|
);
|
|
|
|
//
|
|
// Prevent go forward if color picker control present type does't support map dialog ...
|
|
if (presentType === XFormColorPickerControlPresentType.WithoutDialog) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let selectedColor: string = null;
|
|
const colorPickerControl = this.getControl(control.propName);
|
|
if (colorPickerControl) {
|
|
//
|
|
const colorVal = colorPickerControl.value as string;
|
|
if (!isNullOrEmptyString(colorVal)) {
|
|
selectedColor = colorVal;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare Selector Dialog Config ...
|
|
const controlConfig = await this.getValueAsync(
|
|
this.getColorPickerConfig(control)
|
|
);
|
|
const dialogConfig: XColorPickerDialogConfig = {
|
|
...controlConfig,
|
|
|
|
//
|
|
selectedColor,
|
|
};
|
|
|
|
//
|
|
// Open Dialog ...
|
|
await this.colorPickerDialogService.openDialog(dialogConfig);
|
|
|
|
//
|
|
// Wait for Handle Dialog Result ...
|
|
const s = this.colorPickerDialogService.onResult
|
|
.asObservable()
|
|
.subscribe(async (result) => {
|
|
//
|
|
let value: any;
|
|
|
|
//
|
|
if (
|
|
!isNullOrUndefined(result) &&
|
|
!isNullOrUndefined(result.payload) &&
|
|
result.result === XDialogResult.Ok
|
|
) {
|
|
value = result.payload;
|
|
}
|
|
|
|
//
|
|
if (!isNullOrUndefined(value)) {
|
|
await this.setValue(control.propName, value);
|
|
}
|
|
|
|
//
|
|
s.unsubscribe();
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleColorPickerControlInputValueChanged(
|
|
control: XFormControlConfig,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getColorPickerConfig(control));
|
|
if (
|
|
!config ||
|
|
!config.inputValueChanged ||
|
|
!isFunction(config.inputValueChanged)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.inputValueChanged(event));
|
|
}
|
|
|
|
async handleColorPickerColorSelected(
|
|
control: XFormControlConfig,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setValue(control.propName, event);
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getColorPickerConfig(control));
|
|
if (!config || !config.colorSelected) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.colorSelected.emit(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Avatar UI Handlers ...
|
|
async handleAvatarFileDropAreaFilesChangeEmitter(
|
|
control: XFormControlConfig,
|
|
event?: XOneOrManyType<File>
|
|
) {
|
|
//
|
|
if (!event || !this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getAvatarConfig(control));
|
|
if (
|
|
!config ||
|
|
!config.fileDropAreaFilesChangeEmiter ||
|
|
!isFunction(config.fileDropAreaFilesChangeEmiter)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.fileDropAreaFilesChangeEmiter(event));
|
|
}
|
|
|
|
async handleAvatarAvatarChange(control: XFormControlConfig, event?: File) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setValue(control.propName, event);
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getAvatarConfig(control));
|
|
if (!config || !config.avatarChange || !isFunction(config.avatarChange)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.avatarChange(event));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selector UI Handlers ...
|
|
async handleItemSelectorIconClicked(
|
|
role: XControlIconRoleIdentifier,
|
|
descriptor: XControlIconDescriptor,
|
|
control: XFormControlConfig
|
|
) {
|
|
//
|
|
switch (role) {
|
|
//
|
|
case this.ControlIconRoles.Clear:
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
async () => {
|
|
//
|
|
await this.setValue(control.propName, undefined);
|
|
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
}
|
|
);
|
|
break;
|
|
|
|
//
|
|
case this.ControlIconRoles.Select:
|
|
//
|
|
// Notify Handler ...
|
|
if (
|
|
!isNullOrUndefined(descriptor) &&
|
|
!isNullOrUndefined(descriptor.handler) &&
|
|
isFunction(descriptor.handler)
|
|
) {
|
|
await this.getValueAsync(descriptor.handler());
|
|
}
|
|
|
|
//
|
|
// Prepare Selector Dialog Config ...
|
|
const controlConfig = await this.getValueAsync(
|
|
this.getSelectorConfig(control)
|
|
);
|
|
const dialogConfig: XFormSelectorControlConfig = {
|
|
...controlConfig,
|
|
};
|
|
|
|
//
|
|
// Open Dialog ...
|
|
await this.selectorDialogService.openDialog(dialogConfig);
|
|
|
|
//
|
|
// Wait for Handle Dialog Result ...
|
|
const s = this.selectorDialogService.onResult
|
|
.asObservable()
|
|
.subscribe(async (result) => {
|
|
//
|
|
let content: any;
|
|
|
|
//
|
|
if (
|
|
!isNullOrUndefined(result) &&
|
|
!isNullOrUndefined(result.payload) &&
|
|
result.result === XDialogResult.Ok
|
|
) {
|
|
content = result.payload;
|
|
}
|
|
|
|
//
|
|
if (!isNullOrUndefined(content)) {
|
|
//
|
|
const value =
|
|
!controlConfig ||
|
|
!controlConfig.formatSelectedItem ||
|
|
!isFunction(controlConfig.formatSelectedItem)
|
|
? content
|
|
: await this.getValueAsync(
|
|
controlConfig.formatSelectedItem(content)
|
|
);
|
|
|
|
//
|
|
await this.setValue(control.propName, value);
|
|
}
|
|
|
|
//
|
|
s.unsubscribe();
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleSelectorControlInputValueChanged(
|
|
control: XFormControlConfig,
|
|
event: string
|
|
) {
|
|
//
|
|
if (!this.hasControl(control.propName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getSelectorConfig(control));
|
|
if (
|
|
!config ||
|
|
!config.inputValueChanged ||
|
|
!isFunction(config.inputValueChanged)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(config.inputValueChanged(event));
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* determine a control exists or not ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
hasControl(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const controlName = this.getControlName(name);
|
|
if (!controlName) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return (
|
|
this.FORM.contains(controlName) ||
|
|
!isNullOrUndefined(this.FORM.controls[controlName])
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve a control based on it's name ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
getControl(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.hasControl(name)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const controlName = this.getControlName(name);
|
|
if (!controlName) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.FORM.get(controlName) || null;
|
|
}
|
|
|
|
/**
|
|
* retrieve a form control status if exists in form ...
|
|
*
|
|
* @param control a form control config ...
|
|
*/
|
|
getControlStatus(control: XFormControlConfig) {
|
|
//
|
|
const mControl = this.getControl(control.propName);
|
|
if (!mControl) {
|
|
return XFormStatus.UnKnown;
|
|
}
|
|
|
|
//
|
|
return mControl.status as XFormStatus;
|
|
}
|
|
|
|
/**
|
|
* focus on a control ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
focusOnControl(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const inputElement = this.getElementById(
|
|
this.getControlInputElementIdByName(name)
|
|
);
|
|
if (!inputElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
setTimeout(() => inputElement.focus(), 100);
|
|
}
|
|
|
|
/**
|
|
* blur from a control ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
blurOfControl(name: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.hasControl(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const inputElement = this.getElementById(
|
|
this.getControlInputElementIdByName(name)
|
|
);
|
|
if (!inputElement) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
setTimeout(() => inputElement.blur(), 100);
|
|
}
|
|
|
|
/**
|
|
* determines specific control has value or not ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
controlHasValue(name: XFormControlNameIdentifier) {
|
|
return !this.hasControl(name)
|
|
? false
|
|
: this.getControl(name).value &&
|
|
!isNullOrEmptyString(this.getControl(name).value.toString());
|
|
}
|
|
|
|
/**
|
|
* retrieve an specific control value ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
getControlValue(name: XFormControlNameIdentifier) {
|
|
return !this.hasControl(name) ? undefined : this.getControl(name).value;
|
|
}
|
|
|
|
/**
|
|
* determines a control has error by it's name ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
controlHasErrorByControlName(name: XFormControlNameIdentifier) {
|
|
return !this.hasControl(name)
|
|
? false
|
|
: !isNullOrUndefined(this.getControl(name).errors);
|
|
}
|
|
|
|
/**
|
|
* set a value to an specific control or form ...
|
|
*
|
|
* @param name a control name ...
|
|
* @param value a value of any type ...
|
|
*/
|
|
async setValue(name?: XFormControlNameIdentifier, value?: any) {
|
|
//
|
|
if (!name) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (name) {
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.setValue(value);
|
|
} else {
|
|
this.FORM.setValue(value, { emitEvent: true });
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger markAsDirty on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async markAsDirty(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG || this.uiDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.markAsDirty();
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.markAsDirty();
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger markAsTouched on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async markAsTouched(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.markAsTouched();
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.markAsTouched();
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger markAsPending on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async markAsPending(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.markAsPending();
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.markAsPending();
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger markAsPristine on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async markAsPristine(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.markAsPristine();
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.markAsPristine();
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger markAsUntouched on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async markAsUnTouched(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.markAsUntouched();
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.markAsUntouched();
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger updateValueAndValidity on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async updateValueAndValidity(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.updateValueAndValidity({ emitEvent: true });
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.updateValueAndValidity({ emitEvent: true });
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* trigger setError on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param errors: an instance of ValidationErrors object ...
|
|
* @param name a control name ...
|
|
*/
|
|
async setError(errors: ValidationErrors, name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.setErrors(errors, { emitEvent: true });
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.setErrors(errors, { emitEvent: true });
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* clearErrors on form or specific control ...
|
|
* if provide a control name and it's exists ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async clearError(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.setErrors(null, { emitEvent: true });
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.setErrors(null, { emitEvent: true });
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* enable form or form control ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async enable(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.enable({ emitEvent: true });
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.enable({ emitEvent: true });
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* disable form or form control ...
|
|
*
|
|
* @param name a control name ...
|
|
*/
|
|
async disable(name?: XFormControlNameIdentifier) {
|
|
//
|
|
if (!this.FORM || !this.FORM_CONFIG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const control = this.getControl(name);
|
|
if (!control) {
|
|
//
|
|
this.FORM.disable({ emitEvent: true });
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
control.disable({ emitEvent: true });
|
|
this.detectChanges();
|
|
}
|
|
|
|
/**
|
|
* remove all data and form elements ...
|
|
*/
|
|
async clearData() {
|
|
//
|
|
// this.formConfig = null;
|
|
this.FORM_CONFIG = null;
|
|
this.FORM = null;
|
|
|
|
//
|
|
this.detectChanges();
|
|
|
|
//
|
|
await this.prepareFormGroup();
|
|
}
|
|
|
|
/**
|
|
* refresh component ...
|
|
*/
|
|
async refresh() {
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Prepare Form Group ...
|
|
private async prepareFormGroup() {
|
|
//
|
|
//#region Form Config ...
|
|
//
|
|
this.currentInputFocus = undefined;
|
|
const modelFormConfig = await this.getValueAsync(this.formConfig);
|
|
if (!modelFormConfig) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const formConfig = {
|
|
name: await this.getValueAsync(this.getFormName()),
|
|
model: (await this.getValueAsync(this.formHasModel()))
|
|
? await this.getValueAsync(this.getFormModel())
|
|
: undefined,
|
|
updateOn: await this.getValueAsync(this.getFormUpdateOn()),
|
|
controls: await Promise.all(
|
|
(
|
|
await this.getValueAsync(this.getFormControls())
|
|
).map(async (c) => {
|
|
//
|
|
//#region Action Provider ...
|
|
let actionProvider = c.actionProvider ? c.actionProvider : undefined;
|
|
|
|
//
|
|
if (!actionProvider) {
|
|
//
|
|
if (!this.actionProviders[c.propName]) {
|
|
this.actionProviders[c.propName] = new Subject<any>();
|
|
}
|
|
|
|
//
|
|
actionProvider = this.actionProviders[c.propName];
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control ...
|
|
return {
|
|
index: c.index,
|
|
propName: c.propName,
|
|
type: {
|
|
type: await this.getValueAsync(this.getControlType(c)),
|
|
config: await this.getValueAsync(this.getControlTypeConfig(c)),
|
|
},
|
|
updateOn: await this.getValueAsync(this.getControlUpdateOn(c)),
|
|
validators: (await this.getValueAsync(this.controlHasValidators(c)))
|
|
? await this.getValueAsync(this.getControlValidators(c))
|
|
: undefined,
|
|
actionProvider,
|
|
eventHandlers: (await this.getValueAsync(
|
|
this.controlHasEventHandlers(c)
|
|
))
|
|
? await this.getValueAsync(this.getControlEventHandlers(c))
|
|
: undefined,
|
|
appearance: {
|
|
hidden: await this.getValueAsync(this.getControlHidden(c)),
|
|
disabled: await this.getValueAsync(this.getControlDisabled(c)),
|
|
hint: await this.getValueAsync(this.getControlHint(c)),
|
|
label: await this.getValueAsync(this.getControlLabel(c)),
|
|
tooltip: await this.getValueAsync(this.getControlTooltip(c)),
|
|
placeholder: await this.getValueAsync(
|
|
this.getControlPlaceHolder(c)
|
|
),
|
|
cssClass: await this.getValueAsync(this.getControlCssClass(c)),
|
|
icons: (await this.getValueAsync(this.controlHasIcons(c)))
|
|
? {
|
|
suffix: (await this.getValueAsync(
|
|
this.controlHasSuffixIcon(c)
|
|
))
|
|
? {
|
|
name: await this.getValueAsync(
|
|
this.getControlIconName(
|
|
await this.getValueAsync(
|
|
this.getControlSuffixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
color: await this.getValueAsync(
|
|
this.getControlIconColor(
|
|
await this.getValueAsync(
|
|
this.getControlSuffixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
applyStateColor: await this.getValueAsync(
|
|
this.getControlIconApplyStateColor(
|
|
await this.getValueAsync(
|
|
this.getControlSuffixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
handler: (
|
|
await this.getValueAsync(
|
|
this.getControlSuffixIcon(c)
|
|
)
|
|
).handler,
|
|
}
|
|
: undefined,
|
|
prefix: (await this.getValueAsync(
|
|
this.controlHasPrefixIcon(c)
|
|
))
|
|
? {
|
|
name: await this.getValueAsync(
|
|
this.getControlIconName(
|
|
await this.getValueAsync(
|
|
this.getControlPrefixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
color: await this.getValueAsync(
|
|
this.getControlIconColor(
|
|
await this.getValueAsync(
|
|
this.getControlPrefixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
applyStateColor: await this.getValueAsync(
|
|
this.getControlIconApplyStateColor(
|
|
await this.getValueAsync(
|
|
this.getControlPrefixIcon(c)
|
|
)
|
|
)
|
|
),
|
|
handler: (
|
|
await this.getValueAsync(
|
|
this.getControlPrefixIcon(c)
|
|
)
|
|
).handler,
|
|
}
|
|
: undefined,
|
|
}
|
|
: undefined,
|
|
formatter: (await this.getValueAsync(this.controlHasFormatter(c)))
|
|
? {
|
|
locale: await this.getValueAsync(
|
|
this.getFormatterLocale(c)
|
|
),
|
|
seperator: await this.getValueAsync(
|
|
this.getFormatterSeperator(c)
|
|
),
|
|
type: await this.getValueAsync(this.getFormatterType(c)),
|
|
currencyLable: await this.getValueAsync(
|
|
this.getFormatterCurrencyLabel(c)
|
|
),
|
|
inputType: await this.getValueAsync(
|
|
this.getFormatterInputType(c)
|
|
),
|
|
stringFormatter: await this.getValueAsync(
|
|
this.getFormatterStringFormatter(c)
|
|
),
|
|
}
|
|
: undefined,
|
|
progressBar: (await this.getValueAsync(
|
|
this.controlHasProgressBar(c)
|
|
))
|
|
? {
|
|
color: await this.getValueAsync(
|
|
this.getProgressBarColor(c)
|
|
),
|
|
}
|
|
: undefined,
|
|
autoComplete: (await this.getValueAsync(
|
|
this.controlHasAutoComplete(c)
|
|
))
|
|
? {
|
|
itemTemplate: await this.getValueAsync(
|
|
this.getAutoCompleteItemTemplate(c)
|
|
),
|
|
opened: await this.getValueAsync(
|
|
this.getAutoCompleteOpened(c)
|
|
),
|
|
color: await this.getValueAsync(
|
|
this.getAutoCompleteColor(c)
|
|
),
|
|
onSelect: await this.getValueAsync(
|
|
this.getAutoCompleteOnSelect(c)
|
|
),
|
|
items: await this.getValueAsync(
|
|
this.getAutoCompleteItems(c)
|
|
),
|
|
cssClass: await this.getValueAsync(
|
|
this.getAutoCompleteCssClass(c)
|
|
),
|
|
}
|
|
: undefined,
|
|
appearance: await this.getValueAsync(
|
|
this.getControlAppearance(c)
|
|
),
|
|
labelPosition: await this.getValueAsync(
|
|
this.getControlLabelPosition(c)
|
|
),
|
|
},
|
|
errorHandlers: (await this.getValueAsync(
|
|
this.controlHasErrorHandlers(c)
|
|
))
|
|
? await Promise.all(
|
|
(
|
|
await this.getValueAsync(this.getControlErrorHandlers(c))
|
|
).map(async (e) => {
|
|
return {
|
|
errorName: await this.getValueAsync(e.errorName),
|
|
errorMessage: await this.getResourceValueAsync(
|
|
e.errorMessage
|
|
),
|
|
};
|
|
})
|
|
)
|
|
: undefined,
|
|
};
|
|
//#endregion
|
|
})
|
|
),
|
|
validators: (await this.getValueAsync(this.formHasValidators()))
|
|
? await this.getValueAsync(this.getFormValidators())
|
|
: undefined,
|
|
errorHandlers: (await this.getValueAsync(this.formHasErrorHandlers()))
|
|
? await Promise.all(
|
|
(
|
|
await this.getValueAsync(this.getFormErrorHandlers())
|
|
).map(async (e) => {
|
|
return {
|
|
errorName: await this.getValueAsync(e.errorName),
|
|
errorMessage: await this.getResourceValueAsync(e.errorMessage),
|
|
};
|
|
})
|
|
)
|
|
: undefined,
|
|
};
|
|
|
|
//
|
|
if (!this.FORM_CONFIG) {
|
|
this.FORM_CONFIG = formConfig;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Preparing Form Controls ...
|
|
const controls = assign(
|
|
{},
|
|
...formConfig.controls
|
|
.map((c) => {
|
|
//
|
|
const initialValue = {
|
|
value:
|
|
!isNullOrUndefined(formConfig.model) &&
|
|
!isNullOrUndefined(formConfig.model[c.propName.toString()])
|
|
? formConfig.model[c.propName.toString()]
|
|
: null,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
(c.appearance && c.appearance.disabled
|
|
? c.appearance.disabled
|
|
: false),
|
|
};
|
|
|
|
//
|
|
const formControl = new FormControl(initialValue, {
|
|
updateOn: c.updateOn.toString() as 'change' | 'blur' | 'submit',
|
|
validators: c.validators ? c.validators.validators : null,
|
|
asyncValidators: c.validators ? c.validators.asyncValidators : null,
|
|
});
|
|
|
|
//
|
|
//#region Apply Event Handlers ...
|
|
//
|
|
//#region Value Change ...
|
|
formControl.valueChanges.subscribe(async (res) => {
|
|
//
|
|
const eventModel: XFormControlValueChangeEventModel = {
|
|
name: c.propName,
|
|
value: res,
|
|
};
|
|
|
|
//
|
|
if (
|
|
c.eventHandlers &&
|
|
c.eventHandlers.valueChanged &&
|
|
isFunction(c.eventHandlers.valueChanged)
|
|
) {
|
|
c.eventHandlers.valueChanged(eventModel);
|
|
}
|
|
|
|
//
|
|
await this.handleControlValueChanged(eventModel);
|
|
|
|
//
|
|
//#region Handle Map Control Input Value Change Action ...
|
|
const controlConfig = await this.getValueAsync(
|
|
this.getFormControl(c.propName)
|
|
);
|
|
if (controlConfig) {
|
|
//
|
|
const type = await this.getValueAsync(
|
|
this.getControlType(controlConfig)
|
|
);
|
|
|
|
//
|
|
if (type === XFormControlType.Map) {
|
|
await this.handleMapControlInputValueChanged(
|
|
controlConfig,
|
|
res
|
|
);
|
|
} else if (type === XFormControlType.ColorPicker) {
|
|
await this.handleColorPickerControlInputValueChanged(
|
|
controlConfig,
|
|
res
|
|
);
|
|
} else if (type === XFormControlType.Selector) {
|
|
await this.handleSelectorControlInputValueChanged(
|
|
controlConfig,
|
|
res
|
|
);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
|
|
//
|
|
// Notify Initial Value ...
|
|
if (
|
|
!isNullOrUndefined(initialValue) &&
|
|
!isNullOrUndefined(initialValue.value)
|
|
) {
|
|
//
|
|
const eventModel: XFormControlValueChangeEventModel = {
|
|
name: c.propName,
|
|
value: initialValue.value,
|
|
};
|
|
|
|
//
|
|
if (
|
|
c.eventHandlers &&
|
|
c.eventHandlers.valueChanged &&
|
|
isFunction(c.eventHandlers.valueChanged)
|
|
) {
|
|
c.eventHandlers.valueChanged(eventModel);
|
|
}
|
|
|
|
//
|
|
this.controlValueChanged.emit(eventModel);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Status Change ...
|
|
formControl.statusChanges.subscribe(async (res) => {
|
|
//
|
|
const eventModel: XFormControlStatusChangeEventModel = {
|
|
name: c.propName,
|
|
status: res,
|
|
};
|
|
|
|
//
|
|
if (
|
|
c.eventHandlers &&
|
|
c.eventHandlers.statusChanged &&
|
|
isFunction(c.eventHandlers.statusChanged)
|
|
) {
|
|
c.eventHandlers.statusChanged(eventModel);
|
|
}
|
|
|
|
//
|
|
await this.handleControlStatusChanged(eventModel);
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Apply Action Provider ...
|
|
if (c.actionProvider) {
|
|
//
|
|
c.actionProvider.asObservable().subscribe(async (model) => {
|
|
//
|
|
if (
|
|
!model ||
|
|
!model.name ||
|
|
isNullOrEmptyString(model.name.toString()) ||
|
|
!this.hasControl(model.name)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFormBaseAction.Enable:
|
|
await this.enable(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.Disable:
|
|
await this.disable(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.SetError:
|
|
//
|
|
const errors = model.payload as ValidationErrors;
|
|
if (model.payload && errors) {
|
|
await this.setError(errors, model.name);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.ClearError:
|
|
await this.clearError(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsDirty:
|
|
await this.markAsDirty(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsTouched:
|
|
await this.markAsTouched(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsPending:
|
|
await this.markAsPending(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsPristine:
|
|
await this.markAsPending(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsUnTouched:
|
|
await this.markAsTouched(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.UpdateValueAndValidity:
|
|
await this.updateValueAndValidity(model.name);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
return { name: c.propName, control: formControl };
|
|
})
|
|
.map((fc) => {
|
|
return { key: fc.name.toString(), value: fc.control };
|
|
})
|
|
) as { [key: string]: AbstractControl };
|
|
//#endregion
|
|
|
|
//
|
|
//#region Prepare Form Group ...
|
|
if (!this.FORM) {
|
|
//
|
|
this.FORM = new FormGroup(
|
|
controls,
|
|
formConfig.validators
|
|
? {
|
|
updateOn: formConfig.updateOn.toString() as
|
|
| 'change'
|
|
| 'blur'
|
|
| 'submit',
|
|
validators: formConfig.validators.validators || null,
|
|
asyncValidators: formConfig.validators.asyncValidators || null,
|
|
}
|
|
: null
|
|
);
|
|
|
|
//
|
|
// Form Value Changed ...
|
|
this.FORM.valueChanges.subscribe((res) => {
|
|
//
|
|
if (this.uiDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.valueChanged.emit({
|
|
name: formConfig.name,
|
|
value: res,
|
|
});
|
|
|
|
//
|
|
this.VALUE = res;
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
|
|
//
|
|
// Form Status Changed ...
|
|
this.FORM.statusChanges.subscribe((res) => {
|
|
//
|
|
if (this.uiDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.STATUS = res;
|
|
|
|
//
|
|
if (this.FORM.errors) {
|
|
this.ERRORS = this.FORM.errors;
|
|
} else {
|
|
this.ERRORS = null;
|
|
}
|
|
|
|
//
|
|
this.statusChanged.emit({
|
|
name: formConfig.name,
|
|
status: res,
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
} else {
|
|
//
|
|
entries(controls).forEach((ctrlEtry) => {
|
|
//
|
|
const name = ctrlEtry[0];
|
|
const control = ctrlEtry[1] as AbstractControl;
|
|
|
|
//
|
|
if (this.FORM.contains(name)) {
|
|
this.FORM.setControl(name, control);
|
|
}
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.FORM.markAllAsTouched();
|
|
this.FORM.updateValueAndValidity();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Config Object ...
|
|
//
|
|
private getControlName(name?: XFormControlNameIdentifier) {
|
|
return name ? name.toString() : null;
|
|
}
|
|
|
|
//
|
|
private getCustomControlConfig(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
concatMap((type) => {
|
|
switch (type) {
|
|
//
|
|
case XFormControlType.Map:
|
|
return this.getMapConfig(control);
|
|
|
|
//
|
|
case XFormControlType.Selector:
|
|
return this.getSelectorConfig(control);
|
|
|
|
//
|
|
case XFormControlType.ColorPicker:
|
|
return this.getColorPickerConfig(control);
|
|
|
|
//
|
|
default:
|
|
return of(null);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
private getControlInfo(control: XFormControlConfig) {
|
|
return this.getControlType(control).pipe(
|
|
concatMap((type) =>
|
|
this.getControlDisabled(control).pipe(
|
|
map((disabled) => ({ type, disabled }))
|
|
)
|
|
),
|
|
concatMap((typeInfo) =>
|
|
this.getControlAppearance(control).pipe(
|
|
map((appearance) => ({ ...typeInfo, appearance }))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFormActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFormBaseAction.Enable:
|
|
await this.enable(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.Disable:
|
|
await this.disable(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.Refresh:
|
|
await this.refresh();
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.SetError:
|
|
//
|
|
if (model.payload) {
|
|
await this.setError(model.payload, model.name);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.ClearError:
|
|
await this.clearError(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsDirty:
|
|
await this.markAsDirty(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsTouched:
|
|
await this.markAsTouched(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsPending:
|
|
await this.markAsPending(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsPristine:
|
|
await this.markAsPending(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.MarkAsUnTouched:
|
|
await this.markAsUnTouched(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.UpdateValueAndValidity:
|
|
await this.updateValueAndValidity(model.name);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.SetValue:
|
|
await this.setValue(model.name, model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFormBaseAction.ClearData:
|
|
await this.clearData();
|
|
break;
|
|
|
|
//
|
|
case XFormControlAction.Focuse:
|
|
if (model.name) {
|
|
this.focusOnControl(model.name);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XFormControlAction.Blur:
|
|
if (model.name) {
|
|
this.blurOfControl(model.name);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
//
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
private async handleUiDisabledChanged() {
|
|
//
|
|
if (this.uiDisabled) {
|
|
await this.disable();
|
|
} else {
|
|
await this.enable();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyColors() {
|
|
//
|
|
await this.applyRegularColor();
|
|
await this.applyAccentColor();
|
|
await this.applyHintColor();
|
|
await this.applyPendingColor();
|
|
await this.applyActiveColor();
|
|
await this.applyValidColor();
|
|
await this.applyInvalidColor();
|
|
await this.applyFillColor();
|
|
await this.applyDisabledColor();
|
|
await this.applyDisabledFillColor();
|
|
}
|
|
|
|
private async applyRegularColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.regularColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.RegularColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.RegularColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyAccentColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.accentColor);
|
|
if (!color) {
|
|
color = XColor.Secondary;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.AccentColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.AccentColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyHintColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.hintColor);
|
|
if (!color) {
|
|
color = XColor.Tertiary;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.HintColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.HintColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyPendingColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.pendingColor);
|
|
if (!color) {
|
|
color = XColor.Warning;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.PendingColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.PendingColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyActiveColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.activeColor);
|
|
if (!color) {
|
|
color = XColor.Tertiary;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.ActiveColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.ActiveColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyValidColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.validColor);
|
|
if (!color) {
|
|
color = XColor.Success;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.ValidColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.ValidColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyInvalidColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.invalidColor);
|
|
if (!color) {
|
|
color = XColor.Danger;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.InvalidColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.InvalidColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyFillColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.fillColor);
|
|
if (!color) {
|
|
color = XColorWithBrightness.SecondaryTint;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.FillColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.FillColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyDisabledColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.disabledColor);
|
|
if (!color) {
|
|
color = XColorWithBrightness.LightTint;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.DisableColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.DisableColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyDisabledFillColor() {
|
|
//
|
|
let color = await this.getValueAsync(this.disabledFillColor);
|
|
if (!color) {
|
|
color = XColorWithBrightness.LightShade;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XFormCssVar.DisabledFillColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XFormCssVar.DisabledFillColor,
|
|
`var(${bgColor})`,
|
|
document.documentElement
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.module.ts
|
|
|
|
import {
|
|
LocaleFactory,
|
|
XPersianDateAdapter,
|
|
MatDateFormatFactory,
|
|
} from 'x-framework-core';
|
|
import {
|
|
DateAdapter,
|
|
MAT_DATE_LOCALE,
|
|
MAT_DATE_FORMATS,
|
|
} from '@angular/material/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XMapModule } from '../x-map/x-map.module';
|
|
import { LOCALE_ID, NgModule } from '@angular/core';
|
|
import { XFormComponent } from './x-form.component';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XColorModule } from '../x-color/x-color.module';
|
|
import { XDialogsModule } from '../dialogs/x-dialog.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
import { XMarkdownModule } from '../x-markdown/x-markdown.module';
|
|
import { XDataPagerModule } from '../x-data-pager/x-data-pager.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XFileUploadModule } from '../x-file-upload/x-file-upload.module';
|
|
import { XColorPickerModule } from '../x-color-picker/x-color-picker.module';
|
|
import { XAvatarUploadModule } from '../x-avatar-upload/x-avatar-upload.module';
|
|
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
|
|
|
|
@NgModule({
|
|
entryComponents: [],
|
|
declarations: [XFormComponent],
|
|
imports: [
|
|
XMapModule,
|
|
XCardModule,
|
|
XListModule,
|
|
XIconModule,
|
|
FormsModule,
|
|
CommonModule,
|
|
XColorModule,
|
|
XDialogsModule,
|
|
XSlotterModule,
|
|
XMarkdownModule,
|
|
XDataPagerModule,
|
|
XFileUploadModule,
|
|
XColorPickerModule,
|
|
ReactiveFormsModule,
|
|
XAvatarUploadModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XMapModule,
|
|
XCardModule,
|
|
XListModule,
|
|
XIconModule,
|
|
FormsModule,
|
|
CommonModule,
|
|
XColorModule,
|
|
XDialogsModule,
|
|
XFormComponent,
|
|
XSlotterModule,
|
|
XMarkdownModule,
|
|
XDataPagerModule,
|
|
XFileUploadModule,
|
|
XColorPickerModule,
|
|
ReactiveFormsModule,
|
|
XAvatarUploadModule,
|
|
XBaseComponentModule,
|
|
],
|
|
providers: [
|
|
{
|
|
provide: LOCALE_ID,
|
|
useFactory: LocaleFactory,
|
|
},
|
|
{
|
|
provide: MAT_DATE_LOCALE,
|
|
useFactory: LocaleFactory,
|
|
},
|
|
{
|
|
deps: [MAT_DATE_LOCALE],
|
|
provide: MAT_DATE_FORMATS,
|
|
useFactory: MatDateFormatFactory,
|
|
},
|
|
{
|
|
provide: DateAdapter,
|
|
useClass: XPersianDateAdapter,
|
|
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS],
|
|
},
|
|
],
|
|
})
|
|
export class XFormModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.tools.ts
|
|
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { XColorWithBrightness } from 'x-framework-core';
|
|
import { XControlIconPosition, XControlIconDescriptor } from './x-form.typings';
|
|
|
|
export const defaultFormControlClearIcon: XControlIconDescriptor = {
|
|
name: XIconNames.clear,
|
|
applyStateColor: false,
|
|
color: XColorWithBrightness.Danger,
|
|
position: XControlIconPosition.Suffix,
|
|
}
|
|
|
|
export const defaultFormControlSelectIcon: XControlIconDescriptor = {
|
|
name: XIconNames.touch,
|
|
applyStateColor: false,
|
|
color: XColorWithBrightness.Success,
|
|
position: XControlIconPosition.Suffix,
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XLocale,
|
|
XBaseDto,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XExceptionIdentifier,
|
|
XColorWithBrightness,
|
|
XBorderStyleIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XManagerService,
|
|
XFormInputFormatterIdentifier,
|
|
XStringInputFormatTypeIdentifier,
|
|
} from 'x-framework-services';
|
|
import {
|
|
XMarkdownActionModel,
|
|
XMarkdownModeIdentifier,
|
|
XMarkdownToolbarConfigProps,
|
|
} from '../x-markdown/x-markdown.typings';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XAvatarUploadActionModel,
|
|
XAvatarUploadActionButton,
|
|
} from '../x-avatar-upload/x-avatar-upload.typings';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { AbstractControlOptions } from '@angular/forms';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { IXMapContainer, XMapActionModel } from '../x-map/x-map.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XMapDialogService } from '../x-map/x-map-dialog/x-map-dialog.service';
|
|
import { XColorPickerActionModel } from '../x-color-picker/x-color-picker.typings';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
import { XFileDropAreaActionModel } from '../x-file-drop-area/x-file-drop-area.typings';
|
|
import { XSelectorDialogConfig } from '../dialogs/x-selector-dialog/x-selector-dialog.typings';
|
|
import { XSelectorDialogService } from '../dialogs/x-selector-dialog/x-selector-dialog.service';
|
|
import { XColorPickerDialogConfig } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings';
|
|
import { XColorPickerDialogService } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service';
|
|
|
|
//
|
|
//#region Css Vars ...
|
|
export enum XFormCssVar {
|
|
FillColor = 'fill-color',
|
|
HintColor = 'hint-color',
|
|
ValidColor = 'valid-color',
|
|
ActiveColor = 'active-color',
|
|
AccentColor = 'accent-color',
|
|
RegularColor = 'regular-color',
|
|
PendingColor = 'pending-color',
|
|
InvalidColor = 'invalid-color',
|
|
DisableColor = 'disabled-color',
|
|
DisabledFillColor = 'disabled-fill-color',
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Base Form Control Action Model ...
|
|
export type XFormControlNameIdentifier = string | number | symbol;
|
|
|
|
export interface XBaseFormControlActionModel {
|
|
name?: XFormControlNameIdentifier;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Auto Complete Config ...
|
|
export interface XFormControlAutoCompleteConfig<T extends XBaseDto = any> {
|
|
opened?: XStandardType<boolean>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
onSelect?: (item: T) => XStandardType<void>;
|
|
items: () => XStandardType<XOneOrManyType<T>>;
|
|
itemTemplate: XStandardType<TemplateRef<any>>;
|
|
cssClass?: XStandardType<XOneOrManyType<string>>;
|
|
onEscape?: () => XStandardType<void>;
|
|
onOutsideClicked?: () => XStandardType<void>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XForm Validator Model ...
|
|
export type XFormValidatorDescriptor = Partial<
|
|
Pick<AbstractControlOptions, 'validators' | 'asyncValidators'>
|
|
>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Error Handler Configs ...
|
|
export interface XFormErrorHandler {
|
|
errorName: XStandardType<string>;
|
|
errorMessage: XStandardType<XResourceIdentifier>;
|
|
errorDataProvider?: (errorObject: any) => XStandardType<XResourceIdentifier>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Formatter Config ...
|
|
export interface XFormControlFormatterConfig {
|
|
locale?: XStandardType<XLocale>;
|
|
seperator?: XStandardType<string>;
|
|
type: XStandardType<XFormInputFormatterIdentifier>;
|
|
inputType?: XStandardType<XStringInputFormatTypeIdentifier>;
|
|
currencyLable?: XStandardType<XResourceIdentifier>;
|
|
stringFormatter?: XStandardType<XOneOrManyType<number>>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Control Progressbar Config ...
|
|
export interface XFormControlProgressbarConfig {
|
|
color: XStandardType<XColorIdentifier>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XForm Control Appearance ...
|
|
export enum XFormControlAppearance {
|
|
None = 'none',
|
|
Legacy = 'legacy',
|
|
Standard = 'standard',
|
|
Fill = 'fill',
|
|
Outline = 'outline',
|
|
}
|
|
|
|
export type XFormControlAppearanceIdentifier = XFormControlAppearance | string;
|
|
|
|
export interface XFormControlAppearanceDescriptor {
|
|
hidden?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
hint?: XStandardType<XResourceIdentifier>;
|
|
label: XStandardType<XResourceIdentifier>;
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
placeholder?: XStandardType<XResourceIdentifier>;
|
|
cssClass?: XStandardType<XOneOrManyType<string>>;
|
|
icons?: XStandardType<XFormControlIconDescriptor>;
|
|
formatter?: XStandardType<XFormControlFormatterConfig>;
|
|
progressBar?: XStandardType<XFormControlProgressbarConfig>;
|
|
autoComplete?: XStandardType<XFormControlAutoCompleteConfig>;
|
|
appearance?: XStandardType<XFormControlAppearanceIdentifier>;
|
|
labelPosition?: XStandardType<XFormControlLabelPositionIdentifier>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Icon Configs ...
|
|
export enum XControlIconPosition {
|
|
Prefix = 'prefix',
|
|
Suffix = 'suffix',
|
|
}
|
|
|
|
export type XControlIconPositionIdentifier = XControlIconPosition | string;
|
|
|
|
export enum XControlIconRole {
|
|
Clear = 'clear',
|
|
Select = 'select',
|
|
}
|
|
|
|
export type XControlIconRoleIdentifier = XControlIconRole | string;
|
|
|
|
export interface XControlIconDescriptor {
|
|
handler?: () => XStandardType<void>;
|
|
name?: XStandardType<XIconIdentifier>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
applyStateColor?: XStandardType<boolean>;
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
position?: XStandardType<XControlIconPositionIdentifier>;
|
|
}
|
|
|
|
export interface XFormIconDescriptor
|
|
extends Pick<
|
|
Partial<XControlIconDescriptor>,
|
|
'handler' | 'name' | 'color' | 'applyStateColor' | 'tooltip'
|
|
> {}
|
|
|
|
export interface XFormControlIconDescriptor {
|
|
suffix?: XStandardType<XFormIconDescriptor>;
|
|
prefix?: XStandardType<XFormIconDescriptor>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Control Status and Values Changed ...
|
|
export interface XFormControlValueChangeEventModel
|
|
extends XBaseFormControlActionModel {
|
|
value: any;
|
|
}
|
|
|
|
export interface XFormControlStatusChangeEventModel
|
|
extends XBaseFormControlActionModel {
|
|
status: XFormStatusIdentifier;
|
|
}
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XFormValueChangeEventModel
|
|
extends XFormControlValueChangeEventModel {}
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XFormStatusChangeEventModel
|
|
extends XFormControlStatusChangeEventModel {}
|
|
|
|
//
|
|
// Form and Form Control Status ...
|
|
export enum XFormStatus {
|
|
UnKnown = 'UNKNOWN',
|
|
Valid = 'VALID',
|
|
Invalid = 'INVALID',
|
|
Pending = 'PENDING',
|
|
Disabled = 'DISABLED',
|
|
}
|
|
|
|
export type XFormStatusIdentifier = XFormStatus | string;
|
|
|
|
export interface XFormControlEventsDescriptor {
|
|
statusChanged?: (
|
|
model: XFormControlStatusChangeEventModel
|
|
) => XStandardType<void>;
|
|
valueChanged?: (
|
|
model: XFormControlValueChangeEventModel
|
|
) => XStandardType<void>;
|
|
onBlured?: (model: XBaseFormControlActionModel) => XStandardType<void>;
|
|
onFocused?: (model: XBaseFormControlActionModel) => XStandardType<void>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Control Label Position ...
|
|
export enum XFormControlLabelPosition {
|
|
After = 'after',
|
|
Before = 'before',
|
|
}
|
|
|
|
export type XFormControlLabelPositionIdentifier =
|
|
| XFormControlLabelPosition
|
|
| string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form and Form Control Action Provider ...
|
|
export enum XFormBaseAction {
|
|
//
|
|
MarkAsDirty = 'mark_as_dirty',
|
|
MarkAsTouched = 'mark_as_touched',
|
|
MarkAsPending = 'mark_as_pending',
|
|
MarkAsPristine = 'mark_as_pristine',
|
|
MarkAsUnTouched = 'mark_as_untouched',
|
|
UpdateValueAndValidity = 'update_value_and_validity',
|
|
//
|
|
SetError = 'set_error',
|
|
ClearError = 'clear_error',
|
|
//
|
|
SetValue = 'set_value',
|
|
//
|
|
Enable = 'enable',
|
|
Disable = 'disable',
|
|
//
|
|
Refresh = 'refresh',
|
|
//
|
|
ClearData = 'clear_data',
|
|
}
|
|
|
|
export enum XFormControlAction {
|
|
Focuse = 'focuse',
|
|
Blur = 'blur',
|
|
}
|
|
|
|
export type XFormControlActionIdentifier =
|
|
| XFormBaseAction
|
|
| XFormControlAction
|
|
| string;
|
|
|
|
export interface XFormControlActionProviderModel
|
|
extends XBaseActionModel<XFormControlActionIdentifier>,
|
|
XBaseFormControlActionModel {}
|
|
|
|
export interface XFormActionModel extends XFormControlActionProviderModel {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region XForm and XForm Control Update On ...
|
|
export enum XFormUpdateOn {
|
|
BLUR = 'blur',
|
|
CHANGE = 'change',
|
|
SUBMIT = 'submit',
|
|
}
|
|
|
|
export type XFormUpdateOnIdentifier = XFormUpdateOn | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Control Types ...
|
|
export enum XFormControlType {
|
|
Text = 'text',
|
|
Number = 'number',
|
|
Password = 'password',
|
|
Color = 'color',
|
|
Email = 'email',
|
|
Tel = 'tel',
|
|
Url = 'url',
|
|
Select = 'select',
|
|
Radio = 'radio',
|
|
CheckBox = 'checkbox',
|
|
Hidden = 'hidden',
|
|
Date = 'date',
|
|
Slider = 'slider',
|
|
Toggle = 'toggle',
|
|
MarkDown = 'markdown',
|
|
Map = 'map',
|
|
ColorPicker = 'color_picker',
|
|
AvatarUpload = 'avatar_upload',
|
|
Selector = 'selector',
|
|
}
|
|
|
|
export type XFormControlTypeIdentifier = XFormControlType | string;
|
|
|
|
export type XFormControlTypeConfig =
|
|
| XFormMapControlConfig
|
|
| XFormRadioControlConfig
|
|
| XFormInputControlConfig
|
|
| XFormSelectControlConfig
|
|
| XFormSliderControlConfig
|
|
| XFormSelectorControlConfig
|
|
| XFormMarkdownControlConfig
|
|
| XFormCheckBoxControlConfig
|
|
| XFormDatePickerControlConfig
|
|
| XFormColorPickerControlConfig
|
|
| XFormAvatarUploadControlConfig
|
|
| undefined;
|
|
export interface XFormControlTypeDescriptor {
|
|
type: XStandardType<XFormControlTypeIdentifier>;
|
|
config?: XStandardType<XFormControlTypeConfig>;
|
|
}
|
|
|
|
//
|
|
//#region Type Configs ...
|
|
//
|
|
//#region Input Type ...
|
|
export interface XFormInputControlConfig {
|
|
readonly?: XStandardType<boolean>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Select Type ...
|
|
export interface XFormSelectControlOption<T extends XBaseDto = any> {
|
|
value: XStandardType<T>;
|
|
viewValue: XStandardType<string>;
|
|
}
|
|
|
|
export interface XFormSelectControlConfig<T extends XBaseDto = any> {
|
|
options?: XStandardType<XOneOrManyType<XFormSelectControlOption<T>>>;
|
|
multiple?: XStandardType<boolean>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Radio Type ...
|
|
export interface XFormRadioControlOption<T extends XBaseDto = any> {
|
|
value: XStandardType<T>;
|
|
viewValue: XStandardType<string>;
|
|
}
|
|
|
|
export interface XFormRadioControlConfig<T extends XBaseDto = any> {
|
|
options?: XStandardType<XOneOrManyType<XFormRadioControlOption<T>>>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Date Control Config ...
|
|
export enum XFormDatePickerControlPickerPosition {
|
|
Suffix = 'suffix',
|
|
Prefix = 'prefix',
|
|
}
|
|
|
|
export type XFormDatePickerControlPickerPositionIdentifier =
|
|
| XFormDatePickerControlPickerPosition
|
|
| string;
|
|
|
|
export interface XFormDatePickerControlConfig {
|
|
startAt?: XStandardType<Date>;
|
|
dateFilter?: (d: any) => boolean;
|
|
applyStateColor?: XStandardType<boolean>;
|
|
toggleIcon?: XStandardType<XIconIdentifier>;
|
|
iconColor?: XStandardType<XColorIdentifier>;
|
|
datePickerPosition: XStandardType<XFormDatePickerControlPickerPositionIdentifier>;
|
|
disableInput?: XStandardType<boolean>;
|
|
disablePicker?: XStandardType<boolean>;
|
|
iconTooltip?: XStandardType<XResourceIdentifier>;
|
|
dateInput?: (event: Date) => XStandardType<void>;
|
|
dateChange?: (event: Date) => XStandardType<void>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Slider Control ...
|
|
export interface XFormSliderControlConfig {
|
|
min?: XStandardType<number>;
|
|
max?: XStandardType<number>;
|
|
step?: XStandardType<number>;
|
|
invert?: XStandardType<boolean>;
|
|
vertical?: XStandardType<boolean>;
|
|
thumbLabel?: XStandardType<boolean>;
|
|
formatter?: (value: number) => string;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Markdown Control Config ...
|
|
export interface XFormMarkdownControlConfig {
|
|
//
|
|
isInPage?: XStandardType<boolean>;
|
|
hasToolbar?: XStandardType<boolean>;
|
|
wrapWithCard?: XStandardType<boolean>;
|
|
cardColor?: XStandardType<XColorIdentifier>;
|
|
cardForegroundColor?: XStandardType<boolean>;
|
|
mode?: XStandardType<XMarkdownModeIdentifier>;
|
|
toolbarColor?: XStandardType<XColorIdentifier>;
|
|
cardTitle?: XStandardType<XResourceIdentifier>;
|
|
actionProvider?: Subject<XMarkdownActionModel>;
|
|
toolbarForegroundColor?: XStandardType<boolean>;
|
|
cssClass?: XStandardType<XOneOrManyType<string>>;
|
|
editorBoxColor?: XStandardType<XColorIdentifier>;
|
|
previewBoxColor?: XStandardType<XColorIdentifier>;
|
|
cardSubTitle?: XStandardType<XResourceIdentifier>;
|
|
toolbarCssClass?: XStandardType<XOneOrManyType<string>>;
|
|
contentChanged?: (content: string) => XStandardType<void>;
|
|
toolbarConfig?: XStandardType<XMarkdownToolbarConfigProps>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Check Box Config ...
|
|
export interface XFormCheckBoxControlConfig {
|
|
checkedChanged?: (checked: boolean) => XStandardType<any>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Map Config ...
|
|
export enum XFormMapControlPresentType {
|
|
WithDialog = 'width_dialog',
|
|
WithoutDialog = 'without_dialog',
|
|
}
|
|
|
|
export type XFormMapControlPresentTypeIdentifier =
|
|
| XFormMapControlPresentType
|
|
| string;
|
|
|
|
//
|
|
export interface XFormMapControlConfig
|
|
extends Pick<
|
|
Partial<IXMapContainer>,
|
|
| 'zoom'
|
|
| 'markerStyle'
|
|
| 'cssClass'
|
|
| 'canSelect'
|
|
//
|
|
| 'showProgressBar'
|
|
| 'progressBarColor'
|
|
| 'progressBarPosition'
|
|
//
|
|
| 'showSearchBar'
|
|
| 'searchBarType'
|
|
| 'searchBarValue'
|
|
| 'searchBarDebounce'
|
|
| 'searchBarQueryChange'
|
|
| 'searchBarSpellcheck'
|
|
| 'searchPlaceProvider'
|
|
| 'searchBarColor'
|
|
| 'searchBarForegroundColor'
|
|
| 'searchBarClearButtonIcon'
|
|
| 'searchBarTitle'
|
|
| 'searchBarSearchButtonIcon'
|
|
| 'searchBarSearchInputColor'
|
|
| 'searchBarForegroundSearchInputColor'
|
|
| 'searchResultListColor'
|
|
| 'searchBarActionProvider'
|
|
| 'searchBarClearButtonIconColor'
|
|
| 'searchBarCssClass'
|
|
| 'searchBarSearchButtonIconColor'
|
|
| 'searchBarCancelButtonIcon'
|
|
| 'searchBarPosition'
|
|
| 'searchBarKeyboardType'
|
|
| 'searchBarCancelButtonTitle'
|
|
| 'searchBarEnterKeyHint'
|
|
| 'searchBarShowCancelButton'
|
|
//
|
|
| 'showSelectedLocation'
|
|
| 'selectedLocationPosition'
|
|
//
|
|
| 'showGoMarkedPlace'
|
|
| 'goMarkedPlacePosition'
|
|
//
|
|
| 'showClearMarker'
|
|
| 'clearMarkerPosition'
|
|
//
|
|
| 'showLocator'
|
|
| 'locatorPosition'
|
|
//
|
|
| 'showZoom'
|
|
| 'showRotate'
|
|
| 'showZoomSlider'
|
|
//
|
|
| 'isReady'
|
|
| 'locationSelected'
|
|
//
|
|
| 'isInPage'
|
|
| 'wrapWithCard'
|
|
| 'cardShowFooter'
|
|
| 'cardColor'
|
|
| 'cardForegroundColor'
|
|
| 'cardTitle'
|
|
| 'cardSubTitle'
|
|
> {
|
|
//
|
|
disableIcon?: XStandardType<boolean>;
|
|
disableInput?: XStandardType<boolean>;
|
|
actionProvider?: Subject<XMapActionModel>;
|
|
clearIcon?: XStandardType<XControlIconDescriptor>;
|
|
selectIcon?: XStandardType<XControlIconDescriptor>;
|
|
inputCssClass?: XStandardType<XOneOrManyType<string>>;
|
|
inputValueChanged?: (value?: string) => XStandardType<string>;
|
|
presentType?: XStandardType<XFormMapControlPresentTypeIdentifier>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ColorPicker Config ...
|
|
export enum XFormColorPickerControlPresentType {
|
|
WithDialog = 'width_dialog',
|
|
WithoutDialog = 'without_dialog',
|
|
// Both = 'both',
|
|
}
|
|
|
|
export type XFormColorPickerControlPresentTypeIdentifier =
|
|
| XFormColorPickerControlPresentType
|
|
| string;
|
|
|
|
//
|
|
export interface XFormColorPickerControlConfig
|
|
extends Pick<
|
|
Partial<XColorPickerDialogConfig>,
|
|
| 'color'
|
|
| 'cssClass'
|
|
| 'cardColor'
|
|
| 'cardTitle'
|
|
| 'cursorColor'
|
|
| 'presetColors'
|
|
| 'outputFormat'
|
|
| 'cardSubTitle'
|
|
| 'colorSelected'
|
|
| 'colorTextColor'
|
|
| 'showColorValue'
|
|
| 'showHueChannel'
|
|
| 'showColorInput'
|
|
| 'foregroundColor'
|
|
| 'showPresetColors'
|
|
| 'showAlphaChannel'
|
|
| 'presetColorsLable'
|
|
| 'showPaletteChannel'
|
|
| 'cardForegroundColor'
|
|
| 'showCopyToClipboard'
|
|
| 'colorInputIconLabel'
|
|
| 'colorInputIconColor'
|
|
| 'clearColorIconColor'
|
|
| 'clearColorIconLabel'
|
|
| 'representColorFormats'
|
|
| 'presetColorsLableColor'
|
|
| 'copyToClipboardIconLabel'
|
|
| 'copyToClipboardIconColor'
|
|
| 'showSelectedColorPreview'
|
|
> {
|
|
//
|
|
isInPage?: XStandardType<boolean>;
|
|
disableIcon?: XStandardType<boolean>;
|
|
disableInput?: XStandardType<boolean>;
|
|
wrapWithCard?: XStandardType<boolean>;
|
|
showCardFooter?: XStandardType<boolean>;
|
|
colorViewBorderWidth?: XStandardType<number>;
|
|
actionProvider?: Subject<XColorPickerActionModel>;
|
|
clearIcon?: XStandardType<XControlIconDescriptor>;
|
|
selectIcon?: XStandardType<XControlIconDescriptor>;
|
|
inputCssClass?: XStandardType<XOneOrManyType<string>>;
|
|
colorViewBorderColor?: XStandardType<XColorIdentifier>;
|
|
colorViewBorderStyle?: XStandardType<XBorderStyleIdentifier>;
|
|
inputValueChanged?: (value?: string) => XStandardType<string>;
|
|
presentType?: XStandardType<XFormColorPickerControlPresentTypeIdentifier>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Avatar Upload Config ...
|
|
export interface XFormAvatarUploadControlConfig {
|
|
fileDropAreaFilesChangeEmiter?: (
|
|
files?: XOneOrManyType<File>
|
|
) => XStandardType<void>;
|
|
canDrop?: XStandardType<boolean>;
|
|
isInPage?: XStandardType<boolean>;
|
|
wrapWithCard?: XStandardType<boolean>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
showCardFooter?: XStandardType<boolean>;
|
|
foregroundColor?: XStandardType<boolean>;
|
|
placeHolderAvatar?: XStandardType<string>;
|
|
minAllowedFileSize?: XStandardType<number>;
|
|
maxAllowedFileSize?: XStandardType<number>;
|
|
cardColor?: XStandardType<XColorIdentifier>;
|
|
cardForegroundColor?: XStandardType<boolean>;
|
|
fileDropAreaIsInPage?: XStandardType<boolean>;
|
|
cardTitle?: XStandardType<XResourceIdentifier>;
|
|
cssClass?: XStandardType<XOneOrManyType<string>>;
|
|
fileDropAreaWrapWithCard?: XStandardType<boolean>;
|
|
fileDropAreaIcon?: XStandardType<XIconIdentifier>;
|
|
fileDropAreaDragDisabled?: XStandardType<boolean>;
|
|
cardSubTitle?: XStandardType<XResourceIdentifier>;
|
|
actionProvider?: Subject<XAvatarUploadActionModel>;
|
|
fileDropAreaShowCardFooter?: XStandardType<boolean>;
|
|
fileDropAreaColor?: XStandardType<XColorIdentifier>;
|
|
fileDropAreaForegroundColor?: XStandardType<boolean>;
|
|
avatarChange?: (avatar?: File) => XStandardType<void>;
|
|
fileDropAreaDisableFileCheck?: XStandardType<boolean>;
|
|
fileDropAreaCardColor?: XStandardType<XColorIdentifier>;
|
|
fileDropAreaCardForegroundColor?: XStandardType<boolean>;
|
|
emptyFileException?: XStandardType<XExceptionIdentifier>;
|
|
fileDropAreaErrorColor?: XStandardType<XColorIdentifier>;
|
|
fileDropAreaMessage?: XStandardType<XResourceIdentifier>;
|
|
fileDropAreaAccentColor?: XStandardType<XColorIdentifier>;
|
|
allowedExtensions?: XStandardType<XOneOrManyType<string>>;
|
|
fileDropAreaCardTitle?: XStandardType<XResourceIdentifier>;
|
|
fileDropAreaSuccessColor?: XStandardType<XColorIdentifier>;
|
|
fileDropAreaSupportsMultipleFiles?: XStandardType<boolean>;
|
|
fileDropAreaCssClass?: XStandardType<XOneOrManyType<string>>;
|
|
fileDropAreaCardSubTitle?: XStandardType<XResourceIdentifier>;
|
|
notAllowedFileException?: XStandardType<XExceptionIdentifier>;
|
|
fileDropAreaContentTemplate?: XStandardType<TemplateRef<any>>;
|
|
fileDropAreaActionProvider?: Subject<XFileDropAreaActionModel>;
|
|
minAllowedFileSizeException?: XStandardType<XExceptionIdentifier>;
|
|
maxAllowedFileSizeException?: XStandardType<XExceptionIdentifier>;
|
|
actions?: XStandardType<XOneOrManyType<XAvatarUploadActionButton>>;
|
|
fileDropAreaAllowedExtensions?: XStandardType<XOneOrManyType<string>>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selector Config ...
|
|
export interface XFormSelectorControlConfig
|
|
extends Partial<XSelectorDialogConfig> {
|
|
//
|
|
clearIcon?: XStandardType<XControlIconDescriptor>;
|
|
selectIcon?: XStandardType<XControlIconDescriptor>;
|
|
inputCssClass?: XStandardType<XOneOrManyType<string>>;
|
|
inputValueChanged?: (value?: string) => XStandardType<string>;
|
|
formatSelectedItem?: (item: XOneOrManyType<any>) => XStandardType<string>;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Form Control Config ...
|
|
export interface XFormControlConfig<T extends XBaseDto = any> {
|
|
index: number;
|
|
propName: keyof Partial<T>;
|
|
focusHandler?: Subject<any>;
|
|
type: XStandardType<XFormControlTypeDescriptor>;
|
|
updateOn?: XStandardType<XFormUpdateOnIdentifier>;
|
|
validators?: XStandardType<XFormValidatorDescriptor>;
|
|
actionProvider?: Subject<XFormControlActionProviderModel>;
|
|
eventHandlers?: XStandardType<XFormControlEventsDescriptor>;
|
|
appearance: XStandardType<XFormControlAppearanceDescriptor>;
|
|
errorHandlers?: XStandardType<XOneOrManyType<XFormErrorHandler>>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Form Config ...
|
|
export interface XFormConfig<T extends XBaseDto = any> {
|
|
name: XStandardType<string>;
|
|
model?: XStandardType<Partial<T>>;
|
|
updateOn?: XStandardType<XFormUpdateOnIdentifier>;
|
|
validators?: XStandardType<XFormValidatorDescriptor>;
|
|
controls: XStandardType<XOneOrManyType<XFormControlConfig<T>>>;
|
|
errorHandlers?: XStandardType<XOneOrManyType<XFormErrorHandler>>;
|
|
}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXFormContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XFormActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
formConfig: XStandardType<XFormConfig>;
|
|
applyStatusOnControls: XStandardType<boolean>;
|
|
|
|
//
|
|
regularColor: XStandardType<XColorIdentifier>;
|
|
accentColor: XStandardType<XColorIdentifier>;
|
|
hintColor: XStandardType<XColorIdentifier>;
|
|
activeColor: XStandardType<XColorIdentifier>;
|
|
validColor: XStandardType<XColorIdentifier>;
|
|
invalidColor: XStandardType<XColorIdentifier>;
|
|
pendingColor: XStandardType<XColorIdentifier>;
|
|
fillColor: XStandardType<XColorIdentifier>;
|
|
disabledColor: XStandardType<XColorIdentifier>;
|
|
disabledFillColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
valueChanged: EventEmitter<XFormValueChangeEventModel>;
|
|
statusChanged: EventEmitter<XFormStatusChangeEventModel>;
|
|
controlFocused: EventEmitter<XBaseFormControlActionModel>;
|
|
controlBlured: EventEmitter<XBaseFormControlActionModel>;
|
|
controlValueChanged: EventEmitter<XFormControlValueChangeEventModel>;
|
|
controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFormContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXFormContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XFormActionModel> =
|
|
new Subject<XFormActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly formConfig: XStandardType<XFormConfig> = null;
|
|
readonly applyStatusOnControls: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly regularColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly accentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Secondary;
|
|
readonly hintColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly activeColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly validColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Success;
|
|
readonly invalidColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
readonly pendingColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
readonly fillColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.SecondaryTint;
|
|
readonly disabledColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightTint;
|
|
readonly disabledFillColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
|
|
//
|
|
readonly valueChanged: EventEmitter<XFormValueChangeEventModel> =
|
|
new EventEmitter<XFormValueChangeEventModel>();
|
|
readonly statusChanged: EventEmitter<XFormStatusChangeEventModel> =
|
|
new EventEmitter<XFormStatusChangeEventModel>();
|
|
readonly controlFocused: EventEmitter<XBaseFormControlActionModel> =
|
|
new EventEmitter<XBaseFormControlActionModel>();
|
|
readonly controlBlured: EventEmitter<XBaseFormControlActionModel> =
|
|
new EventEmitter<XBaseFormControlActionModel>();
|
|
readonly controlValueChanged: EventEmitter<XFormControlValueChangeEventModel> =
|
|
new EventEmitter<XFormControlValueChangeEventModel>();
|
|
readonly controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel> =
|
|
new EventEmitter<XFormControlStatusChangeEventModel>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFormContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXFormContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XFormActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
formConfig: XStandardType<XFormConfig> = this.propertyProvider.formConfig;
|
|
|
|
@Input()
|
|
applyStatusOnControls: XStandardType<boolean> =
|
|
this.propertyProvider.applyStatusOnControls;
|
|
|
|
//
|
|
@Input()
|
|
regularColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.regularColor;
|
|
|
|
@Input()
|
|
accentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.accentColor;
|
|
|
|
@Input()
|
|
hintColor: XStandardType<XColorIdentifier> = this.propertyProvider.hintColor;
|
|
|
|
@Input()
|
|
activeColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.activeColor;
|
|
|
|
@Input()
|
|
validColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.validColor;
|
|
|
|
@Input()
|
|
invalidColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.invalidColor;
|
|
|
|
@Input()
|
|
pendingColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.pendingColor;
|
|
|
|
@Input()
|
|
fillColor: XStandardType<XColorIdentifier> = this.propertyProvider.fillColor;
|
|
|
|
@Input()
|
|
disabledColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.disabledColor;
|
|
|
|
@Input()
|
|
disabledFillColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.disabledFillColor;
|
|
|
|
//
|
|
@Output()
|
|
valueChanged: EventEmitter<XFormValueChangeEventModel> = new EventEmitter();
|
|
|
|
@Output()
|
|
statusChanged: EventEmitter<XFormStatusChangeEventModel> = new EventEmitter();
|
|
|
|
@Output()
|
|
controlFocused: EventEmitter<XBaseFormControlActionModel> = new EventEmitter();
|
|
|
|
@Output()
|
|
controlBlured: EventEmitter<XBaseFormControlActionModel> = new EventEmitter();
|
|
|
|
@Output()
|
|
controlValueChanged: EventEmitter<XFormControlValueChangeEventModel> = new EventEmitter();
|
|
|
|
@Output()
|
|
controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFormContainer,
|
|
protected mapDialogService: XMapDialogService,
|
|
protected selectorDialogService: XSelectorDialogService,
|
|
protected colorPickerDialogService: XColorPickerDialogService
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFormContainer
|
|
): Observable<IXFormContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
formConfig: this.getValue(
|
|
container ? container.formConfig : this.formConfig
|
|
),
|
|
applyStatusOnControls: this.getValue(
|
|
container
|
|
? container.applyStatusOnControls
|
|
: this.applyStatusOnControls
|
|
),
|
|
regularColor: this.getValue(
|
|
container ? container.regularColor : this.regularColor
|
|
),
|
|
accentColor: this.getValue(
|
|
container ? container.accentColor : this.accentColor
|
|
),
|
|
hintColor: this.getValue(
|
|
container ? container.hintColor : this.hintColor
|
|
),
|
|
activeColor: this.getValue(
|
|
container ? container.activeColor : this.activeColor
|
|
),
|
|
validColor: this.getValue(
|
|
container ? container.validColor : this.validColor
|
|
),
|
|
invalidColor: this.getValue(
|
|
container ? container.invalidColor : this.invalidColor
|
|
),
|
|
pendingColor: this.getValue(
|
|
container ? container.pendingColor : this.pendingColor
|
|
),
|
|
fillColor: this.getValue(
|
|
container ? container.fillColor : this.fillColor
|
|
),
|
|
disabledColor: this.getValue(
|
|
container ? container.disabledColor : this.disabledColor
|
|
),
|
|
disabledFillColor: this.getValue(
|
|
container ? container.disabledFillColor : this.disabledFillColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
valueChanged: this.valueChanged,
|
|
statusChanged: this.statusChanged,
|
|
controlFocused: this.controlFocused,
|
|
controlBlured: this.controlBlured,
|
|
controlValueChanged: this.controlValueChanged,
|
|
controlStatusChanged: this.controlStatusChanged,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\validators\x-form-validators.ts
|
|
|
|
import {
|
|
isValidURL,
|
|
XCountryCode,
|
|
isNullOrUndefined,
|
|
isValidPhoneNumber,
|
|
isNullOrEmptyString,
|
|
toNumber,
|
|
toXString,
|
|
} from 'x-framework-core';
|
|
import { ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
|
|
|
|
export class XFormValidators {
|
|
/**
|
|
* check given date in between start and end date ...
|
|
*
|
|
* @param startDate start date for validating
|
|
* @param endDate end date for validating
|
|
*/
|
|
static validateDate(
|
|
startDate: Date | string,
|
|
endDate: Date | string
|
|
): ValidatorFn {
|
|
//
|
|
const errorObject = {
|
|
startDate,
|
|
endDate,
|
|
currentDate: new Date(),
|
|
xValidateDate: true,
|
|
};
|
|
|
|
//
|
|
const validatorFn = (control: AbstractControl): ValidationErrors | null => {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(control.value) ||
|
|
isNullOrUndefined(startDate) ||
|
|
isNullOrUndefined(endDate)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const mStartDate = new Date(startDate);
|
|
const mEndDate = new Date(endDate);
|
|
const mDate = new Date(control.value);
|
|
|
|
//
|
|
const isValid = mDate >= mStartDate && mDate <= mEndDate;
|
|
if (!isValid) {
|
|
//
|
|
errorObject.currentDate = mDate;
|
|
return errorObject;
|
|
}
|
|
|
|
//
|
|
return null;
|
|
};
|
|
|
|
//
|
|
return validatorFn;
|
|
}
|
|
|
|
/**
|
|
* check given value be a valid phone number ...
|
|
*
|
|
* @param defaultCountryCode an optional value which used for country code if not exists in value
|
|
*/
|
|
static validatePhoneNumber(defaultCountry?: XCountryCode): ValidatorFn {
|
|
//
|
|
const errorObject = {
|
|
xPhoneNumberValidator: true,
|
|
};
|
|
|
|
//
|
|
const validatorFn = (control: AbstractControl): ValidationErrors | null => {
|
|
//
|
|
if (isNullOrEmptyString(control.value)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const value = control.value as string;
|
|
const isValid = isValidPhoneNumber(value, defaultCountry);
|
|
|
|
//
|
|
if (!isValid) {
|
|
return errorObject;
|
|
}
|
|
|
|
//
|
|
return null;
|
|
};
|
|
|
|
//
|
|
return validatorFn;
|
|
}
|
|
|
|
/**
|
|
* check given value is Valid URL or not ...
|
|
*/
|
|
static validateUrl(): ValidatorFn {
|
|
//
|
|
const errorObject = {
|
|
xUrlValidator: true,
|
|
};
|
|
|
|
//
|
|
const validatorFn = (control: AbstractControl): ValidationErrors | null => {
|
|
//
|
|
if (isNullOrEmptyString(control.value)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const value = control.value as string;
|
|
const isValid = isValidURL(value);
|
|
|
|
//
|
|
if (!isValid) {
|
|
return errorObject;
|
|
}
|
|
|
|
//
|
|
return null;
|
|
};
|
|
|
|
//
|
|
return validatorFn;
|
|
}
|
|
|
|
/**
|
|
* check give value notEquals to Zero ...
|
|
* usually works for id's in Selector Component ...
|
|
*/
|
|
static validateNotZero(): ValidatorFn {
|
|
//
|
|
const errorObject = {
|
|
xNotZeroValidator: true,
|
|
};
|
|
|
|
//
|
|
const validatorFn = (control: AbstractControl): ValidationErrors | null => {
|
|
//
|
|
if (isNullOrEmptyString(control.value)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const value = control.value as string;
|
|
const isValid =
|
|
!isNullOrEmptyString(value) &&
|
|
(toXString(value) !== '0' || toNumber(value) !== 0);
|
|
|
|
//
|
|
if (!isValid) {
|
|
return errorObject;
|
|
}
|
|
|
|
//
|
|
return null;
|
|
};
|
|
|
|
//
|
|
return validatorFn;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="v-card v-no-margin-card"
|
|
[color]="getValue(cardColor) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[ngClass]="getValue(cardCssClass) | async"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[subTitle]="getResourceValue(cardSubTitle) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" actions *ngIf="getValue(cardShowActions) | async">
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="x-footer" footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<div [ngClass]="getCssClasses('container') | async">
|
|
<!-- iFrame By ContentURL -->
|
|
<ng-container *ngIf="notEmptyValue(contentUrl) | async">
|
|
<iframe
|
|
[id]="id"
|
|
#frameView
|
|
scrolling="no"
|
|
[src]="contentUrl"
|
|
allowtransparency="true"
|
|
(load)="onContentLoaded.emit($event)"
|
|
*ngIf="notEmptyValue(contentUrl) | async"
|
|
[ngClass]="getCssClasses('frame') | async"
|
|
></iframe>
|
|
</ng-container>
|
|
|
|
<!-- iFrame By Content -->
|
|
<ng-container *ngIf="notEmptyValue(content) | async">
|
|
<iframe
|
|
[id]="id"
|
|
#frameView
|
|
scrolling="no"
|
|
[srcdoc]="contentHTML"
|
|
allowtransparency="true"
|
|
*ngIf="notEmptyValue(content) | async"
|
|
(load)="onContentLoaded.emit($event)"
|
|
[ngClass]="getCssClasses('frame') | async"
|
|
></iframe>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.scss
|
|
|
|
:host {
|
|
--x-frame-height: auto;
|
|
}
|
|
|
|
.v-frame-frame,
|
|
.v-frame-container {
|
|
width: 100%;
|
|
height: var(--x-frame-height);
|
|
}
|
|
|
|
.v-frame-frame {
|
|
border: unset;
|
|
}
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
generateUuid,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XFrameAction,
|
|
XFrameActionModel,
|
|
XFrameContainerComponent,
|
|
} from './x-frame.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { SafeHtml, SafeResourceUrl } from '@angular/platform-browser';
|
|
|
|
@Component({
|
|
selector: 'x-frame',
|
|
templateUrl: './x-frame.component.html',
|
|
styleUrls: ['./x-frame.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFrameComponent extends XFrameContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly id = generateUuid('VFrame');
|
|
|
|
//
|
|
private ORIGIN: string = '';
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private FRAME_VIEW: ElementRef<HTMLIFrameElement> = null;
|
|
|
|
//
|
|
@ViewChild('frameView', { static: false })
|
|
set frameView(v: ElementRef<HTMLIFrameElement>) {
|
|
//
|
|
if (isNullOrUndefined(v)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.FRAME_VIEW = v;
|
|
this.applyFrameProps();
|
|
}
|
|
|
|
//
|
|
//#region Getters ...
|
|
get iFrame() {
|
|
return this.FRAME_VIEW!.nativeElement;
|
|
}
|
|
|
|
get contentWindow() {
|
|
return this.iFrame!.contentWindow;
|
|
}
|
|
|
|
get contentDocuent() {
|
|
return this.iFrame!.contentDocument;
|
|
}
|
|
|
|
get innerHTML() {
|
|
return this.iFrame!.innerHTML;
|
|
}
|
|
|
|
get innerText() {
|
|
return this.iFrame!.innerText;
|
|
}
|
|
|
|
get frameView() {
|
|
return this.FRAME_VIEW;
|
|
}
|
|
|
|
get origin() {
|
|
return this.ORIGIN;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
contentHTML: SafeHtml;
|
|
contentUrl: SafeResourceUrl;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Providers ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Url Changed ...
|
|
const isUrlChanged = changeKeys.includes(nameof<XFrameComponent>('url'));
|
|
if (isUrlChanged) {
|
|
this.prepareContentUrl();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content ...
|
|
const isContentChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('content')
|
|
);
|
|
if (isContentChanged) {
|
|
this.prepareContent();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region VFrame Props ...
|
|
//
|
|
//#region Allow ...
|
|
const isAllowChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('allow')
|
|
);
|
|
if (isAllowChanged) {
|
|
this.handleAllowChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region FrameLoading ...
|
|
const isFrameLoadingChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('frameLoading')
|
|
);
|
|
if (isFrameLoadingChanged) {
|
|
this.handleFrameLoadingChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region FrameReferrerPolicy ...
|
|
const isReferrerPolicyChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('referrerPolicy')
|
|
);
|
|
if (isReferrerPolicyChanged) {
|
|
this.handleReferrerPolicyChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region FrameSandbox ...
|
|
const isSandboxChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('sandbox')
|
|
);
|
|
if (isSandboxChanged) {
|
|
this.handleSandboxChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region AllowFullScreen ...
|
|
const isAllowFullScreenChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('allowFullscreen')
|
|
);
|
|
if (isAllowFullScreenChanged) {
|
|
this.handleAllowFullScreenChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region AllowPaymentRequest ...
|
|
const isAllowPaymentRequestChanged = changeKeys.includes(
|
|
nameof<XFrameComponent>('allowPaymentRequest')
|
|
);
|
|
if (isAllowPaymentRequestChanged) {
|
|
this.handleAllowPaymentRequestChanged();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region AddAllowTransparency ...
|
|
if (
|
|
isAllowChanged ||
|
|
isSandboxChanged ||
|
|
isFrameLoadingChanged ||
|
|
isReferrerPolicyChanged ||
|
|
isAllowFullScreenChanged ||
|
|
isAllowPaymentRequestChanged
|
|
) {
|
|
this.addTransparency();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerInstanceHandlers() {
|
|
super.registerInstanceHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
getCssClasses(infix: string) {
|
|
return this.getValue(false).pipe(
|
|
concatMap(() => this.getArrayValue(this.cssClass)),
|
|
map((classes) => {
|
|
//
|
|
const result: string[] = [];
|
|
|
|
//
|
|
result.push(`v-frame-${infix}`);
|
|
result.push(`v-frame-${this.id}-${infix}`);
|
|
|
|
//
|
|
if (this.hasChild(classes)) {
|
|
result.push(...classes);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
appendElement(element: HTMLElement) {
|
|
//
|
|
if (
|
|
isNullOrUndefined(element) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.appendChild(this.frameView.nativeElement, element);
|
|
}
|
|
|
|
loadHtml(html: string) {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(html) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentHTML(
|
|
'beforebegin',
|
|
html
|
|
);
|
|
}
|
|
|
|
loadText(text: string) {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(text) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentText(
|
|
'beforebegin',
|
|
text
|
|
);
|
|
}
|
|
|
|
loadElement(element: HTMLElement) {
|
|
//
|
|
if (
|
|
isNullOrUndefined(element) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentElement(
|
|
'beforebegin',
|
|
element
|
|
);
|
|
}
|
|
|
|
applyUrl(url: string) {
|
|
//
|
|
this.contentUrl = url;
|
|
this.detectChanges();
|
|
}
|
|
|
|
applyContent(content: string) {
|
|
//
|
|
this.content = content;
|
|
this.detectChanges();
|
|
}
|
|
|
|
fullScreen(options?: FullscreenOptions) {
|
|
this.frameView.nativeElement.requestFullscreen(options);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFrameActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
// tslint:disable-next-line: deprecation
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFrameAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.AppendElement:
|
|
this.appendElement(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.ApplyContent:
|
|
this.applyContent(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.ApplyUrl:
|
|
this.applyUrl(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.LoadElement:
|
|
this.loadElement(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.LoadText:
|
|
this.loadText(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.LoadHtml:
|
|
this.loadHtml(model.payload);
|
|
break;
|
|
|
|
//
|
|
case XFrameAction.FullScreen:
|
|
this.fullScreen(model.payload);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Preparation ...
|
|
private prepareContent(content?: string) {
|
|
this.getValue(this.content).subscribe((tContent) => {
|
|
//
|
|
this.ORIGIN = '';
|
|
this.contentUrl = '';
|
|
this.contentHTML = '';
|
|
|
|
//
|
|
content = !isNullOrEmptyString(content) ? content : tContent;
|
|
if (isNullOrEmptyString(content)) {
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.contentHTML =
|
|
this.managerService.securityService.toSafeHTML(content);
|
|
});
|
|
}
|
|
|
|
private prepareContentUrl(url?: string) {
|
|
this.getValue(this.url).subscribe((tUrl) => {
|
|
//
|
|
this.ORIGIN = '';
|
|
this.contentUrl = '';
|
|
this.contentHTML = '';
|
|
|
|
//
|
|
url = !isNullOrEmptyString(url) ? url : tUrl;
|
|
if (isNullOrEmptyString(tUrl)) {
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Origin ...
|
|
const mUrl = new URL(url);
|
|
this.ORIGIN = mUrl.origin;
|
|
|
|
//
|
|
this.contentUrl =
|
|
this.managerService.securityService.toSafeResourceURL(url);
|
|
});
|
|
}
|
|
|
|
private applyFrameAttribute(
|
|
attr: string,
|
|
value: string,
|
|
element: ElementRef<HTMLIFrameElement>
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(element) || isNullOrEmptyString(attr)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!isNullOrEmptyString(value)) {
|
|
//
|
|
// Set Attribute ...
|
|
this.setAttribute(attr, value, element);
|
|
} else {
|
|
//
|
|
// Remove Attribute ...
|
|
this.removeAttribute(attr, element);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Frame Props ...
|
|
private applyFrameProps() {
|
|
this.addTransparency();
|
|
this.handleAllowChanged();
|
|
this.handleSandboxChanged();
|
|
this.handleFrameLoadingChanged();
|
|
this.handleReferrerPolicyChanged();
|
|
this.handleAllowFullScreenChanged();
|
|
this.handleAllowPaymentRequestChanged();
|
|
}
|
|
|
|
private addTransparency() {
|
|
//
|
|
const value = true.toString();
|
|
if (
|
|
isNullOrEmptyString(value) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyFrameAttribute('allowtransparency', value, this.frameView);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private handleAllowChanged() {
|
|
this.getArrayValue(this.allow).subscribe((allows) => {
|
|
//
|
|
if (
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const value = this.hasChild(allows) ? allows.join('; ') : null;
|
|
|
|
//
|
|
this.applyFrameAttribute('allow', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private handleSandboxChanged() {
|
|
this.getValue(this.sandbox).subscribe((value) => {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(value) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyFrameAttribute('sandbox', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private handleFrameLoadingChanged() {
|
|
this.getValue(this.frameLoading).subscribe((value) => {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(value) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyFrameAttribute('loading', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private handleReferrerPolicyChanged() {
|
|
this.getArrayValue(this.referrerPolicy).subscribe((referrerPolicies) => {
|
|
//
|
|
if (
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const value = this.hasChild(referrerPolicies)
|
|
? referrerPolicies.join('|')
|
|
: null;
|
|
|
|
//
|
|
this.applyFrameAttribute('referrerpolicy', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private handleAllowFullScreenChanged() {
|
|
this.getValue(this.allowFullscreen).subscribe((allowFullscreen) => {
|
|
//
|
|
const value = allowFullscreen.toString();
|
|
if (
|
|
isNullOrEmptyString(value) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyFrameAttribute('allowfullscreen', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
private handleAllowPaymentRequestChanged() {
|
|
this.getValue(this.allowPaymentRequest).subscribe((allowPaymentRequest) => {
|
|
//
|
|
const value = allowPaymentRequest.toString();
|
|
if (
|
|
isNullOrEmptyString(value) ||
|
|
isNullOrUndefined(this.frameView) ||
|
|
isNullOrUndefined(this.frameView.nativeElement)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyFrameAttribute('allowpaymentrequest', value, this.frameView);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XFrameComponent } from './x-frame.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XFrameComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XCardModule],
|
|
exports: [CommonModule, XBaseComponentModule, XCardModule, XFrameComponent],
|
|
})
|
|
export class XFrameModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { ViewportRuler } from '@angular/cdk/scrolling';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XFrameAction {
|
|
Refresh = 'refresh',
|
|
AppendElement = 'appendElement',
|
|
LoadHtml = 'loadHtml',
|
|
LoadText = 'loadText',
|
|
LoadElement = 'loadElement',
|
|
ApplyUrl = 'applyUrl',
|
|
ApplyContent = 'applyContent',
|
|
FullScreen = 'fullScreen',
|
|
}
|
|
|
|
export type XFrameActionIdentifier = XFrameAction | string;
|
|
|
|
export interface XFrameActionModel
|
|
extends XBaseActionModel<XFrameActionIdentifier> {}
|
|
|
|
//
|
|
//#region XFrame Loading ...
|
|
export enum XFrameLoading {
|
|
Eager = 'eager',
|
|
Lazy = 'lazy',
|
|
}
|
|
|
|
export type XFrameLoadingIdentifier = XFrameLoading | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region XFrame ReferrerPolicy ...
|
|
export enum XFrameReferrerPolicy {
|
|
NoReferrer = 'no-referrer',
|
|
NoReferrerWhenDowngrade = 'no-referrer-when-downgrade',
|
|
Origin = 'origin',
|
|
OriginWhenCrossOrigin = 'origin-when-cross-origin',
|
|
SameOrigin = 'same-origin',
|
|
StrictOriginWhenCrossOrigin = 'strict-origin-when-cross-origin',
|
|
UnsafeUrl = 'unsafe-url',
|
|
}
|
|
|
|
export type XFrameReferrerPolicyIdentifier = XFrameReferrerPolicy | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Sandbox ...
|
|
export enum XFrameSandbox {
|
|
AllowForms = 'allow-forms',
|
|
AllowModals = 'allow-modals',
|
|
AllowOrientationLock = 'allow-orientation-lock',
|
|
AllowPointerLock = 'allow-pointer-lock',
|
|
AllowPopups = 'allow-popups',
|
|
AllowPopupsToEscapeSandbox = 'allow-popups-to-escape-sandbox',
|
|
AllowPresentation = 'allow-presentation',
|
|
AllowSameOrigin = 'allow-same-origin',
|
|
AllowScripts = 'allow-scripts',
|
|
AllowTopNavigation = 'allow-top-navigation',
|
|
AllowTopNavigationByUserActivation = 'allow-top-navigation-by-user-activation',
|
|
}
|
|
|
|
export type XFrameSandboxIdentifier = XFrameSandbox | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Containers ...
|
|
export interface IXFrameContainer extends IXComponentCardContainer {
|
|
url: XStandardType<string>;
|
|
content: XStandardType<string>;
|
|
onContentLoaded: EventEmitter<any>;
|
|
allowFullscreen: XStandardType<boolean>;
|
|
actionProvider: Subject<XFrameActionModel>;
|
|
allowPaymentRequest: XStandardType<boolean>;
|
|
allow: XStandardType<XOneOrManyType<string>>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
sandbox: XStandardType<XFrameSandboxIdentifier>;
|
|
frameLoading: XStandardType<XFrameLoadingIdentifier>;
|
|
referrerPolicy: XStandardType<XOneOrManyType<XFrameReferrerPolicyIdentifier>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XFrameContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXFrameContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly url: XStandardType<string>;
|
|
readonly content: XStandardType<string>;
|
|
readonly referrerPolicy: XStandardType<
|
|
XOneOrManyType<XFrameReferrerPolicyIdentifier>
|
|
> = null;
|
|
readonly actionProvider: Subject<XFrameActionModel> =
|
|
new Subject<XFrameActionModel>();
|
|
readonly allow: XStandardType<XOneOrManyType<string>>;
|
|
readonly allowFullscreen: XStandardType<boolean> = false;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly allowPaymentRequest: XStandardType<boolean> = false;
|
|
readonly sandbox: XStandardType<XFrameSandboxIdentifier> = null;
|
|
readonly frameLoading: XStandardType<XFrameLoadingIdentifier> = null;
|
|
readonly onContentLoaded: EventEmitter<any> = new EventEmitter<any>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFrameContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXFrameContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
allowFullscreen: XStandardType<boolean> =
|
|
this.propertyProvider.allowFullscreen;
|
|
|
|
@Input()
|
|
actionProvider: Subject<XFrameActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
allowPaymentRequest: XStandardType<boolean> =
|
|
this.propertyProvider.allowPaymentRequest;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
sandbox: XStandardType<XFrameSandboxIdentifier> =
|
|
this.propertyProvider.sandbox;
|
|
|
|
@Input()
|
|
frameLoading: XStandardType<XFrameLoadingIdentifier> =
|
|
this.propertyProvider.frameLoading;
|
|
|
|
@Input()
|
|
url: XStandardType<string> = this.propertyProvider.url;
|
|
|
|
@Input()
|
|
content: XStandardType<string> = this.propertyProvider.content;
|
|
|
|
@Input()
|
|
referrerPolicy: XStandardType<
|
|
XOneOrManyType<XFrameReferrerPolicyIdentifier>
|
|
> = this.propertyProvider.referrerPolicy;
|
|
|
|
@Output()
|
|
onContentLoaded: EventEmitter<any> = this.propertyProvider.onContentLoaded;
|
|
|
|
@Input()
|
|
allow: XStandardType<XOneOrManyType<string>> = this.propertyProvider.allow;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFrameContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFrameContainer
|
|
): Observable<IXFrameContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
url: this.getValue(container ? container.url : this.url),
|
|
content: this.getValue(
|
|
container ? container.content : this.content
|
|
),
|
|
allowFullscreen: this.getValue(
|
|
container ? container.allowFullscreen : this.allowFullscreen
|
|
),
|
|
allowPaymentRequest: this.getValue(
|
|
container
|
|
? container.allowPaymentRequest
|
|
: this.allowPaymentRequest
|
|
),
|
|
allow: this.getArrayValue(container ? container.allow : this.allow),
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
sandbox: this.getValue(
|
|
container ? container.sandbox : this.sandbox
|
|
),
|
|
frameLoading: this.getValue(
|
|
container ? container.frameLoading : this.frameLoading
|
|
),
|
|
referrerPolicy: this.getValue(
|
|
container ? container.referrerPolicy : this.referrerPolicy
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
onContentLoaded: container
|
|
? container.onContentLoaded
|
|
: this.onContentLoaded,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else holderRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="holderRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Grid Template -->
|
|
<ng-template #holderRef>
|
|
<div class="x-grid x-wrapper" [class.mobile]="isMobileUi$ | async">
|
|
<!-- Handle Childs -->
|
|
<ng-container *ngIf="items && items.length > 0">
|
|
<ng-container *ngIf="preparedType">
|
|
<!-- Item Holder -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
isTypeLinear()
|
|
? linearRef
|
|
: isTypeGrid()
|
|
? gridRef
|
|
: isTypeFlex()
|
|
? flexRef
|
|
: isTypeStaggedGrid()
|
|
? staggedGrid
|
|
: nothingRef
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Empty Handler -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(showEmpty) | async) &&
|
|
(!items || (items && items.length === 0))
|
|
"
|
|
>
|
|
<x-empty
|
|
(refresh)="emptyRefresh.emit($event)"
|
|
[color]="getValue(emptyColor) | async"
|
|
[message]="getResourceValue(emptyMessage) | async"
|
|
[refreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
[messageColor]="getValue(emptyMessageColor) | async"
|
|
[hasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[foregroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[foregroundColor]="getValue(emptyForegroundColor) | async"
|
|
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
|
|
></x-empty>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Linear Ref -->
|
|
<ng-template #linearRef>
|
|
<!-- -->
|
|
<ion-list [ngClass]="getValue(cssClass) | async">
|
|
<ng-container *ngFor="let item of items; index as i">
|
|
<ion-item lines="none" class="transparent">
|
|
<ng-container
|
|
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
|
|
>
|
|
</ng-container>
|
|
</ion-item>
|
|
</ng-container>
|
|
</ion-list>
|
|
</ng-template>
|
|
|
|
<!-- Grid Ref -->
|
|
<ng-template #gridRef>
|
|
<!-- -->
|
|
<ion-grid [ngClass]="getValue(cssClass) | async">
|
|
<ng-container *ngFor="let item of items; index as i">
|
|
<ng-container *ngIf="isNewRow(i, preparedCols)">
|
|
<ng-container
|
|
*ngTemplateOutlet="rowRef; context: { $implicit: i }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ion-grid>
|
|
</ng-template>
|
|
|
|
<!-- Flex Ref -->
|
|
<ng-template #flexRef>
|
|
<!-- -->
|
|
<div
|
|
class="grid-box"
|
|
[fxLayoutGap]="gap"
|
|
[fxLayout]="layout"
|
|
[fxLayoutAlign]="align"
|
|
*ngIf="items && items.length > 0"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<ng-container *ngFor="let item of items; index as i">
|
|
<div [fxFlexAlign]="'stretch'">
|
|
<ng-container
|
|
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
|
|
>
|
|
</ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- StaggedGrid Ref -->
|
|
<ng-template #staggedGrid>
|
|
<gridster
|
|
#gridster
|
|
*ngIf="options"
|
|
[options]="options"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[class.inCard]="getValue(wrapWithCard) | async"
|
|
>
|
|
<gridster-item
|
|
[item]="toStaggedGrid(idx)"
|
|
*ngFor="let item of items; index as idx"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
|
|
>
|
|
</ng-container>
|
|
</gridster-item>
|
|
</gridster>
|
|
</ng-template>
|
|
|
|
<!-- Nothing Ref -->
|
|
<ng-template #nothingRef></ng-template>
|
|
|
|
<!-- Grid Row Template -->
|
|
<ng-template #rowRef let-index>
|
|
<ion-row>
|
|
<ion-col *ngFor="let item of colItems; index as i">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
itemHolderRef;
|
|
context: { $implicit: items[i + index] }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ion-col>
|
|
</ion-row>
|
|
</ng-template>
|
|
|
|
<!-- Item Holder Template -->
|
|
<ng-template #itemHolderRef let-item>
|
|
<button
|
|
matRipple
|
|
*ngIf="item"
|
|
class="transparent"
|
|
class="x-grid-item-wrapper"
|
|
(click)="handleItemSelected(item)"
|
|
[hidden]="getItemHide(item) | async"
|
|
[disabled]="getItemDisabled(item) | async"
|
|
[matRippleDisabled]="
|
|
(getItemDisabled(item) | async) || !(getValue(selectableItems) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
itemTemplate ? itemTemplate : defaultItemRef;
|
|
context: { $implicit: item }
|
|
"
|
|
></ng-container>
|
|
</button>
|
|
</ng-template>
|
|
|
|
<!-- Default Item Ref -->
|
|
<ng-template #defaultItemRef let-item>
|
|
<h5>{{ item | json }}</h5>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.scss
|
|
|
|
ion-item-option > ion-item {
|
|
--background: transparent !important;
|
|
}
|
|
|
|
ion-button.transparent-button {
|
|
--box-shadow: transparent !important;
|
|
--background: transparent !important;
|
|
--background-hover: transparent !important;
|
|
--background-focused: transparent !important;
|
|
--background-activated: transparent !important;
|
|
}
|
|
|
|
ion-list,
|
|
ion-item.item,
|
|
ion-item-divider {
|
|
--background: transparent !important;
|
|
}
|
|
|
|
ion-item-divider {
|
|
--color: var(--ion-color-dark-shade);
|
|
}
|
|
|
|
ion-item.item.mobile {
|
|
--ion-safe-area-end: 0px;
|
|
|
|
--padding-start: 0px;
|
|
--inner-padding-start: 0px;
|
|
|
|
--padding-end: 0px;
|
|
--inner-padding-end: 0px;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0;
|
|
}
|
|
|
|
.x-menu {
|
|
z-index: 10;
|
|
}
|
|
|
|
.x-check {
|
|
z-index: 1;
|
|
}
|
|
|
|
.grid-box {
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.grid-box.mobile {
|
|
margin-top: 0px;
|
|
}
|
|
|
|
gridster {
|
|
width: 100%;
|
|
display: flex;
|
|
direction: ltr;
|
|
position: inherit;
|
|
flex-direction: column;
|
|
background-color: transparent;
|
|
height: calc(var(--grid-height, inherit));
|
|
|
|
&.inCard {
|
|
position: relative;
|
|
}
|
|
}
|
|
|
|
gridster-item {
|
|
padding: 0;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.x-grid-item-wrapper {
|
|
position: relative;
|
|
background: inherit;
|
|
}
|
|
|
|
a[href=''],
|
|
[disabled],
|
|
.disable {
|
|
color: inherit;
|
|
cursor: default;
|
|
pointer-events: none;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.transparent {
|
|
--background: transparent !important;
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
x-card {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.ts
|
|
|
|
import {
|
|
XGridItem,
|
|
XGridAction,
|
|
XGridActionModel,
|
|
XGridPresentType,
|
|
defaultGridOptions,
|
|
XStaggedGridOptions,
|
|
XGridContainerComponent,
|
|
} from './x-grid.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { nameof, cloneJson, toObservable } from 'x-framework-core';
|
|
import { GridsterItem, GridsterComponent } from 'angular-gridster2';
|
|
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-grid',
|
|
templateUrl: './x-grid.component.html',
|
|
styleUrls: ['./x-grid.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XGridComponent extends XGridContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private COLS: number;
|
|
private TYPE: XGridPresentType;
|
|
private GRIDSTER: GridsterComponent;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
colItems: number[] = [];
|
|
|
|
get preparedCols() {
|
|
return this.COLS;
|
|
}
|
|
|
|
get preparedType() {
|
|
return this.TYPE;
|
|
}
|
|
|
|
//
|
|
@ViewChild('gridster', { static: false })
|
|
set gridster(v: GridsterComponent) {
|
|
//
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.GRIDSTER = v;
|
|
this.prepareData();
|
|
}
|
|
|
|
get gridster() {
|
|
return this.GRIDSTER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
afterViewInit() {
|
|
super.afterContentInit();
|
|
|
|
//
|
|
this.prepareData();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XGridComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
const isColsChanged = changeKeys.includes(nameof<XGridComponent>('cols'));
|
|
const isTypeChanged = changeKeys.includes(nameof<XGridComponent>('type'));
|
|
const isOptionsChanged = changeKeys.includes(
|
|
nameof<XGridComponent>('options')
|
|
);
|
|
|
|
//
|
|
if (isColsChanged) {
|
|
this.COLS = await this.getValueAsync(this.cols);
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
if (isTypeChanged) {
|
|
this.TYPE = await this.getValueAsync(this.type);
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
if (isColsChanged || isTypeChanged || isOptionsChanged) {
|
|
this.prepareData();
|
|
}
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Provider Actions ...
|
|
//
|
|
//#region Type Detectors ...
|
|
isTypeLinear() {
|
|
return this.preparedType === XGridPresentType.AsLinear;
|
|
}
|
|
|
|
isTypeGrid() {
|
|
return this.preparedType === XGridPresentType.AsGrid;
|
|
}
|
|
|
|
isTypeFlex() {
|
|
return this.preparedType === XGridPresentType.AsFlex;
|
|
}
|
|
|
|
isTypeStaggedGrid() {
|
|
return this.preparedType === XGridPresentType.AsStaggedGrid;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
isNewRow(i: number, cols: number) {
|
|
return (i + 1) % cols === 1;
|
|
}
|
|
|
|
//
|
|
toStaggedGrid(index: number) {
|
|
return {
|
|
id: index,
|
|
data: this.items[index],
|
|
cols: 1,
|
|
rows: 1,
|
|
x: 0,
|
|
y: 0,
|
|
} as GridsterItem;
|
|
}
|
|
|
|
//
|
|
getItemHref(item?: XGridItem<any>) {
|
|
//
|
|
if (!item || !item.href) {
|
|
return toObservable('');
|
|
}
|
|
|
|
//
|
|
return this.getValue(item.href);
|
|
}
|
|
|
|
//
|
|
getItemHide(item?: XGridItem<any>) {
|
|
//
|
|
if (!item || !item.hide) {
|
|
return toObservable(false);
|
|
}
|
|
|
|
//
|
|
return this.getValue(item.hide);
|
|
}
|
|
|
|
//
|
|
getItemDisabled(item?: XGridItem<any>) {
|
|
//
|
|
if (!item || !item.disabled) {
|
|
return toObservable(false);
|
|
}
|
|
|
|
//
|
|
return this.getValue(item.disabled);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Type Detectors ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async handleItemSelected(item: XGridItem<any>) {
|
|
//
|
|
if (!this.selectableItems) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hided = await this.toPromise(this.getItemHide(item));
|
|
const disabled = await this.toPromise(this.getItemDisabled(item));
|
|
|
|
//
|
|
if (!hided && !disabled) {
|
|
this.itemSelected.emit(item);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XGridActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XGridAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
private prepareData() {
|
|
//
|
|
if (!this.preparedCols) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const mCols = this.preparedCols < 0 ? 0 : this.preparedCols;
|
|
this.colItems = Array.from(Array(mCols).keys());
|
|
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
this.options = {
|
|
...cloneJson(defaultGridOptions),
|
|
minCols: mCols,
|
|
maxCols: mCols,
|
|
} as XStaggedGridOptions;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}, 300);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { GridsterModule } from 'angular-gridster2';
|
|
import { XGridComponent } from './x-grid.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XGridComponent],
|
|
imports: [
|
|
CommonModule,
|
|
XCardModule,
|
|
XEmptyModule,
|
|
GridsterModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [XCardModule, XGridComponent, XEmptyModule, XBaseComponentModule],
|
|
})
|
|
export class XGridModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
IXCardEmptyContainer,
|
|
XCardEmptyContainer,
|
|
XCardEmptyContainerComponent,
|
|
} from '../classes/i-x-card-empty.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { GridsterConfig } from 'angular-gridster2';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XStandardType, XOneOrManyType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export interface XGridItem<T> {
|
|
data: T;
|
|
hide?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
href?: XStandardType<XOneOrManyType<string>>;
|
|
}
|
|
|
|
export interface XStaggedGridOptions extends Partial<GridsterConfig> {}
|
|
export const defaultGridOptions: XStaggedGridOptions = {
|
|
gridType: 'scrollVertical',
|
|
compactType: 'compactLeft&Up',
|
|
disableWarnings: true,
|
|
draggable: {
|
|
enabled: true,
|
|
},
|
|
pushItems: true,
|
|
resizable: {
|
|
enabled: true,
|
|
},
|
|
minCols: 2,
|
|
maxCols: 2,
|
|
minRows: 1,
|
|
};
|
|
|
|
export enum XGridPresentType {
|
|
AsLinear,
|
|
AsGrid,
|
|
AsFlex,
|
|
AsStaggedGrid,
|
|
}
|
|
|
|
export enum XGridAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XGridActionIdentifier = XGridAction | string;
|
|
|
|
export interface XGridActionModel
|
|
extends XBaseActionModel<XGridActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card/Empty Container ...
|
|
export interface IXGridContainer extends IXCardEmptyContainer {
|
|
//
|
|
actionProvider: Subject<XGridActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
options: XStandardType<XStaggedGridOptions>;
|
|
cols: XStandardType<number>;
|
|
type: XStandardType<XGridPresentType>;
|
|
gap: string;
|
|
layout: string;
|
|
align: string;
|
|
selectableItems: XStandardType<boolean>;
|
|
items: XGridItem<any>[];
|
|
itemTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
itemSelected: EventEmitter<XGridItem<any>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XGridContainer
|
|
extends XCardEmptyContainer
|
|
implements Readonly<IXGridContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XGridActionModel> =
|
|
new Subject<XGridActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly options: XStandardType<XStaggedGridOptions>;
|
|
readonly cols: XStandardType<number>;
|
|
readonly type: XStandardType<XGridPresentType>;
|
|
readonly gap: string = '1px';
|
|
readonly layout: string = 'row wrap';
|
|
readonly align: string = 'center start';
|
|
readonly selectableItems: XStandardType<boolean> = false;
|
|
readonly items: XGridItem<any>[];
|
|
readonly itemTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly itemSelected: EventEmitter<XGridItem<any>>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XGridContainerComponent
|
|
extends XCardEmptyContainerComponent
|
|
implements IXGridContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XGridActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
options: XStandardType<XStaggedGridOptions> = this.propertyProvider.options;
|
|
|
|
@Input()
|
|
cols: XStandardType<number> = this.propertyProvider.cols;
|
|
|
|
@Input()
|
|
type: XStandardType<XGridPresentType> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
gap: string = this.propertyProvider.gap;
|
|
|
|
@Input()
|
|
layout: string = this.propertyProvider.layout;
|
|
|
|
@Input()
|
|
align: string = this.propertyProvider.align;
|
|
|
|
@Input()
|
|
selectableItems: XStandardType<boolean> =
|
|
this.propertyProvider.selectableItems;
|
|
|
|
@Input()
|
|
items: XGridItem<any>[] = this.propertyProvider.items;
|
|
|
|
@Input()
|
|
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
|
|
|
|
//
|
|
@Output()
|
|
itemSelected: EventEmitter<XGridItem<any>> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XGridContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXGridContainer
|
|
): Observable<IXGridContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
options: this.getValue(
|
|
container ? container.options : this.options
|
|
),
|
|
cols: this.getValue(container ? container.cols : this.cols),
|
|
type: this.getValue(container ? container.type : this.type),
|
|
gap: this.getValue(container ? container.gap : this.gap),
|
|
layout: this.getValue(container ? container.layout : this.layout),
|
|
align: this.getValue(container ? container.align : this.align),
|
|
selectableItems: this.getValue(
|
|
container ? container.selectableItems : this.selectableItems
|
|
),
|
|
items: this.getValue(container ? container.items : this.items),
|
|
itemTemplate: this.getValue(
|
|
container ? container.itemTemplate : this.itemTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
itemSelected: this.itemSelected,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.html
|
|
|
|
<!-- Wrapper -->
|
|
<div
|
|
*ngIf="getValue(name) | async"
|
|
[slot]="getValue(slot) | async"
|
|
(click)="handleClicked($event)"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
class="x-icon x-wrapper ion-no-margin ion-no-padding"
|
|
[class.ion-activatable]="
|
|
(getValue(selectable) | async) || (getValue(clickable) | async)
|
|
"
|
|
[class.rtl]="(getValue(applyDirection) | async) && managerService.isRtl"
|
|
>
|
|
<!-- Ripple Effect -->
|
|
<ion-ripple-effect
|
|
*ngIf="
|
|
!(getValue(uiDisabled) | async) &&
|
|
((getValue(selectable) | async) || (getValue(clickable) | async))
|
|
"
|
|
></ion-ripple-effect>
|
|
|
|
<!-- Regular Icons -->
|
|
<ion-icon
|
|
class="ion-no-margin ion-no-padding"
|
|
[name]="!(isCustomIcon() | async) ? (icon | async) : ''"
|
|
[src]="(isCustomIcon() | async) ? (customIconUrl() | async) : ''"
|
|
>
|
|
</ion-icon>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.scss
|
|
|
|
:host {
|
|
//
|
|
--size: 24px;
|
|
|
|
//
|
|
display: inline-block;
|
|
position: relative;
|
|
|
|
//
|
|
font-size: var(--size);
|
|
line-height: var(--size);
|
|
width: var(--size);
|
|
height: var(--size);
|
|
|
|
//
|
|
min-width: var(--size);
|
|
min-height: var(--size);
|
|
|
|
//
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
//
|
|
$delay: 0;
|
|
$duration: 1;
|
|
$transform: scaleX(-1);
|
|
|
|
.x-icon {
|
|
//
|
|
display: inline-block;
|
|
position: relative;
|
|
|
|
//
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
|
|
//
|
|
box-sizing: border-box !important;
|
|
|
|
//
|
|
min-width: var(--size);
|
|
min-height: var(--size);
|
|
|
|
&.rtl {
|
|
//
|
|
transform: $transform;
|
|
-ms-transform: $transform;
|
|
-webkit-transform: $transform;
|
|
|
|
//
|
|
transition: transform;
|
|
-webkit-transition: transform;
|
|
|
|
//
|
|
transition-delay: $delay;
|
|
-webkit-transition-delay: $delay;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
}
|
|
|
|
ion-icon,
|
|
ion-ripple-effect {
|
|
font-size: var(--size);
|
|
|
|
min-width: var(--size);
|
|
min-height: var(--size);
|
|
}
|
|
|
|
.ion-activatable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.ts
|
|
|
|
import {
|
|
XIconAction,
|
|
XCustomIcons,
|
|
XProvidedIcons,
|
|
XIconActionModel,
|
|
XIconContainerComponent,
|
|
} from './x-icon.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-icon',
|
|
templateUrl: './x-icon.component.html',
|
|
styleUrls: ['./x-icon.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XIconComponent extends XIconContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XIconComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Icon Provider Properties ...
|
|
get providedIcons() {
|
|
return XProvidedIcons;
|
|
}
|
|
|
|
get icon() {
|
|
return this.getValue(this.name).pipe(
|
|
map((name) => {
|
|
return (this.providedIcons as any)[name.toString()] as string;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
isCustomIcon() {
|
|
return this.getValue(this.name).pipe(
|
|
map((name) => {
|
|
return name && XCustomIcons.includes(name.toString());
|
|
})
|
|
);
|
|
}
|
|
|
|
customIconUrl() {
|
|
return this.getValue(this.name).pipe(
|
|
map((name) => {
|
|
//
|
|
const svgName = (this.providedIcons as any)[name.toString()]
|
|
return this.name
|
|
? `./assets/icon/svg/${svgName}.svg`
|
|
: null;
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Handlers ...
|
|
async handleClicked(event?: Event) {
|
|
//
|
|
const clickable = await this.toPromise(this.getValue(this.clickable));
|
|
const disabled = this.uiDisabled;
|
|
if (!clickable || disabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (event && event.stopPropagation) {
|
|
event.stopPropagation();
|
|
}
|
|
|
|
//
|
|
this.clicked.emit(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XIconActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XIconAction.Click:
|
|
this.clicked.emit();
|
|
break;
|
|
|
|
//
|
|
case XIconAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconComponent } from './x-icon.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XIconComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XIconComponent],
|
|
})
|
|
export class XIconModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XIconAction {
|
|
Click = 'click',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XIconActionIdentifier = XIconAction | string;
|
|
|
|
export interface XIconActionModel
|
|
extends XBaseActionModel<XIconActionIdentifier> {}
|
|
|
|
export enum XIconNames {
|
|
tv = 'tv',
|
|
ol = 'ol',
|
|
ul = 'ul',
|
|
job = 'job',
|
|
add = 'add',
|
|
sad = 'sad',
|
|
web = 'web',
|
|
map = 'map',
|
|
dns = 'dns',
|
|
dvr = 'dvr',
|
|
fax = 'fax',
|
|
mic = 'mic',
|
|
mop = 'mop',
|
|
info = 'info',
|
|
lock = 'lock',
|
|
mail = 'mail',
|
|
shop = 'shop',
|
|
edit = 'edit',
|
|
done = 'done',
|
|
list = 'list',
|
|
user = 'user',
|
|
star = 'star',
|
|
sync = 'sync',
|
|
undo = 'undo',
|
|
redo = 'redo',
|
|
home = 'home',
|
|
flag = 'flag',
|
|
save = 'save',
|
|
last = 'last',
|
|
next = 'next',
|
|
copy = 'copy',
|
|
link = 'link',
|
|
bold = 'bold',
|
|
code = 'code',
|
|
crop = 'crop',
|
|
call = 'call',
|
|
tabs = 'tabs',
|
|
cast = 'cast',
|
|
wifi = 'wifi',
|
|
stop = 'stop',
|
|
play = 'play',
|
|
phone = 'phone',
|
|
reply = 'reply',
|
|
label = 'label',
|
|
liked = 'liked',
|
|
terms = 'terms',
|
|
event = 'event',
|
|
clear = 'clear',
|
|
input = 'input',
|
|
close = 'close',
|
|
users = 'users',
|
|
files = 'files',
|
|
login = 'login',
|
|
posts = 'posts',
|
|
enter = 'enter',
|
|
power = 'power',
|
|
cloud = 'cloud',
|
|
first = 'first',
|
|
touch = 'touch',
|
|
error = 'error',
|
|
print = 'print',
|
|
share = 'share',
|
|
image = 'image',
|
|
audio = 'audio',
|
|
video = 'video',
|
|
guide = 'guide',
|
|
quote = 'quote',
|
|
toast = 'toast',
|
|
cards = 'cards',
|
|
mouse = 'mouse',
|
|
album = 'album',
|
|
badge = 'badge',
|
|
radio = 'radio',
|
|
watch = 'watch',
|
|
movie = 'movie',
|
|
pause = 'pause',
|
|
unlock = 'unlock',
|
|
cancel = 'cancel',
|
|
expand = 'expand',
|
|
mobile = 'mobile',
|
|
search = 'search',
|
|
survey = 'survey',
|
|
remove = 'remove',
|
|
invite = 'invite',
|
|
logout = 'logout',
|
|
school = 'school',
|
|
server = 'server',
|
|
upload = 'upload',
|
|
locate = 'locate',
|
|
italic = 'italic',
|
|
repeat = 'repeat',
|
|
report = 'report',
|
|
policy = 'policy',
|
|
router = 'router',
|
|
shield = 'shield',
|
|
stylus = 'stylus',
|
|
tv_off = 'tv_off',
|
|
swords = 'swords',
|
|
nearby = 'nearby',
|
|
flight = 'flight',
|
|
memory = 'memory',
|
|
replay = 'replay',
|
|
visible = 'visible',
|
|
checked = 'checked',
|
|
unliked = 'unliked',
|
|
profile = 'profile',
|
|
account = 'account',
|
|
avatars = 'avatars',
|
|
archive = 'archive',
|
|
refresh = 'refresh',
|
|
unknown = 'unknown',
|
|
preview = 'preview',
|
|
heading = 'heading',
|
|
toolbar = 'toolbar',
|
|
dialogs = 'dialogs',
|
|
dialpad = 'dialpad',
|
|
vpn_key = 'vpn_key',
|
|
widgets = 'widgets',
|
|
passkey = 'passkey',
|
|
mic_off = 'mic_off',
|
|
monitor = 'monitor',
|
|
gpp_bad = 'gpp_bad',
|
|
charger = 'charger',
|
|
devices = 'devices',
|
|
capture = 'capture',
|
|
live_tv = 'live_tv',
|
|
sd_card = 'sd_card',
|
|
verified = 'verified',
|
|
collapse = 'collapse',
|
|
arrow_up = 'arrow_up',
|
|
contacts = 'contacts',
|
|
contrast = 'contrast',
|
|
calendar = 'calendar',
|
|
register = 'register',
|
|
explorer = 'explorer',
|
|
settings = 'settings',
|
|
business = 'business',
|
|
bookmark = 'bookmark',
|
|
chat_box = 'chat_box',
|
|
location = 'location',
|
|
previous = 'previous',
|
|
download = 'download',
|
|
language = 'language',
|
|
document = 'document',
|
|
logo_npm = 'logo_npm',
|
|
logo_pwa = 'logo_pwa',
|
|
logo_rss = 'logo_rss',
|
|
logo_usd = 'logo_usd',
|
|
logo_vue = 'logo_vue',
|
|
dropdown = 'dropdown',
|
|
add_call = 'add_call',
|
|
sim_card = 'sim_card',
|
|
security = 'security',
|
|
password = 'password',
|
|
podcasts = 'podcasts',
|
|
wifi_off = 'wifi_off',
|
|
no_sound = 'no_sound',
|
|
keyboard = 'keyboard',
|
|
exercise = 'exercise',
|
|
computer = 'computer',
|
|
autoplay = 'autoplay',
|
|
autostop = 'autostop',
|
|
videocam = 'videocam',
|
|
label_off = 'label_off',
|
|
swap_vert = 'swap_vert',
|
|
dashboard = 'dashboard',
|
|
checkmark = 'checkmark',
|
|
star_half = 'star_half',
|
|
thumbs_up = 'thumbs_up',
|
|
bookmarks = 'bookmarks',
|
|
bluetooth = 'bluetooth',
|
|
analytics = 'analytics',
|
|
clipboard = 'clipboard',
|
|
logo_css3 = 'logo_css3',
|
|
logo_edge = 'logo_edge',
|
|
logo_sass = 'logo_sass',
|
|
touch_app = 'touch_app',
|
|
voicemail = 'voicemail',
|
|
call_made = 'call_made',
|
|
subtitles = 'subtitles',
|
|
music_off = 'music_off',
|
|
encrypted = 'encrypted',
|
|
apartment = 'apartment',
|
|
dark_mode = 'dark_mode',
|
|
deskphone = 'deskphone',
|
|
autopause = 'autopause',
|
|
video_cam = 'video_cam',
|
|
swap_horiz = 'swap_horiz',
|
|
first_name = 'first_name',
|
|
un_checked = 'un_checked',
|
|
arrow_down = 'arrow_down',
|
|
arrow_back = 'arrow_back',
|
|
select_all = 'select_all',
|
|
management = 'management',
|
|
logo_apple = 'logo_apple',
|
|
logo_ionic = 'logo_ionic',
|
|
logo_html5 = 'logo_html5',
|
|
blockchain = 'blockchain',
|
|
logo_react = 'logo_react',
|
|
logo_skype = 'logo_skype',
|
|
logo_slack = 'logo_slack',
|
|
logo_yahoo = 'logo_yahoo',
|
|
data_table = 'data_table',
|
|
device_hub = 'device_hub',
|
|
call_split = 'call_split',
|
|
router_off = 'router_off',
|
|
light_mode = 'light_mode',
|
|
mouse_lock = 'mouse_lock',
|
|
nightlight = 'nightlight',
|
|
volume_off = 'volume_off',
|
|
volume_low = 'volume_low',
|
|
play_arrow = 'play_arrow',
|
|
video_call = 'video_call',
|
|
video_chat = 'video_chat',
|
|
video_file = 'video_file',
|
|
voice_chat = 'voice_chat',
|
|
fit_screen = 'fit_screen',
|
|
fullscreen = 'fullscreen',
|
|
rotate_left = 'rotate_left',
|
|
visible_off = 'visible_off',
|
|
friendships = 'friendships',
|
|
thumbs_down = 'thumbs_down',
|
|
chat_bubble = 'chat_bubble',
|
|
stats_chart = 'stats_chart',
|
|
logo_amazon = 'logo_amazon',
|
|
logo_chrome = 'logo_chrome',
|
|
logo_docker = 'logo_docker',
|
|
logo_github = 'logo_github',
|
|
logo_gitlab = 'logo_gitlab',
|
|
logo_google = 'logo_google',
|
|
blockchain1 = 'blockchain1',
|
|
logo_nodejs = 'logo_nodejs',
|
|
logo_paypal = 'logo_paypal',
|
|
voicemail_2 = 'voicemail_2',
|
|
devices_off = 'devices_off',
|
|
exit_to_app = 'exit_to_app',
|
|
ring_volume = 'ring_volume',
|
|
call_missed = 'call_missed',
|
|
privacy_tip = 'privacy_tip',
|
|
dual_screen = 'dual_screen',
|
|
engineering = 'engineering',
|
|
volume_high = 'volume_high',
|
|
volume_mute = 'volume_mute',
|
|
play_circle = 'play_circle',
|
|
fast_rewind = 'fast_rewind',
|
|
rotate_right = 'rotate_right',
|
|
chat_bubbles = 'chat_bubbles',
|
|
deselect_all = 'deselect_all',
|
|
arrow_dropup = 'arrow_dropup',
|
|
logo_android = 'logo_android',
|
|
logo_angular = 'logo_angular',
|
|
logo_bitcoin = 'logo_bitcoin',
|
|
logo_dropbox = 'logo_dropbox',
|
|
logo_firefox = 'logo_firefox',
|
|
logo_windows = 'logo_windows',
|
|
logo_twitter = 'logo_twitter',
|
|
logo_youtube = 'logo_youtube',
|
|
wifi_calling = 'wifi_calling',
|
|
phone_locked = 'phone_locked',
|
|
phone_missed = 'phone_missed',
|
|
call_quality = 'call_quality',
|
|
screen_share = 'screen_share',
|
|
room_service = 'room_service',
|
|
other_houses = 'other_houses',
|
|
dock_to_left = 'dock_to_left',
|
|
keyboard_off = 'keyboard_off',
|
|
cameraswitch = 'cameraswitch',
|
|
architecture = 'architecture',
|
|
fast_forward = 'fast_forward',
|
|
arrow_forward = 'arrow_forward',
|
|
accessibility = 'accessibility',
|
|
cloud_offline = 'cloud_offline',
|
|
menu_vertical = 'menu_vertical',
|
|
logo_electron = 'logo_electron',
|
|
logo_facebook = 'logo_facebook',
|
|
logo_firebase = 'logo_firebase',
|
|
logo_linkedin = 'logo_linkedin',
|
|
logo_markdown = 'logo_markdown',
|
|
logo_whatsapp = 'logo_whatsapp',
|
|
color_palette = 'color_palette',
|
|
phone_enabled = 'phone_enabled',
|
|
phone_in_talk = 'phone_in_talk',
|
|
call_received = 'call_received',
|
|
print_connect = 'print_connect',
|
|
screen_record = 'screen_record',
|
|
shield_person = 'shield_person',
|
|
verified_user = 'verified_user',
|
|
network_check = 'network_check',
|
|
encrypted_off = 'encrypted_off',
|
|
dock_to_right = 'dock_to_right',
|
|
electric_bolt = 'electric_bolt',
|
|
reset_password = 'reset_password',
|
|
customers_club = 'customers_club',
|
|
checkmark_done = 'checkmark_done',
|
|
arrow_dropdown = 'arrow_dropdown',
|
|
logo_instagram = 'logo_instagram',
|
|
logo_wordpress = 'logo_wordpress',
|
|
devices_fold_2 = 'devices_fold_2',
|
|
perm_phone_msg = 'perm_phone_msg',
|
|
phone_callback = 'phone_callback',
|
|
phone_disabled = 'phone_disabled',
|
|
settings_phone = 'settings_phone',
|
|
print_disabled = 'print_disabled',
|
|
wifi_tethering = 'wifi_tethering',
|
|
speech_to_text = 'speech_to_text',
|
|
mouse_lock_off = 'mouse_lock_off',
|
|
directions_car = 'directions_car',
|
|
local_shipping = 'local_shipping',
|
|
cast_connected = 'cast_connected',
|
|
voice_chat_off = 'voice_chat_off',
|
|
password_change = 'password_change',
|
|
menu_horizontal = 'menu_horizontal',
|
|
logo_javascript = 'logo_javascript',
|
|
phone_forwarded = 'phone_forwarded',
|
|
string_resources = 'string_resources',
|
|
chatbox_ellipses = 'chatbox_ellipses',
|
|
checkmark_circle = 'checkmark_circle',
|
|
select_all_group = 'select_all_group',
|
|
blockchain_block = 'blockchain_block',
|
|
friendship_block = 'friendship_block',
|
|
blockchain_token = 'blockchain_token',
|
|
document_scanner = 'document_scanner',
|
|
splitscreen_left = 'splitscreen_left',
|
|
close_fullscreen = 'close_fullscreen',
|
|
inverse_selection = 'inverse_selection',
|
|
friendship_reuest = 'friendship_reuest',
|
|
friendship_friend = 'friendship_friend',
|
|
friendship_reject = 'friendship_reject',
|
|
friendship_cancel = 'friendship_cancel',
|
|
friendship_accept = 'friendship_accept',
|
|
stop_screen_share = 'stop_screen_share',
|
|
missed_video_call = 'missed_video_call',
|
|
keyboard_lock_off = 'keyboard_lock_off',
|
|
video_camera_back = 'video_camera_back',
|
|
deselect_all_group = 'deselect_all_group',
|
|
logo_stackoverflow = 'logo_stackoverflow',
|
|
logo_web_component = 'logo_web_component',
|
|
blockchain_address = 'blockchain_address',
|
|
friendship_unblock = 'friendship_unblock',
|
|
friendship_unknown = 'friendship_unknown',
|
|
wifi_calling_bar_1 = 'wifi_calling_bar_1',
|
|
wifi_calling_bar_2 = 'wifi_calling_bar_2',
|
|
video_camera_front = 'video_camera_front',
|
|
picture_in_picture = 'picture_in_picture',
|
|
logo_apple_appstore = 'logo_apple_appstore',
|
|
friendship_follower = 'friendship_follower',
|
|
friendship_unfollow = 'friendship_unfollow',
|
|
signal_cellular_alt = 'signal_cellular_alt',
|
|
signal_disconnected = 'signal_disconnected',
|
|
chat_bubble_ellipses = 'chat_bubble_ellipses',
|
|
friendship_following = 'friendship_following',
|
|
call_missed_outgoing = 'call_missed_outgoing',
|
|
audio_video_receiver = 'audio_video_receiver',
|
|
admin_panel_settings = 'admin_panel_settings',
|
|
checkmark_done_circle = 'checkmark_done_circle',
|
|
logo_google_playstore = 'logo_google_playstore',
|
|
video_camera_back_add = 'video_camera_back_add',
|
|
blockchain_transaction = 'blockchain_transaction',
|
|
display_external_input = 'display_external_input',
|
|
picture_in_picture_off = 'picture_in_picture_off',
|
|
video_camera_front_off = 'video_camera_front_off',
|
|
phone_bluetooth_speaker = 'phone_bluetooth_speaker',
|
|
desktop_access_disabled = 'desktop_access_disabled',
|
|
blockchain_smart_contract = 'blockchain_smart_contract',
|
|
blockchain_contract_address = 'blockchain_contract_address',
|
|
}
|
|
|
|
export const defaultIcon = '';
|
|
|
|
export type XIconName = [keyof typeof XIconNames];
|
|
|
|
export type XIconIdentifier = XIconName | XIconNames | string;
|
|
|
|
export type XIconsIndex = {
|
|
[key in keyof typeof XIconNames]?: string;
|
|
};
|
|
|
|
//
|
|
// Contains Path of Custom icons File Names ...
|
|
export const XProvidedIcons = {
|
|
tv: 'tv',
|
|
ol: 'ol',
|
|
ul: 'ul',
|
|
add: 'add',
|
|
dns: 'dns',
|
|
dvr: 'dvr',
|
|
fax: 'fax',
|
|
mic: 'mic',
|
|
mop: 'mop',
|
|
sad: 'sad',
|
|
map: 'map',
|
|
mail: 'mail',
|
|
undo: 'undo',
|
|
redo: 'redo',
|
|
home: 'home',
|
|
flag: 'flag',
|
|
save: 'save',
|
|
sync: 'sync',
|
|
play: 'play',
|
|
star: 'star',
|
|
cast: 'cast',
|
|
wifi: 'wifi',
|
|
call: 'call',
|
|
tabs: 'tabs',
|
|
stop: 'stop',
|
|
code: 'code',
|
|
bold: 'bold',
|
|
crop: 'crop',
|
|
web: 'globe',
|
|
link: 'link',
|
|
last: 'last',
|
|
next: 'next',
|
|
copy: 'copy',
|
|
phone: 'call',
|
|
guide: 'help',
|
|
reply: 'reply',
|
|
label: 'label',
|
|
visible: 'eye',
|
|
liked: 'heart',
|
|
mobile: 'call',
|
|
shop: 'basket',
|
|
event: 'pulse',
|
|
clear: 'close',
|
|
edit: 'create',
|
|
close: 'close',
|
|
enter: 'enter',
|
|
power: 'power',
|
|
pause: 'pause',
|
|
cloud: 'cloud',
|
|
toast: 'toast',
|
|
cards: 'cards',
|
|
mouse: 'mouse',
|
|
album: 'album',
|
|
badge: 'badge',
|
|
radio: 'radio',
|
|
watch: 'watch',
|
|
movie: 'movie',
|
|
image: 'image',
|
|
quote: 'quote',
|
|
touch: 'touch',
|
|
error: 'error',
|
|
first: 'first',
|
|
print: 'print',
|
|
cancel: 'close',
|
|
remove: 'trash',
|
|
terms: 'hammer',
|
|
input: 'pencil',
|
|
login: 'log-in',
|
|
posts: 'albums',
|
|
files: 'folder',
|
|
italic: 'italic',
|
|
locate: 'locate',
|
|
search: 'search',
|
|
job: 'megaphone',
|
|
list: 'list-box',
|
|
rewind: 'rewind',
|
|
school: 'school',
|
|
server: 'server',
|
|
repeat: 'repeat',
|
|
report: 'report',
|
|
policy: 'policy',
|
|
router: 'router',
|
|
shield: 'shield',
|
|
stylus: 'stylus',
|
|
tv_off: 'tv_off',
|
|
swords: 'swords',
|
|
nearby: 'nearby',
|
|
flight: 'flight',
|
|
memory: 'memory',
|
|
replay: 'replay',
|
|
unknown: 'attach',
|
|
video: 'videocam',
|
|
done: 'checkmark',
|
|
logout: 'log-out',
|
|
avatars: 'images',
|
|
account: 'person',
|
|
invite: 'contract',
|
|
archive: 'archive',
|
|
toolbar: 'toolbar',
|
|
dialogs: 'dialogs',
|
|
dialpad: 'dialpad',
|
|
vpn_key: 'vpn_key',
|
|
widgets: 'widgets',
|
|
passkey: 'passkey',
|
|
mic_off: 'mic_off',
|
|
monitor: 'monitor',
|
|
gpp_bad: 'gpp_bad',
|
|
charger: 'charger',
|
|
devices: 'devices',
|
|
sd_card: 'sd_card',
|
|
capture: 'capture',
|
|
live_tv: 'live_tv',
|
|
preview: 'preview',
|
|
heading: 'heading',
|
|
refresh: 'refresh',
|
|
lock: 'lock-closed',
|
|
unlock: 'lock-open',
|
|
un_checked: 'close',
|
|
survey: 'newspaper',
|
|
chat_box: 'chatbox',
|
|
verified: 'verified',
|
|
arrow_up: 'arrow-up',
|
|
business: 'business',
|
|
contrast: 'contrast',
|
|
first_name: 'person',
|
|
calendar: 'calendar',
|
|
checked: 'checkmark',
|
|
dashboard: 'journal',
|
|
explorer: 'browsers',
|
|
settings: 'settings',
|
|
bookmark: 'bookmark',
|
|
dropdown: 'dropdown',
|
|
add_call: 'add_call',
|
|
sim_card: 'sim_card',
|
|
security: 'security',
|
|
password: 'password',
|
|
podcasts: 'podcasts',
|
|
wifi_off: 'wifi_off',
|
|
no_sound: 'no_sound',
|
|
keyboard: 'keyboard',
|
|
exercise: 'exercise',
|
|
computer: 'computer',
|
|
videocam: 'videocam',
|
|
autoplay: 'autoplay',
|
|
autostop: 'autostop',
|
|
logo_npm: 'logo-npm',
|
|
logo_pwa: 'logo-pwa',
|
|
logo_rss: 'logo-rss',
|
|
logo_usd: 'logo-usd',
|
|
logo_vue: 'logo-vue',
|
|
previous: 'previous',
|
|
location: 'location',
|
|
language: 'language',
|
|
document: 'document',
|
|
expand: 'expand_more',
|
|
friendships: 'people',
|
|
user: 'person-circle',
|
|
video_cam: 'videocam',
|
|
share: 'share-social',
|
|
deselect_all: 'close',
|
|
label_off: 'label_off',
|
|
visible_off: 'eye-off',
|
|
users: 'people-circle',
|
|
checkmark: 'checkmark',
|
|
star_half: 'star-half',
|
|
bookmarks: 'bookmarks',
|
|
thumbs_up: 'thumbs-up',
|
|
bluetooth: 'bluetooth',
|
|
logo_css3: 'logo-css3',
|
|
logo_edge: 'logo-edge',
|
|
logo_sass: 'logo-sass',
|
|
voicemail: 'voicemail',
|
|
call_made: 'call_made',
|
|
touch_app: 'touch_app',
|
|
subtitles: 'subtitles',
|
|
music_off: 'music_off',
|
|
encrypted: 'encrypted',
|
|
apartment: 'apartment',
|
|
dark_mode: 'dark_mode',
|
|
deskphone: 'deskphone',
|
|
autopause: 'autopause',
|
|
upload: 'cloud-upload',
|
|
audio: 'musical-notes',
|
|
clipboard: 'clipboard',
|
|
analytics: 'analytics',
|
|
select_all: 'checkbox',
|
|
management: 'construct',
|
|
unliked: 'heart-outline',
|
|
arrow_down: 'arrow-down',
|
|
arrow_back: 'arrow-back',
|
|
profile: 'person-circle',
|
|
register: 'finger-print',
|
|
customers_club: 'trophy',
|
|
volume_off: 'volume-off',
|
|
volume_low: 'volume-low',
|
|
logo_html5: 'logo-html5',
|
|
logo_ionic: 'logo-ionic',
|
|
logo_apple: 'logo-apple',
|
|
logo_react: 'logo-react',
|
|
logo_skype: 'logo-skype',
|
|
logo_slack: 'logo-slack',
|
|
logo_yahoo: 'logo-yahoo',
|
|
blockchain: 'blockchain',
|
|
data_table: 'data_table',
|
|
device_hub: 'device_hub',
|
|
call_split: 'call_split',
|
|
router_off: 'router_off',
|
|
light_mode: 'light_mode',
|
|
mouse_lock: 'mouse_lock',
|
|
nightlight: 'nightlight',
|
|
play_arrow: 'play_arrow',
|
|
video_call: 'video_call',
|
|
video_chat: 'video_chat',
|
|
video_file: 'video_file',
|
|
voice_chat: 'voice_chat',
|
|
fit_screen: 'fit_screen',
|
|
fullscreen: 'fullscreen',
|
|
friendship_reuest: 'add',
|
|
arrow_dropup: 'caret-up',
|
|
collapse: 'chevron_right',
|
|
contacts: 'people-circle',
|
|
friendship_block: 'block',
|
|
chat_bubble: 'chatbubble',
|
|
info: 'information-circle',
|
|
rotate_left: 'rotate_left',
|
|
swap_vert: 'swap-vertical',
|
|
friendship_friend: 'forum',
|
|
download: 'cloud-download',
|
|
thumbs_down: 'thumbs-down',
|
|
stats_chart: 'stats-chart',
|
|
volume_high: 'volume-high',
|
|
volume_mute: 'volume-mute',
|
|
play_circle: 'play-circle',
|
|
logo_amazon: 'logo-amazon',
|
|
logo_chrome: 'logo-chrome',
|
|
logo_docker: 'logo-docker',
|
|
logo_github: 'logo-github',
|
|
logo_gitlab: 'logo-gitlab',
|
|
logo_google: 'logo-google',
|
|
logo_paypal: 'logo-paypal',
|
|
blockchain1: 'blockchain1',
|
|
logo_nodejs: 'logo-nodejs',
|
|
voicemail_2: 'voicemail_2',
|
|
devices_off: 'devices_off',
|
|
exit_to_app: 'exit_to_app',
|
|
ring_volume: 'ring_volume',
|
|
call_missed: 'call_missed',
|
|
privacy_tip: 'privacy_tip',
|
|
dual_screen: 'dual_screen',
|
|
engineering: 'engineering',
|
|
fast_rewind: 'fast_rewind',
|
|
reset_password: 'construct',
|
|
chat_bubbles: 'chatbubbles',
|
|
friendship_reject: 'remove',
|
|
friendship_follower: 'chat',
|
|
rotate_right: 'rotate_right',
|
|
logo_android: 'logo-android',
|
|
logo_angular: 'logo-angular',
|
|
logo_bitcoin: 'logo-bitcoin',
|
|
logo_dropbox: 'logo-dropbox',
|
|
logo_firefox: 'logo-firefox',
|
|
logo_twitter: 'logo-twitter',
|
|
logo_youtube: 'logo-youtube',
|
|
logo_windows: 'logo-windows',
|
|
wifi_calling: 'wifi_calling',
|
|
phone_locked: 'phone_locked',
|
|
phone_missed: 'phone_missed',
|
|
call_quality: 'call_quality',
|
|
screen_share: 'screen_share',
|
|
room_service: 'room_service',
|
|
other_houses: 'other_houses',
|
|
dock_to_left: 'dock_to_left',
|
|
keyboard_off: 'keyboard_off',
|
|
cameraswitch: 'cameraswitch',
|
|
architecture: 'architecture',
|
|
fast_forward: 'fast_forward',
|
|
arrow_dropdown: 'caret-down',
|
|
string_resources: 'pricetags',
|
|
swap_horiz: 'swap-horizontal',
|
|
arrow_forward: 'arrow-forward',
|
|
password_change: 'lock-closed',
|
|
cloud_offline: 'cloud-offline',
|
|
accessibility: 'accessibility',
|
|
logo_electron: 'logo-electron',
|
|
logo_facebook: 'logo-facebook',
|
|
logo_firebase: 'logo-firebase',
|
|
logo_linkedin: 'logo-linkedin',
|
|
logo_markdown: 'logo-markdown',
|
|
logo_whatsapp: 'logo-whatsapp',
|
|
phone_enabled: 'phone_enabled',
|
|
phone_in_talk: 'phone_in_talk',
|
|
call_received: 'call_received',
|
|
print_connect: 'print_connect',
|
|
screen_record: 'screen_record',
|
|
shield_person: 'shield_person',
|
|
verified_user: 'verified_user',
|
|
network_check: 'network_check',
|
|
encrypted_off: 'encrypted_off',
|
|
dock_to_right: 'dock_to_right',
|
|
electric_bolt: 'electric_bolt',
|
|
color_palette: 'color-palette',
|
|
friendship_accept: 'checkmark',
|
|
friendship_following: 'comment',
|
|
checkmark_done: 'checkmark-done',
|
|
logo_instagram: 'logo-instagram',
|
|
logo_wordpress: 'logo-wordpress',
|
|
devices_fold_2: 'devices_fold_2',
|
|
perm_phone_msg: 'perm_phone_msg',
|
|
phone_callback: 'phone_callback',
|
|
phone_disabled: 'phone_disabled',
|
|
settings_phone: 'settings_phone',
|
|
print_disabled: 'print_disabled',
|
|
wifi_tethering: 'wifi_tethering',
|
|
speech_to_text: 'speech_to_text',
|
|
mouse_lock_off: 'mouse_lock_off',
|
|
directions_car: 'directions_car',
|
|
local_shipping: 'local_shipping',
|
|
cast_connected: 'cast_connected',
|
|
voice_chat_off: 'voice_chat_off',
|
|
logo_javascript: 'logo-javascript',
|
|
phone_forwarded: 'phone_forwarded',
|
|
menu_vertical: 'ellipsis-vertical',
|
|
chatbox_ellipses: 'chatbox-ellipses',
|
|
checkmark_circle: 'checkmark-circle',
|
|
blockchain_block: 'blockchain-block',
|
|
blockchain_token: 'blockchain-token',
|
|
document_scanner: 'document_scanner',
|
|
splitscreen_left: 'splitscreen_left',
|
|
close_fullscreen: 'close_fullscreen',
|
|
friendship_unblock: 'thumbs_up_down',
|
|
friendship_unfollow: 'highlight_off',
|
|
select_all_group: 'select_all_group',
|
|
stop_screen_share: 'stop_screen_share',
|
|
missed_video_call: 'missed_video_call',
|
|
keyboard_lock_off: 'keyboard_lock_off',
|
|
video_camera_back: 'video_camera_back',
|
|
menu_horizontal: 'ellipsis-horizontal',
|
|
logo_stackoverflow: 'logo-stackoverflow',
|
|
blockchain_address: 'blockchain-address',
|
|
logo_web_component: 'logo-web-component',
|
|
wifi_calling_bar_1: 'wifi_calling_bar_1',
|
|
wifi_calling_bar_2: 'wifi_calling_bar_2',
|
|
video_camera_front: 'video_camera_front',
|
|
picture_in_picture: 'picture_in_picture',
|
|
deselect_all_group: 'deselect_all_group',
|
|
logo_apple_appstore: 'logo-apple-appstore',
|
|
signal_cellular_alt: 'signal_cellular_alt',
|
|
signal_disconnected: 'signal_disconnected',
|
|
friendship_cancel: 'remove_circle_outline',
|
|
inverse_selection: 'remove-circle-outline',
|
|
chat_bubble_ellipses: 'chatbubble-ellipses',
|
|
call_missed_outgoing: 'call_missed_outgoing',
|
|
audio_video_receiver: 'audio_video_receiver',
|
|
admin_panel_settings: 'admin_panel_settings',
|
|
friendship_unknown: 'radio_button_unchecked',
|
|
checkmark_done_circle: 'checkmark-done-circle',
|
|
video_camera_back_add: 'video_camera_back_add',
|
|
logo_google_playstore: 'logo-google-playstore',
|
|
blockchain_transaction: 'blockchain-transaction',
|
|
video_camera_front_off: 'video_camera_front_off',
|
|
display_external_input: 'display_external_input',
|
|
picture_in_picture_off: 'picture_in_picture_off',
|
|
phone_bluetooth_speaker: 'phone_bluetooth_speaker',
|
|
desktop_access_disabled: 'desktop_access_disabled',
|
|
blockchain_smart_contract: 'blockchain-smart-contract',
|
|
blockchain_contract_address: 'blockchain-contract-address',
|
|
};
|
|
|
|
export const XCustomIcons: string[] = [
|
|
XIconNames.ol,
|
|
XIconNames.ul,
|
|
XIconNames.tv,
|
|
XIconNames.dns,
|
|
XIconNames.dvr,
|
|
XIconNames.fax,
|
|
XIconNames.mic,
|
|
XIconNames.mop,
|
|
XIconNames.call,
|
|
XIconNames.tabs,
|
|
XIconNames.cast,
|
|
XIconNames.wifi,
|
|
XIconNames.stop,
|
|
XIconNames.cast,
|
|
XIconNames.link,
|
|
XIconNames.bold,
|
|
XIconNames.code,
|
|
XIconNames.undo,
|
|
XIconNames.redo,
|
|
XIconNames.next,
|
|
XIconNames.last,
|
|
XIconNames.list,
|
|
XIconNames.toast,
|
|
XIconNames.cards,
|
|
XIconNames.mouse,
|
|
XIconNames.album,
|
|
XIconNames.badge,
|
|
XIconNames.radio,
|
|
XIconNames.watch,
|
|
XIconNames.guide,
|
|
XIconNames.image,
|
|
XIconNames.quote,
|
|
XIconNames.touch,
|
|
XIconNames.error,
|
|
XIconNames.first,
|
|
XIconNames.reply,
|
|
XIconNames.label,
|
|
XIconNames.movie,
|
|
XIconNames.repeat,
|
|
XIconNames.report,
|
|
XIconNames.policy,
|
|
XIconNames.router,
|
|
XIconNames.shield,
|
|
XIconNames.stylus,
|
|
XIconNames.tv_off,
|
|
XIconNames.swords,
|
|
XIconNames.nearby,
|
|
XIconNames.flight,
|
|
XIconNames.memory,
|
|
XIconNames.replay,
|
|
XIconNames.expand,
|
|
XIconNames.italic,
|
|
XIconNames.toolbar,
|
|
XIconNames.devices,
|
|
XIconNames.dialogs,
|
|
XIconNames.dialpad,
|
|
XIconNames.vpn_key,
|
|
XIconNames.widgets,
|
|
XIconNames.passkey,
|
|
XIconNames.mic_off,
|
|
XIconNames.monitor,
|
|
XIconNames.gpp_bad,
|
|
XIconNames.charger,
|
|
XIconNames.devices,
|
|
XIconNames.sd_card,
|
|
XIconNames.capture,
|
|
XIconNames.live_tv,
|
|
XIconNames.monitor,
|
|
XIconNames.preview,
|
|
XIconNames.heading,
|
|
XIconNames.dropdown,
|
|
XIconNames.add_call,
|
|
XIconNames.sim_card,
|
|
XIconNames.security,
|
|
XIconNames.password,
|
|
XIconNames.podcasts,
|
|
XIconNames.wifi_off,
|
|
XIconNames.no_sound,
|
|
XIconNames.keyboard,
|
|
XIconNames.exercise,
|
|
XIconNames.computer,
|
|
XIconNames.videocam,
|
|
XIconNames.autoplay,
|
|
XIconNames.autostop,
|
|
XIconNames.previous,
|
|
XIconNames.collapse,
|
|
XIconNames.verified,
|
|
XIconNames.touch_app,
|
|
XIconNames.voicemail,
|
|
XIconNames.call_made,
|
|
XIconNames.subtitles,
|
|
XIconNames.music_off,
|
|
XIconNames.encrypted,
|
|
XIconNames.apartment,
|
|
XIconNames.dark_mode,
|
|
XIconNames.deskphone,
|
|
XIconNames.autopause,
|
|
XIconNames.label_off,
|
|
XIconNames.data_table,
|
|
XIconNames.device_hub,
|
|
XIconNames.call_split,
|
|
XIconNames.router_off,
|
|
XIconNames.light_mode,
|
|
XIconNames.mouse_lock,
|
|
XIconNames.nightlight,
|
|
XIconNames.play_arrow,
|
|
XIconNames.video_call,
|
|
XIconNames.video_chat,
|
|
XIconNames.video_file,
|
|
XIconNames.voice_chat,
|
|
XIconNames.fit_screen,
|
|
XIconNames.fullscreen,
|
|
XIconNames.blockchain,
|
|
XIconNames.voicemail_2,
|
|
XIconNames.devices_off,
|
|
XIconNames.exit_to_app,
|
|
XIconNames.ring_volume,
|
|
XIconNames.call_missed,
|
|
XIconNames.privacy_tip,
|
|
XIconNames.dual_screen,
|
|
XIconNames.engineering,
|
|
XIconNames.fast_rewind,
|
|
XIconNames.blockchain1,
|
|
XIconNames.logo_docker,
|
|
XIconNames.logo_gitlab,
|
|
XIconNames.logo_paypal,
|
|
XIconNames.rotate_left,
|
|
XIconNames.wifi_calling,
|
|
XIconNames.phone_locked,
|
|
XIconNames.phone_missed,
|
|
XIconNames.call_quality,
|
|
XIconNames.screen_share,
|
|
XIconNames.room_service,
|
|
XIconNames.other_houses,
|
|
XIconNames.dock_to_left,
|
|
XIconNames.keyboard_off,
|
|
XIconNames.cameraswitch,
|
|
XIconNames.architecture,
|
|
XIconNames.rotate_right,
|
|
XIconNames.fast_forward,
|
|
XIconNames.phone_enabled,
|
|
XIconNames.phone_in_talk,
|
|
XIconNames.call_received,
|
|
XIconNames.print_connect,
|
|
XIconNames.screen_record,
|
|
XIconNames.shield_person,
|
|
XIconNames.verified_user,
|
|
XIconNames.network_check,
|
|
XIconNames.encrypted_off,
|
|
XIconNames.dock_to_right,
|
|
XIconNames.electric_bolt,
|
|
XIconNames.devices_fold_2,
|
|
XIconNames.perm_phone_msg,
|
|
XIconNames.phone_callback,
|
|
XIconNames.phone_disabled,
|
|
XIconNames.settings_phone,
|
|
XIconNames.print_disabled,
|
|
XIconNames.wifi_tethering,
|
|
XIconNames.speech_to_text,
|
|
XIconNames.mouse_lock_off,
|
|
XIconNames.directions_car,
|
|
XIconNames.local_shipping,
|
|
XIconNames.cast_connected,
|
|
XIconNames.voice_chat_off,
|
|
XIconNames.phone_forwarded,
|
|
XIconNames.document_scanner,
|
|
XIconNames.splitscreen_left,
|
|
XIconNames.close_fullscreen,
|
|
XIconNames.blockchain_block,
|
|
XIconNames.blockchain_token,
|
|
XIconNames.select_all_group,
|
|
XIconNames.friendship_block,
|
|
XIconNames.stop_screen_share,
|
|
XIconNames.missed_video_call,
|
|
XIconNames.keyboard_lock_off,
|
|
XIconNames.video_camera_back,
|
|
XIconNames.friendship_friend,
|
|
XIconNames.friendship_reject,
|
|
XIconNames.friendship_cancel,
|
|
XIconNames.wifi_calling_bar_1,
|
|
XIconNames.wifi_calling_bar_2,
|
|
XIconNames.video_camera_front,
|
|
XIconNames.picture_in_picture,
|
|
XIconNames.blockchain_address,
|
|
XIconNames.deselect_all_group,
|
|
XIconNames.friendship_unblock,
|
|
XIconNames.friendship_unknown,
|
|
XIconNames.signal_cellular_alt,
|
|
XIconNames.signal_disconnected,
|
|
XIconNames.friendship_follower,
|
|
XIconNames.friendship_unfollow,
|
|
XIconNames.call_missed_outgoing,
|
|
XIconNames.audio_video_receiver,
|
|
XIconNames.admin_panel_settings,
|
|
XIconNames.friendship_following,
|
|
XIconNames.video_camera_back_add,
|
|
XIconNames.video_camera_front_off,
|
|
XIconNames.display_external_input,
|
|
XIconNames.picture_in_picture_off,
|
|
XIconNames.blockchain_transaction,
|
|
XIconNames.phone_bluetooth_speaker,
|
|
XIconNames.desktop_access_disabled,
|
|
XIconNames.blockchain_smart_contract,
|
|
XIconNames.blockchain_contract_address,
|
|
];
|
|
|
|
export type XIconSlot = 'start' | 'end';
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXIconContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XIconActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
slot: XStandardType<XIconSlot>;
|
|
name: XStandardType<XIconIdentifier>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
applyDirection: XStandardType<boolean>;
|
|
|
|
//
|
|
selectable: XStandardType<boolean>;
|
|
clickable: XStandardType<boolean>;
|
|
clicked: EventEmitter<Event>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XIconContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXIconContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XIconActionModel> =
|
|
new Subject<XIconActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly slot: XStandardType<XIconSlot> = 'start';
|
|
readonly name: XStandardType<XIconIdentifier>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier>;
|
|
readonly foregroundColor: XStandardType<boolean> = true;
|
|
|
|
readonly selectable: XStandardType<boolean> = false;
|
|
readonly clickable: XStandardType<boolean> = false;
|
|
readonly applyDirection: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly clicked = new EventEmitter<Event>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XIconContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXIconContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XIconActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
slot: XStandardType<XIconSlot> = this.propertyProvider.slot;
|
|
|
|
@Input()
|
|
name: XStandardType<XIconIdentifier> = this.propertyProvider.name;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
selectable: XStandardType<boolean> = this.propertyProvider.selectable;
|
|
|
|
@Input()
|
|
clickable: XStandardType<boolean> = this.propertyProvider.clickable;
|
|
|
|
@Input()
|
|
applyDirection: XStandardType<boolean> = this.propertyProvider.applyDirection;
|
|
|
|
@Output()
|
|
clicked: EventEmitter<Event> = new EventEmitter<Event>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XIconContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXIconContainer
|
|
): Observable<IXIconContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
slot: this.getValue(container ? container.slot : this.slot),
|
|
name: this.getValue(container ? container.name : this.name),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
selectable: this.getValue(
|
|
container ? container.selectable : this.selectable
|
|
),
|
|
clickable: this.getValue(
|
|
container ? container.clickable : this.clickable
|
|
),
|
|
applyDirection: this.getValue(
|
|
container ? container.applyDirection : this.applyDirection
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
clicked: this.clicked,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="v-card v-no-margin-card"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[subTitle]="getResourceValue(cardSubTitle) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" actions *ngIf="getValue(cardShowActions) | async">
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="x-footer" footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<div class="x-component-wrapper" [ngClass]="getValue(cssClass) | async">
|
|
<!-- Toolbar -->
|
|
<x-action-bar
|
|
[color]="actionBarColor"
|
|
[cssClass]="actionBarCssClass"
|
|
[actionProvider]="actionBarActionProvider"
|
|
[foregroundColor]="actionBarForegroundColor"
|
|
(actionFired)="handleActionBarActionFired($event)"
|
|
*ngIf="
|
|
(getValue(showActionBar) | async) &&
|
|
(hasChildValue(actionBarActions) | async) &&
|
|
(hasChildValue(availableActionBarItems) | async)
|
|
"
|
|
[actions]="getArrayValue(actionBarActions) | async"
|
|
></x-action-bar>
|
|
|
|
<!-- Tabs -->
|
|
<ng-container *ngIf="(countChildsValue(Sessions) | async) > 1">
|
|
<x-tabs
|
|
[loopTabs]="true"
|
|
[swipable]="false"
|
|
[actionProvider]="tabsActionProvider"
|
|
[alignTabs]="getValue(alignTabs) | async"
|
|
[headerPosition]="TabHeaderPositions.ABOVE"
|
|
[tabIndicatorColor]="ColorNames.Transparent"
|
|
[headerColor]="getValue(tabHeaderColor) | async"
|
|
[activeTabColor]="getValue(activeTabColor) | async"
|
|
(selectedTabChange)="handleTabsSelectedTabChanged($event)"
|
|
>
|
|
<x-tab *ngFor="let tab of Sessions">
|
|
<div x-tab-label>
|
|
{{ tab.name }}
|
|
</div>
|
|
</x-tab>
|
|
</x-tabs>
|
|
</ng-container>
|
|
|
|
<!-- Editor -->
|
|
<div class="code-editor" #codeEditor></div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
HostListener,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XIDEMode,
|
|
XIDETheme,
|
|
XIDEAction,
|
|
XIDEActionModel,
|
|
XIDEMinFontSize,
|
|
XIDEMaxFontSize,
|
|
XIDEActionBarItem,
|
|
XIDETabDescriptor,
|
|
XIDEModeIdentifier,
|
|
XIDEDefaultTabName,
|
|
XIDEThemeIdentifier,
|
|
XIDEContainerComponent,
|
|
} from './x-ide.typings';
|
|
import {
|
|
nameof,
|
|
toArray,
|
|
isNumber,
|
|
toBoolean,
|
|
isBoolean,
|
|
countChild,
|
|
XStandardType,
|
|
toNormalString,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XTabAlign,
|
|
XTabsAction,
|
|
XTabChangeEvent,
|
|
XTabsActionModel,
|
|
XTabsHeaderPosition,
|
|
} from '../x-tabs/x-tabs.typings';
|
|
import * as ace from 'ace-builds';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarItemSlot,
|
|
XActionBarActionFiredModel,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import 'ace-builds/src-noconflict/ext-beautify';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import 'ace-builds/src-noconflict/ext-language_tools';
|
|
import { forkJoin, Subject, Subscription } from 'rxjs';
|
|
import { XPopoverOption } from '../dialogs/x-popover/x-popover.typings';
|
|
|
|
//
|
|
//#region Themes ...
|
|
import 'ace-builds/src-noconflict/theme-ambiance';
|
|
import 'ace-builds/src-noconflict/theme-chaos';
|
|
import 'ace-builds/src-noconflict/theme-chrome';
|
|
import 'ace-builds/src-noconflict/theme-cloud9_day';
|
|
import 'ace-builds/src-noconflict/theme-cloud9_night';
|
|
import 'ace-builds/src-noconflict/theme-cloud9_night_low_color';
|
|
import 'ace-builds/src-noconflict/theme-clouds';
|
|
import 'ace-builds/src-noconflict/theme-clouds_midnight';
|
|
import 'ace-builds/src-noconflict/theme-cobalt';
|
|
import 'ace-builds/src-noconflict/theme-crimson_editor';
|
|
import 'ace-builds/src-noconflict/theme-dawn';
|
|
import 'ace-builds/src-noconflict/theme-dracula';
|
|
import 'ace-builds/src-noconflict/theme-dreamweaver';
|
|
import 'ace-builds/src-noconflict/theme-eclipse';
|
|
import 'ace-builds/src-noconflict/theme-github';
|
|
import 'ace-builds/src-noconflict/theme-gob';
|
|
import 'ace-builds/src-noconflict/theme-gruvbox';
|
|
import 'ace-builds/src-noconflict/theme-gruvbox_dark_hard';
|
|
import 'ace-builds/src-noconflict/theme-gruvbox_light_hard';
|
|
import 'ace-builds/src-noconflict/theme-idle_fingers';
|
|
import 'ace-builds/src-noconflict/theme-iplastic';
|
|
import 'ace-builds/src-noconflict/theme-katzenmilch';
|
|
import 'ace-builds/src-noconflict/theme-kr_theme';
|
|
import 'ace-builds/src-noconflict/theme-kuroir';
|
|
import 'ace-builds/src-noconflict/theme-merbivore';
|
|
import 'ace-builds/src-noconflict/theme-merbivore_soft';
|
|
import 'ace-builds/src-noconflict/theme-mono_industrial';
|
|
import 'ace-builds/src-noconflict/theme-monokai';
|
|
import 'ace-builds/src-noconflict/theme-nord_dark';
|
|
import 'ace-builds/src-noconflict/theme-one_dark';
|
|
import 'ace-builds/src-noconflict/theme-pastel_on_dark';
|
|
import 'ace-builds/src-noconflict/theme-solarized_dark';
|
|
import 'ace-builds/src-noconflict/theme-solarized_light';
|
|
import 'ace-builds/src-noconflict/theme-sqlserver';
|
|
import 'ace-builds/src-noconflict/theme-terminal';
|
|
import 'ace-builds/src-noconflict/theme-textmate';
|
|
import 'ace-builds/src-noconflict/theme-tomorrow';
|
|
import 'ace-builds/src-noconflict/theme-tomorrow_night';
|
|
import 'ace-builds/src-noconflict/theme-tomorrow_night_blue';
|
|
import 'ace-builds/src-noconflict/theme-tomorrow_night_bright';
|
|
import 'ace-builds/src-noconflict/theme-tomorrow_night_eighties';
|
|
import 'ace-builds/src-noconflict/theme-twilight';
|
|
import 'ace-builds/src-noconflict/theme-vibrant_ink';
|
|
import 'ace-builds/src-noconflict/theme-xcode';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Modes ...
|
|
import 'ace-builds/src-noconflict/mode-abap';
|
|
import 'ace-builds/src-noconflict/mode-abc';
|
|
import 'ace-builds/src-noconflict/mode-actionscript';
|
|
import 'ace-builds/src-noconflict/mode-ada';
|
|
import 'ace-builds/src-noconflict/mode-alda';
|
|
import 'ace-builds/src-noconflict/mode-apache_conf';
|
|
import 'ace-builds/src-noconflict/mode-apex';
|
|
import 'ace-builds/src-noconflict/mode-applescript';
|
|
import 'ace-builds/src-noconflict/mode-aql';
|
|
import 'ace-builds/src-noconflict/mode-asciidoc';
|
|
import 'ace-builds/src-noconflict/mode-asl';
|
|
import 'ace-builds/src-noconflict/mode-assembly_x86';
|
|
import 'ace-builds/src-noconflict/mode-autohotkey';
|
|
import 'ace-builds/src-noconflict/mode-batchfile';
|
|
import 'ace-builds/src-noconflict/mode-c9search';
|
|
import 'ace-builds/src-noconflict/mode-c_cpp';
|
|
import 'ace-builds/src-noconflict/mode-cirru';
|
|
import 'ace-builds/src-noconflict/mode-clojure';
|
|
import 'ace-builds/src-noconflict/mode-cobol';
|
|
import 'ace-builds/src-noconflict/mode-coffee';
|
|
import 'ace-builds/src-noconflict/mode-coldfusion';
|
|
import 'ace-builds/src-noconflict/mode-crystal';
|
|
import 'ace-builds/src-noconflict/mode-csharp';
|
|
import 'ace-builds/src-noconflict/mode-csound_document';
|
|
import 'ace-builds/src-noconflict/mode-csound_orchestra';
|
|
import 'ace-builds/src-noconflict/mode-csound_score';
|
|
import 'ace-builds/src-noconflict/mode-csp';
|
|
import 'ace-builds/src-noconflict/mode-css';
|
|
import 'ace-builds/src-noconflict/mode-curly';
|
|
import 'ace-builds/src-noconflict/mode-d';
|
|
import 'ace-builds/src-noconflict/mode-dart';
|
|
import 'ace-builds/src-noconflict/mode-diff';
|
|
import 'ace-builds/src-noconflict/mode-django';
|
|
import 'ace-builds/src-noconflict/mode-dockerfile';
|
|
import 'ace-builds/src-noconflict/mode-dot';
|
|
import 'ace-builds/src-noconflict/mode-drools';
|
|
import 'ace-builds/src-noconflict/mode-edifact';
|
|
import 'ace-builds/src-noconflict/mode-eiffel';
|
|
import 'ace-builds/src-noconflict/mode-ejs';
|
|
import 'ace-builds/src-noconflict/mode-elixir';
|
|
import 'ace-builds/src-noconflict/mode-elm';
|
|
import 'ace-builds/src-noconflict/mode-erlang';
|
|
import 'ace-builds/src-noconflict/mode-forth';
|
|
import 'ace-builds/src-noconflict/mode-fortran';
|
|
import 'ace-builds/src-noconflict/mode-fsharp';
|
|
import 'ace-builds/src-noconflict/mode-fsl';
|
|
import 'ace-builds/src-noconflict/mode-ftl';
|
|
import 'ace-builds/src-noconflict/mode-gcode';
|
|
import 'ace-builds/src-noconflict/mode-gherkin';
|
|
import 'ace-builds/src-noconflict/mode-gitignore';
|
|
import 'ace-builds/src-noconflict/mode-glsl';
|
|
import 'ace-builds/src-noconflict/mode-gobstones';
|
|
import 'ace-builds/src-noconflict/mode-golang';
|
|
import 'ace-builds/src-noconflict/mode-graphqlschema';
|
|
import 'ace-builds/src-noconflict/mode-groovy';
|
|
import 'ace-builds/src-noconflict/mode-haml';
|
|
import 'ace-builds/src-noconflict/mode-handlebars';
|
|
import 'ace-builds/src-noconflict/mode-haskell';
|
|
import 'ace-builds/src-noconflict/mode-haskell_cabal';
|
|
import 'ace-builds/src-noconflict/mode-haxe';
|
|
import 'ace-builds/src-noconflict/mode-hjson';
|
|
import 'ace-builds/src-noconflict/mode-html';
|
|
import 'ace-builds/src-noconflict/mode-html_elixir';
|
|
import 'ace-builds/src-noconflict/mode-html_ruby';
|
|
import 'ace-builds/src-noconflict/mode-ini';
|
|
import 'ace-builds/src-noconflict/mode-io';
|
|
import 'ace-builds/src-noconflict/mode-ion';
|
|
import 'ace-builds/src-noconflict/mode-jack';
|
|
import 'ace-builds/src-noconflict/mode-jade';
|
|
import 'ace-builds/src-noconflict/mode-java';
|
|
import 'ace-builds/src-noconflict/mode-javascript';
|
|
import 'ace-builds/src-noconflict/mode-json';
|
|
import 'ace-builds/src-noconflict/mode-json5';
|
|
import 'ace-builds/src-noconflict/mode-jsoniq';
|
|
import 'ace-builds/src-noconflict/mode-jsp';
|
|
import 'ace-builds/src-noconflict/mode-jssm';
|
|
import 'ace-builds/src-noconflict/mode-jsx';
|
|
import 'ace-builds/src-noconflict/mode-julia';
|
|
import 'ace-builds/src-noconflict/mode-kotlin';
|
|
import 'ace-builds/src-noconflict/mode-latex';
|
|
import 'ace-builds/src-noconflict/mode-latte';
|
|
import 'ace-builds/src-noconflict/mode-less';
|
|
import 'ace-builds/src-noconflict/mode-liquid';
|
|
import 'ace-builds/src-noconflict/mode-lisp';
|
|
import 'ace-builds/src-noconflict/mode-livescript';
|
|
import 'ace-builds/src-noconflict/mode-logiql';
|
|
import 'ace-builds/src-noconflict/mode-logtalk';
|
|
import 'ace-builds/src-noconflict/mode-lsl';
|
|
import 'ace-builds/src-noconflict/mode-lua';
|
|
import 'ace-builds/src-noconflict/mode-luapage';
|
|
import 'ace-builds/src-noconflict/mode-lucene';
|
|
import 'ace-builds/src-noconflict/mode-makefile';
|
|
import 'ace-builds/src-noconflict/mode-markdown';
|
|
import 'ace-builds/src-noconflict/mode-mask';
|
|
import 'ace-builds/src-noconflict/mode-matlab';
|
|
import 'ace-builds/src-noconflict/mode-maze';
|
|
import 'ace-builds/src-noconflict/mode-mediawiki';
|
|
import 'ace-builds/src-noconflict/mode-mel';
|
|
import 'ace-builds/src-noconflict/mode-mips';
|
|
import 'ace-builds/src-noconflict/mode-mixal';
|
|
import 'ace-builds/src-noconflict/mode-mushcode';
|
|
import 'ace-builds/src-noconflict/mode-mysql';
|
|
import 'ace-builds/src-noconflict/mode-nginx';
|
|
import 'ace-builds/src-noconflict/mode-nim';
|
|
import 'ace-builds/src-noconflict/mode-nix';
|
|
import 'ace-builds/src-noconflict/mode-nsis';
|
|
import 'ace-builds/src-noconflict/mode-nunjucks';
|
|
import 'ace-builds/src-noconflict/mode-objectivec';
|
|
import 'ace-builds/src-noconflict/mode-ocaml';
|
|
import 'ace-builds/src-noconflict/mode-partiql';
|
|
import 'ace-builds/src-noconflict/mode-pascal';
|
|
import 'ace-builds/src-noconflict/mode-perl';
|
|
import 'ace-builds/src-noconflict/mode-pgsql';
|
|
import 'ace-builds/src-noconflict/mode-php';
|
|
import 'ace-builds/src-noconflict/mode-php_laravel_blade';
|
|
import 'ace-builds/src-noconflict/mode-pig';
|
|
import 'ace-builds/src-noconflict/mode-plain_text';
|
|
import 'ace-builds/src-noconflict/mode-powershell';
|
|
import 'ace-builds/src-noconflict/mode-praat';
|
|
import 'ace-builds/src-noconflict/mode-prisma';
|
|
import 'ace-builds/src-noconflict/mode-prolog';
|
|
import 'ace-builds/src-noconflict/mode-properties';
|
|
import 'ace-builds/src-noconflict/mode-protobuf';
|
|
import 'ace-builds/src-noconflict/mode-puppet';
|
|
import 'ace-builds/src-noconflict/mode-python';
|
|
import 'ace-builds/src-noconflict/mode-qml';
|
|
import 'ace-builds/src-noconflict/mode-r';
|
|
import 'ace-builds/src-noconflict/mode-raku';
|
|
import 'ace-builds/src-noconflict/mode-razor';
|
|
import 'ace-builds/src-noconflict/mode-rdoc';
|
|
import 'ace-builds/src-noconflict/mode-red';
|
|
import 'ace-builds/src-noconflict/mode-redshift';
|
|
import 'ace-builds/src-noconflict/mode-rhtml';
|
|
import 'ace-builds/src-noconflict/mode-robot';
|
|
import 'ace-builds/src-noconflict/mode-rst';
|
|
import 'ace-builds/src-noconflict/mode-ruby';
|
|
import 'ace-builds/src-noconflict/mode-rust';
|
|
import 'ace-builds/src-noconflict/mode-sac';
|
|
import 'ace-builds/src-noconflict/mode-sass';
|
|
import 'ace-builds/src-noconflict/mode-scad';
|
|
import 'ace-builds/src-noconflict/mode-scala';
|
|
import 'ace-builds/src-noconflict/mode-scheme';
|
|
import 'ace-builds/src-noconflict/mode-scrypt';
|
|
import 'ace-builds/src-noconflict/mode-scss';
|
|
import 'ace-builds/src-noconflict/mode-sh';
|
|
import 'ace-builds/src-noconflict/mode-sjs';
|
|
import 'ace-builds/src-noconflict/mode-slim';
|
|
import 'ace-builds/src-noconflict/mode-smarty';
|
|
import 'ace-builds/src-noconflict/mode-smithy';
|
|
import 'ace-builds/src-noconflict/mode-snippets';
|
|
import 'ace-builds/src-noconflict/mode-soy_template';
|
|
import 'ace-builds/src-noconflict/mode-space';
|
|
import 'ace-builds/src-noconflict/mode-sparql';
|
|
import 'ace-builds/src-noconflict/mode-sql';
|
|
import 'ace-builds/src-noconflict/mode-sqlserver';
|
|
import 'ace-builds/src-noconflict/mode-stylus';
|
|
import 'ace-builds/src-noconflict/mode-svg';
|
|
import 'ace-builds/src-noconflict/mode-swift';
|
|
import 'ace-builds/src-noconflict/mode-tcl';
|
|
import 'ace-builds/src-noconflict/mode-terraform';
|
|
import 'ace-builds/src-noconflict/mode-tex';
|
|
import 'ace-builds/src-noconflict/mode-text';
|
|
import 'ace-builds/src-noconflict/mode-textile';
|
|
import 'ace-builds/src-noconflict/mode-toml';
|
|
import 'ace-builds/src-noconflict/mode-tsx';
|
|
import 'ace-builds/src-noconflict/mode-turtle';
|
|
import 'ace-builds/src-noconflict/mode-twig';
|
|
import 'ace-builds/src-noconflict/mode-typescript';
|
|
import 'ace-builds/src-noconflict/mode-vala';
|
|
import 'ace-builds/src-noconflict/mode-vbscript';
|
|
import 'ace-builds/src-noconflict/mode-velocity';
|
|
import 'ace-builds/src-noconflict/mode-verilog';
|
|
import 'ace-builds/src-noconflict/mode-vhdl';
|
|
import 'ace-builds/src-noconflict/mode-visualforce';
|
|
import 'ace-builds/src-noconflict/mode-wollok';
|
|
import 'ace-builds/src-noconflict/mode-xml';
|
|
import 'ace-builds/src-noconflict/mode-xquery';
|
|
import 'ace-builds/src-noconflict/mode-yaml';
|
|
import 'ace-builds/src-noconflict/mode-zeek';
|
|
//#endregion
|
|
|
|
@Component({
|
|
selector: 'x-ide',
|
|
templateUrl: './x-ide.component.html',
|
|
styleUrls: ['./x-ide.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XIDEComponent extends XIDEContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Private Props ...
|
|
private CODE_EDITOR_BEAUTIFY: any = null;
|
|
private CODE_EDITOR: ace.Ace.Editor = null;
|
|
private CODE_EDITOR_UNDO_MANAGER: any;
|
|
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private CONTENT_CHANGE_SUBJECT = new Subject<string>();
|
|
|
|
//
|
|
readonly Modes = Object.assign({}, XIDEMode);
|
|
readonly Themes = Object.assign({}, XIDETheme);
|
|
readonly TabAligns = Object.assign({}, XTabAlign);
|
|
readonly IconNames = Object.assign({}, XIconNames);
|
|
readonly ColorNames = Object.assign({}, XColorWithBrightness);
|
|
readonly ActionBarItems = Object.assign({}, XIDEActionBarItem);
|
|
readonly ActionBarItemSlots = Object.assign({}, XActionBarItemSlot);
|
|
readonly TabHeaderPositions = Object.assign({}, XTabsHeaderPosition);
|
|
|
|
//
|
|
readonly tabsActionProvider = new Subject<XTabsActionModel>();
|
|
//#endregion
|
|
|
|
//
|
|
@ViewChild('codeEditor')
|
|
codeEditorElmRef: ElementRef<HTMLDivElement>;
|
|
|
|
@HostListener('resize', ['$event'])
|
|
onResize (event: any) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.resize();
|
|
}
|
|
|
|
//
|
|
lastContent: string;
|
|
currentTab = XIDEDefaultTabName;
|
|
|
|
//
|
|
readonly Sessions: Pick<
|
|
XIDETabDescriptor,
|
|
'name' | 'session' | 'canSave' | 'canBeautify'
|
|
>[] = [];
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
afterViewInit () {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
this.prepareCodeEditor();
|
|
}
|
|
|
|
async onChange (changeKeys: string[]): Promise<void> {
|
|
//
|
|
//#region Action Provider Changed ...
|
|
//
|
|
const isActionProviderChaged = changeKeys.includes(
|
|
nameof<XIDEComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChaged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Theme Changed ...
|
|
const isThemeChanged = changeKeys.includes(nameof<XIDEComponent>('theme'));
|
|
if (isThemeChanged) {
|
|
this.setTheme(this.theme);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Mode Changed ...
|
|
const isModeChanged = changeKeys.includes(nameof<XIDEComponent>('mode'));
|
|
if (isModeChanged) {
|
|
this.setMode(this.mode);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region MinLines Changed ...
|
|
const isMinLinesChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('minLines')
|
|
);
|
|
if (isMinLinesChanged) {
|
|
this.setMinLines(this.minLines);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region MaxLines Changed ...
|
|
const isMaxLinesChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('maxLines')
|
|
);
|
|
if (isMaxLinesChanged) {
|
|
this.setMaxLines(this.maxLines);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region FontSize Changed ...
|
|
const isFontSizeChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('fontSize')
|
|
);
|
|
if (isFontSizeChanged) {
|
|
this.setFontSize(this.fontSize);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Readonly Changed ...
|
|
const isReadonlyChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('readonly')
|
|
);
|
|
if (isReadonlyChanged) {
|
|
this.setReadOnly(this.readonly);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content Changed ...
|
|
const isContentChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('content')
|
|
);
|
|
if (isContentChanged) {
|
|
this.setContent(this.content);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region WordWrapping Changed ...
|
|
const isWordWrappingChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('wordWrapping')
|
|
);
|
|
if (isWordWrappingChanged) {
|
|
this.setWordWrapping(this.wordWrapping);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ShowPrintMargin Changed ...
|
|
const isShowPrintMarginChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('showPrintMargin')
|
|
);
|
|
if (isShowPrintMarginChanged) {
|
|
this.setShowPrintMargin(this.showPrintMargin);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region HighlightActiveLine Changed ...
|
|
const isHighlightActiveLineChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('highlightActiveLine')
|
|
);
|
|
if (isHighlightActiveLineChanged) {
|
|
this.setHighlightActiveLine(this.highlightActiveLine);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region BasicAutocompletion Changed ...
|
|
const isBasicAutocompletionChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('basicAutocompletion')
|
|
);
|
|
if (isBasicAutocompletionChanged) {
|
|
this.setBasicAutocompletion(this.basicAutocompletion);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region DefaultTabName Changed ...
|
|
const isDefaultTabNameChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('defaultTabName')
|
|
);
|
|
if (isDefaultTabNameChanged) {
|
|
await this.handleDefaultTabNameChanged(this.defaultTabName);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
const isDefaultActionBarItemColorChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('defaultActionBarItemColor')
|
|
);
|
|
const isAvailableActionBarItemsChanged = changeKeys.includes(
|
|
nameof<XIDEComponent>('availableActionBarItems')
|
|
);
|
|
if (
|
|
isAvailableActionBarItemsChanged ||
|
|
isDefaultActionBarItemColorChanged
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(this.availableActionBarItems)) {
|
|
this.availableActionBarItems =
|
|
this.propertyProvider.availableActionBarItems;
|
|
}
|
|
await this.prepareActionBar();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy () {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerViewHandlers (): void {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.CONTENT_CHANGE_SUBJECT.asObservable()
|
|
).subscribe(async (content) => {
|
|
//
|
|
if (content === this.lastContent) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.lastContent = content;
|
|
this.updateCurrentTabDescriptor({
|
|
canSave: true,
|
|
canBeautify: true,
|
|
});
|
|
|
|
//
|
|
this.contentChange.emit(content);
|
|
|
|
//
|
|
await this.prepareActionBar();
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleActionBarActionFired (model: XActionBarActionFiredModel) {
|
|
//
|
|
if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case this.ActionBarItems.ChangeMode:
|
|
this.handleActionModeFired(model.event);
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.ChangeTheme:
|
|
this.handleActionThemFired(model.event);
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.Close:
|
|
this.closeTab(this.currentTab);
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.Undo:
|
|
this.undo();
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.Redo:
|
|
this.redo();
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.Beautify:
|
|
await this.beautifyCode();
|
|
break;
|
|
|
|
//
|
|
case this.ActionBarItems.Save:
|
|
//
|
|
this.updateCurrentTabDescriptor({
|
|
canSave: false,
|
|
});
|
|
this.prepareActionBar();
|
|
break;
|
|
}
|
|
|
|
//
|
|
this.actionBarActionFired.emit(model);
|
|
}
|
|
|
|
async handleTabsSelectedTabChanged (event: XTabChangeEvent) {
|
|
//
|
|
if (
|
|
event.index < 0 ||
|
|
isNullOrUndefined(event) ||
|
|
event.index > this.Sessions.length ||
|
|
isNullOrUndefined(this.CODE_EDITOR)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const descriptor = this.Sessions[event.index];
|
|
this.showTab(descriptor.name);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
setTheme (theme: XStandardType<XIDEThemeIdentifier>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(theme).subscribe((value) => {
|
|
//
|
|
if (isNullOrEmptyString(value)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.setTheme(value);
|
|
});
|
|
}
|
|
|
|
setMode (mode: XStandardType<XIDEModeIdentifier>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(mode).subscribe((value) => {
|
|
//
|
|
if (isNullOrEmptyString(value)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.getSession().setMode(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setMinLines (minLines: XStandardType<number>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(minLines).subscribe((value) => {
|
|
//
|
|
if (value <= 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.setOption('minLines', value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setMaxLines (maxLines: XStandardType<number>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(maxLines).subscribe((value) => {
|
|
//
|
|
if (value <= 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.setOption('maxLines', value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setFontSize (fontSize: XStandardType<number>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(fontSize).subscribe((value) => {
|
|
//
|
|
if (value <= XIDEMinFontSize || value >= XIDEMaxFontSize) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.setFontSize(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setReadOnly (readonly: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(readonly).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setReadOnly(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
getFontSize () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
return this.CODE_EDITOR.getFontSize();
|
|
}
|
|
|
|
setHighlightActiveLine (highlightActiveLine: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(highlightActiveLine).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setOption('highlightActiveLine', value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setBasicAutocompletion (basicAutocompletion: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(basicAutocompletion).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setOption('enableBasicAutocompletion' as any, value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setWordWrapping (wordWrapping: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(wordWrapping).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.getSession().setUseWrapMode(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setShowLineNumbers (showLineNumbers: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(showLineNumbers).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setOption('showLineNumbers', value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setShowPrintMargin (showPrintMargin: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(showPrintMargin).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setShowPrintMargin(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
setShowFoldWidgets (showFoldWidgets: XStandardType<boolean>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(showFoldWidgets).subscribe((value) => {
|
|
//
|
|
this.CODE_EDITOR.setShowFoldWidgets(value);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
|
|
//
|
|
//#region IDEEdit ...
|
|
async beautifyCode () {
|
|
//
|
|
if (
|
|
isNullOrUndefined(this.CODE_EDITOR) ||
|
|
isNullOrUndefined(this.CODE_EDITOR_BEAUTIFY)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
this.CODE_EDITOR_BEAUTIFY.beautify(session);
|
|
|
|
//
|
|
this.updateCurrentTabDescriptor({
|
|
canBeautify: false,
|
|
});
|
|
await this.prepareActionBar();
|
|
}
|
|
|
|
getContent () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const result = this.CODE_EDITOR.getValue();
|
|
return result;
|
|
}
|
|
|
|
setContent (value: XStandardType<string>) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.getValue(value).subscribe((content) => {
|
|
//
|
|
if (isNullOrEmptyString(content)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (value === this.getContent()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.setValue(content);
|
|
});
|
|
}
|
|
|
|
clearcontent (force = false) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!!force) {
|
|
//
|
|
this.CODE_EDITOR.setValue('');
|
|
this.detectChanges();
|
|
} else {
|
|
//
|
|
this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
|
|
this.CODE_EDITOR.setValue('');
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
}
|
|
|
|
goToLine (lineNumber: number) {
|
|
//
|
|
const totalLines = this.getTotalLines();
|
|
if (
|
|
lineNumber <= 0 ||
|
|
totalLines <= 0 ||
|
|
lineNumber > totalLines ||
|
|
isNullOrUndefined(this.CODE_EDITOR)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR.gotoLine(lineNumber, 0, true);
|
|
}
|
|
|
|
getTotalLines () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
return this.CODE_EDITOR.getSession().getLength();
|
|
}
|
|
|
|
canUndo () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
if (isNullOrUndefined(session)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const undoManager = session.getUndoManager();
|
|
if (isNullOrUndefined(undoManager)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return undoManager.canUndo();
|
|
}
|
|
|
|
undo (dontSelect = true) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
if (isNullOrUndefined(session)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const undoManager = session.getUndoManager();
|
|
if (isNullOrUndefined(undoManager) || !this.canUndo()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
undoManager.undo(session, dontSelect);
|
|
this.prepareActionBar();
|
|
}
|
|
|
|
canRedo () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
if (isNullOrUndefined(session)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const undoManager = session.getUndoManager();
|
|
if (isNullOrUndefined(undoManager)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return undoManager.canRedo();
|
|
}
|
|
|
|
redo (dontSelect = true) {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
if (isNullOrUndefined(session)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const undoManager = session.getUndoManager();
|
|
if (isNullOrUndefined(undoManager) || !this.canRedo()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
undoManager.redo(session, dontSelect);
|
|
this.prepareActionBar();
|
|
}
|
|
|
|
cleaEditorHistory () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const session = this.CODE_EDITOR.getSession();
|
|
if (isNullOrUndefined(session)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const undoManager = session.getUndoManager();
|
|
if (isNullOrUndefined(undoManager)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
undoManager.reset();
|
|
this.prepareActionBar();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region IDETabs ...
|
|
getTabDescritor (name: string) {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(name) ||
|
|
!this.hasChild(this.Sessions) ||
|
|
isNullOrUndefined(this.CODE_EDITOR)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.Sessions.find(
|
|
(sd) => toNormalString(sd.name) === toNormalString(name)
|
|
);
|
|
}
|
|
|
|
getTabDescritorIndex (name: string) {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(name) ||
|
|
!this.hasChild(this.Sessions) ||
|
|
isNullOrUndefined(this.CODE_EDITOR)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.Sessions.findIndex(
|
|
(sd) => toNormalString(sd.name) === toNormalString(name)
|
|
);
|
|
}
|
|
|
|
getCurrentTabDescritor () {
|
|
return this.getTabDescritor(this.currentTab);
|
|
}
|
|
|
|
updateCurrentTabDescriptor (
|
|
options: Pick<XIDETabDescriptor, 'canSave' | 'canBeautify'>
|
|
) {
|
|
//
|
|
const currentTabDescriptor = this.getCurrentTabDescritor();
|
|
const currentTabdescriptorIndex = this.Sessions.findIndex(
|
|
(sd) => toNormalString(sd.name) === toNormalString(this.currentTab)
|
|
);
|
|
if (
|
|
currentTabdescriptorIndex < 0 ||
|
|
isNullOrUndefined(currentTabDescriptor)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const optionsKeys = Object.keys(options);
|
|
const hasCanSave = optionsKeys.includes(
|
|
nameof<XIDETabDescriptor>('canSave')
|
|
);
|
|
const hasCanBeautify = optionsKeys.includes(
|
|
nameof<XIDETabDescriptor>('canBeautify')
|
|
);
|
|
|
|
//
|
|
const canSave = hasCanSave ? options.canSave : currentTabDescriptor.canSave;
|
|
const canBeautify = hasCanBeautify
|
|
? options.canBeautify
|
|
: currentTabDescriptor.canBeautify;
|
|
|
|
//
|
|
this.Sessions[currentTabdescriptorIndex] = {
|
|
...currentTabDescriptor,
|
|
canSave,
|
|
canBeautify,
|
|
};
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
addTab (
|
|
tab: Pick<XIDETabDescriptor, 'name' | 'mode' | 'content' | 'forceShow'>
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(tab) || isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set Default Content if not Provided ...
|
|
if (isNullOrEmptyString(tab.content)) {
|
|
tab.content = '';
|
|
}
|
|
|
|
//
|
|
// Set Default Mode if Not Provided ...
|
|
if (
|
|
isNullOrEmptyString(tab.mode) ||
|
|
isNullOrUndefined(tab.mode as XIDEMode) ||
|
|
!isNullOrUndefined(this.getTabDescritor(tab.name))
|
|
) {
|
|
tab.mode = XIDEMode.Text;
|
|
}
|
|
|
|
//
|
|
// Create Editor Session ...
|
|
const session = ace.createEditSession(tab.content, tab.mode as any);
|
|
const undoManager = new this.CODE_EDITOR_UNDO_MANAGER();
|
|
|
|
//
|
|
session.setUndoManager(undoManager);
|
|
undoManager.reset();
|
|
|
|
//
|
|
this.Sessions.push({
|
|
session,
|
|
name: tab.name,
|
|
});
|
|
|
|
//
|
|
if (!!tab.forceShow) {
|
|
//
|
|
this.runTimedOut(() => {
|
|
//
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.TO,
|
|
payload: this.Sessions.length - 1,
|
|
});
|
|
}, 500);
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
addTabs (
|
|
tabs: XOneOrManyType<Pick<XIDETabDescriptor, 'name' | 'mode' | 'content'>>
|
|
) {
|
|
//
|
|
if (!this.hasChild(tabs) || isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
toArray(tabs).forEach((tab) =>
|
|
this.addTab({
|
|
...tab,
|
|
forceShow: false,
|
|
})
|
|
);
|
|
}
|
|
|
|
showTab (name: string) {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(name) ||
|
|
!this.hasChild(this.Sessions) ||
|
|
isNullOrUndefined(this.CODE_EDITOR)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const tabDescriptor = this.getTabDescritor(name);
|
|
if (isNullOrUndefined(tabDescriptor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.currentTab = tabDescriptor.name;
|
|
this.lastContent = tabDescriptor.session.getValue();
|
|
this.CODE_EDITOR.setSession(tabDescriptor.session);
|
|
|
|
//
|
|
this.prepareActionBar();
|
|
}
|
|
|
|
closeTab (name: string, force = false) {
|
|
//
|
|
this.getValue(this.defaultTabName).subscribe((defaultTabName) => {
|
|
//
|
|
if (
|
|
isNullOrEmptyString(name) ||
|
|
!this.hasChild(this.Sessions) ||
|
|
isNullOrUndefined(this.CODE_EDITOR) ||
|
|
toNormalString(name) === toNormalString(defaultTabName)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const destinationTab = this.getTabDescritor(name);
|
|
const destinationTabIndex = this.getTabDescritorIndex(name);
|
|
if (isNullOrUndefined(destinationTab) || destinationTabIndex < 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!!force || !destinationTab.canSave) {
|
|
//
|
|
this.handleRemoveTab(destinationTab.name, destinationTabIndex);
|
|
this.detectChanges();
|
|
} else {
|
|
//
|
|
this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
|
|
//
|
|
this.handleRemoveTab(destinationTab.name, destinationTabIndex);
|
|
this.detectChanges();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider () {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XIDEActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe((action) => {
|
|
//
|
|
if (isNullOrUndefined(action) || isNullOrEmptyString(action.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (action.action) {
|
|
//
|
|
// Undo ...
|
|
case XIDEAction.Undo:
|
|
//
|
|
const undoDontSelect = toBoolean(action.payload) || false;
|
|
this.undo(undoDontSelect);
|
|
break;
|
|
|
|
//
|
|
// Redo ...
|
|
case XIDEAction.Redo:
|
|
//
|
|
const redoDontSelect = toBoolean(action.payload) || false;
|
|
this.redo(redoDontSelect);
|
|
break;
|
|
|
|
//
|
|
// CleaEditorHistory ...
|
|
case XIDEAction.CleaEditorHistory:
|
|
this.cleaEditorHistory();
|
|
break;
|
|
|
|
//
|
|
// AddTab ...
|
|
case XIDEAction.AddTab:
|
|
//
|
|
const tabDescriptor = action.payload as XIDETabDescriptor;
|
|
if (
|
|
!isNullOrUndefined(tabDescriptor) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.addTab({
|
|
...tabDescriptor,
|
|
});
|
|
}
|
|
break;
|
|
|
|
//
|
|
// AddTabs ...
|
|
case XIDEAction.AddTabs:
|
|
//
|
|
const tabDescriptors = action.payload as XIDETabDescriptor[];
|
|
if (
|
|
this.hasChild(tabDescriptors) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.addTabs([...tabDescriptors]);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// ShowTab ...
|
|
case XIDEAction.ShowTab:
|
|
//
|
|
const showTabDescriptor = action.payload as string;
|
|
if (
|
|
!isNullOrEmptyString(showTabDescriptor) &&
|
|
!isNullOrEmptyString(action.payload)
|
|
) {
|
|
//
|
|
const index = this.getTabDescritorIndex(showTabDescriptor);
|
|
|
|
//
|
|
this.runTimedOut(() => {
|
|
//
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.TO,
|
|
payload: index,
|
|
});
|
|
}, 500).then(() => {
|
|
this.showTab(showTabDescriptor);
|
|
});
|
|
}
|
|
break;
|
|
|
|
//
|
|
// CloseTab ...
|
|
case XIDEAction.CloseTab:
|
|
//
|
|
const forceCloseTab = action.payload.force || false;
|
|
const closeTabDescriptor = action.payload.name as string;
|
|
if (
|
|
!isNullOrEmptyString(closeTabDescriptor) &&
|
|
!isNullOrEmptyString(action.payload)
|
|
) {
|
|
this.closeTab(closeTabDescriptor, forceCloseTab);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Refresh ...
|
|
case XIDEAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
// SetMode ...
|
|
case XIDEAction.SetMode:
|
|
//
|
|
const mode = action.payload as XIDEMode;
|
|
if (
|
|
!isNullOrUndefined(mode) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setMode(mode);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Beautify ...
|
|
case XIDEAction.Beautify:
|
|
this.beautifyCode();
|
|
break;
|
|
|
|
//
|
|
// SetTheme ...
|
|
case XIDEAction.SetTheme:
|
|
//
|
|
const theme = action.payload as XIDETheme;
|
|
if (
|
|
!isNullOrUndefined(theme) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setTheme(theme);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// GoToLine ...
|
|
case XIDEAction.GoToLine:
|
|
//
|
|
const lineNumber = action.payload as number;
|
|
if (
|
|
isNumber(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.goToLine(lineNumber);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetContent ...
|
|
case XIDEAction.SetContent:
|
|
//
|
|
const content = action.payload as string;
|
|
if (
|
|
!isNullOrEmptyString(content) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setContent(content);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetMinLines ...
|
|
case XIDEAction.SetMinLines:
|
|
//
|
|
const minLines = action.payload as number;
|
|
if (
|
|
isNumber(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setMinLines(minLines);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetMaxLines ...
|
|
case XIDEAction.SetMaxLines:
|
|
//
|
|
const maxLines = action.payload as number;
|
|
if (
|
|
isNumber(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setMaxLines(maxLines);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetReadOnly ...
|
|
case XIDEAction.SetReadOnly:
|
|
//
|
|
const isReadonly = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setReadOnly(isReadonly);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetFontSize ...
|
|
case XIDEAction.SetFontSize:
|
|
//
|
|
const fontSize = action.payload as number;
|
|
if (
|
|
isNumber(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setFontSize(fontSize);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// ClearContent ...
|
|
case XIDEAction.ClearContent:
|
|
//
|
|
const isForceClearContent = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.clearcontent(isForceClearContent);
|
|
} else {
|
|
this.clearcontent();
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetWordWrapping ...
|
|
case XIDEAction.SetWordWrapping:
|
|
//
|
|
const isWrapping = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setWordWrapping(isWrapping);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetShowFoldWidgets ...
|
|
case XIDEAction.SetShowFoldWidgets:
|
|
//
|
|
const showFoldingWidgets = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setReadOnly(showFoldingWidgets);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetShowLineNumbers ...
|
|
case XIDEAction.SetShowLineNumbers:
|
|
//
|
|
const showLineNumbers = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setShowLineNumbers(showLineNumbers);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetShowPrintMargin ...
|
|
case XIDEAction.SetShowPrintMargin:
|
|
//
|
|
const showPrintMargin = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setShowPrintMargin(showPrintMargin);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetHighlightActiveLine ...
|
|
case XIDEAction.SetHighlightActiveLine:
|
|
//
|
|
const highlightActiveLine = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setHighlightActiveLine(highlightActiveLine);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// SetBasicAutocompletion ...
|
|
case XIDEAction.SetBasicAutocompletion:
|
|
//
|
|
const basicAutoCompletion = toBoolean(action.payload);
|
|
if (
|
|
isBoolean(action.payload) &&
|
|
!isNullOrUndefined(action.payload)
|
|
) {
|
|
this.setBasicAutocompletion(basicAutoCompletion);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider () {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private prepareCodeEditor () {
|
|
//
|
|
const element = this.codeEditorElmRef.nativeElement;
|
|
if (isNullOrUndefined(element)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.CODE_EDITOR_BEAUTIFY = ace.require('ace/ext/beautify');
|
|
this.CODE_EDITOR_UNDO_MANAGER = ace.require('ace/undomanager').UndoManager;
|
|
|
|
//
|
|
this.CODE_EDITOR = ace.edit(element, {
|
|
minLines: 1,
|
|
maxLines: 1,
|
|
});
|
|
|
|
//
|
|
//#region Attach Undo Manager ...
|
|
this.CODE_EDITOR.getSession().setUndoManager(
|
|
new this.CODE_EDITOR_UNDO_MANAGER()
|
|
);
|
|
//#endregion
|
|
|
|
//
|
|
//#region Apply Code Editor Options ...
|
|
this.setMode(this.mode);
|
|
this.setTheme(this.theme);
|
|
this.setMinLines(this.minLines);
|
|
this.setMaxLines(this.maxLines);
|
|
this.setFontSize(this.fontSize);
|
|
this.setReadOnly(this.readonly);
|
|
this.setWordWrapping(this.wordWrapping);
|
|
this.setShowLineNumbers(this.showLineNumbers);
|
|
this.setShowPrintMargin(this.showPrintMargin);
|
|
this.setShowFoldWidgets(this.showFoldWidgets);
|
|
this.setHighlightActiveLine(this.highlightActiveLine);
|
|
this.setBasicAutocompletion(this.basicAutocompletion);
|
|
//#endregion
|
|
|
|
//
|
|
//#region Setting Default Content ...
|
|
this.setContent(this.content);
|
|
|
|
//
|
|
// Reset Undo Manager after first code attached ...
|
|
this.CODE_EDITOR.getSession().getUndoManager().reset();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Default Session Handler ...
|
|
forkJoin({
|
|
mode: this.getValue(this.mode),
|
|
content: this.getValue(this.content),
|
|
name: this.getValue(this.defaultTabName).pipe(
|
|
map((defTabName) => defTabName || XIDEDefaultTabName)
|
|
),
|
|
}).subscribe((info) => {
|
|
//
|
|
const name = info.name;
|
|
const session = this.CODE_EDITOR.getSession();
|
|
this.Sessions.push({
|
|
session,
|
|
name,
|
|
});
|
|
});
|
|
//#endregion
|
|
|
|
//
|
|
//#region Code Editor Event Handlers ...
|
|
//
|
|
// Change Event handler ...
|
|
this.CODE_EDITOR.on('change', (e) => {
|
|
//
|
|
const currentContent = this.getContent();
|
|
this.CONTENT_CHANGE_SUBJECT.next(currentContent);
|
|
});
|
|
//#endregion
|
|
|
|
//
|
|
this.prepareActionBar();
|
|
|
|
//
|
|
// Detectin Changes ...
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async prepareActionBar () {
|
|
//
|
|
if (isNullOrUndefined(this.CODE_EDITOR)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const showActionBar = await this.getValueAsync(this.showActionBar);
|
|
if (!showActionBar) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region DefaultActionBarActions ...
|
|
//
|
|
const defaultThemeItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
title: this.ResourceIDs.theme,
|
|
icon: this.IconNames.color_palette,
|
|
slot: this.ActionBarItemSlots.START,
|
|
id: this.ActionBarItems.ChangeTheme,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
|
|
//
|
|
const defaultModeItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.list,
|
|
title: this.ResourceIDs.ide_mode,
|
|
id: this.ActionBarItems.ChangeMode,
|
|
slot: this.ActionBarItemSlots.START,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
|
|
//
|
|
const defaultSaveItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.save,
|
|
title: this.ResourceIDs.save,
|
|
id: this.ActionBarItems.Save,
|
|
slot: this.ActionBarItemSlots.END,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
|
|
//
|
|
const defaultCloseItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.close,
|
|
title: this.ResourceIDs.close,
|
|
id: this.ActionBarItems.Close,
|
|
slot: this.ActionBarItemSlots.END,
|
|
iconColor: this.ColorNames.Danger,
|
|
};
|
|
|
|
//
|
|
const defaultUndoItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.undo,
|
|
title: this.ResourceIDs.undo,
|
|
id: this.ActionBarItems.Undo,
|
|
slot: this.ActionBarItemSlots.END,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
|
|
//
|
|
const defaultRedoItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.redo,
|
|
title: this.ResourceIDs.redo,
|
|
id: this.ActionBarItems.Redo,
|
|
slot: this.ActionBarItemSlots.END,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
|
|
//
|
|
const defaultBeautifyItem: XActionBarItem = {
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled,
|
|
icon: this.IconNames.ul,
|
|
id: this.ActionBarItems.Beautify,
|
|
slot: this.ActionBarItemSlots.END,
|
|
title: this.ResourceIDs.ide_format,
|
|
iconColor: this.defaultActionBarItemColor,
|
|
};
|
|
//#endregion
|
|
|
|
//
|
|
this.actionBarActions = [];
|
|
this.detectChanges();
|
|
|
|
//
|
|
const availableItems = await this.getArrayValueAsync(
|
|
this.availableActionBarItems
|
|
);
|
|
if (!this.hasChild(availableItems)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const actionBarItems: XActionBarItem[] = [];
|
|
const currentTabDescriptor = this.getCurrentTabDescritor();
|
|
|
|
//
|
|
//#region Save ...
|
|
const hasSaveItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.Save);
|
|
|
|
//
|
|
if (hasSaveItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.Save
|
|
);
|
|
const providedSaveItem = selectedItem.descriptor;
|
|
let saveItem = {
|
|
...defaultSaveItem,
|
|
};
|
|
if (!isNullOrUndefined(providedSaveItem)) {
|
|
saveItem = {
|
|
...saveItem,
|
|
...providedSaveItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
saveItem = {
|
|
...saveItem,
|
|
disabled:
|
|
this.uiDisabled || !isNullOrUndefined(currentTabDescriptor)
|
|
? !currentTabDescriptor.canSave
|
|
: true,
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(saveItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Close ...
|
|
const hasCloseItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.Close);
|
|
const hasCloseOnDefaultTab = await this.getValueAsync(
|
|
this.hasCloseOnDefaultTab
|
|
);
|
|
|
|
//
|
|
const currentTabIndex = this.getTabDescritorIndex(this.currentTab);
|
|
if (
|
|
hasCloseItem
|
|
&& (!!hasCloseOnDefaultTab
|
|
? true
|
|
: currentTabIndex !== 0
|
|
)
|
|
&& currentTabIndex > -1) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.Close
|
|
);
|
|
const providedCloseItem = selectedItem.descriptor;
|
|
let closeItem = {
|
|
...defaultCloseItem,
|
|
};
|
|
if (!isNullOrUndefined(providedCloseItem)) {
|
|
closeItem = {
|
|
...closeItem,
|
|
...providedCloseItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
closeItem = {
|
|
...closeItem,
|
|
disabled: this.uiDisabled,
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(closeItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Unde ...
|
|
const hasUndoItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.Undo);
|
|
|
|
//
|
|
if (hasUndoItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.Undo
|
|
);
|
|
const providedUndoItem = selectedItem.descriptor;
|
|
let undoItem = {
|
|
...defaultUndoItem,
|
|
};
|
|
if (!isNullOrUndefined(providedUndoItem)) {
|
|
undoItem = {
|
|
...undoItem,
|
|
...providedUndoItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
// Prepare Disable/Enable Toggling of Item ...
|
|
undoItem = {
|
|
...undoItem,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
!this.CODE_EDITOR.getSession().getUndoManager().canUndo() ||
|
|
isNullOrUndefined(this.CODE_EDITOR.getSession().getUndoManager()),
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(undoItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Redo ...
|
|
const hasRedoItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.Redo);
|
|
|
|
//
|
|
if (hasRedoItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.Redo
|
|
);
|
|
const providedRedoItem = selectedItem.descriptor;
|
|
let redoItem = {
|
|
...defaultRedoItem,
|
|
};
|
|
if (!isNullOrUndefined(providedRedoItem)) {
|
|
redoItem = {
|
|
...redoItem,
|
|
...providedRedoItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
// Prepare Disable/Enable Toggling of Item ...
|
|
redoItem = {
|
|
...redoItem,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
!this.CODE_EDITOR.getSession().getUndoManager().canRedo() ||
|
|
isNullOrUndefined(this.CODE_EDITOR.getSession().getUndoManager()),
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(redoItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Beautify ...
|
|
const hasBeautifyItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.Beautify);
|
|
|
|
//
|
|
if (hasBeautifyItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.Beautify
|
|
);
|
|
const providedBeautifyItem = selectedItem.descriptor;
|
|
let beautifyItem = {
|
|
...defaultBeautifyItem,
|
|
};
|
|
if (!isNullOrUndefined(providedBeautifyItem)) {
|
|
beautifyItem = {
|
|
...beautifyItem,
|
|
...providedBeautifyItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
// Prepare Disable/Enable Toggling of Item ...
|
|
beautifyItem = {
|
|
...beautifyItem,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
isNullOrUndefined(this.CODE_EDITOR) ||
|
|
!isNullOrUndefined(currentTabDescriptor)
|
|
? !currentTabDescriptor.canBeautify
|
|
: true || isNullOrUndefined(this.CODE_EDITOR_BEAUTIFY),
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(beautifyItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Mode ...
|
|
const hasModeChangeItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.ChangeMode);
|
|
|
|
//
|
|
if (hasModeChangeItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.ChangeMode
|
|
);
|
|
const providedModeItem = selectedItem.descriptor;
|
|
let modeItem = {
|
|
...defaultModeItem,
|
|
};
|
|
if (!isNullOrUndefined(providedModeItem)) {
|
|
modeItem = {
|
|
...modeItem,
|
|
...providedModeItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
modeItem = {
|
|
...modeItem,
|
|
disabled: this.uiDisabled,
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(modeItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Theme ...
|
|
const hasThemeChangeItem = availableItems
|
|
.map((ai) => ai.actionId)
|
|
.includes(this.ActionBarItems.ChangeTheme);
|
|
|
|
//
|
|
if (hasThemeChangeItem) {
|
|
//
|
|
const selectedItem = availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.ChangeTheme
|
|
);
|
|
const providedThemeItem = selectedItem.descriptor;
|
|
let themeItem = {
|
|
...defaultThemeItem,
|
|
};
|
|
if (!isNullOrUndefined(providedThemeItem)) {
|
|
themeItem = {
|
|
...themeItem,
|
|
...providedThemeItem,
|
|
};
|
|
}
|
|
|
|
//
|
|
themeItem = {
|
|
...themeItem,
|
|
disabled: this.uiDisabled,
|
|
};
|
|
|
|
//
|
|
actionBarItems.push(themeItem);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.actionBarActions = [...actionBarItems];
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
//#region Tabs Handlers ...
|
|
private async handleDefaultTabNameChanged (
|
|
defaultTabName: XStandardType<string>
|
|
) {
|
|
//
|
|
let value = await this.getValueAsync(defaultTabName);
|
|
if (isNullOrEmptyString(value)) {
|
|
value = XIDEDefaultTabName;
|
|
}
|
|
|
|
//
|
|
if (!this.hasChild(this.Sessions)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (
|
|
this.currentTab === XIDEDefaultTabName ||
|
|
this.currentTab === this.Sessions[0].name
|
|
) {
|
|
this.currentTab = value;
|
|
}
|
|
|
|
//
|
|
this.Sessions[0].name = value;
|
|
|
|
//
|
|
this.prepareActionBar();
|
|
this.detectChanges();
|
|
}
|
|
|
|
private handleRemoveTab (name: string, destinationTabIndex: number) {
|
|
//
|
|
if (
|
|
destinationTabIndex <= 0 ||
|
|
isNullOrEmptyString(name) ||
|
|
destinationTabIndex > this.Sessions.length - 1
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.Sessions.splice(destinationTabIndex, 1);
|
|
this.detectChanges();
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.Refresh,
|
|
});
|
|
|
|
//
|
|
const canShowNewTab = name === this.currentTab;
|
|
if (canShowNewTab) {
|
|
//
|
|
const newTabIndex = this.Sessions.length - 1;
|
|
|
|
//
|
|
if (countChild(this.Sessions) > 1) {
|
|
//
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.TO,
|
|
payload: newTabIndex,
|
|
});
|
|
|
|
//
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.Refresh,
|
|
});
|
|
}
|
|
|
|
//
|
|
const newTab = this.Sessions[newTabIndex];
|
|
this.showTab(newTab.name);
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar Handlers ...
|
|
private handleActionModeFired (event: Event) {
|
|
this.getValue(this.mode)
|
|
.pipe(
|
|
concatMap((mode) =>
|
|
this.getArrayValue(this.availableActionBarItems).pipe(
|
|
map((availableItems) => {
|
|
return {
|
|
mode,
|
|
availableItems,
|
|
};
|
|
})
|
|
)
|
|
)
|
|
)
|
|
.subscribe((info) => {
|
|
//
|
|
// Selected Item Model ...
|
|
const selectedItemModel = info.availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.ChangeMode
|
|
);
|
|
|
|
//
|
|
// get Item Colors ...
|
|
const itemsColor = selectedItemModel.itemsColor;
|
|
|
|
//
|
|
// Retrieve Popover Present Options ...
|
|
const popoverPresentOptions = selectedItemModel.popoverPresentOptions;
|
|
|
|
//
|
|
// Generate Available Modes ...
|
|
const availableModes = Object.keys(this.Modes)
|
|
//
|
|
// By Filtering Curent Mode ...
|
|
.filter((key) => this.Modes[key] !== info.mode);
|
|
|
|
//
|
|
// Convert Available Modes to XPopoverOptions ...
|
|
const options = availableModes.map((key) => {
|
|
return {
|
|
id: key,
|
|
color: !isNullOrEmptyString(itemsColor)
|
|
? itemsColor
|
|
: this.ColorNames.Dark,
|
|
title: key,
|
|
handler: () => {
|
|
//
|
|
this.mode = this.Modes[key];
|
|
this.setMode(this.Modes[key]);
|
|
},
|
|
} as XPopoverOption;
|
|
});
|
|
|
|
//
|
|
// Present Popover Options ...
|
|
this.popoverService.presentContextMenu(
|
|
options,
|
|
event,
|
|
popoverPresentOptions
|
|
);
|
|
});
|
|
}
|
|
|
|
private handleActionThemFired (event: Event) {
|
|
this.getValue(this.theme)
|
|
.pipe(
|
|
concatMap((theme) =>
|
|
this.getArrayValue(this.availableActionBarItems).pipe(
|
|
map((availableItems) => {
|
|
return {
|
|
theme,
|
|
availableItems,
|
|
};
|
|
})
|
|
)
|
|
)
|
|
)
|
|
.subscribe((info) => {
|
|
//
|
|
// Selected Item Model ...
|
|
const selectedItemModel = info.availableItems.find(
|
|
(ai) => ai.actionId === this.ActionBarItems.ChangeTheme
|
|
);
|
|
|
|
//
|
|
// get Item Colors ...
|
|
const itemsColor = selectedItemModel.itemsColor;
|
|
|
|
//
|
|
// Retrieve Popover Present Options ...
|
|
const popoverPresentOptions = selectedItemModel.popoverPresentOptions;
|
|
|
|
//
|
|
// Generate Available Themes ...
|
|
const availableThemes = Object.keys(this.Themes)
|
|
//
|
|
// By Filtering Curent Theme ...
|
|
.filter((key) => this.Themes[key] !== info.theme);
|
|
|
|
//
|
|
// Convert Available Themes to XPopoverOptions ...
|
|
const options = availableThemes.map((key) => {
|
|
return {
|
|
id: key,
|
|
color: !isNullOrEmptyString(itemsColor)
|
|
? itemsColor
|
|
: this.ColorNames.Dark,
|
|
title: key,
|
|
handler: () => {
|
|
//
|
|
this.theme = this.Themes[key];
|
|
this.setTheme(this.Themes[key]);
|
|
},
|
|
} as XPopoverOption;
|
|
});
|
|
|
|
//
|
|
// Present Popover Options ...
|
|
this.popoverService.presentContextMenu(
|
|
options,
|
|
event,
|
|
popoverPresentOptions
|
|
);
|
|
});
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIDEComponent } from './x-ide.component';
|
|
import { XTabsModule } from '../x-tabs/x-tabs.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XActionBarModule } from '../x-action-bar/x-action-bar.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XIDEComponent],
|
|
imports: [
|
|
XTabsModule,
|
|
XIconModule,
|
|
XCardModule,
|
|
CommonModule,
|
|
XActionBarModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XTabsModule,
|
|
XIconModule,
|
|
XCardModule,
|
|
CommonModule,
|
|
XIDEComponent,
|
|
XActionBarModule,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XIDEModule { }
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardActionModel,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
} from '../x-card/x-card.typings';
|
|
import * as ace from 'ace-builds';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarActionModel,
|
|
XActionBarActionFiredModel,
|
|
XComponentActionBarContainer,
|
|
IXComponentActionBarContainer,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/scrolling';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XPopoverService } from '../dialogs/x-popover/x-popover.service';
|
|
import { XTabAlign, XTabAlignIdentifier } from '../x-tabs/x-tabs.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XPopoverPresentOptions } from '../dialogs/x-popover/x-popover.typings';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Action Provider ...
|
|
export enum XIDEAction {
|
|
//
|
|
Refresh = 'refresh',
|
|
SetReadOnly = 'set_read_only',
|
|
|
|
//
|
|
AddTab = 'add_tab',
|
|
ShowTab = 'show_tab',
|
|
AddTabs = 'add_tabs',
|
|
CloseTab = 'close_tab',
|
|
|
|
//
|
|
Undo = 'undo',
|
|
Redo = 'redo',
|
|
CleaEditorHistory = 'clear_editor_history',
|
|
Beautify = 'beautify',
|
|
GoToLine = 'go_to_line',
|
|
SetContent = 'set_content',
|
|
ClearContent = 'clear_content',
|
|
|
|
//
|
|
SetMode = 'set_mode',
|
|
SetTheme = 'set_theme',
|
|
SetMinLines = 'set_min_lines',
|
|
SetMaxLines = 'set_max_lines',
|
|
SetFontSize = 'set_font_size',
|
|
SetWordWrapping = 'set_word_wrapping',
|
|
SetShowFoldWidgets = 'set_show_fold_widgets',
|
|
SetShowLineNumbers = 'set_show_line_numbers',
|
|
SetShowPrintMargin = 'set_show_print_margin',
|
|
SetHighlightActiveLine = 'set_highlight_active_line',
|
|
SetBasicAutocompletion = 'set_basic_autoc_ompletion',
|
|
}
|
|
|
|
export type XIDEActionIdentifier = XIDEAction | string;
|
|
|
|
export interface XIDEActionModel
|
|
extends XBaseActionModel<XIDEActionIdentifier> {}
|
|
//#endregion
|
|
|
|
//
|
|
// Font Size Constants ...
|
|
export const XIDEMinFontSize = 12;
|
|
export const XIDEMaxFontSize = 25;
|
|
|
|
export const XIDEDefaultTabName = 'DEFAULT';
|
|
|
|
//
|
|
type AnyTypeIndex = {
|
|
[key: string]: any;
|
|
};
|
|
|
|
//
|
|
export type XIDEOptionsType = Partial<ace.Ace.EditorOptions> & AnyTypeIndex;
|
|
|
|
//
|
|
//#region Theme ...
|
|
export enum XIDETheme {
|
|
Ambiance = 'ace/theme/ambiance',
|
|
Chaos = 'ace/theme/chaos',
|
|
Chrome = 'ace/theme/chrome',
|
|
Cloud9Day = 'ace/theme/cloud9_day',
|
|
Cloud9Night = 'ace/theme/cloud9_night',
|
|
Cloud9NightLowColor = 'ace/theme/cloud9_night_low_color',
|
|
Clouds = 'ace/theme/clouds',
|
|
CloudsMidnight = 'ace/theme/clouds_midnight',
|
|
Cobalt = 'ace/theme/cobalt',
|
|
CrimsonEditor = 'ace/theme/crimson_editor',
|
|
Dawn = 'ace/theme/dawn',
|
|
Dracula = 'ace/theme/dracula',
|
|
Dreamweaver = 'ace/theme/dreamweaver',
|
|
Eclipse = 'ace/theme/eclipse',
|
|
Github = 'ace/theme/github',
|
|
Gob = 'ace/theme/gob',
|
|
Gruvbox = 'ace/theme/gruvbox',
|
|
GruvboxDarkHard = 'ace/theme/gruvbox_dark_hard',
|
|
GruvboxLightHard = 'ace/theme/gruvbox_light_hard',
|
|
IdleFingers = 'ace/theme/idle_fingers',
|
|
Iplastic = 'ace/theme/iplastic',
|
|
Katzenmilch = 'ace/theme/katzenmilch',
|
|
KrTheme = 'ace/theme/kr_theme',
|
|
Kuroir = 'ace/theme/kuroir',
|
|
Merbivore = 'ace/theme/merbivore',
|
|
MerbivoreSoft = 'ace/theme/merbivore_soft',
|
|
MonoIndustrial = 'ace/theme/mono_industrial',
|
|
Monokai = 'ace/theme/monokai',
|
|
NordDark = 'ace/theme/nord_dark',
|
|
OneDark = 'ace/theme/one_dark',
|
|
PastelOnDark = 'ace/theme/pastel_on_dark',
|
|
SolarizedDark = 'ace/theme/solarized_dark',
|
|
SolarizedLight = 'ace/theme/solarized_light',
|
|
Sqlserver = 'ace/theme/sqlserver',
|
|
Terminal = 'ace/theme/terminal',
|
|
Textmate = 'ace/theme/textmate',
|
|
Tomorrow = 'ace/theme/tomorrow',
|
|
TomorrowNight = 'ace/theme/tomorrow_night',
|
|
TomorrowNightBlue = 'ace/theme/tomorrow_night_blue',
|
|
TomorrowNightBright = 'ace/theme/tomorrow_night_bright',
|
|
TomorrowNightEighties = 'ace/theme/tomorrow_night_eighties',
|
|
Twilight = 'ace/theme/twilight',
|
|
VibrantInk = 'ace/theme/vibrant_ink',
|
|
Xcode = 'ace/theme/xcode',
|
|
}
|
|
|
|
export type XIDEThemeIdentifier = XIDETheme | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Mode ...
|
|
export enum XIDEMode {
|
|
Abap = 'ace/mode/abap',
|
|
Abc = 'ace/mode/abc',
|
|
Actionscript = 'ace/mode/actionscript',
|
|
Ada = 'ace/mode/ada',
|
|
Alda = 'ace/mode/alda',
|
|
ApacheConf = 'ace/mode/apache_conf',
|
|
Apex = 'ace/mode/apex',
|
|
Applescript = 'ace/mode/applescript',
|
|
Aql = 'ace/mode/aql',
|
|
Asciidoc = 'ace/mode/asciidoc',
|
|
Asl = 'ace/mode/asl',
|
|
AssemblyX86 = 'ace/mode/assembly_x86',
|
|
Autohotkey = 'ace/mode/autohotkey',
|
|
Batchfile = 'ace/mode/batchfile',
|
|
C9search = 'ace/mode/c9search',
|
|
CCpp = 'ace/mode/c_cpp',
|
|
Cirru = 'ace/mode/cirru',
|
|
Clojure = 'ace/mode/clojure',
|
|
Cobol = 'ace/mode/cobol',
|
|
Coffee = 'ace/mode/coffee',
|
|
Coldfusion = 'ace/mode/coldfusion',
|
|
Crystal = 'ace/mode/crystal',
|
|
Csharp = 'ace/mode/csharp',
|
|
CsoundDocument = 'ace/mode/csound_document',
|
|
CsoundOrchestra = 'ace/mode/csound_orchestra',
|
|
CsoundScore = 'ace/mode/csound_score',
|
|
Csp = 'ace/mode/csp',
|
|
Css = 'ace/mode/css',
|
|
Curly = 'ace/mode/curly',
|
|
D = 'ace/mode/d',
|
|
Dart = 'ace/mode/dart',
|
|
Diff = 'ace/mode/diff',
|
|
Django = 'ace/mode/django',
|
|
Dockerfile = 'ace/mode/dockerfile',
|
|
Dot = 'ace/mode/dot',
|
|
Drools = 'ace/mode/drools',
|
|
Edifact = 'ace/mode/edifact',
|
|
Eiffel = 'ace/mode/eiffel',
|
|
Ejs = 'ace/mode/ejs',
|
|
Elixir = 'ace/mode/elixir',
|
|
Elm = 'ace/mode/elm',
|
|
Erlang = 'ace/mode/erlang',
|
|
Forth = 'ace/mode/forth',
|
|
Fortran = 'ace/mode/fortran',
|
|
Fsharp = 'ace/mode/fsharp',
|
|
Fsl = 'ace/mode/fsl',
|
|
Ftl = 'ace/mode/ftl',
|
|
Gcode = 'ace/mode/gcode',
|
|
Gherkin = 'ace/mode/gherkin',
|
|
Gitignore = 'ace/mode/gitignore',
|
|
Glsl = 'ace/mode/glsl',
|
|
Gobstones = 'ace/mode/gobstones',
|
|
Golang = 'ace/mode/golang',
|
|
Graphqlschema = 'ace/mode/graphqlschema',
|
|
Groovy = 'ace/mode/groovy',
|
|
Haml = 'ace/mode/haml',
|
|
Handlebars = 'ace/mode/handlebars',
|
|
Haskell = 'ace/mode/haskell',
|
|
HaskellCabal = 'ace/mode/haskell_cabal',
|
|
Haxe = 'ace/mode/haxe',
|
|
Hjson = 'ace/mode/hjson',
|
|
Html = 'ace/mode/html',
|
|
HtmlElixir = 'ace/mode/html_elixir',
|
|
HtmlRuby = 'ace/mode/html_ruby',
|
|
Ini = 'ace/mode/ini',
|
|
Io = 'ace/mode/io',
|
|
Ion = 'ace/mode/ion',
|
|
Jack = 'ace/mode/jack',
|
|
Jade = 'ace/mode/jade',
|
|
Java = 'ace/mode/java',
|
|
Javascript = 'ace/mode/javascript',
|
|
Json = 'ace/mode/json',
|
|
Json5 = 'ace/mode/json5',
|
|
Jsoniq = 'ace/mode/jsoniq',
|
|
Jsp = 'ace/mode/jsp',
|
|
Jssm = 'ace/mode/jssm',
|
|
Jsx = 'ace/mode/jsx',
|
|
Julia = 'ace/mode/julia',
|
|
Kotlin = 'ace/mode/kotlin',
|
|
Latex = 'ace/mode/latex',
|
|
Latte = 'ace/mode/latte',
|
|
Less = 'ace/mode/less',
|
|
Liquid = 'ace/mode/liquid',
|
|
Lisp = 'ace/mode/lisp',
|
|
Livescript = 'ace/mode/livescript',
|
|
Logiql = 'ace/mode/logiql',
|
|
Logtalk = 'ace/mode/logtalk',
|
|
Lsl = 'ace/mode/lsl',
|
|
Lua = 'ace/mode/lua',
|
|
Luapage = 'ace/mode/luapage',
|
|
Lucene = 'ace/mode/lucene',
|
|
Makefile = 'ace/mode/makefile',
|
|
Markdown = 'ace/mode/markdown',
|
|
Mask = 'ace/mode/mask',
|
|
Matlab = 'ace/mode/matlab',
|
|
Maze = 'ace/mode/maze',
|
|
Mediawiki = 'ace/mode/mediawiki',
|
|
Mel = 'ace/mode/mel',
|
|
Mips = 'ace/mode/mips',
|
|
Mixal = 'ace/mode/mixal',
|
|
Mushcode = 'ace/mode/mushcode',
|
|
Mysql = 'ace/mode/mysql',
|
|
Nginx = 'ace/mode/nginx',
|
|
Nim = 'ace/mode/nim',
|
|
Nix = 'ace/mode/nix',
|
|
Nsis = 'ace/mode/nsis',
|
|
Nunjucks = 'ace/mode/nunjucks',
|
|
ObjectiveC = 'ace/mode/objectivec',
|
|
Ocaml = 'ace/mode/ocaml',
|
|
Partiql = 'ace/mode/partiql',
|
|
Pascal = 'ace/mode/pascal',
|
|
Perl = 'ace/mode/perl',
|
|
Pgsql = 'ace/mode/pgsql',
|
|
Php = 'ace/mode/php',
|
|
PhpLaravelBlade = 'ace/mode/php_laravel_blade',
|
|
Pig = 'ace/mode/pig',
|
|
PlainText = 'ace/mode/plain_text',
|
|
Powershell = 'ace/mode/powershell',
|
|
Praat = 'ace/mode/praat',
|
|
Prisma = 'ace/mode/prisma',
|
|
Prolog = 'ace/mode/prolog',
|
|
Properties = 'ace/mode/properties',
|
|
Protobuf = 'ace/mode/protobuf',
|
|
Puppet = 'ace/mode/puppet',
|
|
Python = 'ace/mode/python',
|
|
Qml = 'ace/mode/qml',
|
|
R = 'ace/mode/r',
|
|
Raku = 'ace/mode/raku',
|
|
Razor = 'ace/mode/razor',
|
|
Rdoc = 'ace/mode/rdoc',
|
|
Red = 'ace/mode/red',
|
|
Redshift = 'ace/mode/redshift',
|
|
Rhtml = 'ace/mode/rhtml',
|
|
Robot = 'ace/mode/robot',
|
|
Rst = 'ace/mode/rst',
|
|
Ruby = 'ace/mode/ruby',
|
|
Rust = 'ace/mode/rust',
|
|
Sac = 'ace/mode/sac',
|
|
Sass = 'ace/mode/sass',
|
|
Scad = 'ace/mode/scad',
|
|
Scala = 'ace/mode/scala',
|
|
Scheme = 'ace/mode/scheme',
|
|
Scrypt = 'ace/mode/scrypt',
|
|
Scss = 'ace/mode/scss',
|
|
Sh = 'ace/mode/sh',
|
|
Sjs = 'ace/mode/sjs',
|
|
Slim = 'ace/mode/slim',
|
|
Smarty = 'ace/mode/smarty',
|
|
Smithy = 'ace/mode/smithy',
|
|
Snippets = 'ace/mode/snippets',
|
|
SoyTemplate = 'ace/mode/soy_template',
|
|
Space = 'ace/mode/space',
|
|
Sparql = 'ace/mode/sparql',
|
|
Sql = 'ace/mode/sql',
|
|
Sqlserver = 'ace/mode/sqlserver',
|
|
Stylus = 'ace/mode/stylus',
|
|
Svg = 'ace/mode/svg',
|
|
Swift = 'ace/mode/swift',
|
|
Tcl = 'ace/mode/tcl',
|
|
Terraform = 'ace/mode/terraform',
|
|
Tex = 'ace/mode/tex',
|
|
Text = 'ace/mode/text',
|
|
Textile = 'ace/mode/textile',
|
|
Toml = 'ace/mode/toml',
|
|
Tsx = 'ace/mode/tsx',
|
|
Turtle = 'ace/mode/turtle',
|
|
Twig = 'ace/mode/twig',
|
|
Typescript = 'ace/mode/typescript',
|
|
Vala = 'ace/mode/vala',
|
|
Vbscript = 'ace/mode/vbscript',
|
|
Velocity = 'ace/mode/velocity',
|
|
Verilog = 'ace/mode/verilog',
|
|
Vhdl = 'ace/mode/vhdl',
|
|
Visualforce = 'ace/mode/visualforce',
|
|
Wollok = 'ace/mode/wollok',
|
|
Xml = 'ace/mode/xml',
|
|
Xquery = 'ace/mode/xquery',
|
|
Yaml = 'ace/mode/yaml',
|
|
Zeek = 'ace/mode/zeek',
|
|
}
|
|
|
|
export type XIDEModeIdentifier = XIDEMode | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
export enum XIDEActionBarItem {
|
|
ChangeMode = 'change_mode',
|
|
ChangeTheme = 'change_theme',
|
|
Save = 'save',
|
|
Close = 'close',
|
|
Undo = 'undo',
|
|
Redo = 'redo',
|
|
Beautify = 'beautify',
|
|
}
|
|
|
|
export type XIDEActionBarItemIdentifier = XIDEActionBarItem | string;
|
|
|
|
export type XIDEActionBarItemDescriptor = Partial<
|
|
Pick<
|
|
XActionBarItem,
|
|
| 'slot'
|
|
| 'icon'
|
|
| 'title'
|
|
| 'color'
|
|
| 'onlyIcon'
|
|
| 'iconColor'
|
|
| 'titleColor'
|
|
>
|
|
>;
|
|
|
|
export interface XIDEAvailableActionBarItem {
|
|
itemsColor?: XColorIdentifier;
|
|
actionId: XIDEActionBarItemIdentifier;
|
|
descriptor?: XIDEActionBarItemDescriptor;
|
|
popoverPresentOptions?: XPopoverPresentOptions;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region IDETabs ...
|
|
export interface XIDETabDescriptor {
|
|
name: string;
|
|
content?: string;
|
|
canSave?: boolean;
|
|
forceShow?: boolean;
|
|
canBeautify?: boolean;
|
|
mode?: XIDEModeIdentifier;
|
|
session?: ace.Ace.EditSession;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Container ...
|
|
type TXIDEContainer = IXComponentCardContainer & IXComponentActionBarContainer;
|
|
export interface IXIDEContainer extends TXIDEContainer {
|
|
//
|
|
//#region Props ...
|
|
content: XStandardType<string>;
|
|
minLines: XStandardType<number>;
|
|
maxLines: XStandardType<number>;
|
|
fontSize: XStandardType<number>;
|
|
readonly: XStandardType<boolean>;
|
|
contentChange: EventEmitter<string>;
|
|
wordWrapping: XStandardType<boolean>;
|
|
defaultTabName: XStandardType<string>;
|
|
showLineNumbers: XStandardType<boolean>;
|
|
showPrintMargin: XStandardType<boolean>;
|
|
showFoldWidgets: XStandardType<boolean>;
|
|
mode: XStandardType<XIDEModeIdentifier>;
|
|
actionProvider: Subject<XIDEActionModel>;
|
|
theme: XStandardType<XIDEThemeIdentifier>;
|
|
highlightActiveLine: XStandardType<boolean>;
|
|
basicAutocompletion: XStandardType<boolean>;
|
|
hasCloseOnDefaultTab: XStandardType<boolean>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
//#region Tabs ...
|
|
alignTabs: XStandardType<XTabAlignIdentifier>;
|
|
tabHeaderColor: XStandardType<XColorIdentifier>;
|
|
activeTabColor: XStandardType<XColorIdentifier>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
defaultActionBarItemColor: XStandardType<XColorIdentifier>;
|
|
availableActionBarItems: XStandardType<
|
|
XOneOrManyType<XIDEAvailableActionBarItem>
|
|
>;
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XIDEContainer extends XBaseContainer implements IXIDEContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self Props ...
|
|
readonly content: XStandardType<string> = '';
|
|
readonly minLines: XStandardType<number> = 10;
|
|
readonly fontSize: XStandardType<number> = XIDEMinFontSize;
|
|
readonly readonly: XStandardType<boolean> = false;
|
|
readonly actionProvider: Subject<XIDEActionModel> =
|
|
new Subject<XIDEActionModel>();
|
|
readonly maxLines: XStandardType<number> = Infinity;
|
|
readonly wordWrapping: XStandardType<boolean> = true;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly showLineNumbers: XStandardType<boolean> = true;
|
|
readonly showFoldWidgets: XStandardType<boolean> = true;
|
|
readonly showPrintMargin: XStandardType<boolean> = false;
|
|
readonly highlightActiveLine: XStandardType<boolean> = true;
|
|
readonly basicAutocompletion: XStandardType<boolean> = true;
|
|
readonly hasCloseOnDefaultTab: XStandardType<boolean> = false;
|
|
readonly defaultTabName: XStandardType<string> = XIDEDefaultTabName;
|
|
readonly mode: XStandardType<XIDEModeIdentifier> = XIDEMode.Typescript;
|
|
readonly theme: XStandardType<XIDEThemeIdentifier> = XIDETheme.Dracula;
|
|
readonly contentChange: EventEmitter<string> = new EventEmitter<string>();
|
|
|
|
//
|
|
//#region Tabs ...
|
|
readonly alignTabs: XStandardType<XTabAlignIdentifier> = XTabAlign.START;
|
|
readonly tabHeaderColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly activeTabColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
//#endregion
|
|
|
|
//
|
|
readonly availableActionBarItems: XStandardType<
|
|
XOneOrManyType<XIDEAvailableActionBarItem>
|
|
> = [
|
|
{
|
|
actionId: XIDEActionBarItem.Save,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.Close,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.Undo,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.Redo,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.Beautify,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.ChangeTheme,
|
|
},
|
|
{
|
|
actionId: XIDEActionBarItem.ChangeMode,
|
|
},
|
|
];
|
|
readonly defaultActionBarItemColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentCard Props ...
|
|
readonly isInPage: XStandardType<boolean> =
|
|
this.cardPropertyProvider.isInPage;
|
|
readonly wrapWithCard: XStandardType<boolean> =
|
|
this.cardPropertyProvider.wrapWithCard;
|
|
readonly cardActionProvider: Subject<XCardActionModel> =
|
|
this.cardPropertyProvider.cardActionProvider;
|
|
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.cardPropertyProvider.cardCssClass;
|
|
readonly cardColor: XStandardType<XColorIdentifier> =
|
|
this.cardPropertyProvider.cardColor;
|
|
readonly cardForegroundColor: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardForegroundColor;
|
|
readonly cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardTitle;
|
|
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.cardPropertyProvider.cardSubTitle;
|
|
readonly cardShowFooter: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowFooter;
|
|
readonly cardShowActions: XStandardType<boolean> =
|
|
this.cardPropertyProvider.cardShowActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentActionBar Props ...
|
|
readonly showActionBar: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.showActionBar;
|
|
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.actionBarPropertyProvider.actionBarActionProvider;
|
|
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.actionBarPropertyProvider.actionBarCssClass;
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.actionBarPropertyProvider.actionBarColor;
|
|
readonly actionBarForegroundColor: XStandardType<boolean> =
|
|
this.actionBarPropertyProvider.actionBarForegroundColor;
|
|
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.actionBarPropertyProvider.actionBarActions;
|
|
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.actionBarPropertyProvider.actionBarActionFired;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected cardPropertyProvider: XComponentCardContainer,
|
|
protected actionBarPropertyProvider: XComponentActionBarContainer
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XIDEContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXIDEContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self Props ...
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
defaultTabName: XStandardType<string> = this.propertyProvider.defaultTabName;
|
|
|
|
@Input()
|
|
hasCloseOnDefaultTab: XStandardType<boolean> = this.propertyProvider.hasCloseOnDefaultTab;
|
|
|
|
@Input()
|
|
theme: XStandardType<XIDEThemeIdentifier> = this.propertyProvider.theme;
|
|
|
|
@Input()
|
|
mode: XStandardType<XIDEModeIdentifier> = this.propertyProvider.mode;
|
|
|
|
@Input()
|
|
minLines: XStandardType<number> = this.propertyProvider.minLines;
|
|
|
|
@Input()
|
|
maxLines: XStandardType<number> = this.propertyProvider.maxLines;
|
|
|
|
@Input()
|
|
fontSize: XStandardType<number> = this.propertyProvider.fontSize;
|
|
|
|
@Input()
|
|
readonly: XStandardType<boolean> = this.propertyProvider.readonly;
|
|
|
|
@Input()
|
|
highlightActiveLine: XStandardType<boolean> =
|
|
this.propertyProvider.highlightActiveLine;
|
|
|
|
@Input()
|
|
wordWrapping: XStandardType<boolean> = this.propertyProvider.wordWrapping;
|
|
|
|
@Input()
|
|
showLineNumbers: XStandardType<boolean> =
|
|
this.propertyProvider.showLineNumbers;
|
|
|
|
@Input()
|
|
showPrintMargin: XStandardType<boolean> =
|
|
this.propertyProvider.showPrintMargin;
|
|
|
|
@Input()
|
|
showFoldWidgets: XStandardType<boolean> =
|
|
this.propertyProvider.showFoldWidgets;
|
|
|
|
@Input()
|
|
basicAutocompletion: XStandardType<boolean> =
|
|
this.propertyProvider.basicAutocompletion;
|
|
|
|
@Input()
|
|
content: XStandardType<string> = this.propertyProvider.content;
|
|
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XIDEActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Output()
|
|
contentChange: EventEmitter<string> = this.propertyProvider.contentChange;
|
|
|
|
//
|
|
//#region Tabs ...
|
|
@Input()
|
|
alignTabs: XStandardType<XTabAlignIdentifier> =
|
|
this.propertyProvider.alignTabs;
|
|
|
|
@Input()
|
|
tabHeaderColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.tabHeaderColor;
|
|
|
|
@Input()
|
|
activeTabColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.activeTabColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
@Input()
|
|
defaultActionBarItemColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.defaultActionBarItemColor;
|
|
|
|
@Input()
|
|
availableActionBarItems: XStandardType<
|
|
XOneOrManyType<XIDEAvailableActionBarItem>
|
|
> = this.propertyProvider.availableActionBarItems;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentCard Props ...
|
|
@Input()
|
|
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
|
|
|
|
@Input()
|
|
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
|
|
|
|
@Input()
|
|
cardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
|
|
@Input()
|
|
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
|
|
|
|
@Input()
|
|
cardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
|
|
@Input()
|
|
cardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
|
|
@Input()
|
|
cardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
|
|
@Input()
|
|
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
|
|
|
|
@Input()
|
|
cardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
|
|
@Input()
|
|
cardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentActionBar Props ...
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
@Input()
|
|
actionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
|
|
@Output()
|
|
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.propertyProvider.actionBarActionFired;
|
|
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XIDEContainer,
|
|
protected popoverService: XPopoverService
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstracts ...
|
|
public extractProps(container?: IXIDEContainer): Observable<IXIDEContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region Self Props ...
|
|
minLines: this.getValue(container ? container.minLines : this.minLines),
|
|
maxLines: this.getValue(container ? container.maxLines : this.maxLines),
|
|
fontSize: this.getValue(container ? container.fontSize : this.fontSize),
|
|
readonly: this.getValue(container ? container.readonly : this.readonly),
|
|
content: this.getValue(container ? container.content : this.content),
|
|
mode: this.getValue(container ? container.mode : this.mode),
|
|
theme: this.getValue(container ? container.theme : this.theme),
|
|
highlightActiveLine: this.getValue(
|
|
container ? container.highlightActiveLine : this.highlightActiveLine
|
|
),
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
basicAutocompletion: this.getValue(
|
|
container ? container.basicAutocompletion : this.basicAutocompletion
|
|
),
|
|
wordWrapping: this.getValue(
|
|
container ? container.wordWrapping : this.wordWrapping
|
|
),
|
|
showPrintMargin: this.getValue(
|
|
container ? container.showPrintMargin : this.showPrintMargin
|
|
),
|
|
showLineNumbers: this.getValue(
|
|
container ? container.showLineNumbers : this.showLineNumbers
|
|
),
|
|
showFoldWidgets: this.getValue(
|
|
container ? container.showFoldWidgets : this.showFoldWidgets
|
|
),
|
|
defaultTabName: this.getValue(
|
|
container ? container.defaultTabName : this.defaultTabName
|
|
),
|
|
hasCloseOnDefaultTab: this.getValue(
|
|
container ? container.hasCloseOnDefaultTab : this.hasCloseOnDefaultTab
|
|
),
|
|
|
|
//
|
|
//#region Tabs ...
|
|
alignTabs: this.getValue(
|
|
container ? container.alignTabs : this.alignTabs
|
|
),
|
|
tabHeaderColor: this.getValue(
|
|
container ? container.tabHeaderColor : this.tabHeaderColor
|
|
),
|
|
activeTabColor: this.getValue(
|
|
container ? container.activeTabColor : this.activeTabColor
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
// ActionBar ...
|
|
defaultActionBarItemColor: this.getValue(
|
|
container
|
|
? container.defaultActionBarItemColor
|
|
: this.defaultActionBarItemColor
|
|
),
|
|
availableActionBarItems: this.getArrayValue(
|
|
container
|
|
? container.availableActionBarItems
|
|
: this.availableActionBarItems
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentCard ...
|
|
cardCssClass: this.getArrayValue(
|
|
container ? container.cardCssClass : this.cardCssClass
|
|
),
|
|
isInPage: this.getValue(container ? container.isInPage : this.isInPage),
|
|
wrapWithCard: this.getValue(
|
|
container ? container.wrapWithCard : this.wrapWithCard
|
|
),
|
|
cardShowFooter: this.getValue(
|
|
container ? container.cardShowFooter : this.cardShowFooter
|
|
),
|
|
cardShowActions: this.getValue(
|
|
container ? container.cardShowActions : this.cardShowActions
|
|
),
|
|
cardColor: this.getValue(
|
|
container ? container.cardColor : this.cardColor
|
|
),
|
|
cardForegroundColor: this.getValue(
|
|
container ? container.cardForegroundColor : this.cardForegroundColor
|
|
),
|
|
cardTitle: this.getValue(
|
|
container ? container.cardTitle : this.cardTitle
|
|
),
|
|
cardSubTitle: this.getValue(
|
|
container ? container.cardSubTitle : this.cardSubTitle
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region XComponentActionBar ...
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
actionBarActions: this.getValue(
|
|
container ? container.actionBarActions : this.actionBarActions
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
cardActionProvider: container
|
|
? container.cardActionProvider
|
|
: this.cardActionProvider,
|
|
|
|
//
|
|
actionBarActionProvider: container
|
|
? container.actionBarActionProvider
|
|
: this.actionBarActionProvider,
|
|
|
|
//
|
|
contentChange: this.contentChange,
|
|
actionBarActionFired: this.actionBarActionFired,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.html
|
|
|
|
<div
|
|
xOnEscPress="onCancel()"
|
|
[style.text-align]="alignImage"
|
|
class="x-image-croppert x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<img
|
|
#sourceImage
|
|
class="source-image"
|
|
[src]="safeImgDataUrl"
|
|
(load)="handleImageLoadedInView()"
|
|
[style.visibility]="imageVisible ? 'visible' : 'hidden'"
|
|
/>
|
|
<div
|
|
class="cropper"
|
|
*ngIf="imageVisible"
|
|
[class.rounded]="roundCropper"
|
|
[style.top.px]="cropper.y1"
|
|
[style.left.px]="cropper.x1"
|
|
[style.width.px]="cropper.x2 - cropper.x1"
|
|
[style.height.px]="cropper.y2 - cropper.y1"
|
|
[style.margin-left]="alignImage === 'center' ? marginLeft : null"
|
|
[style.visibility]="imageVisible ? 'visible' : 'hidden'"
|
|
>
|
|
<div
|
|
(mousedown)="handleStartMove($event, 'move')"
|
|
(touchstart)="handleStartMove($event, 'move')"
|
|
class="move"
|
|
>
|
|
|
|
</div>
|
|
<span
|
|
class="resize topleft"
|
|
(mousedown)="handleStartMove($event, 'resize', 'topleft')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'topleft')"
|
|
><span class="square"></span
|
|
></span>
|
|
<span class="resize top"><span class="square"></span></span>
|
|
<span
|
|
class="resize topright"
|
|
(mousedown)="handleStartMove($event, 'resize', 'topright')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'topright')"
|
|
><span class="square"></span
|
|
></span>
|
|
<span class="resize right"><span class="square"></span></span>
|
|
<span
|
|
class="resize bottomright"
|
|
(mousedown)="handleStartMove($event, 'resize', 'bottomright')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'bottomright')"
|
|
><span class="square"></span
|
|
></span>
|
|
<span class="resize bottom"><span class="square"></span></span>
|
|
<span
|
|
class="resize bottomleft"
|
|
(mousedown)="handleStartMove($event, 'resize', 'bottomleft')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'bottomleft')"
|
|
><span class="square"></span
|
|
></span>
|
|
<span class="resize left"><span class="square"></span></span>
|
|
<span
|
|
class="resize-bar top"
|
|
(mousedown)="handleStartMove($event, 'resize', 'top')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'top')"
|
|
></span>
|
|
<span
|
|
class="resize-bar right"
|
|
(mousedown)="handleStartMove($event, 'resize', 'right')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'right')"
|
|
></span>
|
|
<span
|
|
class="resize-bar bottom"
|
|
(mousedown)="handleStartMove($event, 'resize', 'bottom')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'bottom')"
|
|
></span>
|
|
<span
|
|
class="resize-bar left"
|
|
(mousedown)="handleStartMove($event, 'resize', 'left')"
|
|
(touchstart)="handleStartMove($event, 'resize', 'left')"
|
|
></span>
|
|
</div>
|
|
|
|
<div class="actions" fxLayout="col" fxLayoutAlign="space-between center">
|
|
<button color="primary" mat-raised-button (click)="handleCancel()">
|
|
<x-icon [name]="'cancel'"></x-icon>
|
|
</button>
|
|
|
|
<button color="primary" mat-raised-button (click)="handleRotateLeft()">
|
|
<x-icon [name]="'rotate_left'"></x-icon>
|
|
</button>
|
|
|
|
<button color="primary" mat-raised-button (click)="handleFlipHorizontal()">
|
|
<x-icon [name]="'swap_horiz'"></x-icon>
|
|
</button>
|
|
|
|
<button color="primary" mat-raised-button (click)="handleFlipVertical()">
|
|
<x-icon [name]="'swap_vert'"></x-icon>
|
|
</button>
|
|
|
|
<button color="primary" mat-raised-button (click)="handleRotateRight()">
|
|
<x-icon [name]="'rotate_right'"></x-icon>
|
|
</button>
|
|
|
|
<button color="primary" mat-raised-button (click)="handleOk()">
|
|
<x-icon [name]="'done'"></x-icon>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.scss
|
|
|
|
:host::ng-deep .mat-dialog-container {
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
}
|
|
|
|
x-icon,
|
|
mat-icon {
|
|
color: white;
|
|
}
|
|
|
|
|
|
:host {
|
|
display: flex;
|
|
position: relative;
|
|
|
|
width: 100%;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
|
|
padding-top: 6px;
|
|
|
|
overflow: hidden;
|
|
|
|
text-align: center;
|
|
-webkit-user-select: none;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
user-select: none;
|
|
}
|
|
|
|
:host > div {
|
|
position: relative;
|
|
width: 100%;
|
|
}
|
|
|
|
:host div > img.source-image {
|
|
max-width: 98%;
|
|
max-height: 98%;
|
|
}
|
|
|
|
.actions {
|
|
margin: 2px;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.actions > button {
|
|
width: 36px;
|
|
min-width: 36px;
|
|
|
|
height: 36px36px;
|
|
min-height: 36px;
|
|
|
|
padding: 0;
|
|
}
|
|
|
|
.cropper {
|
|
position: absolute;
|
|
display: flex;
|
|
color: #53535c;
|
|
background: transparent;
|
|
outline-color: rgba(255, 255, 255, 0.3);
|
|
outline-width: 100vw;
|
|
outline-style: solid;
|
|
touch-action: none;
|
|
}
|
|
@media (orientation: portrait) {
|
|
.cropper {
|
|
outline-width: 100vh;
|
|
}
|
|
}
|
|
.cropper:after {
|
|
position: absolute;
|
|
content: '';
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
pointer-events: none;
|
|
border: dashed 1px;
|
|
opacity: 0.75;
|
|
color: inherit;
|
|
z-index: 1;
|
|
}
|
|
.cropper .move {
|
|
width: 100%;
|
|
cursor: move;
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
.cropper .resize {
|
|
position: absolute;
|
|
display: inline-block;
|
|
line-height: 6px;
|
|
padding: 8px;
|
|
opacity: 0.85;
|
|
z-index: 1;
|
|
}
|
|
.cropper .resize .square {
|
|
display: inline-block;
|
|
background: #53535c;
|
|
width: 6px;
|
|
height: 6px;
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
box-sizing: content-box;
|
|
}
|
|
.cropper .resize.topleft {
|
|
top: -12px;
|
|
left: -12px;
|
|
cursor: nwse-resize;
|
|
}
|
|
.cropper .resize.top {
|
|
top: -12px;
|
|
left: calc(50% - 12px);
|
|
cursor: ns-resize;
|
|
}
|
|
.cropper .resize.topright {
|
|
top: -12px;
|
|
right: -12px;
|
|
cursor: nesw-resize;
|
|
}
|
|
.cropper .resize.right {
|
|
top: calc(50% - 12px);
|
|
right: -12px;
|
|
cursor: ew-resize;
|
|
}
|
|
.cropper .resize.bottomright {
|
|
bottom: -12px;
|
|
right: -12px;
|
|
cursor: nwse-resize;
|
|
}
|
|
.cropper .resize.bottom {
|
|
bottom: -12px;
|
|
left: calc(50% - 12px);
|
|
cursor: ns-resize;
|
|
}
|
|
.cropper .resize.bottomleft {
|
|
bottom: -12px;
|
|
left: -12px;
|
|
cursor: nesw-resize;
|
|
}
|
|
.cropper .resize.left {
|
|
top: calc(50% - 12px);
|
|
left: -12px;
|
|
cursor: ew-resize;
|
|
}
|
|
.cropper .resize-bar {
|
|
position: absolute;
|
|
z-index: 1;
|
|
}
|
|
.cropper .resize-bar.top {
|
|
top: -11px;
|
|
left: 11px;
|
|
width: calc(100% - 22px);
|
|
height: 22px;
|
|
cursor: ns-resize;
|
|
}
|
|
.cropper .resize-bar.right {
|
|
top: 11px;
|
|
right: -11px;
|
|
height: calc(100% - 22px);
|
|
width: 22px;
|
|
cursor: ew-resize;
|
|
}
|
|
.cropper .resize-bar.bottom {
|
|
bottom: -11px;
|
|
left: 11px;
|
|
width: calc(100% - 22px);
|
|
height: 22px;
|
|
cursor: ns-resize;
|
|
}
|
|
.cropper .resize-bar.left {
|
|
top: 11px;
|
|
left: -11px;
|
|
height: calc(100% - 22px);
|
|
width: 22px;
|
|
cursor: ew-resize;
|
|
}
|
|
.cropper.rounded {
|
|
outline-color: transparent;
|
|
}
|
|
.cropper.rounded:after {
|
|
border-radius: 100%;
|
|
box-shadow: 0 0 0 100vw rgba(255, 255, 255, 0.3);
|
|
}
|
|
@media (orientation: portrait) {
|
|
.cropper.rounded:after {
|
|
box-shadow: 0 0 0 100vh rgba(255, 255, 255, 0.3);
|
|
}
|
|
}
|
|
.cropper.rounded .move {
|
|
border-radius: 100%;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.ts
|
|
|
|
import {
|
|
NgZone,
|
|
Inject,
|
|
Component,
|
|
ViewChild,
|
|
Renderer2,
|
|
ElementRef,
|
|
HostListener,
|
|
ChangeDetectorRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
isPromise,
|
|
resizeCanvas,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
resetExifOrientation,
|
|
transformBase64BasedOnExifRotation,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XMoveStart,
|
|
XDimensions,
|
|
XOutputType,
|
|
XCropperPosition,
|
|
XImageCroppedEvent,
|
|
XImageCropperAction,
|
|
XImageCropperContainer,
|
|
XImageCropperProperties,
|
|
XImageCropperActionModel,
|
|
XImageCropperContainerComponent,
|
|
} from './x-image-cropper.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
import { SafeUrl, SafeStyle, DomSanitizer } from '@angular/platform-browser';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from './../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-image-cropper',
|
|
templateUrl: './x-image-cropper.component.html',
|
|
styleUrls: ['./x-image-cropper.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XImageCropperComponent extends XImageCropperContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
private originalImage: any;
|
|
private originalBase64: string;
|
|
private moveStart: XMoveStart;
|
|
private maxSize: XDimensions;
|
|
private originalSize: XDimensions;
|
|
private setImageMaxSizeRetries = 0;
|
|
private cropperScaledMinWidth = 20;
|
|
private cropperScaledMinHeight = 20;
|
|
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
safeImgDataUrl: SafeUrl | string;
|
|
marginLeft: SafeStyle | string = '0px';
|
|
marginRight: SafeStyle | string = '0px';
|
|
imageVisible = false;
|
|
|
|
//
|
|
@ViewChild('sourceImage', { static: false })
|
|
sourceImage: ElementRef;
|
|
|
|
//
|
|
//#region Host Listeners ...
|
|
@HostListener('window:resize')
|
|
onResize(): void {
|
|
this.resizeCropperPosition();
|
|
this.setMaxSize();
|
|
this.setCropperScaledMinSize();
|
|
}
|
|
|
|
@HostListener('document:mousemove', ['$event'])
|
|
@HostListener('document:touchmove', ['$event'])
|
|
moveImg(event: any): void {
|
|
if (this.moveStart.active) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
if (this.moveStart.type === 'move') {
|
|
this.move(event);
|
|
this.checkCropperPosition(true);
|
|
} else if (this.moveStart.type === 'resize') {
|
|
this.resize(event);
|
|
this.checkCropperPosition(false);
|
|
}
|
|
this.changeDetector.detectChanges();
|
|
}
|
|
}
|
|
|
|
@HostListener('document:mouseup')
|
|
@HostListener('document:touchend')
|
|
moveStop(): void {
|
|
if (this.moveStart.active) {
|
|
this.moveStart.active = false;
|
|
this.doAutoCrop();
|
|
}
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XImageCropperContainer,
|
|
private sanitizer: DomSanitizer,
|
|
@Inject(MAT_DIALOG_DATA) private data: any,
|
|
private dialogRef: MatDialogRef<XImageCropperComponent>
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onInit() {
|
|
this.startUp();
|
|
}
|
|
|
|
onChanges(changeKeys: string[]): void {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ImageFileChanged ...
|
|
const isImageFileChangedChanged = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('imageFileChanged')
|
|
);
|
|
if (isImageFileChangedChanged) {
|
|
//
|
|
this.initCropper();
|
|
if (this.imageFileChanged) {
|
|
this.loadImageFile(this.imageFileChanged);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Image Changed Event Changed ...
|
|
const isImageChangedEventChanged = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('imageChangedEvent')
|
|
);
|
|
if (isImageChangedEventChanged) {
|
|
//
|
|
this.initCropper();
|
|
if (
|
|
this.imageChangedEvent &&
|
|
this.imageChangedEvent.target &&
|
|
this.imageChangedEvent.target.files &&
|
|
this.imageChangedEvent.target.files.length > 0
|
|
) {
|
|
this.loadImageFile(this.imageChangedEvent.target.files[0]);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region CropperChanged ...
|
|
const isCropperChanged = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('cropper')
|
|
);
|
|
if (isCropperChanged) {
|
|
//
|
|
this.setMaxSize();
|
|
this.setCropperScaledMinSize();
|
|
this.checkCropperPosition(false);
|
|
this.doAutoCrop();
|
|
this.changeDetector.markForCheck();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Aspect Ratio Changed ...
|
|
const isAspectRatioChanged = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('aspectRatio')
|
|
);
|
|
if (isAspectRatioChanged && this.imageVisible) {
|
|
this.resetCropperPosition();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ImageBase64 Changed ...
|
|
const isImageBase64Changed = changeKeys.includes(
|
|
nameof<XImageCropperComponent>('imageBase64')
|
|
);
|
|
if (isImageBase64Changed) {
|
|
//
|
|
this.initCropper();
|
|
if (!isNullOrEmptyString(this.imageBase64)) {
|
|
this.loadBase64Image(this.imageBase64);
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
handleImageLoadedInView(): void {
|
|
if (this.originalImage != null) {
|
|
this.imageLoaded.emit();
|
|
this.setImageMaxSizeRetries = 0;
|
|
setTimeout(() => this.checkImageMaxSizeRecursively());
|
|
}
|
|
}
|
|
|
|
handleCancel(): void {
|
|
this.dialogRef.close({
|
|
result: XDialogResult.Cancel,
|
|
});
|
|
}
|
|
|
|
handleOk(): void {
|
|
//
|
|
// Get Crop Result and make Dialog close
|
|
// Strategy based on it ...
|
|
const res = this.crop();
|
|
|
|
//
|
|
// if result is null ...
|
|
if (isNullOrUndefined(res)) {
|
|
//
|
|
this.dialogRef.close({
|
|
event: null,
|
|
result: XDialogResult.Ok,
|
|
});
|
|
//
|
|
// if result is Promise Object ...
|
|
} else if (isPromise(res)) {
|
|
//
|
|
(res as Promise<XImageCroppedEvent>).then((event) => {
|
|
this.dialogRef.close({
|
|
event,
|
|
result: XDialogResult.Ok,
|
|
});
|
|
});
|
|
//
|
|
// if result ir ImagedCroppedEvent instance ...
|
|
} else {
|
|
this.dialogRef.close({
|
|
event: res,
|
|
result: XDialogResult.Ok,
|
|
});
|
|
}
|
|
}
|
|
|
|
handleRotateLeft() {
|
|
this.rotateLeft();
|
|
}
|
|
|
|
handleFlipHorizontal() {
|
|
this.flipHorizontal();
|
|
}
|
|
|
|
handleFlipVertical() {
|
|
this.flipVertical();
|
|
}
|
|
|
|
handleRotateRight() {
|
|
this.rotateRight();
|
|
}
|
|
|
|
handleStartMove(
|
|
event: any,
|
|
moveType: string,
|
|
position: string | null = null
|
|
): void {
|
|
event.preventDefault();
|
|
this.moveStart = {
|
|
active: true,
|
|
type: moveType,
|
|
position,
|
|
clientX: this.getClientX(event),
|
|
clientY: this.getClientY(event),
|
|
...this.cropper,
|
|
};
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
rotateLeft() {
|
|
this.transformBase64(8);
|
|
}
|
|
|
|
rotateRight() {
|
|
this.transformBase64(6);
|
|
}
|
|
|
|
flipHorizontal() {
|
|
this.transformBase64(2);
|
|
}
|
|
|
|
flipVertical() {
|
|
this.transformBase64(4);
|
|
}
|
|
|
|
crop(
|
|
outputType: XOutputType = this.outputType
|
|
): XImageCroppedEvent | Promise<XImageCroppedEvent> | null {
|
|
if (this.sourceImage.nativeElement && this.originalImage != null) {
|
|
this.startCropImage.emit();
|
|
const imagePosition = this.getImagePosition();
|
|
const width = imagePosition.x2 - imagePosition.x1;
|
|
const height = imagePosition.y2 - imagePosition.y1;
|
|
|
|
const cropCanvas = document.createElement('canvas') as HTMLCanvasElement;
|
|
cropCanvas.width = width;
|
|
cropCanvas.height = height;
|
|
|
|
const ctx = cropCanvas.getContext('2d');
|
|
if (ctx) {
|
|
ctx.drawImage(
|
|
this.originalImage,
|
|
imagePosition.x1,
|
|
imagePosition.y1,
|
|
width,
|
|
height,
|
|
0,
|
|
0,
|
|
width,
|
|
height
|
|
);
|
|
const output = {
|
|
width,
|
|
height,
|
|
imagePosition,
|
|
cropperPosition: { ...this.cropper },
|
|
};
|
|
const resizeRatio = this.getResizeRatio(width);
|
|
if (resizeRatio !== 1) {
|
|
output.width = Math.floor(width * resizeRatio);
|
|
output.height = Math.floor(height * resizeRatio);
|
|
resizeCanvas(cropCanvas, output.width, output.height);
|
|
}
|
|
|
|
//
|
|
const result = this.cropToOutputType(outputType, cropCanvas, output);
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XImageCropperActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XImageCropperAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XImageCropperAction.RotateLeft:
|
|
this.rotateLeft();
|
|
break;
|
|
|
|
//
|
|
case XImageCropperAction.RotateRight:
|
|
this.rotateRight();
|
|
break;
|
|
|
|
//
|
|
case XImageCropperAction.FlipVertical:
|
|
this.flipVertical();
|
|
break;
|
|
|
|
//
|
|
case XImageCropperAction.FlipHorizontal:
|
|
this.flipHorizontal();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private startUp() {
|
|
//
|
|
// Handle Dialog Data ...
|
|
if (this.data) {
|
|
//
|
|
//#region Handle Properties ...
|
|
if (this.data.props) {
|
|
//
|
|
const props = this.data.props as XImageCropperProperties;
|
|
|
|
//
|
|
if (props.imagefile) {
|
|
this.imageFileChanged = props.imagefile;
|
|
}
|
|
|
|
//
|
|
if (props.imageChangedEvent) {
|
|
this.imageChangedEvent = props.imageChangedEvent;
|
|
}
|
|
|
|
//
|
|
if (props.imageBase64) {
|
|
this.imageBase64 = props.imageBase64;
|
|
}
|
|
|
|
//
|
|
if (props.format) {
|
|
this.format = props.format;
|
|
}
|
|
|
|
//
|
|
if (props.outputType) {
|
|
this.outputType = props.outputType;
|
|
}
|
|
|
|
//
|
|
if (props.alignImage) {
|
|
this.alignImage = props.alignImage;
|
|
}
|
|
|
|
//
|
|
if (props.cropper) {
|
|
this.cropper = props.cropper;
|
|
}
|
|
|
|
//
|
|
if (props.autoCrop) {
|
|
this.autoCrop = props.autoCrop;
|
|
}
|
|
|
|
//
|
|
if (props.aspectRatio) {
|
|
this.aspectRatio = props.aspectRatio;
|
|
}
|
|
|
|
//
|
|
if (props.imageQuality) {
|
|
this.imageQuality = props.imageQuality;
|
|
}
|
|
|
|
//
|
|
if (props.resizeToWidth) {
|
|
this.resizeToWidth = props.resizeToWidth;
|
|
}
|
|
|
|
//
|
|
if (props.roundCropper) {
|
|
this.roundCropper = props.roundCropper;
|
|
}
|
|
|
|
//
|
|
if (props.onlyScaleDown) {
|
|
this.onlyScaleDown = props.onlyScaleDown;
|
|
}
|
|
|
|
//
|
|
if (props.cropperMinWidth) {
|
|
this.cropperMinWidth = props.cropperMinWidth;
|
|
}
|
|
|
|
//
|
|
if (props.cropperMinHeight) {
|
|
this.cropperMinHeight = props.cropperMinHeight;
|
|
}
|
|
|
|
//
|
|
if (props.maintainAspectRatio) {
|
|
this.maintainAspectRatio = props.maintainAspectRatio;
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//
|
|
this.initCropper();
|
|
if (this.imageFileChanged) {
|
|
this.loadImageFile(this.imageFileChanged);
|
|
}
|
|
}
|
|
|
|
private initCropper(): void {
|
|
this.imageVisible = false;
|
|
this.originalImage = null;
|
|
this.safeImgDataUrl =
|
|
'data:image/png;base64,iVBORw0KGg' +
|
|
'oAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAU' +
|
|
'AAarVyFEAAAAASUVORK5CYII=';
|
|
this.moveStart = {
|
|
active: false,
|
|
type: null,
|
|
position: null,
|
|
x1: 0,
|
|
y1: 0,
|
|
x2: 0,
|
|
y2: 0,
|
|
clientX: 0,
|
|
clientY: 0,
|
|
};
|
|
this.maxSize = {
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
this.originalSize = {
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
this.cropper.x1 = -100;
|
|
this.cropper.y1 = -100;
|
|
this.cropper.x2 = 10000;
|
|
this.cropper.y2 = 10000;
|
|
}
|
|
|
|
private loadImageFile(file: File): void {
|
|
const fileReader = new FileReader();
|
|
fileReader.onload = (event: any) => {
|
|
const imageType = file.type;
|
|
if (this.isValidImageType(imageType)) {
|
|
resetExifOrientation(event.target.result)
|
|
.then((resultBase64: string) => this.loadBase64Image(resultBase64))
|
|
.catch(() => this.loadImageFailed.emit());
|
|
} else {
|
|
this.loadImageFailed.emit();
|
|
}
|
|
};
|
|
fileReader.readAsDataURL(file);
|
|
}
|
|
|
|
private isValidImageType(type: string): boolean {
|
|
return /image\/(png|jpg|jpeg|bmp|gif|tiff)/.test(type);
|
|
}
|
|
|
|
private loadBase64Image(imageBase64: string): void {
|
|
this.originalBase64 = imageBase64;
|
|
this.safeImgDataUrl =
|
|
this.sanitizer.bypassSecurityTrustResourceUrl(imageBase64);
|
|
this.originalImage = new Image();
|
|
this.originalImage.onload = () => {
|
|
this.originalSize.width = this.originalImage.width;
|
|
this.originalSize.height = this.originalImage.height;
|
|
this.changeDetector.markForCheck();
|
|
};
|
|
this.originalImage.src = imageBase64;
|
|
}
|
|
|
|
private checkImageMaxSizeRecursively(): void {
|
|
if (this.setImageMaxSizeRetries > 40) {
|
|
this.loadImageFailed.emit();
|
|
} else if (
|
|
this.sourceImage &&
|
|
this.sourceImage.nativeElement &&
|
|
this.sourceImage.nativeElement.offsetWidth > 0
|
|
) {
|
|
this.setMaxSize();
|
|
this.setCropperScaledMinSize();
|
|
this.resetCropperPosition();
|
|
this.cropperReady.emit();
|
|
this.changeDetector.markForCheck();
|
|
} else {
|
|
this.setImageMaxSizeRetries++;
|
|
setTimeout(() => {
|
|
this.checkImageMaxSizeRecursively();
|
|
}, 50);
|
|
}
|
|
}
|
|
|
|
private transformBase64(exifOrientation: number): void {
|
|
if (this.originalBase64) {
|
|
transformBase64BasedOnExifRotation(
|
|
this.originalBase64,
|
|
exifOrientation
|
|
).then((rotatedBase64: string) => this.loadBase64Image(rotatedBase64));
|
|
}
|
|
}
|
|
|
|
private resizeCropperPosition(): void {
|
|
const sourceImageElement = this.sourceImage.nativeElement;
|
|
if (
|
|
this.maxSize.width !== sourceImageElement.offsetWidth ||
|
|
this.maxSize.height !== sourceImageElement.offsetHeight
|
|
) {
|
|
this.cropper.x1 =
|
|
(this.cropper.x1 * sourceImageElement.offsetWidth) / this.maxSize.width;
|
|
this.cropper.x2 =
|
|
(this.cropper.x2 * sourceImageElement.offsetWidth) / this.maxSize.width;
|
|
this.cropper.y1 =
|
|
(this.cropper.y1 * sourceImageElement.offsetHeight) /
|
|
this.maxSize.height;
|
|
this.cropper.y2 =
|
|
(this.cropper.y2 * sourceImageElement.offsetHeight) /
|
|
this.maxSize.height;
|
|
}
|
|
}
|
|
|
|
private resetCropperPosition(): void {
|
|
const sourceImageElement = this.sourceImage.nativeElement;
|
|
if (!this.maintainAspectRatio) {
|
|
this.cropper.x1 = 0;
|
|
this.cropper.x2 = sourceImageElement.offsetWidth;
|
|
this.cropper.y1 = 0;
|
|
this.cropper.y2 = sourceImageElement.offsetHeight;
|
|
} else if (
|
|
sourceImageElement.offsetWidth / this.aspectRatio <
|
|
sourceImageElement.offsetHeight
|
|
) {
|
|
this.cropper.x1 = 0;
|
|
this.cropper.x2 = sourceImageElement.offsetWidth;
|
|
const cropperHeight = sourceImageElement.offsetWidth / this.aspectRatio;
|
|
this.cropper.y1 = (sourceImageElement.offsetHeight - cropperHeight) / 2;
|
|
this.cropper.y2 = this.cropper.y1 + cropperHeight;
|
|
} else {
|
|
this.cropper.y1 = 0;
|
|
this.cropper.y2 = sourceImageElement.offsetHeight;
|
|
const cropperWidth = sourceImageElement.offsetHeight * this.aspectRatio;
|
|
this.cropper.x1 = (sourceImageElement.offsetWidth - cropperWidth) / 2;
|
|
this.cropper.x2 = this.cropper.x1 + cropperWidth;
|
|
}
|
|
this.doAutoCrop();
|
|
this.imageVisible = true;
|
|
}
|
|
|
|
private setMaxSize(): void {
|
|
const sourceImageElement = this.sourceImage.nativeElement;
|
|
this.maxSize.width = sourceImageElement.offsetWidth;
|
|
this.maxSize.height = sourceImageElement.offsetHeight;
|
|
this.marginLeft = this.sanitizer.bypassSecurityTrustStyle(
|
|
'calc(50% - ' + this.maxSize.width / 2 + 'px)'
|
|
);
|
|
this.marginRight = this.sanitizer.bypassSecurityTrustStyle(
|
|
'calc(50% - ' + this.maxSize.width / 2 + 'px)'
|
|
);
|
|
}
|
|
|
|
private setCropperScaledMinSize(): void {
|
|
if (this.originalImage) {
|
|
this.setCropperScaledMinWidth();
|
|
this.setCropperScaledMinHeight();
|
|
} else {
|
|
this.cropperScaledMinWidth = 20;
|
|
this.cropperScaledMinHeight = 20;
|
|
}
|
|
}
|
|
|
|
private setCropperScaledMinWidth(): void {
|
|
this.cropperScaledMinWidth =
|
|
this.cropperMinWidth > 0
|
|
? Math.max(
|
|
20,
|
|
(this.cropperMinWidth / this.originalImage.width) *
|
|
this.maxSize.width
|
|
)
|
|
: 20;
|
|
}
|
|
|
|
private setCropperScaledMinHeight(): void {
|
|
if (this.maintainAspectRatio) {
|
|
this.cropperScaledMinHeight = Math.max(
|
|
20,
|
|
this.cropperScaledMinWidth / this.aspectRatio
|
|
);
|
|
} else if (this.cropperMinHeight > 0) {
|
|
this.cropperScaledMinHeight = Math.max(
|
|
20,
|
|
(this.cropperMinHeight / this.originalImage.height) *
|
|
this.maxSize.height
|
|
);
|
|
} else {
|
|
this.cropperScaledMinHeight = 20;
|
|
}
|
|
}
|
|
|
|
private checkCropperPosition(maintainSize = false): void {
|
|
if (this.cropper.x1 < 0) {
|
|
this.cropper.x2 -= maintainSize ? this.cropper.x1 : 0;
|
|
this.cropper.x1 = 0;
|
|
}
|
|
if (this.cropper.y1 < 0) {
|
|
this.cropper.y2 -= maintainSize ? this.cropper.y1 : 0;
|
|
this.cropper.y1 = 0;
|
|
}
|
|
if (this.cropper.x2 > this.maxSize.width) {
|
|
this.cropper.x1 -= maintainSize
|
|
? this.cropper.x2 - this.maxSize.width
|
|
: 0;
|
|
this.cropper.x2 = this.maxSize.width;
|
|
}
|
|
if (this.cropper.y2 > this.maxSize.height) {
|
|
this.cropper.y1 -= maintainSize
|
|
? this.cropper.y2 - this.maxSize.height
|
|
: 0;
|
|
this.cropper.y2 = this.maxSize.height;
|
|
}
|
|
}
|
|
|
|
private move(event: any) {
|
|
const diffX = this.getClientX(event) - this.moveStart.clientX;
|
|
const diffY = this.getClientY(event) - this.moveStart.clientY;
|
|
|
|
this.cropper.x1 = this.moveStart.x1 + diffX;
|
|
this.cropper.y1 = this.moveStart.y1 + diffY;
|
|
this.cropper.x2 = this.moveStart.x2 + diffX;
|
|
this.cropper.y2 = this.moveStart.y2 + diffY;
|
|
}
|
|
|
|
private resize(event: any): void {
|
|
const diffX = this.getClientX(event) - this.moveStart.clientX;
|
|
const diffY = this.getClientY(event) - this.moveStart.clientY;
|
|
switch (this.moveStart.position) {
|
|
case 'left':
|
|
this.cropper.x1 = Math.min(
|
|
this.moveStart.x1 + diffX,
|
|
this.cropper.x2 - this.cropperScaledMinWidth
|
|
);
|
|
break;
|
|
case 'topleft':
|
|
this.cropper.x1 = Math.min(
|
|
this.moveStart.x1 + diffX,
|
|
this.cropper.x2 - this.cropperScaledMinWidth
|
|
);
|
|
this.cropper.y1 = Math.min(
|
|
this.moveStart.y1 + diffY,
|
|
this.cropper.y2 - this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
case 'top':
|
|
this.cropper.y1 = Math.min(
|
|
this.moveStart.y1 + diffY,
|
|
this.cropper.y2 - this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
case 'topright':
|
|
this.cropper.x2 = Math.max(
|
|
this.moveStart.x2 + diffX,
|
|
this.cropper.x1 + this.cropperScaledMinWidth
|
|
);
|
|
this.cropper.y1 = Math.min(
|
|
this.moveStart.y1 + diffY,
|
|
this.cropper.y2 - this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
case 'right':
|
|
this.cropper.x2 = Math.max(
|
|
this.moveStart.x2 + diffX,
|
|
this.cropper.x1 + this.cropperScaledMinWidth
|
|
);
|
|
break;
|
|
case 'bottomright':
|
|
this.cropper.x2 = Math.max(
|
|
this.moveStart.x2 + diffX,
|
|
this.cropper.x1 + this.cropperScaledMinWidth
|
|
);
|
|
this.cropper.y2 = Math.max(
|
|
this.moveStart.y2 + diffY,
|
|
this.cropper.y1 + this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
case 'bottom':
|
|
this.cropper.y2 = Math.max(
|
|
this.moveStart.y2 + diffY,
|
|
this.cropper.y1 + this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
case 'bottomleft':
|
|
this.cropper.x1 = Math.min(
|
|
this.moveStart.x1 + diffX,
|
|
this.cropper.x2 - this.cropperScaledMinWidth
|
|
);
|
|
this.cropper.y2 = Math.max(
|
|
this.moveStart.y2 + diffY,
|
|
this.cropper.y1 + this.cropperScaledMinHeight
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (this.maintainAspectRatio) {
|
|
this.checkAspectRatio();
|
|
}
|
|
}
|
|
|
|
private checkAspectRatio(): void {
|
|
let overflowX = 0;
|
|
let overflowY = 0;
|
|
|
|
switch (this.moveStart.position) {
|
|
case 'top':
|
|
this.cropper.x2 =
|
|
this.cropper.x1 +
|
|
(this.cropper.y2 - this.cropper.y1) * this.aspectRatio;
|
|
overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0);
|
|
overflowY = Math.max(0 - this.cropper.y1, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y1 +=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
case 'bottom':
|
|
this.cropper.x2 =
|
|
this.cropper.x1 +
|
|
(this.cropper.y2 - this.cropper.y1) * this.aspectRatio;
|
|
overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0);
|
|
overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
case 'topleft':
|
|
this.cropper.y1 =
|
|
this.cropper.y2 -
|
|
(this.cropper.x2 - this.cropper.x1) / this.aspectRatio;
|
|
overflowX = Math.max(0 - this.cropper.x1, 0);
|
|
overflowY = Math.max(0 - this.cropper.y1, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x1 +=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y1 +=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
case 'topright':
|
|
this.cropper.y1 =
|
|
this.cropper.y2 -
|
|
(this.cropper.x2 - this.cropper.x1) / this.aspectRatio;
|
|
overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0);
|
|
overflowY = Math.max(0 - this.cropper.y1, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y1 +=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
case 'right':
|
|
case 'bottomright':
|
|
this.cropper.y2 =
|
|
this.cropper.y1 +
|
|
(this.cropper.x2 - this.cropper.x1) / this.aspectRatio;
|
|
overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0);
|
|
overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
case 'left':
|
|
case 'bottomleft':
|
|
this.cropper.y2 =
|
|
this.cropper.y1 +
|
|
(this.cropper.x2 - this.cropper.x1) / this.aspectRatio;
|
|
overflowX = Math.max(0 - this.cropper.x1, 0);
|
|
overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0);
|
|
if (overflowX > 0 || overflowY > 0) {
|
|
this.cropper.x1 +=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY * this.aspectRatio
|
|
: overflowX;
|
|
this.cropper.y2 -=
|
|
overflowY * this.aspectRatio > overflowX
|
|
? overflowY
|
|
: overflowX / this.aspectRatio;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private doAutoCrop(): void {
|
|
if (this.autoCrop) {
|
|
this.crop();
|
|
}
|
|
}
|
|
|
|
private getImagePosition(): XCropperPosition {
|
|
const sourceImageElement = this.sourceImage.nativeElement;
|
|
const ratio = this.originalSize.width / sourceImageElement.offsetWidth;
|
|
return {
|
|
x1: Math.round(this.cropper.x1 * ratio),
|
|
y1: Math.round(this.cropper.y1 * ratio),
|
|
x2: Math.min(
|
|
Math.round(this.cropper.x2 * ratio),
|
|
this.originalSize.width
|
|
),
|
|
y2: Math.min(
|
|
Math.round(this.cropper.y2 * ratio),
|
|
this.originalSize.height
|
|
),
|
|
};
|
|
}
|
|
|
|
private cropToOutputType(
|
|
outputType: XOutputType,
|
|
cropCanvas: HTMLCanvasElement,
|
|
output: XImageCroppedEvent
|
|
): XImageCroppedEvent | Promise<XImageCroppedEvent> {
|
|
switch (outputType) {
|
|
case 'file':
|
|
return this.cropToFile(cropCanvas).then((result: Blob | null) => {
|
|
output.file = result;
|
|
this.imageCropped.emit(output);
|
|
return output;
|
|
});
|
|
case 'both':
|
|
return this.cropToFile(cropCanvas).then((result: Blob | null) => {
|
|
output.base64 = this.cropToBase64(cropCanvas);
|
|
output.file = result;
|
|
this.imageCropped.emit(output);
|
|
return output;
|
|
});
|
|
default:
|
|
output.base64 = this.cropToBase64(cropCanvas);
|
|
this.imageCropped.emit(output);
|
|
return output;
|
|
}
|
|
}
|
|
|
|
private cropToBase64(cropCanvas: HTMLCanvasElement): string {
|
|
const imageBase64 = cropCanvas.toDataURL(
|
|
'image/' + this.format,
|
|
this.getQuality()
|
|
);
|
|
this.imageCroppedBase64.emit(imageBase64);
|
|
return imageBase64;
|
|
}
|
|
|
|
private cropToFile(cropCanvas: HTMLCanvasElement): Promise<Blob | null> {
|
|
return this.getCanvasBlob(cropCanvas).then((result: Blob | null) => {
|
|
if (result) {
|
|
this.imageCroppedFile.emit(result);
|
|
}
|
|
return result;
|
|
});
|
|
}
|
|
|
|
private getCanvasBlob(cropCanvas: HTMLCanvasElement): Promise<Blob | null> {
|
|
return new Promise((resolve) => {
|
|
cropCanvas.toBlob(
|
|
(result: Blob | null) => this.zone.run(() => resolve(result)),
|
|
'image/' + this.format,
|
|
this.getQuality()
|
|
);
|
|
});
|
|
}
|
|
|
|
private getQuality(): number {
|
|
return Math.min(1, Math.max(0, this.imageQuality / 100));
|
|
}
|
|
|
|
private getResizeRatio(width: number): number {
|
|
return this.resizeToWidth > 0 &&
|
|
(!this.onlyScaleDown || width > this.resizeToWidth)
|
|
? this.resizeToWidth / width
|
|
: 1;
|
|
}
|
|
|
|
private getClientX(event: any): number {
|
|
return (
|
|
event.clientX ||
|
|
(event.touches && event.touches[0] && event.touches[0].clientX)
|
|
);
|
|
}
|
|
|
|
private getClientY(event: any): number {
|
|
return (
|
|
event.clientY ||
|
|
(event.touches && event.touches[0] && event.touches[0].clientY)
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XImageCropperService } from './x-image-cropper.service';
|
|
import { XImageCropperComponent } from './x-image-cropper.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
providers: [XImageCropperService],
|
|
declarations: [XImageCropperComponent],
|
|
entryComponents: [XImageCropperComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XIconModule],
|
|
exports: [XBaseComponentModule, XIconModule, XImageCropperComponent]
|
|
})
|
|
export class XImageCropperModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.service.ts
|
|
|
|
import {
|
|
toFileBlob,
|
|
blobToFile,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import {
|
|
MatDialog,
|
|
MatDialogRef,
|
|
MatDialogConfig,
|
|
} from '@angular/material/dialog';
|
|
import {
|
|
XImageCroppedEvent,
|
|
XImageCropperResult,
|
|
XImageCropperProperties,
|
|
} from './x-image-cropper.typings';
|
|
import { XImageCropperComponent } from './x-image-cropper.component';
|
|
import { Injectable, Output, EventEmitter, Inject } from '@angular/core';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XImageCropperService {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private dialogMaxWidth: number;
|
|
private dialogMinWidth: number;
|
|
|
|
//
|
|
private sourceFile: File;
|
|
private DIALOG_REF: MatDialogRef<XImageCropperComponent>;
|
|
|
|
//
|
|
// tslint:disable-next-line:no-output-on-prefix
|
|
@Output()
|
|
onResult = new EventEmitter<XImageCropperResult>();
|
|
|
|
//
|
|
minAllowedImageSize: number;
|
|
maxAllowedImageSize: number;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
private dialog: MatDialog,
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig
|
|
) {
|
|
//
|
|
this.minAllowedImageSize = config.minAllowedImageSize;
|
|
this.maxAllowedImageSize = config.maxAllowedImageSize;
|
|
|
|
//
|
|
this.dialogMinWidth = Math.min(window.innerWidth * 0.8, 300);
|
|
this.dialogMaxWidth = Math.min(window.innerWidth * 0.8, 400);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Public Actions ...
|
|
/**
|
|
* show Image Cropper ...
|
|
* @param file the source image file ...
|
|
* @param props Image Cropper Properties ...
|
|
*/
|
|
showCropper(file: File, props?: XImageCropperProperties) {
|
|
//
|
|
this.sourceFile = file;
|
|
|
|
//
|
|
// Prepare Cropper Props ...
|
|
let cropperProps: XImageCropperProperties;
|
|
if (props) {
|
|
cropperProps = props;
|
|
if (!props.imagefile) {
|
|
cropperProps.imagefile = file;
|
|
}
|
|
cropperProps.maxSingleFileThumbSize = this.maxAllowedImageSize;
|
|
} else {
|
|
cropperProps = this.getDefaultCropperProperties(file);
|
|
}
|
|
|
|
//
|
|
const config: MatDialogConfig = {
|
|
width: this.dialogMinWidth + 'px',
|
|
minWidth: this.dialogMinWidth + 'px',
|
|
maxWidth: this.dialogMaxWidth + 'px',
|
|
data: {
|
|
props: cropperProps,
|
|
},
|
|
};
|
|
|
|
//
|
|
// Show Cropper inside a Dialog ...
|
|
this.DIALOG_REF = this.dialog.open(XImageCropperComponent, config);
|
|
this.DIALOG_REF.disableClose = true;
|
|
|
|
//
|
|
//#region Register Event Handlers ...
|
|
//
|
|
// Subscribe to Event Listener for catching Cropper Change ...
|
|
const cropperComponent = this.DIALOG_REF
|
|
? this.DIALOG_REF.componentInstance
|
|
: null;
|
|
if (cropperComponent) {
|
|
//
|
|
if (cropperProps.startCropImage) {
|
|
cropperComponent.startCropImage.asObservable().subscribe(() => {
|
|
cropperProps.startCropImage();
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.imageCropped) {
|
|
cropperComponent.imageCropped
|
|
.asObservable()
|
|
.subscribe((event: XImageCroppedEvent) => {
|
|
cropperProps.imageCropped(event);
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.imageCroppedBase64) {
|
|
cropperComponent.imageCroppedBase64
|
|
.asObservable()
|
|
.subscribe((data: string) => {
|
|
cropperProps.imageCroppedBase64(data);
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.imageCroppedFile) {
|
|
cropperComponent.imageCroppedFile
|
|
.asObservable()
|
|
.subscribe((mFile: Blob) => {
|
|
cropperProps.imageCroppedFile(mFile);
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.imageLoaded) {
|
|
cropperComponent.imageLoaded.asObservable().subscribe(() => {
|
|
cropperProps.imageLoaded();
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.cropperReady) {
|
|
cropperComponent.cropperReady.asObservable().subscribe(() => {
|
|
cropperProps.cropperReady();
|
|
});
|
|
}
|
|
|
|
//
|
|
if (cropperProps.loadImageFailed) {
|
|
cropperComponent.loadImageFailed.asObservable().subscribe(() => {
|
|
cropperProps.loadImageFailed();
|
|
});
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Handle Dialog Result ...
|
|
this.DIALOG_REF.afterClosed().subscribe((result) => {
|
|
//
|
|
if (isNullOrUndefined(result) || result.result !== XDialogResult.Ok) {
|
|
//
|
|
// Cancel Cropper ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
} else {
|
|
//
|
|
// Use Cropper Result ...
|
|
const res: XImageCroppedEvent = result.event as XImageCroppedEvent;
|
|
|
|
//
|
|
let mFile: File;
|
|
if (res.file) {
|
|
//
|
|
mFile = this.toFile(res.file);
|
|
this.sourceFile = mFile;
|
|
}
|
|
|
|
//
|
|
this.onResult.emit({
|
|
result: result.result,
|
|
data: res.base64,
|
|
file: mFile,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* close opened Dialog manually ...
|
|
*/
|
|
closeCropper() {
|
|
//
|
|
if (this.DIALOG_REF != null) {
|
|
this.DIALOG_REF.close();
|
|
}
|
|
|
|
//
|
|
this.DIALOG_REF = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private Actions ...
|
|
/**
|
|
* Prepare Default Properties for Image Cropper ...
|
|
*/
|
|
private getDefaultCropperProperties(file: File) {
|
|
return {
|
|
//
|
|
imagefile: file,
|
|
|
|
//
|
|
aspectRatio: 1,
|
|
maintainAspectRatio: true,
|
|
|
|
//
|
|
resizeToWidth: this.dialogMinWidth,
|
|
cropperMinWidth: this.minAllowedImageSize,
|
|
cropperMinHeight: this.minAllowedImageSize,
|
|
|
|
//
|
|
onlyScaleDown: true,
|
|
roundCropper: true,
|
|
|
|
//
|
|
format: 'png',
|
|
outputType: 'both',
|
|
|
|
//
|
|
maxSingleFileThumbSize: this.maxAllowedImageSize,
|
|
} as XImageCropperProperties;
|
|
}
|
|
|
|
/**
|
|
* Generate a File Blob Object based on Source Image and Cropped file ...
|
|
*/
|
|
private toFile(file: Blob): File {
|
|
//
|
|
if (!this.sourceFile) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const fileBlob = toFileBlob(this.sourceFile);
|
|
|
|
//
|
|
return blobToFile(file, fileBlob.name);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XDialogResult, XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Definitions ...
|
|
export interface XCropperPosition {
|
|
x1: number;
|
|
y1: number;
|
|
x2: number;
|
|
y2: number;
|
|
}
|
|
|
|
export interface XDimensions {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
export interface XImageCroppedEvent {
|
|
base64?: string | null;
|
|
file?: Blob | null;
|
|
width: number;
|
|
height: number;
|
|
cropperPosition: XCropperPosition;
|
|
imagePosition: XCropperPosition;
|
|
}
|
|
|
|
export interface XMoveStart {
|
|
active: boolean;
|
|
type: string | null;
|
|
position: string | null;
|
|
x1: number;
|
|
y1: number;
|
|
x2: number;
|
|
y2: number;
|
|
clientX: number;
|
|
clientY: number;
|
|
}
|
|
|
|
export interface XImageCropperProperties {
|
|
//
|
|
imageChangedEvent?: (event: any) => void;
|
|
|
|
//
|
|
imagefile?: File;
|
|
imageBase64?: string;
|
|
|
|
//
|
|
format?: XImageFormat;
|
|
outputType?: XOutputType;
|
|
alignImage?: XImageAlign;
|
|
cropper?: XCropperPosition;
|
|
|
|
//
|
|
autoCrop?: boolean;
|
|
aspectRatio?: number;
|
|
imageQuality?: number;
|
|
resizeToWidth?: number;
|
|
roundCropper?: boolean;
|
|
onlyScaleDown?: boolean;
|
|
cropperMinWidth?: number;
|
|
cropperMinHeight?: number;
|
|
maintainAspectRatio?: boolean;
|
|
|
|
//
|
|
maxSingleFileThumbSize: number;
|
|
|
|
//
|
|
startCropImage?: () => void;
|
|
imageCropped?: (event: XImageCroppedEvent) => void;
|
|
imageCroppedBase64?: (data: string) => void;
|
|
imageCroppedFile?: (file: Blob) => void;
|
|
imageLoaded?: () => void;
|
|
cropperReady?: () => void;
|
|
loadImageFailed?: () => void;
|
|
}
|
|
|
|
export interface XImageCropperResult {
|
|
result: XDialogResult;
|
|
data?: string;
|
|
file?: File;
|
|
}
|
|
|
|
export type XOutputType = 'base64' | 'file' | 'both';
|
|
|
|
export type XImageFormat = 'png' | 'jpeg' | 'bmp' | 'webp' | 'ico';
|
|
|
|
export type XImageAlign = 'left' | 'center';
|
|
//#endregion
|
|
|
|
export enum XImageCropperAction {
|
|
//
|
|
RotateLeft = 'rotate-left',
|
|
RotateRight = 'rotate-right',
|
|
FlipHorizontal = 'flip-horizontal',
|
|
FlipVertical = 'flip-vertical',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XImageCropperActionIdentifier = XImageCropperAction | string;
|
|
|
|
export interface XImageCropperActionModel
|
|
extends XBaseActionModel<XImageCropperActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXImageCropperContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XImageCropperActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
imageFileChanged: File;
|
|
imageChangedEvent: any;
|
|
imageBase64: string;
|
|
format: XImageFormat;
|
|
outputType: XOutputType;
|
|
maintainAspectRatio: boolean;
|
|
aspectRatio: number;
|
|
resizeToWidth: number;
|
|
cropperMinWidth: number;
|
|
cropperMinHeight: number;
|
|
roundCropper: boolean;
|
|
onlyScaleDown: boolean;
|
|
imageQuality: number;
|
|
autoCrop: boolean;
|
|
alignImage: XImageAlign;
|
|
cropper: XCropperPosition;
|
|
|
|
//
|
|
startCropImage: EventEmitter<void>;
|
|
imageCropped: EventEmitter<XImageCroppedEvent>;
|
|
imageCroppedBase64: EventEmitter<string>;
|
|
imageCroppedFile: EventEmitter<Blob>;
|
|
imageLoaded: EventEmitter<void>;
|
|
cropperReady: EventEmitter<void>;
|
|
loadImageFailed: EventEmitter<void>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XImageCropperContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXImageCropperContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XImageCropperActionModel> =
|
|
new Subject<XImageCropperActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly imageFileChanged: File;
|
|
readonly imageChangedEvent: any;
|
|
readonly imageBase64: string;
|
|
readonly format: XImageFormat = 'png';
|
|
readonly outputType: XOutputType = 'both';
|
|
readonly maintainAspectRatio: boolean = true;
|
|
readonly aspectRatio: number = 1;
|
|
readonly resizeToWidth: number = 0;
|
|
readonly cropperMinWidth: number = 0;
|
|
readonly cropperMinHeight: number = 0;
|
|
readonly roundCropper: boolean = false;
|
|
readonly onlyScaleDown: boolean = false;
|
|
readonly imageQuality: number = 92;
|
|
readonly autoCrop: boolean = true;
|
|
readonly alignImage: XImageAlign = 'center';
|
|
readonly cropper: XCropperPosition = {
|
|
x1: -100,
|
|
y1: -100,
|
|
x2: 10000,
|
|
y2: 10000,
|
|
};
|
|
|
|
//
|
|
readonly startCropImage: EventEmitter<void> = new EventEmitter<void>();
|
|
readonly imageCropped: EventEmitter<XImageCroppedEvent> =
|
|
new EventEmitter<XImageCroppedEvent>();
|
|
readonly imageCroppedBase64: EventEmitter<string> =
|
|
new EventEmitter<string>();
|
|
readonly imageCroppedFile: EventEmitter<Blob> = new EventEmitter<Blob>();
|
|
readonly imageLoaded: EventEmitter<void> = new EventEmitter<void>();
|
|
readonly cropperReady: EventEmitter<void> = new EventEmitter<void>();
|
|
readonly loadImageFailed: EventEmitter<void> = new EventEmitter<void>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XImageCropperContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXImageCropperContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XImageCropperActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
imageFileChanged: File = this.propertyProvider.imageFileChanged;
|
|
|
|
@Input()
|
|
imageChangedEvent: any = this.propertyProvider.imageChangedEvent;
|
|
|
|
@Input()
|
|
imageBase64: string = this.propertyProvider.imageBase64;
|
|
|
|
@Input()
|
|
format: XImageFormat = this.propertyProvider.format;
|
|
|
|
@Input()
|
|
outputType: XOutputType = this.propertyProvider.outputType;
|
|
|
|
@Input()
|
|
maintainAspectRatio: boolean = this.propertyProvider.maintainAspectRatio;
|
|
|
|
@Input()
|
|
aspectRatio: number = this.propertyProvider.aspectRatio;
|
|
|
|
@Input()
|
|
resizeToWidth: number = this.propertyProvider.resizeToWidth;
|
|
|
|
@Input()
|
|
cropperMinWidth: number = this.propertyProvider.cropperMinWidth;
|
|
|
|
@Input()
|
|
cropperMinHeight: number = this.propertyProvider.cropperMinHeight;
|
|
|
|
@Input()
|
|
roundCropper: boolean = this.propertyProvider.roundCropper;
|
|
|
|
@Input()
|
|
onlyScaleDown: boolean = this.propertyProvider.onlyScaleDown;
|
|
|
|
@Input()
|
|
imageQuality: number = this.propertyProvider.imageQuality;
|
|
|
|
@Input()
|
|
autoCrop: boolean = this.propertyProvider.autoCrop;
|
|
|
|
@Input()
|
|
alignImage: XImageAlign = this.propertyProvider.alignImage;
|
|
|
|
@Input()
|
|
cropper: XCropperPosition = this.propertyProvider.cropper;
|
|
|
|
//
|
|
@Output()
|
|
startCropImage: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Output()
|
|
imageCropped: EventEmitter<XImageCroppedEvent> = new EventEmitter();
|
|
|
|
@Output()
|
|
imageCroppedBase64: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
imageCroppedFile: EventEmitter<Blob> = new EventEmitter();
|
|
|
|
@Output()
|
|
imageLoaded: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Output()
|
|
cropperReady: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Output()
|
|
loadImageFailed: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XImageCropperContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXImageCropperContainer
|
|
): Observable<IXImageCropperContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
imageFileChanged: this.getValue(
|
|
container ? container.imageFileChanged : this.imageFileChanged
|
|
),
|
|
imageChangedEvent: this.getValue(
|
|
container ? container.imageChangedEvent : this.imageChangedEvent
|
|
),
|
|
imageBase64: this.getValue(
|
|
container ? container.imageBase64 : this.imageBase64
|
|
),
|
|
format: this.getValue(container ? container.format : this.format),
|
|
outputType: this.getValue(
|
|
container ? container.outputType : this.outputType
|
|
),
|
|
maintainAspectRatio: this.getValue(
|
|
container ? container.maintainAspectRatio : this.maintainAspectRatio
|
|
),
|
|
aspectRatio: this.getValue(
|
|
container ? container.aspectRatio : this.aspectRatio
|
|
),
|
|
resizeToWidth: this.getValue(
|
|
container ? container.resizeToWidth : this.resizeToWidth
|
|
),
|
|
cropperMinWidth: this.getValue(
|
|
container ? container.cropperMinWidth : this.cropperMinWidth
|
|
),
|
|
cropperMinHeight: this.getValue(
|
|
container ? container.cropperMinHeight : this.cropperMinHeight
|
|
),
|
|
roundCropper: this.getValue(
|
|
container ? container.roundCropper : this.roundCropper
|
|
),
|
|
onlyScaleDown: this.getValue(
|
|
container ? container.onlyScaleDown : this.onlyScaleDown
|
|
),
|
|
imageQuality: this.getValue(
|
|
container ? container.imageQuality : this.imageQuality
|
|
),
|
|
autoCrop: this.getValue(container ? container.autoCrop : this.autoCrop),
|
|
alignImage: this.getValue(
|
|
container ? container.alignImage : this.alignImage
|
|
),
|
|
cropper: this.getValue(container ? container.cropper : this.cropper),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
startCropImage: this.startCropImage,
|
|
imageCropped: this.imageCropped,
|
|
imageCroppedBase64: this.imageCroppedBase64,
|
|
imageCroppedFile: this.imageCroppedFile,
|
|
imageLoaded: this.imageLoaded,
|
|
cropperReady: this.cropperReady,
|
|
loadImageFailed: this.loadImageFailed,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else listRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="listRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- List ItSelf Template -->
|
|
<ng-template #listRef>
|
|
<div class="x-list x-wrapper" [class.mobile]="isMobileUi$ | async">
|
|
<!-- Action and Search Area Container -->
|
|
<div
|
|
class="x-list-toolbar"
|
|
*ngIf="getValue(showToolbar) | async"
|
|
[class.sticky]="getValue(stickyToolbar) | async"
|
|
>
|
|
<!-- ActionBar -->
|
|
<x-action-bar
|
|
*ngIf="getValue(showActionBar) | async"
|
|
[color]="getValue(actionBarColor) | async"
|
|
[actionProvider]="actionBarActionProvider"
|
|
[cssClass]="getValue(actionBarCssClass) | async"
|
|
(actionFired)="handleActionBarActionFired($event)"
|
|
[actions]="getArrayValue(actionBarActions) | async"
|
|
[foregroundColor]="getValue(actionBarForegroundColor) | async"
|
|
></x-action-bar>
|
|
|
|
<!-- SearchBar -->
|
|
<x-search-bar
|
|
(queryChange)="filterItems($event)"
|
|
*ngIf="getValue(showSearchBar) | async"
|
|
(onEvent)="searchBarOnEvent.emit($event)"
|
|
[type]="getValue(searchBarType) | async"
|
|
[actionProvider]="searchBarActionProvider"
|
|
[color]="getValue(searchBarColor) | async"
|
|
[value]="getValue(searchBarValue) | async"
|
|
[debounce]="getValue(searchBarDebounce) | async"
|
|
[cssClass]="getValue(searchBarCssClass) | async"
|
|
[title]="getResourceValue(searchBarTitle) | async"
|
|
[spellcheck]="getValue(searchBarSpellcheck) | async"
|
|
[foregroundSearchInputColor]="
|
|
getValue(searchBarForegroundSearchInputColor) | async
|
|
"
|
|
[enterKeyHint]="getValue(searchBarEnterKeyHint) | async"
|
|
[keyboardType]="getValue(searchBarKeyboardType) | async"
|
|
[clearButtonIcon]="getValue(searchBarClearButtonIcon) | async"
|
|
[foregroundColor]="getValue(searchBarForegroundColor) | async"
|
|
[searchButtonIcon]="getValue(searchBarSearchButtonIcon) | async"
|
|
[searchInputColor]="getValue(searchBarSearchInputColor) | async"
|
|
[cancelButtonIcon]="getValue(searchBarCancelButtonIcon) | async"
|
|
[showCancelButton]="getValue(searchBarShowCancelButton) | async"
|
|
[cancelButtonTitle]="getValue(searchBarCancelButtonTitle) | async"
|
|
[clearButtonIconColor]="getValue(searchBarClearButtonIconColor) | async"
|
|
[searchButtonIconColor]="
|
|
getValue(searchBarSearchButtonIconColor) | async
|
|
"
|
|
></x-search-bar>
|
|
</div>
|
|
|
|
<!-- List -->
|
|
<ion-list
|
|
#list
|
|
class="ion-no-padding ion-no-margin"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
*ngIf="hasChildValue(filteredItems) | async"
|
|
>
|
|
<ion-reorder-group
|
|
id="reorder"
|
|
disabled="false"
|
|
(ionItemReorder)="handleDoReorderItems($event)"
|
|
>
|
|
<ng-container *ngFor="let item of filteredItems; let idx = index">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showOptionsAsSlide) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
? slidingItemRef
|
|
: nonSlidingItemRef;
|
|
context: { item: item, index: idx }
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-reorder-group>
|
|
</ion-list>
|
|
|
|
<!-- Empty List Handler -->
|
|
<ng-container
|
|
*ngIf="
|
|
!filteredItems ||
|
|
(filteredItems &&
|
|
filteredItems.length === 0 &&
|
|
(getValue(showEmpty) | async))
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="defaultEmptyListRef"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Sliding Item Ref -->
|
|
<ng-template #slidingItemRef let-item="item" let-index="index">
|
|
<ion-item-sliding
|
|
#slide
|
|
[xColor]="getValue(color) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<!-- Item It Self Clickable -->
|
|
<ion-item
|
|
class="item slidable"
|
|
xStopClickPropagation
|
|
[button]="clickableItems"
|
|
[xColor]="getValue(color) | async"
|
|
[lines]="getIonItemLine() | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
(click)="handleActionItemSelected(item)"
|
|
[disabled]="getValue(item.disabled) | async"
|
|
[class.ion-hide]="getValue(item.hide) | async"
|
|
[class.in-card]="getValue(wrapWithCard) | async"
|
|
[detail]="getValue(item.showDetailedIcon) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="itemHolderRef; context: { item: item, index: index }"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Itemp ReOrdering -->
|
|
<ion-reorder slot="end" *ngIf="enableReordering"></ion-reorder>
|
|
|
|
<!-- Menu Button -->
|
|
<ion-button
|
|
slot="end"
|
|
class="x-menu"
|
|
[xColor]="'inherit'"
|
|
xStopClickPropagation
|
|
[class.button-solid]="false"
|
|
[disabled]="getValue(item.disabled) | async"
|
|
*ngIf="
|
|
(getValue(showItemOptions) | async) &&
|
|
(getValue(showOptionsAsMenu) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
"
|
|
(click)="handleMoreButtonClicked($event, slide, item)"
|
|
>
|
|
<x-icon [name]="'menu_vertical'"></x-icon>
|
|
</ion-button>
|
|
</ion-item>
|
|
|
|
<!-- Item End Menus -->
|
|
<ion-item-options
|
|
side="end"
|
|
*ngIf="
|
|
(getValue(showItemOptions) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
"
|
|
>
|
|
<ion-item-option
|
|
xStopClickPropagation
|
|
[slot]="getOptionSlot(option) | async"
|
|
[color]="getValue(option.color) | async"
|
|
[matTooltip]="getResourceValue(option.title) | async"
|
|
*ngFor="let option of getEndSlides(item)"
|
|
[disabled]="
|
|
(getValue(item.disabled) | async) ||
|
|
(getValue(option.disabled) | async)
|
|
"
|
|
(click)="handleActionOptionSelected(slide, option.id, item)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
slidingOptionTemplate
|
|
? slidingOptionTemplate
|
|
: defaultSlidingOptionRef;
|
|
context: { $implicit: option }
|
|
"
|
|
></ng-container>
|
|
</ion-item-option>
|
|
</ion-item-options>
|
|
|
|
<!-- Item Start Menus -->
|
|
<ion-item-options
|
|
side="start"
|
|
*ngIf="
|
|
(getValue(showItemOptions) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
"
|
|
>
|
|
<ion-item-option
|
|
xStopClickPropagation
|
|
[slot]="getOptionSlot(option) | async"
|
|
[color]="getValue(option.color) | async"
|
|
[matTooltip]="getResourceValue(option.title) | async"
|
|
*ngFor="let option of getStartSlides(item)"
|
|
[disabled]="
|
|
(getValue(item.disabled) | async) ||
|
|
(getValue(option.disabled) | async)
|
|
"
|
|
(click)="handleActionOptionSelected(slide, option.id, item)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
slidingOptionTemplate
|
|
? slidingOptionTemplate
|
|
: defaultSlidingOptionRef;
|
|
context: { $implicit: option }
|
|
"
|
|
></ng-container>
|
|
</ion-item-option>
|
|
</ion-item-options>
|
|
</ion-item-sliding>
|
|
</ng-template>
|
|
|
|
<!-- Non Sliding Item Ref -->
|
|
<ng-template #nonSlidingItemRef let-item="item" let-index="index">
|
|
<!-- Item It Self -->
|
|
<ion-item
|
|
xStopClickPropagation
|
|
class="item not-slideable"
|
|
[button]="clickableItems"
|
|
[xColor]="getValue(color) | async"
|
|
[lines]="getIonItemLine() | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
(click)="handleActionItemSelected(item)"
|
|
[disabled]="getValue(item.disabled) | async"
|
|
[class.ion-hide]="getValue(item.hide) | async"
|
|
[class.in-card]="getValue(wrapWithCard) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
[detail]="getValue(item.showDetailedIcon) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="itemHolderRef; context: { item: item, index: index }"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Menu Button -->
|
|
<ion-button
|
|
slot="end"
|
|
class="x-menu"
|
|
[xColor]="'inherit'"
|
|
xStopClickPropagation
|
|
[class.button-solid]="false"
|
|
[disabled]="getValue(item.disabled) | async"
|
|
*ngIf="
|
|
(getValue(showItemOptions) | async) &&
|
|
(getValue(showOptionsAsMenu) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
"
|
|
(click)="handleMoreButtonClicked($event, null, item)"
|
|
>
|
|
<x-icon [name]="'menu_vertical'"></x-icon>
|
|
</ion-button>
|
|
|
|
<!-- Item Menus -->
|
|
<ion-buttons
|
|
slot="end"
|
|
*ngIf="
|
|
(getValue(showItemOptions) | async) &&
|
|
!(getValue(showOptionsAsMenu) | async) &&
|
|
(hasChildValue(item.slideOptions) | async)
|
|
"
|
|
>
|
|
<!-- Start Options -->
|
|
<ion-button
|
|
xStopClickPropagation
|
|
[slot]="getOptionSlot(option) | async"
|
|
[color]="getValue(option.color) | async"
|
|
[disabled]="
|
|
(getValue(item.disabled) | async) ||
|
|
(getValue(option.disabled) | async)
|
|
"
|
|
*ngFor="let option of getStartSlides(item)"
|
|
[matTooltip]="getResourceValue(option.title) | async"
|
|
(click)="handleActionOptionSelected(null, option.id, item)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nonSlidingOptionTemplate
|
|
? nonSlidingOptionTemplate
|
|
: defaultNonSlidingOptionRef;
|
|
context: { $implicit: option }
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
|
|
<!-- End Options -->
|
|
<ion-button
|
|
xStopClickPropagation
|
|
[slot]="getOptionSlot(option) | async"
|
|
[color]="getValue(option.color) | async"
|
|
[disabled]="
|
|
(getValue(item.disabled) | async) ||
|
|
(getValue(option.disabled) | async)
|
|
"
|
|
*ngFor="let option of getEndSlides(item)"
|
|
[matTooltip]="getResourceValue(option.title) | async"
|
|
(click)="handleActionOptionSelected(null, option.id, item)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nonSlidingOptionTemplate
|
|
? nonSlidingOptionTemplate
|
|
: defaultNonSlidingOptionRef;
|
|
context: { $implicit: option }
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
|
|
<!-- Itemp ReOrdering -->
|
|
<ion-reorder
|
|
slot="end"
|
|
*ngIf="
|
|
(getValue(enableReordering) | async) &&
|
|
(countChildsValue(items) | async) ===
|
|
(countChildsValue(filteredItems) | async)
|
|
"
|
|
></ion-reorder>
|
|
</ion-item>
|
|
</ng-template>
|
|
|
|
<!-- Item Holder Template -->
|
|
<ng-template #itemHolderRef let-item="item" let-index="index">
|
|
<!-- Itemp Template -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
itemTemplate ? itemTemplate : defaultItemRef;
|
|
context: { item: item, index: index }
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Itemp Checkbox -->
|
|
<ion-checkbox
|
|
slot="start"
|
|
class="x-check"
|
|
[checked]="item.isSelected"
|
|
*ngIf="getValue(selectableItems) | async"
|
|
[disabled]="getValue(item.disabled) | async"
|
|
></ion-checkbox>
|
|
</ng-template>
|
|
|
|
<!-- Default Sliding Option Ref -->
|
|
<ng-template #defaultSlidingOptionRef let-option>
|
|
<ion-item lines="none">
|
|
<ion-label
|
|
*ngIf="
|
|
(notEmptyValue(option.title) | async) &&
|
|
(getOptionOnlyIcon(option) | async) === false
|
|
"
|
|
>{{ getResourceValue(option.title) | async }}</ion-label
|
|
>
|
|
<x-icon
|
|
*ngIf="option.icon"
|
|
[foregroundColor]="false"
|
|
[name]="getValue(option.icon) | async"
|
|
[color]="getValue(option.color) | async"
|
|
></x-icon>
|
|
</ion-item>
|
|
</ng-template>
|
|
|
|
<!-- Default Non Sliding Option Ref -->
|
|
<ng-template #defaultNonSlidingOptionRef let-option>
|
|
<ng-container *ngIf="!(getOptionOnlyIcon(option) | async)">
|
|
{{ getResourceValue(option.title) | async }}
|
|
</ng-container>
|
|
<x-icon
|
|
*ngIf="option.icon"
|
|
[foregroundColor]="true"
|
|
[name]="getValue(option.icon) | async"
|
|
[color]="getValue(option.color) | async"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Default Item Ref -->
|
|
<ng-template #defaultItemRef let-item="item" let-index="index">
|
|
<h5 style="width: 100%">{{ item | json }}</h5>
|
|
</ng-template>
|
|
|
|
<!-- Default Empty Content -->
|
|
<ng-template #defaultEmptyListRef>
|
|
<x-empty
|
|
(refresh)="emptyRefresh.emit($event)"
|
|
[color]="getValue(emptyColor) | async"
|
|
[message]="getResourceValue(emptyMessage) | async"
|
|
[refreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
[messageColor]="getValue(emptyMessageColor) | async"
|
|
[hasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[foregroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[foregroundColor]="getValue(emptyForegroundColor) | async"
|
|
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
|
|
></x-empty>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.scss
|
|
|
|
ion-item-option > ion-item {
|
|
--background: transparent !important;
|
|
}
|
|
|
|
ion-list,
|
|
ion-item.item,
|
|
ion-item-divider {
|
|
--background: transparent !important;
|
|
}
|
|
|
|
ion-item-divider {
|
|
--color: var(--ion-color-dark-shade);
|
|
}
|
|
|
|
ion-item.item.mobile {
|
|
--ion-safe-area-end: 0px;
|
|
|
|
--padding-start: 8px;
|
|
--inner-padding-start: 0px;
|
|
|
|
--padding-end: 8px;
|
|
--inner-padding-end: 0px;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0;
|
|
}
|
|
|
|
.x-menu {
|
|
z-index: 10;
|
|
}
|
|
|
|
.x-check {
|
|
z-index: 1;
|
|
}
|
|
|
|
x-card {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
:host ::ng-deep .button-solid {
|
|
--color: unset !important;
|
|
--background: unset !important;
|
|
--box-shadow: unset !important;
|
|
}
|
|
|
|
.x-list-toolbar {
|
|
&.sticky {
|
|
top: 0;
|
|
position: sticky;
|
|
position: -webkit-sticky;
|
|
z-index: 200;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
toArray,
|
|
hasChild,
|
|
isFunction,
|
|
removeItem,
|
|
XOneOrManyType,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XListItem,
|
|
XListAction,
|
|
XListActionModel,
|
|
XListItemSlideOption,
|
|
XListContainerComponent,
|
|
} from './x-list.typings';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarAction,
|
|
XActionBarActionModel,
|
|
DefaultActionBarItemIds,
|
|
defaultActionBarAddItem,
|
|
defaultActionBarRemoveItem,
|
|
XActionBarActionFiredModel,
|
|
defaultActionBarSelectAllItem,
|
|
defaultActionBarDeSelectAllItem,
|
|
defaultActionBarInverseSelectionItem,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { IonItemSliding } from '@ionic/angular';
|
|
import {
|
|
XPopoverResult,
|
|
XPopoverOption,
|
|
XPopoverComponentProps,
|
|
} from '../dialogs/x-popover/x-popover.typings';
|
|
import { moveItemInArray } from '@angular/cdk/drag-drop';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { Subject, Subscription, BehaviorSubject, of } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { toPopoverOptions } from '../dialogs/x-popover/x-popover.tools';
|
|
import { XSearchBarAction } from '../x-search-bar/x-search-bar.typings';
|
|
import { XPopoverComponent } from '../dialogs/x-popover/x-popover.component';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line: component-selector
|
|
selector: 'x-list',
|
|
templateUrl: './x-list.component.html',
|
|
styleUrls: ['./x-list.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XListComponent extends XListContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private SELECTED_ITEMS: XListItem<any>[] = [];
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
private ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
private HIDE_ADD = false;
|
|
private DISABLE_ADD = false;
|
|
private addDisablerSubject = new BehaviorSubject<boolean>(false);
|
|
|
|
//
|
|
private HIDE_REMOVE = false;
|
|
private DISABLE_REMOVE = false;
|
|
private removeDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
|
|
//
|
|
private HIDE_SELECT_ALL = false;
|
|
private DISABLE_SELECT_ALL = false;
|
|
private selectAllDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
|
|
//
|
|
private HIDE_DESELECT_ALL = false;
|
|
private DISABLE_DESELECT_ALL = false;
|
|
private deSelectAllDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
|
|
//
|
|
private HIDE_INVERSE_SELECTION = false;
|
|
private DISABLE_INVERSE_SELECTION = false;
|
|
private inverseSelectionDisablerSubject = new BehaviorSubject<boolean>(true);
|
|
|
|
//
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
|
|
//
|
|
filteredItems: XListItem<any>[] = [];
|
|
|
|
//
|
|
get count() {
|
|
return this.items ? this.getValue(this.items) : of(0);
|
|
}
|
|
|
|
get filteredItemsCount() {
|
|
return this.filteredItems ? this.filteredItems.length : 0;
|
|
}
|
|
|
|
get selectedItems() {
|
|
return this.SELECTED_ITEMS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
// await this.handleStartup();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XListComponent>('actionProvider')
|
|
);
|
|
const isActionBarActionProviderChanged = changeKeys.includes(
|
|
nameof<XListComponent>('actionBarActionProvider')
|
|
);
|
|
if (isActionProviderChanged || isActionBarActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
//
|
|
const isItemsChanged = changeKeys.includes(nameof<XListComponent>('items'));
|
|
if (isItemsChanged) {
|
|
//
|
|
await this.handleStartup();
|
|
this.itemsChanged.emit();
|
|
}
|
|
|
|
//
|
|
const isActionBarActionsChanged = changeKeys.includes(
|
|
nameof<XListComponent>('actionBarActions')
|
|
);
|
|
const isActionBarHideActionsChanged = changeKeys.includes(
|
|
nameof<XListComponent>('actionBarHideActions')
|
|
);
|
|
if (isActionBarActionsChanged || isActionBarHideActionsChanged) {
|
|
await this.prepareActionBarActions();
|
|
}
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
getStartSlides(item: XListItem<any>) {
|
|
return item && item.slideOptions
|
|
? item.slideOptions.filter((opt) => opt.slot === 'start')
|
|
: null;
|
|
}
|
|
|
|
getEndSlides(item: XListItem<any>) {
|
|
return item && item.slideOptions
|
|
? item.slideOptions.filter((opt) => opt.slot === 'end')
|
|
: null;
|
|
}
|
|
|
|
getOptionSlot(option: XListItemSlideOption) {
|
|
return this.getOptionOnlyIcon(option).pipe(
|
|
map((onlyIcon) => {
|
|
return onlyIcon ? 'icon-only' : '';
|
|
})
|
|
);
|
|
}
|
|
|
|
getOptionIconSlot(option: XListItemSlideOption) {
|
|
return this.getOptionOnlyIcon(option).pipe(
|
|
concatMap((onlyIcon) => {
|
|
return this.getOptionSlot(option).pipe(
|
|
map((slot) => {
|
|
return onlyIcon ? '' : slot;
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
getNonSlidingOptionIconSlot(option: XListItemSlideOption) {
|
|
return this.getOptionOnlyIcon(option).pipe(
|
|
map((onlyIcon) => {
|
|
return onlyIcon ? 'icon-only' : 'end';
|
|
})
|
|
);
|
|
}
|
|
|
|
getOptionOnlyIcon(option: XListItemSlideOption) {
|
|
return this.getValue(!isNullOrUndefined(option) ? option.onlyIcon : false);
|
|
}
|
|
|
|
getIonItemLine() {
|
|
return this.getValue(this.showDivider).pipe(
|
|
map((showDivider) => (showDivider ? 'full' : 'none'))
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
handleActionItemSelected(item: XListItem<any>) {
|
|
//
|
|
if (this.selectableItems) {
|
|
item.isSelected = !item.isSelected;
|
|
this.issueSelectionChanged();
|
|
}
|
|
|
|
//
|
|
this.itemSelected.emit(item);
|
|
}
|
|
|
|
handleDoReorderItems(ev: CustomEvent | any) {
|
|
//
|
|
const to = ev.detail.to;
|
|
// tslint:disable-next-line:no-shadowed-variable
|
|
const from = ev.detail.from;
|
|
moveItemInArray(this.filteredItems, from, to);
|
|
|
|
//
|
|
this.orderChanged.emit();
|
|
ev.detail.complete();
|
|
}
|
|
|
|
async handleMoreButtonClicked(
|
|
event: Event,
|
|
slide: IonItemSliding,
|
|
item: XListItem<any>
|
|
) {
|
|
//
|
|
if (!isNullOrUndefined(slide)) {
|
|
await slide.closeOpened();
|
|
}
|
|
|
|
//
|
|
// Disable Only Icons for Menu Options ...
|
|
const options: XPopoverOption[] = toArray(toPopoverOptions(item));
|
|
options.forEach((o) => {
|
|
//
|
|
o.onlyIcon = false;
|
|
|
|
//
|
|
o.slot = 'end';
|
|
|
|
//
|
|
o.handler = undefined;
|
|
});
|
|
|
|
//
|
|
// Prepare PopOver Component Props ...
|
|
const componentProps: XPopoverComponentProps = {
|
|
options,
|
|
};
|
|
|
|
//
|
|
// Present Context Menu Options ...
|
|
const popOver = await this.managerService.dialogService.presentPopover({
|
|
event,
|
|
componentProps,
|
|
translucent: true,
|
|
showBackdrop: true,
|
|
component: XPopoverComponent,
|
|
});
|
|
|
|
//
|
|
// Extract Data from PopOver ...
|
|
const { data } = await popOver.onWillDismiss();
|
|
if (!data) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const result = data as XPopoverResult;
|
|
if (
|
|
isNullOrUndefined(result.option) ||
|
|
isNullOrEmptyString(result.option.id)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.handleActionOptionSelected(slide, result.option.id, item);
|
|
}
|
|
|
|
async handleActionOptionSelected(
|
|
slide: IonItemSliding,
|
|
id: string,
|
|
item: XListItem<any>
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(id) || isNullOrUndefined(item)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if (!isNullOrUndefined)
|
|
const action = item.slideOptions.find((i) => i.id === id);
|
|
if (
|
|
!isNullOrUndefined(action) &&
|
|
!isNullOrUndefined(action.handler) &&
|
|
isFunction(action.handler)
|
|
) {
|
|
await this.getValueAsync(action.handler());
|
|
}
|
|
|
|
//
|
|
if (this.closeOptionsAfterSelect && !isNullOrUndefined(slide)) {
|
|
//
|
|
slide.closeOpened().then(() => {
|
|
//
|
|
this.optionSelected.emit({
|
|
id,
|
|
data: item,
|
|
});
|
|
});
|
|
} else {
|
|
//
|
|
this.optionSelected.emit({
|
|
id,
|
|
data: item,
|
|
});
|
|
}
|
|
}
|
|
|
|
async handleActionRemoveItems() {
|
|
//
|
|
if (!this.hasChild(this.SELECTED_ITEMS)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const items = this.SELECTED_ITEMS.map((i) => i.data);
|
|
|
|
//
|
|
const confirmRemove = await this.getValueAsync(this.confirmRemove);
|
|
if (confirmRemove) {
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
() => {
|
|
this.removeItems.emit({
|
|
items,
|
|
});
|
|
}
|
|
);
|
|
} else {
|
|
this.removeItems.emit({
|
|
items,
|
|
});
|
|
}
|
|
}
|
|
|
|
async handleActionBarActionFired(model: XActionBarActionFiredModel) {
|
|
//
|
|
if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case DefaultActionBarItemIds.SelectAll:
|
|
await this.selectAll();
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.DeSelectAll:
|
|
await this.deselectAll();
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.InverseSelection:
|
|
await this.inverseSelection();
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.Remove:
|
|
//
|
|
await this.handleActionRemoveItems();
|
|
break;
|
|
}
|
|
|
|
//
|
|
this.actionBarActionFired.emit(model);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async selectAll() {
|
|
//
|
|
this.filteredItems.forEach((item) => {
|
|
if (!item.disabled) {
|
|
//
|
|
item.isSelected = true;
|
|
this.changeDetector.markForCheck();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.issueSelectionChanged();
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async deselectAll() {
|
|
//
|
|
this.filteredItems.forEach((item) => {
|
|
if (!item.disabled) {
|
|
//
|
|
item.isSelected = false;
|
|
this.changeDetector.markForCheck();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.issueSelectionChanged();
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async inverseSelection() {
|
|
//
|
|
this.filteredItems.forEach((item) => {
|
|
if (!item.disabled) {
|
|
//
|
|
item.isSelected = !item.isSelected;
|
|
this.changeDetector.markForCheck();
|
|
}
|
|
});
|
|
|
|
//
|
|
this.issueSelectionChanged();
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async clearFilter(fill = false) {
|
|
this.filteredItems = [];
|
|
|
|
//
|
|
if (fill) {
|
|
//
|
|
const items = await this.getValueAsync(this.items);
|
|
this.filteredItems = items;
|
|
}
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async filterItems(query: string) {
|
|
//
|
|
this.searchBarQueryChange.emit(query);
|
|
|
|
//
|
|
await this.clearFilter();
|
|
const items = await this.getValueAsync(this.items);
|
|
|
|
//
|
|
if (isNullOrEmptyString(query)) {
|
|
//
|
|
this.filteredItems = items;
|
|
this.handleChangeDetection();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const result = await this.getValueAsync(
|
|
this.filteringHandler(query, items)
|
|
);
|
|
this.filteredItems = result;
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XListActionModel>();
|
|
}
|
|
|
|
//
|
|
if (!this.actionBarActionProvider) {
|
|
this.actionBarActionProvider = new Subject<XActionBarActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XListAction.Add:
|
|
//
|
|
const newItem = model.payload as XListItem<any>;
|
|
if (newItem) {
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
this.items = [...items, newItem];
|
|
this.itemsChanged.emit();
|
|
this.handleChangeDetection();
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XListAction.Set:
|
|
//
|
|
const newItems = model.payload as XListItem<any>[];
|
|
if (newItems) {
|
|
//
|
|
this.items = [...newItems];
|
|
this.itemsChanged.emit();
|
|
this.handleChangeDetection();
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XListAction.Remove:
|
|
//
|
|
const mustRemoveItem = model.payload as XListItem<any>;
|
|
if (mustRemoveItem) {
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
this.items = [...removeItem(items, mustRemoveItem)];
|
|
this.itemsChanged.emit();
|
|
this.handleChangeDetection();
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XListAction.SelectAll:
|
|
await this.selectAll();
|
|
break;
|
|
|
|
//
|
|
case XListAction.DeselectAll:
|
|
await this.deselectAll();
|
|
break;
|
|
|
|
//
|
|
case XListAction.InverseSelection:
|
|
await this.inverseSelection();
|
|
break;
|
|
|
|
//
|
|
case XListAction.Refresh:
|
|
this.handleChangeDetection();
|
|
break;
|
|
}
|
|
});
|
|
|
|
//
|
|
// Handle ActionBar Provider ...
|
|
this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION = this.actionBarActionProvider
|
|
.asObservable()
|
|
.subscribe((model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XActionBarAction.EnableAction:
|
|
//
|
|
switch (model.id) {
|
|
//
|
|
case DefaultActionBarItemIds.Add:
|
|
//
|
|
this.DISABLE_ADD = false;
|
|
this.addDisablerSubject.next(false);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.Remove:
|
|
//
|
|
this.DISABLE_REMOVE = false;
|
|
this.removeDisablerSubject.next(false);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.SelectAll:
|
|
//
|
|
this.DISABLE_SELECT_ALL = false;
|
|
this.selectAllDisablerSubject.next(false);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.DeSelectAll:
|
|
//
|
|
this.DISABLE_DESELECT_ALL = false;
|
|
this.deSelectAllDisablerSubject.next(false);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.InverseSelection:
|
|
//
|
|
this.DISABLE_INVERSE_SELECTION = false;
|
|
this.inverseSelectionDisablerSubject.next(false);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XActionBarAction.DisbaleAction:
|
|
//
|
|
switch (model.id) {
|
|
//
|
|
case DefaultActionBarItemIds.Add:
|
|
//
|
|
this.DISABLE_ADD = true;
|
|
this.addDisablerSubject.next(true);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.Remove:
|
|
//
|
|
this.DISABLE_REMOVE = true;
|
|
this.removeDisablerSubject.next(true);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.SelectAll:
|
|
//
|
|
this.DISABLE_SELECT_ALL = true;
|
|
this.selectAllDisablerSubject.next(true);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.DeSelectAll:
|
|
//
|
|
this.DISABLE_DESELECT_ALL = true;
|
|
this.deSelectAllDisablerSubject.next(true);
|
|
break;
|
|
|
|
//
|
|
case DefaultActionBarItemIds.InverseSelection:
|
|
//
|
|
this.DISABLE_INVERSE_SELECTION = true;
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
if (this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION) {
|
|
//
|
|
this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
}
|
|
|
|
private async handleStartup() {
|
|
//
|
|
await this.prepareActionBarActions();
|
|
|
|
//
|
|
this.SELECTED_ITEMS = [];
|
|
|
|
//
|
|
const items = await this.getValueAsync(
|
|
isNullOrUndefined(this.items) ? [] : this.items
|
|
);
|
|
if (!hasChild(items)) {
|
|
this.filteredItems = [];
|
|
} else {
|
|
this.filteredItems = items;
|
|
}
|
|
|
|
//
|
|
this.issueSelectionChanged();
|
|
// this.handleChangeDetection();
|
|
}
|
|
|
|
private handleChangeDetection() {
|
|
//
|
|
this.actionBarActionProvider.next({
|
|
action: XActionBarAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.searchBarActionProvider.next({
|
|
action: XSearchBarAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private issueSelectionChanged() {
|
|
//
|
|
this.SELECTED_ITEMS = [];
|
|
if (!this.selectableItems) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const selectedItems = this.filteredItems.filter((item) => item.isSelected);
|
|
this.SELECTED_ITEMS = [...selectedItems];
|
|
|
|
//
|
|
this.selectionChanged.emit(selectedItems);
|
|
this.prepareActionBarActionsSubjects(selectedItems);
|
|
}
|
|
|
|
//
|
|
//#region ActionBar Preparations ...
|
|
private async prepareActionBarActions() {
|
|
//
|
|
//#region Prepare Default Actions ...
|
|
const hideActions = await this.getArrayValueAsync(
|
|
this.actionBarHideActions
|
|
);
|
|
|
|
//
|
|
let idx = 0;
|
|
const defaultActions: XOneOrManyType<XActionBarItem> = [];
|
|
|
|
//
|
|
// Remove ...
|
|
const removeId = DefaultActionBarItemIds.Remove.toString();
|
|
if (!hideActions.includes(removeId)) {
|
|
//
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarRemoveItem,
|
|
|
|
//
|
|
index: idx,
|
|
disabled: this.removeDisablerSubject.asObservable(),
|
|
});
|
|
|
|
//
|
|
idx++;
|
|
}
|
|
|
|
//
|
|
// Add ...
|
|
const addId = DefaultActionBarItemIds.Add.toString();
|
|
if (!hideActions.includes(addId)) {
|
|
//
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarAddItem,
|
|
|
|
//
|
|
index: idx,
|
|
disabled: this.addDisablerSubject.asObservable(),
|
|
});
|
|
|
|
//
|
|
idx++;
|
|
}
|
|
|
|
//
|
|
// Select All ...
|
|
const selectAllId = DefaultActionBarItemIds.SelectAll.toString();
|
|
if (!hideActions.includes(selectAllId)) {
|
|
//
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarSelectAllItem,
|
|
|
|
//
|
|
index: idx,
|
|
disabled: this.selectAllDisablerSubject.asObservable(),
|
|
});
|
|
|
|
//
|
|
idx++;
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
const inverseSelectionId =
|
|
DefaultActionBarItemIds.InverseSelection.toString();
|
|
if (!hideActions.includes(inverseSelectionId)) {
|
|
//
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarInverseSelectionItem,
|
|
|
|
//
|
|
index: idx,
|
|
disabled: this.inverseSelectionDisablerSubject.asObservable(),
|
|
});
|
|
|
|
//
|
|
idx++;
|
|
}
|
|
|
|
//
|
|
// De Select All ...
|
|
const deselectAllId = DefaultActionBarItemIds.DeSelectAll.toString();
|
|
if (!hideActions.includes(deselectAllId)) {
|
|
//
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarDeSelectAllItem,
|
|
|
|
//
|
|
index: idx,
|
|
disabled: this.deSelectAllDisablerSubject.asObservable(),
|
|
});
|
|
|
|
//
|
|
idx++;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
const useDefaultActions = await this.getValueAsync(this.useDefaultActions);
|
|
if (!this.actionBarActions && !!useDefaultActions) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
return;
|
|
}
|
|
|
|
//
|
|
const actions = await this.getArrayValueAsync(this.actionBarActions);
|
|
if (!hasChild(actions) && !!useDefaultActions) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actionBarActions = actions;
|
|
}
|
|
|
|
private async prepareActionBarActionsSubjects(items: XListItem<File>[]) {
|
|
//
|
|
const listItems = await this.getValueAsync(this.items);
|
|
|
|
//
|
|
// Check Select All ...
|
|
if (!hasChild(listItems)) {
|
|
//
|
|
// Remove ...
|
|
if (!this.DISABLE_REMOVE) {
|
|
this.removeDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Select All ...
|
|
if (!this.DISABLE_SELECT_ALL) {
|
|
this.selectAllDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Deselect All ...
|
|
if (!this.DISABLE_DESELECT_ALL) {
|
|
this.deSelectAllDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
if (!this.DISABLE_INVERSE_SELECTION) {
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
}
|
|
} else {
|
|
//
|
|
// DeSelectAll ...
|
|
if (!hasChild(items)) {
|
|
//
|
|
// Remove ...
|
|
if (!this.DISABLE_REMOVE) {
|
|
this.removeDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Deselect All ...
|
|
if (!this.DISABLE_DESELECT_ALL) {
|
|
this.deSelectAllDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
if (!this.DISABLE_INVERSE_SELECTION) {
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
}
|
|
} else {
|
|
//
|
|
// Remove ...
|
|
if (!this.DISABLE_REMOVE) {
|
|
this.removeDisablerSubject.next(false);
|
|
}
|
|
|
|
//
|
|
// Deselect All ...
|
|
if (!this.DISABLE_DESELECT_ALL) {
|
|
this.deSelectAllDisablerSubject.next(false);
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
if (!this.DISABLE_INVERSE_SELECTION) {
|
|
this.inverseSelectionDisablerSubject.next(false);
|
|
}
|
|
}
|
|
|
|
//
|
|
if (listItems.length === items.length) {
|
|
//
|
|
// Select All ...
|
|
if (!this.DISABLE_SELECT_ALL) {
|
|
this.selectAllDisablerSubject.next(true);
|
|
}
|
|
|
|
//
|
|
// Inverse Selection ...
|
|
if (!this.DISABLE_INVERSE_SELECTION) {
|
|
this.inverseSelectionDisablerSubject.next(true);
|
|
}
|
|
} else {
|
|
//
|
|
// Select All ...
|
|
if (!this.DISABLE_SELECT_ALL) {
|
|
this.selectAllDisablerSubject.next(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XListComponent } from './x-list.component';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XActionBarModule } from '../x-action-bar/x-action-bar.module';
|
|
import { XSearchBarModule } from '../x-search-bar/x-search-bar.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XListComponent],
|
|
imports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XEmptyModule,
|
|
CommonModule,
|
|
XActionBarModule,
|
|
XSearchBarModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XEmptyModule,
|
|
CommonModule,
|
|
XListComponent,
|
|
XActionBarModule,
|
|
XSearchBarModule,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XListModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
Injectable,
|
|
ElementRef,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
isFile,
|
|
hasChild,
|
|
toJsonString,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
toNormalString,
|
|
XColorIdentifier,
|
|
fileToJsonString,
|
|
XResourceIdentifier,
|
|
XBaseRangeRequestDto,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBaseComponentContainer,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import {
|
|
XCardEmptyActionSearchBarContainer,
|
|
IXCardEmptyActionSearchBarContainer,
|
|
XCardEmptyActionSearchBarContainerComponent,
|
|
} from '../classes/i-x-card-empty.container';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarActionModel,
|
|
XActionBarActionIdentifier,
|
|
XActionBarActionFiredModel,
|
|
} from '../x-action-bar/x-action-bar.typings';
|
|
import {
|
|
XSearchBarActionModel,
|
|
XSearchBarTypeIdentifier,
|
|
XSearchBarEventIdentifier,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XCardActionModel } from '../x-card/x-card.typings';
|
|
import { XEmptyActionModel } from '../x-empty/x-empty.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Definitions ...
|
|
export type XListItemOptionSlot = 'end' | 'start';
|
|
|
|
export interface XListItemSlideOption {
|
|
id: string;
|
|
icon?: XStandardType<XIconIdentifier>;
|
|
title?: XStandardType<XResourceIdentifier>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
onlyIcon?: XStandardType<boolean>;
|
|
slot: XStandardType<XListItemOptionSlot>;
|
|
handler?: (info?: any) => XStandardType<void>;
|
|
disabled?: XStandardType<boolean>;
|
|
}
|
|
|
|
export interface XListItem<T> {
|
|
data: T;
|
|
hide?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
isSelected?: boolean;
|
|
href?: XOneOrManyType<string>;
|
|
showDetailedIcon?: XStandardType<boolean>;
|
|
slideOptions?: XListItemSlideOption[];
|
|
}
|
|
|
|
export interface XListItemOptionSelectedEvent {
|
|
id: string;
|
|
data: any;
|
|
}
|
|
|
|
export enum XListAction {
|
|
//
|
|
Add = 'add',
|
|
Set = 'set',
|
|
Remove = 'remove',
|
|
|
|
//
|
|
SelectAll = 'select_all',
|
|
DeselectAll = 'deselect_all',
|
|
InverseSelection = 'inverse_selection',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XListActionIdentifier = XListAction | string;
|
|
|
|
export interface XListActionModel
|
|
extends XBaseActionModel<XListActionIdentifier> {}
|
|
|
|
export type XListFilteringHandler = (
|
|
query: string,
|
|
source: XListItem<any>[]
|
|
) => XStandardType<XListItem<any>[]>;
|
|
|
|
export function itemToJson(item: any) {
|
|
return isFile(item) ? fileToJsonString(item) : toJsonString(item);
|
|
}
|
|
|
|
export const defaultListFilteringHandler: XListFilteringHandler = (
|
|
query: string,
|
|
items: XListItem<any>[]
|
|
) => {
|
|
//
|
|
if (!query || !hasChild(items)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
const result = items.filter((i) =>
|
|
toNormalString(itemToJson(i.data)).includes(toNormalString(query))
|
|
);
|
|
|
|
//
|
|
return result;
|
|
};
|
|
//#endregion
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXListContainer extends IXCardEmptyActionSearchBarContainer {
|
|
//
|
|
actionProvider: Subject<XListActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
>;
|
|
|
|
//
|
|
useDefaultActions: XStandardType<boolean>;
|
|
|
|
//
|
|
showToolbar: XStandardType<boolean>;
|
|
stickyToolbar: XStandardType<boolean>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
enableReordering: XStandardType<boolean>;
|
|
showDivider: XStandardType<boolean>;
|
|
showOptionsAsSlide: XStandardType<boolean>;
|
|
closeOptionsAfterSelect: XStandardType<boolean>;
|
|
showOptionsAsMenu: XStandardType<boolean>;
|
|
|
|
//
|
|
selectableItems: XStandardType<boolean>;
|
|
clickableItems: XStandardType<boolean>;
|
|
itemTemplate: TemplateRef<any>;
|
|
slidingOptionTemplate: TemplateRef<any>;
|
|
nonSlidingOptionTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
itemSelected: EventEmitter<XListItem<any>>;
|
|
optionSelected: EventEmitter<XListItemOptionSelectedEvent>;
|
|
confirmRemove: XStandardType<boolean>;
|
|
removeItems: EventEmitter<XBaseRangeRequestDto<any>>;
|
|
|
|
//
|
|
selectionChanged: EventEmitter<XListItem<any>[]>;
|
|
orderChanged: EventEmitter<void>;
|
|
items: XStandardType<XListItem<any>[]>;
|
|
showItemOptions: XStandardType<boolean>;
|
|
itemsChanged: EventEmitter<void>;
|
|
filteringHandler: XListFilteringHandler;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XListContainer
|
|
extends XCardEmptyActionSearchBarContainer
|
|
implements Readonly<IXListContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XListActionModel> =
|
|
new Subject<XListActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
>;
|
|
|
|
readonly useDefaultActions: XStandardType<boolean> = true;
|
|
|
|
readonly showToolbar: XStandardType<boolean> = false;
|
|
readonly stickyToolbar: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly enableReordering: XStandardType<boolean> = false;
|
|
readonly showDivider: XStandardType<boolean> = true;
|
|
readonly showOptionsAsSlide: XStandardType<boolean> = false;
|
|
readonly closeOptionsAfterSelect: XStandardType<boolean> = true;
|
|
readonly showOptionsAsMenu: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly selectableItems: XStandardType<boolean> = false;
|
|
readonly clickableItems: XStandardType<boolean> = false;
|
|
readonly itemTemplate: TemplateRef<any>;
|
|
readonly slidingOptionTemplate: TemplateRef<any>;
|
|
readonly nonSlidingOptionTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly itemSelected: EventEmitter<XListItem<any>> = new EventEmitter<
|
|
XListItem<any>
|
|
>();
|
|
readonly optionSelected: EventEmitter<XListItemOptionSelectedEvent> =
|
|
new EventEmitter<XListItemOptionSelectedEvent>();
|
|
readonly confirmRemove: XStandardType<boolean> = true;
|
|
readonly removeItems: EventEmitter<XBaseRangeRequestDto<any>> =
|
|
new EventEmitter<XBaseRangeRequestDto<any>>();
|
|
|
|
//
|
|
readonly selectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter<
|
|
XListItem<any>[]
|
|
>();
|
|
readonly orderChanged: EventEmitter<void> = new EventEmitter<void>();
|
|
readonly items: XStandardType<XListItem<any>[]> = [];
|
|
readonly showItemOptions: XStandardType<boolean> = true;
|
|
readonly itemsChanged: EventEmitter<void> = new EventEmitter<void>();
|
|
readonly filteringHandler: XListFilteringHandler =
|
|
defaultListFilteringHandler;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XListContainerComponent
|
|
extends XCardEmptyActionSearchBarContainerComponent
|
|
implements IXListContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XListActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
actionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
> = this.propertyProvider.actionBarHideActions;
|
|
|
|
@Input()
|
|
useDefaultActions: XStandardType<boolean> =
|
|
this.propertyProvider.useDefaultActions;
|
|
|
|
@Input()
|
|
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
|
|
|
|
@Input()
|
|
stickyToolbar: XStandardType<boolean> = this.propertyProvider.stickyToolbar;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
enableReordering: XStandardType<boolean> =
|
|
this.propertyProvider.enableReordering;
|
|
|
|
@Input()
|
|
showDivider: XStandardType<boolean> = this.propertyProvider.showDivider;
|
|
|
|
@Input()
|
|
showOptionsAsSlide: XStandardType<boolean> =
|
|
this.propertyProvider.showOptionsAsSlide;
|
|
|
|
@Input()
|
|
closeOptionsAfterSelect: XStandardType<boolean> =
|
|
this.propertyProvider.closeOptionsAfterSelect;
|
|
|
|
@Input()
|
|
showOptionsAsMenu: XStandardType<boolean> =
|
|
this.propertyProvider.showOptionsAsMenu;
|
|
|
|
@Input()
|
|
selectableItems: XStandardType<boolean> =
|
|
this.propertyProvider.selectableItems;
|
|
|
|
@Input()
|
|
clickableItems: XStandardType<boolean> = this.propertyProvider.clickableItems;
|
|
|
|
@Input()
|
|
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
|
|
|
|
@Input()
|
|
slidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.slidingOptionTemplate;
|
|
|
|
@Input()
|
|
nonSlidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.nonSlidingOptionTemplate;
|
|
|
|
//
|
|
@Output()
|
|
itemSelected: EventEmitter<XListItem<any>> = new EventEmitter();
|
|
|
|
@Output()
|
|
optionSelected: EventEmitter<XListItemOptionSelectedEvent> = new EventEmitter();
|
|
|
|
@Input()
|
|
confirmRemove: XStandardType<boolean> = this.propertyProvider.confirmRemove;
|
|
|
|
@Output()
|
|
removeItems: EventEmitter<XBaseRangeRequestDto<any>> = new EventEmitter();
|
|
|
|
//
|
|
@Output()
|
|
selectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter();
|
|
|
|
@Output()
|
|
orderChanged: EventEmitter<void> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
items: XStandardType<XListItem<any>[]> = this.propertyProvider.items;
|
|
|
|
@Input()
|
|
showItemOptions: XStandardType<boolean> =
|
|
this.propertyProvider.showItemOptions;
|
|
|
|
@Output()
|
|
itemsChanged: EventEmitter<void> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
filteringHandler: XListFilteringHandler =
|
|
this.propertyProvider.filteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XListContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXListContainer
|
|
): Observable<IXListContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
actionBarHideActions: this.getValue(
|
|
container
|
|
? container.actionBarHideActions
|
|
: this.actionBarHideActions
|
|
),
|
|
useDefaultActions: this.getValue(
|
|
container ? container.useDefaultActions : this.useDefaultActions
|
|
),
|
|
showToolbar: this.getValue(
|
|
container ? container.showToolbar : this.showToolbar
|
|
),
|
|
stickyToolbar: this.getValue(
|
|
container ? container.stickyToolbar : this.stickyToolbar
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
enableReordering: this.getValue(
|
|
container ? container.enableReordering : this.enableReordering
|
|
),
|
|
showDivider: this.getValue(
|
|
container ? container.showDivider : this.showDivider
|
|
),
|
|
showOptionsAsSlide: this.getValue(
|
|
container ? container.showOptionsAsSlide : this.showOptionsAsSlide
|
|
),
|
|
closeOptionsAfterSelect: this.getValue(
|
|
container
|
|
? container.closeOptionsAfterSelect
|
|
: this.closeOptionsAfterSelect
|
|
),
|
|
showOptionsAsMenu: this.getValue(
|
|
container ? container.showOptionsAsMenu : this.showOptionsAsMenu
|
|
),
|
|
selectableItems: this.getValue(
|
|
container ? container.selectableItems : this.selectableItems
|
|
),
|
|
clickableItems: this.getValue(
|
|
container ? container.clickableItems : this.clickableItems
|
|
),
|
|
itemTemplate: this.getValue(
|
|
container ? container.itemTemplate : this.itemTemplate
|
|
),
|
|
slidingOptionTemplate: this.getValue(
|
|
container
|
|
? container.slidingOptionTemplate
|
|
: this.slidingOptionTemplate
|
|
),
|
|
nonSlidingOptionTemplate: this.getValue(
|
|
container
|
|
? container.nonSlidingOptionTemplate
|
|
: this.nonSlidingOptionTemplate
|
|
),
|
|
confirmRemove: this.getValue(
|
|
container ? container.confirmRemove : this.confirmRemove
|
|
),
|
|
items: this.getValue(container ? container.items : this.items),
|
|
showItemOptions: this.getValue(
|
|
container ? container.showItemOptions : this.showItemOptions
|
|
),
|
|
filteringHandler: this.getValue(
|
|
container ? container.filteringHandler : this.filteringHandler
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
itemsChanged: this.itemsChanged,
|
|
itemSelected: this.itemSelected,
|
|
optionSelected: this.optionSelected,
|
|
removeItems: this.removeItems,
|
|
selectionChanged: this.selectionChanged,
|
|
orderChanged: this.orderChanged,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentListContainer = {
|
|
[TKey in keyof IXListContainer as `list${Capitalize<
|
|
string & TKey
|
|
>}`]: IXListContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentListContainer
|
|
extends TXComponentListContainer,
|
|
IXBaseComponentContainer {
|
|
showList: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentListContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentListContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
//
|
|
readonly showList: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly listActionProvider: Subject<XListActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly listCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly listActionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
> = this.propertyProvider.actionBarHideActions;
|
|
readonly listUseDefaultActions: XStandardType<boolean> =
|
|
this.propertyProvider.useDefaultActions;
|
|
readonly listShowToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.showToolbar;
|
|
readonly listStickyToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.stickyToolbar;
|
|
|
|
//
|
|
readonly listColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly listForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly listEnableReordering: XStandardType<boolean> =
|
|
this.propertyProvider.enableReordering;
|
|
readonly listShowDivider: XStandardType<boolean> =
|
|
this.propertyProvider.showDivider;
|
|
readonly listShowOptionsAsSlide: XStandardType<boolean> =
|
|
this.propertyProvider.showOptionsAsSlide;
|
|
readonly listCloseOptionsAfterSelect: XStandardType<boolean> =
|
|
this.propertyProvider.closeOptionsAfterSelect;
|
|
readonly listShowOptionsAsMenu: XStandardType<boolean> =
|
|
this.propertyProvider.showOptionsAsMenu;
|
|
|
|
//
|
|
readonly listSelectableItems: XStandardType<boolean> =
|
|
this.propertyProvider.selectableItems;
|
|
readonly listClickableItems: XStandardType<boolean> =
|
|
this.propertyProvider.clickableItems;
|
|
readonly listItemTemplate: TemplateRef<any> =
|
|
this.propertyProvider.itemTemplate;
|
|
readonly listSlidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.slidingOptionTemplate;
|
|
readonly listNonSlidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.nonSlidingOptionTemplate;
|
|
|
|
//
|
|
readonly listItemSelected: EventEmitter<XListItem<any>> =
|
|
this.propertyProvider.itemSelected;
|
|
readonly listOptionSelected: EventEmitter<XListItemOptionSelectedEvent> =
|
|
this.propertyProvider.optionSelected;
|
|
readonly listConfirmRemove: XStandardType<boolean> =
|
|
this.propertyProvider.confirmRemove;
|
|
readonly listRemoveItems: EventEmitter<XBaseRangeRequestDto<any>> =
|
|
this.propertyProvider.removeItems;
|
|
|
|
//
|
|
readonly listSelectionChanged: EventEmitter<XListItem<any>[]> =
|
|
this.propertyProvider.selectionChanged;
|
|
readonly listOrderChanged: EventEmitter<void> =
|
|
this.propertyProvider.orderChanged;
|
|
readonly listItems: XStandardType<XListItem<any>[]> =
|
|
this.propertyProvider.items;
|
|
readonly listShowItemOptions: XStandardType<boolean> =
|
|
this.propertyProvider.showItemOptions;
|
|
readonly listItemsChanged: EventEmitter<void> =
|
|
this.propertyProvider.itemsChanged;
|
|
readonly listFilteringHandler: XListFilteringHandler =
|
|
this.propertyProvider.filteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Card ...
|
|
readonly listIsInPage: XStandardType<boolean> =
|
|
this.propertyProvider.isInPage;
|
|
readonly listWrapWithCard: XStandardType<boolean> =
|
|
this.propertyProvider.wrapWithCard;
|
|
readonly listCardShowFooter: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowFooter;
|
|
readonly listCardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.cardShowActions;
|
|
readonly listCardColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.cardColor;
|
|
readonly listCardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.cardForegroundColor;
|
|
readonly listCardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardTitle;
|
|
readonly listCardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.cardActionProvider;
|
|
readonly listCardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cardSubTitle;
|
|
readonly listCardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Empty ...
|
|
//
|
|
readonly listShowEmpty: XStandardType<boolean> =
|
|
this.propertyProvider.showEmpty;
|
|
readonly listEmptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.emptyHasRefresh;
|
|
readonly listEmptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.emptyActionProvider;
|
|
readonly listEmptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.emptyCssClass;
|
|
readonly listEmptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyColor;
|
|
readonly listEmptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundColor;
|
|
readonly listEmptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyMessageColor;
|
|
readonly listEmptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundMessageColor;
|
|
readonly listEmptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyRefreshButtonColor;
|
|
readonly listEmptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.emptyForegroundRefreshButtonColor;
|
|
readonly listEmptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.emptyMessage;
|
|
readonly listEmptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.emptyRefreshIcon;
|
|
readonly listEmptyRefresh: EventEmitter<void> =
|
|
this.propertyProvider.emptyRefresh;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
readonly listShowActionBar: XStandardType<boolean> =
|
|
this.propertyProvider.showActionBar;
|
|
|
|
//
|
|
readonly listActionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.actionBarActionProvider;
|
|
readonly listActionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
//
|
|
readonly listActionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
readonly listActionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
|
|
//
|
|
readonly listActionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.actionBarActions;
|
|
|
|
//
|
|
readonly listActionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
|
|
this.propertyProvider.actionBarActionFired;
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
readonly listShowSearchBar: XStandardType<boolean> =
|
|
this.propertyProvider.showSearchBar;
|
|
|
|
//
|
|
readonly listSearchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.searchBarActionProvider;
|
|
readonly listSearchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
readonly listSearchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
readonly listSearchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
readonly listSearchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchInputColor;
|
|
readonly listSearchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
readonly listSearchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarType;
|
|
readonly listSearchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarTitle;
|
|
readonly listSearchBarValue: XStandardType<string> =
|
|
this.propertyProvider.searchBarValue;
|
|
readonly listSearchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.searchBarEnterKeyHint;
|
|
readonly listSearchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarKeyboardType;
|
|
readonly listSearchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarSpellcheck;
|
|
readonly listSearchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
readonly listSearchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowCancelButton;
|
|
readonly listSearchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIcon;
|
|
readonly listSearchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonTitle;
|
|
readonly listSearchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
readonly listSearchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowClearButton;
|
|
readonly listSearchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIcon;
|
|
readonly listSearchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
readonly listSearchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIcon;
|
|
readonly listSearchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
readonly listSearchBarQueryChange: EventEmitter<string> =
|
|
this.propertyProvider.searchBarQueryChange;
|
|
readonly listSearchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
|
|
this.propertyProvider.searchBarOnEvent;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XListContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XComponentListContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentListContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
//
|
|
@Input()
|
|
showList: XStandardType<boolean> = this.propertyProvider.showList;
|
|
|
|
//
|
|
@Input()
|
|
listActionProvider: Subject<XListActionModel> =
|
|
this.propertyProvider.listActionProvider;
|
|
|
|
@Input()
|
|
listCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listCssClass;
|
|
|
|
//
|
|
@Input()
|
|
listActionBarHideActions: XStandardType<
|
|
XOneOrManyType<XActionBarActionIdentifier>
|
|
> = this.propertyProvider.listActionBarHideActions;
|
|
|
|
@Input()
|
|
listUseDefaultActions: XStandardType<boolean> =
|
|
this.propertyProvider.listUseDefaultActions;
|
|
|
|
@Input()
|
|
listShowToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.listShowToolbar;
|
|
|
|
@Input()
|
|
listStickyToolbar: XStandardType<boolean> =
|
|
this.propertyProvider.listStickyToolbar;
|
|
|
|
//
|
|
@Input()
|
|
listColor: XStandardType<XColorIdentifier> = this.propertyProvider.listColor;
|
|
|
|
@Input()
|
|
listForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.listForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
listEnableReordering: XStandardType<boolean> =
|
|
this.propertyProvider.listEnableReordering;
|
|
|
|
@Input()
|
|
listShowDivider: XStandardType<boolean> =
|
|
this.propertyProvider.listShowDivider;
|
|
|
|
@Input()
|
|
listShowOptionsAsSlide: XStandardType<boolean> =
|
|
this.propertyProvider.listShowOptionsAsSlide;
|
|
|
|
@Input()
|
|
listCloseOptionsAfterSelect: XStandardType<boolean> =
|
|
this.propertyProvider.listCloseOptionsAfterSelect;
|
|
|
|
@Input()
|
|
listShowOptionsAsMenu: XStandardType<boolean> =
|
|
this.propertyProvider.listShowOptionsAsMenu;
|
|
|
|
//
|
|
@Input()
|
|
listSelectableItems: XStandardType<boolean> =
|
|
this.propertyProvider.listSelectableItems;
|
|
|
|
@Input()
|
|
listClickableItems: XStandardType<boolean> =
|
|
this.propertyProvider.listClickableItems;
|
|
|
|
@Input()
|
|
listItemTemplate: TemplateRef<any> = this.propertyProvider.listItemTemplate;
|
|
|
|
@Input()
|
|
listSlidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.listSlidingOptionTemplate;
|
|
|
|
@Input()
|
|
listNonSlidingOptionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.listNonSlidingOptionTemplate;
|
|
|
|
//
|
|
@Output()
|
|
listItemSelected: EventEmitter<XListItem<any>> = new EventEmitter();
|
|
|
|
@Output()
|
|
listOptionSelected: EventEmitter<XListItemOptionSelectedEvent> = new EventEmitter();
|
|
|
|
@Input()
|
|
listConfirmRemove: XStandardType<boolean> =
|
|
this.propertyProvider.listConfirmRemove;
|
|
|
|
@Output()
|
|
listRemoveItems: EventEmitter<XBaseRangeRequestDto<any>> = new EventEmitter();
|
|
|
|
//
|
|
@Output()
|
|
listSelectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter();
|
|
|
|
@Output()
|
|
listOrderChanged: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Input()
|
|
listItems: XStandardType<XListItem<any>[]> = this.propertyProvider.listItems;
|
|
|
|
@Input()
|
|
listShowItemOptions: XStandardType<boolean> =
|
|
this.propertyProvider.listShowItemOptions;
|
|
|
|
@Output()
|
|
listItemsChanged: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Input()
|
|
listFilteringHandler: XListFilteringHandler =
|
|
this.propertyProvider.listFilteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Card ...
|
|
@Input()
|
|
listIsInPage: XStandardType<boolean> = this.propertyProvider.listIsInPage;
|
|
|
|
@Input()
|
|
listWrapWithCard: XStandardType<boolean> =
|
|
this.propertyProvider.listWrapWithCard;
|
|
|
|
@Input()
|
|
listCardShowFooter: XStandardType<boolean> =
|
|
this.propertyProvider.listCardShowFooter;
|
|
|
|
@Input()
|
|
listCardShowActions: XStandardType<boolean> =
|
|
this.propertyProvider.listCardShowActions;
|
|
|
|
@Input()
|
|
listCardColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listCardColor;
|
|
|
|
@Input()
|
|
listCardForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.listCardForegroundColor;
|
|
|
|
@Input()
|
|
listCardTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.listCardTitle;
|
|
|
|
@Input()
|
|
listCardActionProvider: Subject<XCardActionModel> =
|
|
this.propertyProvider.listCardActionProvider;
|
|
|
|
@Input()
|
|
listCardSubTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.listCardSubTitle;
|
|
|
|
@Input()
|
|
listCardCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listCardCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Empty ...
|
|
//
|
|
@Input()
|
|
listShowEmpty: XStandardType<boolean> = this.propertyProvider.listShowEmpty;
|
|
|
|
@Input()
|
|
listEmptyHasRefresh: XStandardType<boolean> =
|
|
this.propertyProvider.listEmptyHasRefresh;
|
|
|
|
@Input()
|
|
listEmptyActionProvider: Subject<XEmptyActionModel> =
|
|
this.propertyProvider.listEmptyActionProvider;
|
|
|
|
@Input()
|
|
listEmptyCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listEmptyCssClass;
|
|
|
|
@Input()
|
|
listEmptyColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listEmptyColor;
|
|
|
|
@Input()
|
|
listEmptyForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.listEmptyForegroundColor;
|
|
|
|
@Input()
|
|
listEmptyMessageColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listEmptyMessageColor;
|
|
|
|
@Input()
|
|
listEmptyForegroundMessageColor: XStandardType<boolean> =
|
|
this.propertyProvider.listEmptyForegroundMessageColor;
|
|
|
|
@Input()
|
|
listEmptyRefreshButtonColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listEmptyRefreshButtonColor;
|
|
|
|
@Input()
|
|
listEmptyForegroundRefreshButtonColor: XStandardType<boolean> =
|
|
this.propertyProvider.listEmptyForegroundRefreshButtonColor;
|
|
|
|
@Input()
|
|
listEmptyMessage: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.listEmptyMessage;
|
|
|
|
@Input()
|
|
listEmptyRefreshIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.listEmptyRefreshIcon;
|
|
|
|
@Output()
|
|
listEmptyRefresh: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
//
|
|
@Input()
|
|
listShowActionBar: XStandardType<boolean> =
|
|
this.propertyProvider.listShowActionBar;
|
|
|
|
//
|
|
@Input()
|
|
listActionBarActionProvider: Subject<XActionBarActionModel> =
|
|
this.propertyProvider.listActionBarActionProvider;
|
|
|
|
@Input()
|
|
listActionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listActionBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
listActionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listActionBarColor;
|
|
|
|
@Input()
|
|
listActionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.listActionBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
listActionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
|
|
this.propertyProvider.listActionBarActions;
|
|
|
|
//
|
|
@Output()
|
|
listActionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar ...
|
|
//
|
|
@Input()
|
|
listShowSearchBar: XStandardType<boolean> =
|
|
this.propertyProvider.listShowSearchBar;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.listSearchBarActionProvider;
|
|
|
|
@Input()
|
|
listSearchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.listSearchBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listSearchBarColor;
|
|
|
|
@Input()
|
|
listSearchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.listSearchBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listSearchBarSearchInputColor;
|
|
|
|
@Input()
|
|
listSearchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.listSearchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.listSearchBarType;
|
|
|
|
@Input()
|
|
listSearchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.listSearchBarTitle;
|
|
|
|
@Input()
|
|
listSearchBarValue: XStandardType<string> =
|
|
this.propertyProvider.listSearchBarValue;
|
|
|
|
@Input()
|
|
listSearchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.listSearchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
listSearchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.listSearchBarKeyboardType;
|
|
|
|
@Input()
|
|
listSearchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.listSearchBarSpellcheck;
|
|
|
|
@Input()
|
|
listSearchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.listSearchBarDebounce;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.listSearchBarShowCancelButton;
|
|
|
|
@Input()
|
|
listSearchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.listSearchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.listSearchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
listSearchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listSearchBarCancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.listSearchBarShowClearButton;
|
|
|
|
@Input()
|
|
listSearchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.listSearchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listSearchBarClearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
listSearchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.listSearchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.listSearchBarSearchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
listSearchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
listSearchBarOnEvent: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentListContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentListContainer
|
|
): Observable<IXComponentListContainer> {
|
|
return forkJoin({
|
|
//
|
|
showList: this.getValue(container ? container.showList : this.showList),
|
|
listCssClass: this.getValue(
|
|
container ? container.listCssClass : this.listCssClass
|
|
),
|
|
listActionBarHideActions: this.getValue(
|
|
container
|
|
? container.listActionBarHideActions
|
|
: this.listActionBarHideActions
|
|
),
|
|
listUseDefaultActions: this.getValue(
|
|
container ? container.listUseDefaultActions : this.listUseDefaultActions
|
|
),
|
|
listShowToolbar: this.getValue(
|
|
container ? container.listShowToolbar : this.listShowToolbar
|
|
),
|
|
listStickyToolbar: this.getValue(
|
|
container ? container.listStickyToolbar : this.listStickyToolbar
|
|
),
|
|
listColor: this.getValue(
|
|
container ? container.listColor : this.listColor
|
|
),
|
|
listForegroundColor: this.getValue(
|
|
container ? container.listForegroundColor : this.listForegroundColor
|
|
),
|
|
listEnableReordering: this.getValue(
|
|
container ? container.listEnableReordering : this.listEnableReordering
|
|
),
|
|
listShowDivider: this.getValue(
|
|
container ? container.listShowDivider : this.listShowDivider
|
|
),
|
|
listShowOptionsAsSlide: this.getValue(
|
|
container
|
|
? container.listShowOptionsAsSlide
|
|
: this.listShowOptionsAsSlide
|
|
),
|
|
listCloseOptionsAfterSelect: this.getValue(
|
|
container
|
|
? container.listCloseOptionsAfterSelect
|
|
: this.listCloseOptionsAfterSelect
|
|
),
|
|
listShowOptionsAsMenu: this.getValue(
|
|
container ? container.listShowOptionsAsMenu : this.listShowOptionsAsMenu
|
|
),
|
|
listSelectableItems: this.getValue(
|
|
container ? container.listSelectableItems : this.listSelectableItems
|
|
),
|
|
listClickableItems: this.getValue(
|
|
container ? container.listClickableItems : this.listClickableItems
|
|
),
|
|
listItemTemplate: this.getValue(
|
|
container ? container.listItemTemplate : this.listItemTemplate
|
|
),
|
|
listSlidingOptionTemplate: this.getValue(
|
|
container
|
|
? container.listSlidingOptionTemplate
|
|
: this.listSlidingOptionTemplate
|
|
),
|
|
listNonSlidingOptionTemplate: this.getValue(
|
|
container
|
|
? container.listNonSlidingOptionTemplate
|
|
: this.listNonSlidingOptionTemplate
|
|
),
|
|
listConfirmRemove: this.getValue(
|
|
container ? container.listConfirmRemove : this.listConfirmRemove
|
|
),
|
|
listItems: this.getValue(
|
|
container ? container.listItems : this.listItems
|
|
),
|
|
listShowItemOptions: this.getValue(
|
|
container ? container.listShowItemOptions : this.listShowItemOptions
|
|
),
|
|
listFilteringHandler: this.getValue(
|
|
container ? container.listFilteringHandler : this.listFilteringHandler
|
|
),
|
|
listIsInPage: this.getValue(
|
|
container ? container.listIsInPage : this.listIsInPage
|
|
),
|
|
listWrapWithCard: this.getValue(
|
|
container ? container.listWrapWithCard : this.listWrapWithCard
|
|
),
|
|
listCardShowFooter: this.getValue(
|
|
container ? container.listCardShowFooter : this.listCardShowFooter
|
|
),
|
|
listCardShowActions: this.getValue(
|
|
container ? container.listCardShowActions : this.listCardShowActions
|
|
),
|
|
listCardColor: this.getValue(
|
|
container ? container.listCardColor : this.listCardColor
|
|
),
|
|
listCardForegroundColor: this.getValue(
|
|
container
|
|
? container.listCardForegroundColor
|
|
: this.listCardForegroundColor
|
|
),
|
|
listCardTitle: this.getValue(
|
|
container ? container.listCardTitle : this.listCardTitle
|
|
),
|
|
listCardSubTitle: this.getValue(
|
|
container ? container.listCardSubTitle : this.listCardSubTitle
|
|
),
|
|
listCardCssClass: this.getValue(
|
|
container ? container.listCardCssClass : this.listCardCssClass
|
|
),
|
|
listShowEmpty: this.getValue(
|
|
container ? container.listShowEmpty : this.listShowEmpty
|
|
),
|
|
listEmptyHasRefresh: this.getValue(
|
|
container ? container.listEmptyHasRefresh : this.listEmptyHasRefresh
|
|
),
|
|
listEmptyCssClass: this.getValue(
|
|
container ? container.listEmptyCssClass : this.listEmptyCssClass
|
|
),
|
|
listEmptyColor: this.getValue(
|
|
container ? container.listEmptyColor : this.listEmptyColor
|
|
),
|
|
listEmptyForegroundColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundColor
|
|
: this.listEmptyForegroundColor
|
|
),
|
|
listEmptyMessageColor: this.getValue(
|
|
container ? container.listEmptyMessageColor : this.listEmptyMessageColor
|
|
),
|
|
listEmptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundMessageColor
|
|
: this.listEmptyForegroundMessageColor
|
|
),
|
|
listEmptyRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.listEmptyRefreshButtonColor
|
|
: this.listEmptyRefreshButtonColor
|
|
),
|
|
listEmptyForegroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundRefreshButtonColor
|
|
: this.listEmptyForegroundRefreshButtonColor
|
|
),
|
|
listEmptyMessage: this.getValue(
|
|
container ? container.listEmptyMessage : this.listEmptyMessage
|
|
),
|
|
listEmptyRefreshIcon: this.getValue(
|
|
container ? container.listEmptyRefreshIcon : this.listEmptyRefreshIcon
|
|
),
|
|
listShowActionBar: this.getValue(
|
|
container ? container.listShowActionBar : this.listShowActionBar
|
|
),
|
|
listActionBarCssClass: this.getValue(
|
|
container ? container.listActionBarCssClass : this.listActionBarCssClass
|
|
),
|
|
listActionBarColor: this.getValue(
|
|
container ? container.listActionBarColor : this.listActionBarColor
|
|
),
|
|
listActionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.listActionBarForegroundColor
|
|
: this.listActionBarForegroundColor
|
|
),
|
|
listActionBarActions: this.getValue(
|
|
container ? container.listActionBarActions : this.listActionBarActions
|
|
),
|
|
listShowSearchBar: this.getValue(
|
|
container ? container.listShowSearchBar : this.listShowSearchBar
|
|
),
|
|
listSearchBarCssClass: this.getValue(
|
|
container ? container.listSearchBarCssClass : this.listSearchBarCssClass
|
|
),
|
|
listSearchBarColor: this.getValue(
|
|
container ? container.listSearchBarColor : this.listSearchBarColor
|
|
),
|
|
listSearchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.listSearchBarForegroundColor
|
|
: this.listSearchBarForegroundColor
|
|
),
|
|
listSearchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchInputColor
|
|
: this.listSearchBarSearchInputColor
|
|
),
|
|
listSearchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.listSearchBarForegroundSearchInputColor
|
|
: this.listSearchBarForegroundSearchInputColor
|
|
),
|
|
listSearchBarType: this.getValue(
|
|
container ? container.listSearchBarType : this.listSearchBarType
|
|
),
|
|
listSearchBarTitle: this.getValue(
|
|
container ? container.listSearchBarTitle : this.listSearchBarTitle
|
|
),
|
|
listSearchBarValue: this.getValue(
|
|
container ? container.listSearchBarValue : this.listSearchBarValue
|
|
),
|
|
listSearchBarEnterKeyHint: this.getValue(
|
|
container
|
|
? container.listSearchBarEnterKeyHint
|
|
: this.listSearchBarEnterKeyHint
|
|
),
|
|
listSearchBarKeyboardType: this.getValue(
|
|
container
|
|
? container.listSearchBarKeyboardType
|
|
: this.listSearchBarKeyboardType
|
|
),
|
|
listSearchBarSpellcheck: this.getValue(
|
|
container
|
|
? container.listSearchBarSpellcheck
|
|
: this.listSearchBarSpellcheck
|
|
),
|
|
listSearchBarDebounce: this.getValue(
|
|
container ? container.listSearchBarDebounce : this.listSearchBarDebounce
|
|
),
|
|
listSearchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.listSearchBarShowCancelButton
|
|
: this.listSearchBarShowCancelButton
|
|
),
|
|
listSearchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarCancelButtonIcon
|
|
: this.listSearchBarCancelButtonIcon
|
|
),
|
|
listSearchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.listSearchBarCancelButtonTitle
|
|
: this.listSearchBarCancelButtonTitle
|
|
),
|
|
listSearchBarCancelButtonIconColor: this.getValue(
|
|
container
|
|
? container.listSearchBarCancelButtonIconColor
|
|
: this.listSearchBarCancelButtonIconColor
|
|
),
|
|
listSearchBarShowClearButton: this.getValue(
|
|
container
|
|
? container.listSearchBarShowClearButton
|
|
: this.listSearchBarShowClearButton
|
|
),
|
|
listSearchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarClearButtonIcon
|
|
: this.listSearchBarClearButtonIcon
|
|
),
|
|
listSearchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.listSearchBarClearButtonIconColor
|
|
: this.listSearchBarClearButtonIconColor
|
|
),
|
|
listSearchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchButtonIcon
|
|
: this.listSearchBarSearchButtonIcon
|
|
),
|
|
listSearchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchButtonIconColor
|
|
: this.listSearchBarSearchButtonIconColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
listActionProvider: container
|
|
? container.listActionProvider
|
|
: this.listActionProvider,
|
|
|
|
//
|
|
listItemSelected: this.listItemSelected,
|
|
listOptionSelected: this.listOptionSelected,
|
|
listRemoveItems: this.listRemoveItems,
|
|
listSelectionChanged: this.listSelectionChanged,
|
|
listOrderChanged: this.listOrderChanged,
|
|
listItemsChanged: this.listItemsChanged,
|
|
|
|
//
|
|
listCardActionProvider: container
|
|
? container.listCardActionProvider
|
|
: this.listCardActionProvider,
|
|
listEmptyActionProvider: container
|
|
? container.listEmptyActionProvider
|
|
: this.listEmptyActionProvider,
|
|
|
|
//
|
|
listEmptyRefresh: this.listEmptyRefresh,
|
|
|
|
//
|
|
listActionBarActionProvider: container
|
|
? container.listActionBarActionProvider
|
|
: this.listActionBarActionProvider,
|
|
|
|
//
|
|
listActionBarActionFired: this.listActionBarActionFired,
|
|
|
|
//
|
|
listSearchBarActionProvider: container
|
|
? container.listSearchBarActionProvider
|
|
: this.listSearchBarActionProvider,
|
|
|
|
//
|
|
listSearchBarQueryChange: this.listSearchBarQueryChange,
|
|
listSearchBarOnEvent: this.listSearchBarOnEvent,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else mapRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="mapRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Map Ref -->
|
|
<ng-template #mapRef>
|
|
<div class="x-map x-wrapper" [hidden]="!(getValue(showMapView) | async)">
|
|
<!-- Map View -->
|
|
<div #mapView [id]="componentId" class="x-map-inner"></div>
|
|
|
|
<!-- Top -->
|
|
<div class="x-map-top">
|
|
<!-- Search -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showSearchBar) | async) &&
|
|
(getValue(searchBarPosition) | async) === ItemPositions.TOP
|
|
? searchRef
|
|
: nothingRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- ProgressBar -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showProgressBar) | async) &&
|
|
(getValue(progressBarPosition) | async) === ItemPositions.TOP
|
|
? progressBarRef
|
|
: nothingRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Plugins -->
|
|
<div #pluginsBar>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(canShowPlugins(ItemPositions.TOP) | async)
|
|
? pluginsRef
|
|
: nothingRef;
|
|
context: { position: ItemPositions.TOP }
|
|
"
|
|
>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bottom -->
|
|
<div class="x-map-bottom">
|
|
<!-- Plugins -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(canShowPlugins(ItemPositions.BOTTOM) | async)
|
|
? pluginsRef
|
|
: nothingRef;
|
|
context: { position: ItemPositions.BOTTOM }
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- Search -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showSearchBar) | async) &&
|
|
(getValue(searchBarPosition) | async) === ItemPositions.BOTTOM
|
|
? searchRef
|
|
: nothingRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
|
|
<!-- ProgressBar -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showProgressBar) | async) &&
|
|
(getValue(progressBarPosition) | async) === ItemPositions.BOTTOM
|
|
? progressBarRef
|
|
: nothingRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Search Template -->
|
|
<ng-template #searchRef>
|
|
<!-- SearchBar -->
|
|
<x-search-bar
|
|
#searchBar
|
|
(queryChange)="handleSeach($event)"
|
|
*ngIf="getValue(showSearchBar) | async"
|
|
[type]="getValue(searchBarType) | async"
|
|
(onEvent)="handleSearchBarEvents($event)"
|
|
[loading]="getValue(isSearching) | async"
|
|
[actionProvider]="searchBarActionProvider"
|
|
[color]="getValue(searchBarColor) | async"
|
|
[value]="getValue(searchBarValue) | async"
|
|
[uiDisabled]="getValue(isSearching) | async"
|
|
[debounce]="getValue(searchBarDebounce) | async"
|
|
[cssClass]="getValue(searchBarCssClass) | async"
|
|
[title]="getResourceValue(searchBarTitle) | async"
|
|
[spellcheck]="getValue(searchBarSpellcheck) | async"
|
|
[foregroundSearchInputColor]="
|
|
getValue(searchBarForegroundSearchInputColor) | async
|
|
"
|
|
[enterKeyHint]="getValue(searchBarEnterKeyHint) | async"
|
|
[keyboardType]="getValue(searchBarKeyboardType) | async"
|
|
[foregroundColor]="getValue(searchBarForegroundColor) | async"
|
|
[clearButtonIcon]="getValue(searchBarClearButtonIcon) | async"
|
|
[searchButtonIcon]="getValue(searchBarSearchButtonIcon) | async"
|
|
[searchInputColor]="getValue(searchBarSearchInputColor) | async"
|
|
[cancelButtonIcon]="getValue(searchBarCancelButtonIcon) | async"
|
|
[showCancelButton]="getValue(searchBarShowCancelButton) | async"
|
|
[cancelButtonTitle]="getValue(searchBarCancelButtonTitle) | async"
|
|
[clearButtonIconColor]="getValue(searchBarClearButtonIconColor) | async"
|
|
[searchButtonIconColor]="getValue(searchBarSearchButtonIconColor) | async"
|
|
></x-search-bar>
|
|
|
|
<!-- Search Result -->
|
|
<x-list
|
|
xMouseHandler
|
|
[showEmpty]="false"
|
|
[wrapWithCard]="false"
|
|
[clickableItems]="true"
|
|
class="x-map-search-list"
|
|
[uiDisabled]="uiDisabled"
|
|
[itemTemplate]="resultRef"
|
|
[items]="searchResultListItems"
|
|
(itemSelected)="handleChangeLocation($event)"
|
|
[class.open]="getValue(searchPaneOpen) | async"
|
|
[color]="getValue(searchResultListColor) | async"
|
|
[enableHandler]="getValue(searchPaneOpen) | async"
|
|
[class.has-search]="getValue(showSearchBar) | async"
|
|
(onWindowFinished)="handleLocationResultClickOutside($event)"
|
|
></x-list>
|
|
</ng-template>
|
|
|
|
<!-- ProgressBar Template -->
|
|
<ng-template #progressBarRef>
|
|
<!-- Progressbar for Loading -->
|
|
<ion-progress-bar
|
|
type="indeterminate"
|
|
[color]="getValue(progressBarColor) | async"
|
|
*ngIf="
|
|
(getValue(showProgressBar) | async) &&
|
|
(getValue(loading) | async)
|
|
"
|
|
></ion-progress-bar>
|
|
</ng-template>
|
|
|
|
<!-- Plugins Template -->
|
|
<ng-template #pluginsRef let-position="position">
|
|
<div class="x-map-plugins-wrapper">
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[endBottomSlotCssClass]="'x-auto-size-flex'"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot [name]="SlotNames.START" [cssClass]="'ion-text-start'">
|
|
<!-- Locator -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showLocator) | async) &&
|
|
(getValue(locatorPosition) | async) === position
|
|
? locatorRef
|
|
: nothingRef
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Go Marked Place -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showGoMarkedPlace) | async) &&
|
|
(getValue(goMarkedPlacePosition) | async) === position
|
|
? goMarkedPlaceRef
|
|
: nothingRef
|
|
"
|
|
></ng-container>
|
|
|
|
<!-- Clear Marker -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showClearMarker) | async) &&
|
|
(getValue(clearMarkerPosition) | async) === position
|
|
? clearMarkerRef
|
|
: nothingRef
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
class="x-auto-size-flex"
|
|
[cssClass]="'ion-text-end'"
|
|
>
|
|
<!-- Selected Location -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getValue(showSelectedLocation) | async) &&
|
|
(getValue(selectedLocationPosition) | async) === position
|
|
? selectedLocationRef
|
|
: nothingRef
|
|
"
|
|
></ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- SelectedLocation Template -->
|
|
<ng-template #selectedLocationRef>
|
|
<span
|
|
*ngIf="notEmptyValue(currentPosition) | async"
|
|
class="x-map-plugin x-selected-location ol-control"
|
|
>
|
|
<button (click)="handleSlectedLocationClicked(currentPosition)">
|
|
{{ getValue(currentPosition) | async }}
|
|
</button>
|
|
</span>
|
|
</ng-template>
|
|
|
|
<!-- Locator Template -->
|
|
<ng-template #locatorRef>
|
|
<span class="x-map-plugin x-locator ol-control">
|
|
<button
|
|
(click)="handleLocate()"
|
|
[disabled]="
|
|
(getValue(uiDisabled) | async) || (getValue(loading) | async)
|
|
"
|
|
>
|
|
<ion-icon name="locate-outline"></ion-icon>
|
|
</button>
|
|
</span>
|
|
</ng-template>
|
|
|
|
<!-- GoMarkedLocation Template -->
|
|
<ng-template #goMarkedPlaceRef>
|
|
<span
|
|
*ngIf="getValue(hasMarker) | async"
|
|
class="x-map-plugin x-go-marked-place ol-control"
|
|
>
|
|
<button
|
|
(click)="handleGoMarkedPlace()"
|
|
[disabled]="
|
|
(getValue(uiDisabled) | async) || (getValue(loading) | async)
|
|
"
|
|
>
|
|
<ion-icon name="navigate"></ion-icon>
|
|
</button>
|
|
</span>
|
|
</ng-template>
|
|
|
|
<!-- ClearMarker Template -->
|
|
<ng-template #clearMarkerRef>
|
|
<span
|
|
*ngIf="getValue(hasMarker) | async"
|
|
class="x-map-plugin x-clear-marker ol-control"
|
|
>
|
|
<button
|
|
(click)="handleClearMarker()"
|
|
[disabled]="
|
|
(getValue(uiDisabled) | async) || (getValue(loading) | async)
|
|
"
|
|
>
|
|
<ion-icon name="close-outline"></ion-icon>
|
|
</button>
|
|
</span>
|
|
</ng-template>
|
|
|
|
<!-- Place Result Template -->
|
|
<ng-template #resultRef let-item>
|
|
{{ item.data.display_name }}
|
|
</ng-template>
|
|
|
|
<!-- Nothing Template -->
|
|
<ng-template #nothingRef></ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.scss
|
|
|
|
:host {
|
|
--map-height: 200px;
|
|
--map-controls-offest: 5px;
|
|
}
|
|
|
|
:host ::ng-deep .x-auto-size-flex {
|
|
flex-grow: 0 !important;
|
|
flex-shrink: 1 !important;
|
|
flex-basis: auto !important;
|
|
}
|
|
|
|
.x-map {
|
|
position: relative;
|
|
}
|
|
|
|
.x-map-inner {
|
|
height: var(--map-height);
|
|
width: 100%;
|
|
}
|
|
|
|
.x-map-top,
|
|
.x-map-bottom {
|
|
width: 100%;
|
|
position: absolute;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.x-map-top {
|
|
top: 0;
|
|
}
|
|
|
|
.x-map-bottom {
|
|
bottom: 0;
|
|
}
|
|
|
|
.x-map-plugins-wrapper {
|
|
margin: .5em;
|
|
}
|
|
|
|
.x-map-plugin {
|
|
&.ol-control {
|
|
padding: 0;
|
|
position: relative;
|
|
margin-top: 0 !important;
|
|
}
|
|
|
|
button {
|
|
padding: 3px;
|
|
width: fit-content;
|
|
display: inline-block;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Search Result ...
|
|
//
|
|
$duration: 250ms;
|
|
$transform-show: scaleY(1);
|
|
$transform-hide: scaleY(0);
|
|
|
|
//
|
|
.x-map-search-list {
|
|
//
|
|
position: absolute;
|
|
|
|
//
|
|
z-index: 110;
|
|
|
|
//
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 0;
|
|
|
|
//
|
|
transform: $transform-hide;
|
|
-ms-transform: $transform-hide;
|
|
-webkit-transform: $transform-hide;
|
|
|
|
//
|
|
transition: transform;
|
|
-webkit-transition: transform;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
|
|
//
|
|
&.open {
|
|
//
|
|
height: auto;
|
|
|
|
//
|
|
transform: $transform-show;
|
|
-ms-transform: $transform-show;
|
|
-webkit-transform: $transform-show;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
|
|
//
|
|
&.has-search {
|
|
top: 56px;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ol Theme ...
|
|
|
|
:host ::ng-deep {
|
|
.x-content.mat-card-content {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
.ol-control {
|
|
margin-top: var(--map-controls-offest);
|
|
}
|
|
|
|
.ol-box {
|
|
box-sizing: border-box;
|
|
border-radius: 2px;
|
|
border: 2px solid blue;
|
|
}
|
|
|
|
.ol-mouse-position {
|
|
top: 8px;
|
|
right: 8px;
|
|
position: absolute;
|
|
}
|
|
|
|
.ol-scale-line {
|
|
background: rgba(0, 60, 136, 0.3);
|
|
border-radius: 4px;
|
|
bottom: 8px;
|
|
left: 8px;
|
|
padding: 2px;
|
|
position: absolute;
|
|
}
|
|
|
|
.ol-scale-line-inner {
|
|
border: 1px solid #eee;
|
|
border-top: none;
|
|
color: #eee;
|
|
font-size: 10px;
|
|
text-align: center;
|
|
margin: 1px;
|
|
will-change: contents, width;
|
|
transition: all 0.25s;
|
|
}
|
|
|
|
.ol-scale-bar {
|
|
position: absolute;
|
|
bottom: 8px;
|
|
left: 8px;
|
|
}
|
|
|
|
.ol-scale-step-marker {
|
|
width: 1px;
|
|
height: 15px;
|
|
background-color: #000000;
|
|
float: right;
|
|
z-index: 10;
|
|
}
|
|
|
|
.ol-scale-step-text {
|
|
position: absolute;
|
|
bottom: -5px;
|
|
font-size: 12px;
|
|
z-index: 11;
|
|
color: #000000;
|
|
text-shadow: -2px 0 #ffffff, 0 2px #ffffff, 2px 0 #ffffff, 0 -2px #ffffff;
|
|
}
|
|
|
|
.ol-scale-text {
|
|
position: absolute;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
bottom: 25px;
|
|
color: #000000;
|
|
text-shadow: -2px 0 #ffffff, 0 2px #ffffff, 2px 0 #ffffff, 0 -2px #ffffff;
|
|
}
|
|
|
|
.ol-scale-singlebar {
|
|
position: relative;
|
|
height: 10px;
|
|
z-index: 9;
|
|
border: 1px solid black;
|
|
}
|
|
|
|
.ol-unsupported {
|
|
display: none;
|
|
}
|
|
|
|
.ol-viewport,
|
|
.ol-unselectable {
|
|
-webkit-touch-callout: none;
|
|
-webkit-user-select: none;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
user-select: none;
|
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
}
|
|
|
|
.ol-selectable {
|
|
-webkit-touch-callout: default;
|
|
-webkit-user-select: text;
|
|
-moz-user-select: text;
|
|
-ms-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.ol-grabbing {
|
|
cursor: -webkit-grabbing;
|
|
cursor: -moz-grabbing;
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.ol-grab {
|
|
cursor: move;
|
|
cursor: -webkit-grab;
|
|
cursor: -moz-grab;
|
|
cursor: grab;
|
|
}
|
|
|
|
.ol-control {
|
|
position: absolute;
|
|
background-color: rgba(255, 255, 255, 0.4);
|
|
border-radius: 4px;
|
|
padding: 2px;
|
|
}
|
|
|
|
.ol-control:hover {
|
|
background-color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.ol-zoom {
|
|
top: 0.5em;
|
|
left: 0.5em;
|
|
}
|
|
|
|
.ol-rotate {
|
|
top: 0.5em;
|
|
right: 0.5em;
|
|
transition: opacity 0.25s linear, visibility 0s linear;
|
|
}
|
|
|
|
.ol-rotate.ol-hidden {
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: opacity 0.25s linear, visibility 0s linear 0.25s;
|
|
}
|
|
|
|
.ol-zoom-extent {
|
|
top: 4.643em;
|
|
left: 0.5em;
|
|
}
|
|
|
|
.ol-full-screen {
|
|
right: 0.5em;
|
|
top: 0.5em;
|
|
}
|
|
|
|
.ol-control button {
|
|
display: block;
|
|
margin: 1px;
|
|
padding: 0;
|
|
color: white;
|
|
font-size: 1.14em;
|
|
font-weight: bold;
|
|
text-decoration: none;
|
|
text-align: center;
|
|
height: 1.375em;
|
|
width: 1.375em;
|
|
line-height: 0.4em;
|
|
background-color: rgba(0, 60, 136, 0.5);
|
|
border: none;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.ol-control button::-moz-focus-inner {
|
|
border: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.ol-zoom-extent button {
|
|
line-height: 1.4em;
|
|
}
|
|
|
|
.ol-compass {
|
|
display: block;
|
|
font-weight: normal;
|
|
font-size: 1.2em;
|
|
will-change: transform;
|
|
}
|
|
|
|
.ol-touch .ol-control button {
|
|
font-size: 1.5em;
|
|
}
|
|
|
|
.ol-touch .ol-zoom-extent {
|
|
top: 5.5em;
|
|
}
|
|
|
|
.ol-control button:hover,
|
|
.ol-control button:focus {
|
|
text-decoration: none;
|
|
background-color: rgba(0, 60, 136, 0.7);
|
|
}
|
|
|
|
.ol-zoom .ol-zoom-in {
|
|
border-radius: 2px 2px 0 0;
|
|
}
|
|
|
|
.ol-zoom .ol-zoom-out {
|
|
border-radius: 0 0 2px 2px;
|
|
}
|
|
|
|
.ol-attribution {
|
|
text-align: right;
|
|
bottom: 0.5em;
|
|
right: 0.5em;
|
|
max-width: calc(100% - 1.3em);
|
|
}
|
|
|
|
.ol-attribution ul {
|
|
margin: 0;
|
|
padding: 0 0.5em;
|
|
color: #000;
|
|
text-shadow: 0 0 2px #fff;
|
|
}
|
|
|
|
.ol-attribution li {
|
|
display: inline;
|
|
list-style: none;
|
|
}
|
|
|
|
.ol-attribution li:not(:last-child):after {
|
|
content: ' ';
|
|
}
|
|
|
|
.ol-attribution img {
|
|
max-height: 2em;
|
|
max-width: inherit;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.ol-attribution ul,
|
|
.ol-attribution button {
|
|
display: inline-block;
|
|
}
|
|
|
|
.ol-attribution.ol-collapsed ul {
|
|
display: none;
|
|
}
|
|
|
|
.ol-attribution:not(.ol-collapsed) {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.ol-attribution.ol-uncollapsible {
|
|
bottom: 0;
|
|
right: 0;
|
|
border-radius: 4px 0 0;
|
|
}
|
|
|
|
.ol-attribution.ol-uncollapsible img {
|
|
margin-top: -0.2em;
|
|
max-height: 1.6em;
|
|
}
|
|
|
|
.ol-attribution.ol-uncollapsible button {
|
|
display: none;
|
|
}
|
|
|
|
.ol-zoomslider {
|
|
top: 4.5em;
|
|
left: 0.5em;
|
|
height: 200px;
|
|
}
|
|
|
|
.ol-zoomslider button {
|
|
position: relative;
|
|
height: 10px;
|
|
}
|
|
|
|
.ol-touch .ol-zoomslider {
|
|
top: 5.5em;
|
|
}
|
|
|
|
.ol-overviewmap {
|
|
left: 0.5em;
|
|
bottom: 0.5em;
|
|
}
|
|
|
|
.ol-overviewmap.ol-uncollapsible {
|
|
bottom: 0;
|
|
left: 0;
|
|
border-radius: 0 4px 0 0;
|
|
}
|
|
|
|
.ol-overviewmap .ol-overviewmap-map,
|
|
.ol-overviewmap button {
|
|
display: inline-block;
|
|
}
|
|
|
|
.ol-overviewmap .ol-overviewmap-map {
|
|
border: 1px solid #7b98bc;
|
|
height: 150px;
|
|
margin: 2px;
|
|
width: 150px;
|
|
}
|
|
|
|
.ol-overviewmap:not(.ol-collapsed) button {
|
|
bottom: 1px;
|
|
left: 2px;
|
|
position: absolute;
|
|
}
|
|
|
|
.ol-overviewmap.ol-collapsed .ol-overviewmap-map,
|
|
.ol-overviewmap.ol-uncollapsible button {
|
|
display: none;
|
|
}
|
|
|
|
.ol-overviewmap:not(.ol-collapsed) {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.ol-overviewmap-box {
|
|
border: 2px dotted rgba(0, 60, 136, 0.7);
|
|
}
|
|
|
|
.ol-overviewmap .ol-overviewmap-box:hover {
|
|
cursor: move;
|
|
}
|
|
|
|
//
|
|
// Disable Attribution ...
|
|
.ol-attribution {
|
|
display: none !important;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.ts
|
|
|
|
import {
|
|
of,
|
|
Subject,
|
|
forkJoin,
|
|
Observable,
|
|
throwError,
|
|
Subscription,
|
|
} from 'rxjs';
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XMapAction,
|
|
XMapCSSVar,
|
|
XPlaceResult,
|
|
XMapLocation,
|
|
XMapActionModel,
|
|
XMapItemPosition,
|
|
XMapContainerComponent,
|
|
XMapItemPositionIdentifier,
|
|
} from './x-map.typings';
|
|
import {
|
|
DragPan,
|
|
DragZoom,
|
|
PinchZoom,
|
|
DragRotate,
|
|
Interaction,
|
|
PinchRotate,
|
|
KeyboardPan,
|
|
KeyboardZoom,
|
|
MouseWheelZoom,
|
|
DoubleClickZoom,
|
|
} from 'ol/interaction';
|
|
import {
|
|
tap,
|
|
map,
|
|
concatMap,
|
|
catchError,
|
|
debounceTime,
|
|
distinctUntilChanged,
|
|
} from 'rxjs/operators';
|
|
import {
|
|
nameof,
|
|
XHeader,
|
|
applyLocale,
|
|
applyFinally,
|
|
XContentType,
|
|
generateUuid,
|
|
XExceptionIDs,
|
|
XStandardType,
|
|
toNormalString,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { Point } from 'ol/geom';
|
|
import BaseLayer from 'ol/layer/Base';
|
|
import { MapOptions } from 'ol/PluggableMap';
|
|
import {
|
|
XSearchBarEvent,
|
|
XSearchBarEventIdentifier,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import { toMapLocation } from './x-map.tools';
|
|
import { fromLonLat, transform } from 'ol/proj';
|
|
import { HttpHeaders } from '@angular/common/http';
|
|
import { XListItem } from '../x-list/x-list.typings';
|
|
import { OSM, Vector as VectorSource } from 'ol/source';
|
|
import { Map, View, Feature, Overlay, Kinetic } from 'ol';
|
|
import { Zoom, Rotate, ZoomSlider, Control } from 'ol/control';
|
|
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
|
|
import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { XSearchBarComponent } from '../x-search-bar/x-search-bar.component';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-map',
|
|
templateUrl: './x-map.component.html',
|
|
styleUrls: ['./x-map.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XMapComponent extends XMapContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ZOOM_DELTA = 2;
|
|
private IMPORTANT_ZOOM = 18;
|
|
private MAP: Map = undefined;
|
|
private ANIMATION_DURATION = 500;
|
|
private MARKER: VectorLayer<any>;
|
|
private ZOOM_CONTROL = new Zoom();
|
|
private IS_MAP_INITIALIZED = false;
|
|
private MARKER_POSITION: XMapLocation;
|
|
private ROTATE_CONTROL = new Rotate();
|
|
private ACTION_WAITIONG_DURATION = 500;
|
|
private MAP_OPTIONS: MapOptions = undefined;
|
|
private ZOOM_SLIDER_CONTROL = new ZoomSlider();
|
|
private positionProvider = new Subject<string>();
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private searchFilterSubject$ = new Subject<string>();
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly componentId = generateUuid('XMapComponent');
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
readonly ItemPositions = Object.assign({}, XMapItemPosition);
|
|
|
|
//
|
|
isSearching = false;
|
|
searchPaneOpen = false;
|
|
currentPosition: string = '';
|
|
searchResult: XPlaceResult[] = [];
|
|
showMapView: XStandardType<boolean> = false;
|
|
searchResultListItems: XListItem<XPlaceResult>[] = [];
|
|
|
|
//
|
|
get isInitialized() {
|
|
return this.IS_MAP_INITIALIZED;
|
|
}
|
|
|
|
get map() {
|
|
return this.MAP;
|
|
}
|
|
|
|
get options() {
|
|
return this.MAP_OPTIONS as MapOptions;
|
|
}
|
|
|
|
get hasMarker() {
|
|
return !isNullOrUndefined(this.MARKER);
|
|
}
|
|
|
|
get markerPosition() {
|
|
return this.MARKER_POSITION;
|
|
}
|
|
|
|
get currentZoom() {
|
|
return !this.isInitialized ? -1 : this.MAP.getView().getZoom();
|
|
}
|
|
|
|
get currentLatitude() {
|
|
//
|
|
if (!this.isInitialized) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
const lonLat = this.map.getView().getCenter();
|
|
const location = toMapLocation(lonLat);
|
|
|
|
//
|
|
return +location.latitude;
|
|
}
|
|
|
|
get currentLongitude() {
|
|
//
|
|
if (!this.isInitialized) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
const lonLat = this.map.getView().getCenter();
|
|
const location = toMapLocation(lonLat);
|
|
|
|
//
|
|
return +location.longitude;
|
|
}
|
|
|
|
@ViewChild('mapView')
|
|
mapView: ElementRef;
|
|
|
|
@ViewChild('pluginsBar')
|
|
pluginsBar: ElementRef<HTMLDivElement>;
|
|
|
|
@ViewChild('searchBar')
|
|
searchBar: XSearchBarComponent;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
await this.initializeMap();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region CanSelect Change ...
|
|
const isCanSelectChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('canSelect')
|
|
);
|
|
if (isCanSelectChanged) {
|
|
await this.applyCanSelect();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Location Info changed ...
|
|
// const isZoomChanged = changeKeys.includes(nameof<XMapComponent>('zoom'));
|
|
// const isLatitudeChanged = changeKeys.includes(
|
|
// nameof<XMapComponent>('latitude')
|
|
// );
|
|
// const isLongitudeChanged = changeKeys.includes(
|
|
// nameof<XMapComponent>('longitude')
|
|
// );
|
|
// const isAddMarkerOnSelectedLocationChanged = changeKeys.includes(
|
|
// nameof<XMapComponent>('addMarkerOnSelectedLocation')
|
|
// );
|
|
// if (
|
|
// isZoomChanged ||
|
|
// isLatitudeChanged ||
|
|
// isLongitudeChanged ||
|
|
// isAddMarkerOnSelectedLocationChanged
|
|
// ) {
|
|
// await this.applyLocationInfo();
|
|
// }
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Zoom changed ...
|
|
const isShowZoomChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('showZoom')
|
|
);
|
|
if (isShowZoomChanged) {
|
|
await this.applyZoom();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Rotate changed ...
|
|
const isShowRotateChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('showRotate')
|
|
);
|
|
if (isShowRotateChanged) {
|
|
await this.applyRotate();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Show Zoom Slider changed ...
|
|
const isShowZoomSliderChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('showZoomSlider')
|
|
);
|
|
if (isShowZoomSliderChanged) {
|
|
await this.applyZoomSlider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Offset Height Handling ...
|
|
const isShowSearchBarChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('showSearchBar')
|
|
);
|
|
const isSearchBarPositionChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('searchBarPosition')
|
|
);
|
|
const isShowSelectedLoactionChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('showSelectedLocation')
|
|
);
|
|
const isSelectedLocationPositionChanged = changeKeys.includes(
|
|
nameof<XMapComponent>('selectedLocationPosition')
|
|
);
|
|
if (
|
|
isShowRotateChanged ||
|
|
isShowZoomChanged ||
|
|
isShowZoomSliderChanged ||
|
|
isShowSearchBarChanged ||
|
|
isSearchBarPositionChanged ||
|
|
isShowSelectedLoactionChanged ||
|
|
isSelectedLocationPositionChanged
|
|
) {
|
|
await this.applyContentOffset();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
// Register Action Provider ...
|
|
this.registerActionProvider();
|
|
|
|
//
|
|
// Register Search ...
|
|
this.registerPluginHandler();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Providers ...
|
|
async getCenter(
|
|
latitude?: number | XStandardType<number>,
|
|
longitude?: number | XStandardType<number>
|
|
) {
|
|
//
|
|
const desiredLatitude = await this.getNormallizedLatitued(latitude);
|
|
const desiredLongitude = await this.getNormallizedLongitude(longitude);
|
|
const result = fromLonLat([desiredLongitude, desiredLatitude]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
canShowPlugins(position: XMapItemPositionIdentifier) {
|
|
return this.getValue(position).pipe(
|
|
concatMap((pos) =>
|
|
isNullOrEmptyString(pos)
|
|
? of(false)
|
|
: forkJoin({
|
|
//
|
|
// progressBar: forkJoin({
|
|
// canShow: this.getValue(this.showProgressBar),
|
|
// position: this.getValue(this.progressBarPosition),
|
|
// }),
|
|
|
|
//
|
|
locator: forkJoin({
|
|
canShow: this.getValue(this.showLocator),
|
|
position: this.getValue(this.locatorPosition),
|
|
}),
|
|
|
|
//
|
|
clearMarker: forkJoin({
|
|
canShow: this.getValue(this.showClearMarker),
|
|
position: this.getValue(this.clearMarkerPosition),
|
|
}),
|
|
|
|
//
|
|
goMarkedPlace: forkJoin({
|
|
canShow: this.getValue(this.showGoMarkedPlace),
|
|
position: this.getValue(this.goMarkedPlacePosition),
|
|
}),
|
|
|
|
//
|
|
selectedLocation: forkJoin({
|
|
canShow: this.getValue(this.showSelectedLocation),
|
|
position: this.getValue(this.selectedLocationPosition),
|
|
}),
|
|
}).pipe(
|
|
map((info) => {
|
|
return {
|
|
pos,
|
|
info,
|
|
};
|
|
}),
|
|
map((data) => {
|
|
return (
|
|
//
|
|
// ProgressBar ...
|
|
// (data.info.progressBar.canShow &&
|
|
// data.info.progressBar.position === data.pos) ||
|
|
//
|
|
// Locator ...
|
|
(data.info.locator.canShow &&
|
|
data.info.locator.position === data.pos) ||
|
|
//
|
|
// ClearMarker ...
|
|
(data.info.clearMarker.canShow &&
|
|
data.info.clearMarker.position === data.pos) ||
|
|
//
|
|
// Go Marked Place ...
|
|
(data.info.goMarkedPlace.canShow &&
|
|
data.info.goMarkedPlace.position === data.pos) ||
|
|
//
|
|
// Selected Location ...
|
|
(data.info.selectedLocation.canShow &&
|
|
data.info.selectedLocation.position === data.pos)
|
|
);
|
|
})
|
|
)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleSeach(query: string) {
|
|
//
|
|
this.searchBarQueryChange.emit(query);
|
|
|
|
//
|
|
if (this.isSearching) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.handleSeach(query),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (isNullOrEmptyString(query)) {
|
|
//
|
|
this.searchResult = [];
|
|
this.isSearching = false;
|
|
this.searchPaneOpen = false;
|
|
this.searchResultListItems = [];
|
|
await this.setLoadingState(false);
|
|
return;
|
|
}
|
|
|
|
//
|
|
query = toNormalString(query);
|
|
this.searchFilterSubject$.next(query);
|
|
}
|
|
|
|
async handleSearchBarEvents(event: XSearchBarEventIdentifier) {
|
|
//
|
|
switch (event) {
|
|
//
|
|
case XSearchBarEvent.FOCUS:
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
this.searchPaneOpen =
|
|
this.hasChild(this.searchResult) &&
|
|
this.hasChild(this.searchResultListItems);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
break;
|
|
|
|
//
|
|
case XSearchBarEvent.BLUR:
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
this.searchPaneOpen = false;
|
|
this.detectChanges();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleChangeLocation(item: XListItem<XPlaceResult>) {
|
|
//
|
|
const zoom = this.IMPORTANT_ZOOM - 4;
|
|
const addMarker = await this.getValueAsync(
|
|
this.addMarkerOnSelectedLocation
|
|
);
|
|
if (addMarker) {
|
|
await this.addMarker(item.data.lat, item.data.lon, zoom);
|
|
} else {
|
|
await this.setCenter(item.data.lat, item.data.lon, zoom);
|
|
}
|
|
}
|
|
|
|
async handleLocationResultClickOutside(event: any) {
|
|
//
|
|
this.searchPaneOpen = false;
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleGoMarkedPlace() {
|
|
await this.goMarkedPlace();
|
|
}
|
|
|
|
async handleClearMarker() {
|
|
await this.clearMarker();
|
|
}
|
|
|
|
async handleLocate() {
|
|
await this.locate();
|
|
}
|
|
|
|
async handleSlectedLocationClicked(message: string) {
|
|
//
|
|
message = applyLocale(message, 'en-US');
|
|
this.managerService.saveToClipboard(message);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async updateMap() {
|
|
//
|
|
// Recalling ...
|
|
if (!this.isInitialized) {
|
|
setTimeout(async () => {
|
|
await this.updateMap();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Update ...
|
|
this.MAP.render();
|
|
this.detectChanges();
|
|
this.MAP.updateSize();
|
|
this.MAP.renderSync();
|
|
this.managerService.dispatchResizeEvent();
|
|
if (this.mapView && this.mapView.nativeElement) {
|
|
//
|
|
const mapView = this.mapView.nativeElement as HTMLElement;
|
|
mapView.blur();
|
|
mapView.focus();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
setTimeout(async () => {
|
|
await this.updateMap();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
}
|
|
|
|
async setZoom(zoom?: number | XStandardType<number>) {
|
|
//
|
|
const desiredZoom = await this.getNormallizedZoom(zoom);
|
|
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.setZoom(zoom);
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.map.getView().animate({
|
|
zoom: desiredZoom,
|
|
duration: this.ANIMATION_DURATION,
|
|
});
|
|
}
|
|
|
|
async setCenter(
|
|
latitude?: number | XStandardType<number>,
|
|
longitude?: number | XStandardType<number>,
|
|
zoom?: number | XStandardType<number>
|
|
) {
|
|
//
|
|
const desiredZoom = await this.getNormallizedZoom(zoom);
|
|
const center = await this.getCenter(latitude, longitude);
|
|
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.setCenter(latitude, longitude, zoom);
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.map.getView().animate({
|
|
center,
|
|
zoom: desiredZoom,
|
|
duration: this.ANIMATION_DURATION,
|
|
});
|
|
}
|
|
|
|
async addMarker(
|
|
latitude?: number | XStandardType<number>,
|
|
longitude?: number | XStandardType<number>,
|
|
zoom?: number | XStandardType<number>
|
|
) {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.addMarker(latitude, longitude, zoom);
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const desiredZoom = await this.getNormallizedZoom(zoom);
|
|
const desiredLat = await this.getNormallizedLatitued(latitude);
|
|
const desiredLong = await this.getNormallizedLongitude(longitude);
|
|
|
|
//
|
|
if (this.MARKER) {
|
|
//
|
|
this.MAP.removeLayer(this.MARKER);
|
|
this.MARKER = null;
|
|
this.actionProvider.next({ action: XMapAction.HasNotMarker });
|
|
}
|
|
|
|
//
|
|
this.MARKER_POSITION = {
|
|
zoom: desiredZoom.toString(),
|
|
latitude: desiredLat.toString(),
|
|
longitude: desiredLong.toString(),
|
|
};
|
|
|
|
//
|
|
const markerStyle = await this.getValueAsync(this.markerStyle);
|
|
|
|
//
|
|
this.MARKER = new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [
|
|
new Feature({
|
|
geometry: new Point(
|
|
transform([desiredLong, desiredLat], 'EPSG:4326', 'EPSG:3857')
|
|
),
|
|
}),
|
|
],
|
|
}),
|
|
style: markerStyle,
|
|
});
|
|
|
|
//
|
|
// Netify Selected Location ...
|
|
await this.updateSelectedLocation(latitude, longitude);
|
|
this.actionProvider.next({ action: XMapAction.HasMarker });
|
|
|
|
//
|
|
// Emit Location Selected Event ...
|
|
this.locationSelected.emit(this.MARKER_POSITION);
|
|
|
|
//
|
|
this.MAP.addLayer(this.MARKER);
|
|
|
|
//
|
|
setTimeout(async () => {
|
|
await this.setCenter(desiredLat, desiredLong, desiredZoom);
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
}
|
|
|
|
async clearMarker() {
|
|
//
|
|
if (!this.MARKER) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.clearMarker();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.MAP.removeLayer(this.MARKER);
|
|
this.MARKER = null;
|
|
this.MARKER_POSITION = null;
|
|
|
|
//
|
|
this.positionProvider.next('');
|
|
this.actionProvider.next({
|
|
action: XMapAction.HasNotMarker,
|
|
});
|
|
}
|
|
|
|
async goMarkedPlace() {
|
|
//
|
|
if (!this.hasMarker) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.goMarkedPlace();
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setCenter(
|
|
+this.markerPosition.latitude,
|
|
+this.markerPosition.longitude
|
|
);
|
|
}
|
|
|
|
async locate() {
|
|
//
|
|
await this.setLoadingState(true);
|
|
const location = await this.getValueAsync(
|
|
applyFinally(
|
|
this.managerService.geoLocationService.getCurrentLocation().pipe(
|
|
catchError((err) => {
|
|
//
|
|
this.showError(err);
|
|
|
|
//
|
|
return throwError(err);
|
|
})
|
|
),
|
|
async () => await this.setLoadingState(false)
|
|
)
|
|
);
|
|
|
|
//
|
|
if (!isNullOrUndefined(location)) {
|
|
//
|
|
this.zoom = this.IMPORTANT_ZOOM;
|
|
this.latitude = location.coords.latitude;
|
|
this.longitude = location.coords.longitude;
|
|
|
|
//
|
|
await this.addMarker(
|
|
location.coords.latitude,
|
|
location.coords.longitude,
|
|
this.zoom
|
|
);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async prepareMapOptions() {
|
|
//
|
|
this.MAP = null;
|
|
this.MAP_OPTIONS = null;
|
|
this.showMapView = false;
|
|
|
|
//
|
|
const zoom = 0; // await this.getNormallizedZoom();
|
|
|
|
//
|
|
const desiredLatitude = 0; // await this.getNormallizedLatitued();
|
|
const desiredLongitude = 0; // await this.getNormallizedLongitude();
|
|
const center = fromLonLat([desiredLatitude, desiredLongitude]);
|
|
|
|
//
|
|
const view = new View({
|
|
zoom,
|
|
center,
|
|
});
|
|
|
|
//
|
|
const layers: BaseLayer[] = [];
|
|
layers.push(
|
|
new TileLayer({
|
|
source: new OSM(),
|
|
})
|
|
);
|
|
|
|
//
|
|
const controls: Control[] = await this.getControls();
|
|
|
|
//
|
|
const interactions: Interaction[] = await this.getInteractions();
|
|
|
|
//
|
|
const overlays: Overlay[] = [];
|
|
|
|
//
|
|
this.MAP_OPTIONS = {
|
|
view,
|
|
layers,
|
|
controls,
|
|
overlays,
|
|
target: this.componentId,
|
|
interactions,
|
|
keyboardEventTarget: this.componentId,
|
|
};
|
|
}
|
|
|
|
private async initializeMap() {
|
|
//
|
|
if (!isNullOrUndefined(this.MAP)) {
|
|
this.MAP = null;
|
|
}
|
|
|
|
//
|
|
await this.prepareMapOptions();
|
|
|
|
//
|
|
this.MAP = new Map(this.options);
|
|
|
|
//
|
|
//#region Attached Events ...
|
|
//
|
|
// Map Event Handler ...
|
|
this.MAP.on('rendercomplete', async (e: any) => {
|
|
//
|
|
this.isReady.emit();
|
|
|
|
//
|
|
this.IS_MAP_INITIALIZED = true;
|
|
|
|
//
|
|
this.managerService.dispatchResizeEvent();
|
|
Promise.resolve().then(() => this.managerService.dispatchResizeEvent());
|
|
setTimeout(
|
|
() => this.managerService.dispatchResizeEvent(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
});
|
|
|
|
//
|
|
// Zoom End ...
|
|
this.MAP.on('moveend', async (e: any) => {
|
|
//
|
|
const zoom = this.map.getView().getZoom();
|
|
const lonLat = this.map.getView().getCenter();
|
|
const location = toMapLocation(lonLat);
|
|
location.zoom = zoom.toString();
|
|
|
|
//
|
|
this.zoom = zoom;
|
|
|
|
//
|
|
this.viewChanged.emit(location);
|
|
});
|
|
//#endregion
|
|
|
|
//
|
|
this.showMapView = true;
|
|
await this.applyContentOffset();
|
|
await this.updateMap();
|
|
await this.applyCanSelect();
|
|
|
|
//
|
|
await this.applyLocationInfo();
|
|
}
|
|
|
|
private async getInteractions() {
|
|
//
|
|
const result: Interaction[] = [];
|
|
|
|
//
|
|
const delta = this.ZOOM_DELTA;
|
|
const duration = this.ANIMATION_DURATION;
|
|
|
|
//
|
|
const dragPan = true;
|
|
const pinchZoom = true;
|
|
const onFocusOnly = true;
|
|
const pinchRotate = true;
|
|
const keyboardPan = true;
|
|
const keyboardZoom = true;
|
|
const shiftDragZoom = true;
|
|
const mouseWheelZoom = true;
|
|
const doubleClickZoom = true;
|
|
const altShiftDragRotate = true;
|
|
|
|
//
|
|
//#region Preperation ...
|
|
//
|
|
// DragRotate ...
|
|
const kinetic = new Kinetic(-0.005, 0.05, 100);
|
|
if (altShiftDragRotate) {
|
|
result.push(new DragRotate());
|
|
}
|
|
|
|
//
|
|
// DoubleClickZoom ...
|
|
if (doubleClickZoom) {
|
|
result.push(
|
|
new DoubleClickZoom({
|
|
delta,
|
|
duration,
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
// DragPan ...
|
|
if (dragPan) {
|
|
result.push(
|
|
new DragPan({
|
|
onFocusOnly,
|
|
kinetic,
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
// PinchRotate ...
|
|
if (pinchRotate) {
|
|
result.push(new PinchRotate());
|
|
}
|
|
|
|
//
|
|
// PinchZoom ...
|
|
if (pinchZoom) {
|
|
result.push(
|
|
new PinchZoom({
|
|
duration,
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
// KeyboardPan ...
|
|
if (keyboardPan) {
|
|
result.push(new KeyboardPan());
|
|
}
|
|
|
|
//
|
|
// KeyboardZoom ...
|
|
if (keyboardZoom) {
|
|
result.push(
|
|
new KeyboardZoom({
|
|
delta,
|
|
duration,
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
// MouseWheelZoom ...
|
|
if (mouseWheelZoom) {
|
|
result.push(
|
|
new MouseWheelZoom({
|
|
duration,
|
|
onFocusOnly,
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
// DragZoom ...
|
|
if (shiftDragZoom) {
|
|
result.push(
|
|
new DragZoom({
|
|
duration,
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private async getControls() {
|
|
//
|
|
const result: Control[] = [];
|
|
|
|
//
|
|
//#region Adding Controls ...
|
|
//
|
|
// Zoom ...
|
|
const showZoom = await this.getValueAsync(this.showZoom);
|
|
if (showZoom) {
|
|
result.push(this.ZOOM_CONTROL);
|
|
}
|
|
|
|
//
|
|
// Rotate ...
|
|
const showRotate = await this.getValueAsync(this.showRotate);
|
|
if (showRotate) {
|
|
result.push(this.ROTATE_CONTROL);
|
|
}
|
|
|
|
//
|
|
// ZoomSlider ...
|
|
const showZoomSlider = await this.getValueAsync(this.showZoomSlider);
|
|
if (showZoomSlider) {
|
|
result.push(this.ZOOM_SLIDER_CONTROL);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XMapActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XMapAction.AddMarker:
|
|
//
|
|
if (model.payload) {
|
|
//
|
|
const result: XMapLocation = model.payload;
|
|
if (result) {
|
|
//
|
|
const lat = +result.latitude;
|
|
const long = +result.longitude;
|
|
const zoom = +result.zoom;
|
|
|
|
//
|
|
await this.addMarker(lat, long, zoom);
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XMapAction.ClearMarker:
|
|
await this.clearMarker();
|
|
break;
|
|
|
|
//
|
|
case XMapAction.GoMarkedPlace:
|
|
await this.goMarkedPlace();
|
|
break;
|
|
|
|
//
|
|
case XMapAction.SetCenter:
|
|
//
|
|
if (model.payload) {
|
|
//
|
|
const result: XMapLocation = model.payload;
|
|
if (result) {
|
|
//
|
|
const zoom = +result.zoom;
|
|
const lat = +result.latitude;
|
|
const long = +result.longitude;
|
|
|
|
//
|
|
await this.setCenter(lat, long, zoom);
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XMapAction.SetZoom:
|
|
//
|
|
if (model.payload) {
|
|
//
|
|
const zoom = +model.payload;
|
|
await this.setZoom(zoom);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XMapAction.Locate:
|
|
await this.locate();
|
|
break;
|
|
|
|
//
|
|
case XMapAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
|
|
private registerPluginHandler() {
|
|
//
|
|
// Register Query Change ...
|
|
this.applyTakeUntilWrapper(
|
|
this.searchFilterSubject$
|
|
.asObservable()
|
|
.pipe(debounceTime(800), distinctUntilChanged())
|
|
).subscribe(async (query) => {
|
|
await this.handleSearchAction(query);
|
|
});
|
|
|
|
//
|
|
// Register LocationProvider ...
|
|
this.applyTakeUntilWrapper(this.positionProvider.asObservable()).subscribe(
|
|
(position) => {
|
|
//
|
|
this.currentPosition = position;
|
|
this.detectChanges();
|
|
}
|
|
);
|
|
}
|
|
|
|
private async getNormallizedLatitued(
|
|
latitude?: number | XStandardType<number>
|
|
) {
|
|
const result = await this.getValueAsync(latitude || this.latitude || 0);
|
|
return result || 0;
|
|
}
|
|
|
|
private async getNormallizedLongitude(
|
|
longitude?: number | XStandardType<number>
|
|
) {
|
|
const result = await this.getValueAsync(longitude || this.longitude || 0);
|
|
return result || 0;
|
|
}
|
|
|
|
private async getNormallizedZoom(zoom?: number | XStandardType<number>) {
|
|
//
|
|
let result = 0;
|
|
if (!zoom) {
|
|
result = await this.getValueAsync(this.zoom);
|
|
} else {
|
|
result = await this.getValueAsync(zoom);
|
|
}
|
|
|
|
//
|
|
result =
|
|
result > this.IMPORTANT_ZOOM
|
|
? this.IMPORTANT_ZOOM
|
|
: result < 0
|
|
? 0
|
|
: result;
|
|
|
|
//
|
|
return result || 0;
|
|
}
|
|
|
|
private async getSummarySelectedLocationMessage(
|
|
latitude?: number | XStandardType<number>,
|
|
longitude?: number | XStandardType<number>
|
|
) {
|
|
//
|
|
const desiredLat = await this.getNormallizedLatitued(latitude);
|
|
const desiredLong = await this.getNormallizedLongitude(longitude);
|
|
|
|
//
|
|
const mLat = this.applyLocale(desiredLat.toString());
|
|
const mLong = this.applyLocale(desiredLong.toString());
|
|
|
|
//
|
|
const result = `${mLat}, ${mLong}`;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
private async applyLocationInfo() {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyLocationInfo(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const normallizedZoom = await this.getNormallizedZoom();
|
|
const latitude = await this.getNormallizedLatitued();
|
|
const longitude = await this.getNormallizedLongitude();
|
|
|
|
//
|
|
const addMarker = await this.getValueAsync(
|
|
this.addMarkerOnSelectedLocation
|
|
);
|
|
const zoom = addMarker ? this.IMPORTANT_ZOOM : normallizedZoom;
|
|
|
|
//
|
|
if (this.longitude && this.latitude) {
|
|
//
|
|
setTimeout(async () => {
|
|
//
|
|
if (addMarker) {
|
|
await this.addMarker(latitude, longitude, zoom);
|
|
} else {
|
|
await this.setCenter(latitude, longitude, zoom);
|
|
}
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (this.zoom) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.setZoom(normallizedZoom);
|
|
}, 1000);
|
|
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
|
|
private async applyContentOffset() {
|
|
//
|
|
let result = 5;
|
|
|
|
//
|
|
const showSerach = await this.getValueAsync(this.showSearchBar);
|
|
if (showSerach) {
|
|
//
|
|
const searchBarPosition = await this.getValueAsync(
|
|
this.searchBarPosition
|
|
);
|
|
|
|
//
|
|
if (searchBarPosition === XMapItemPosition.TOP && this.searchBar) {
|
|
//
|
|
const searchBarHeight = this.searchBar.getElementBoundaryHeight();
|
|
if (searchBarHeight === 0) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyContentOffset(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
result += searchBarHeight;
|
|
}
|
|
}
|
|
|
|
//
|
|
const canShowPluginBarAtTop = await this.getValueAsync(
|
|
this.canShowPlugins(this.ItemPositions.TOP)
|
|
);
|
|
if (canShowPluginBarAtTop && this.pluginsBar) {
|
|
//
|
|
const pluginsBarHeight =
|
|
this.pluginsBar.nativeElement.getBoundingClientRect().height;
|
|
if (pluginsBarHeight === 0) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyContentOffset(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
result += pluginsBarHeight;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XMapCSSVar.MapControlOffset, `${result}px`);
|
|
}
|
|
|
|
private async applyCanSelect() {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyCanSelect(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Add Marker on Map Clicked ...
|
|
const canSelect = await this.getValueAsync(this.canSelect);
|
|
if (canSelect) {
|
|
this.MAP.on('click', async (args: any) => {
|
|
//
|
|
this.searchPaneOpen = false;
|
|
|
|
//
|
|
const lonlat = transform(args.coordinate, 'EPSG:3857', 'EPSG:4326');
|
|
|
|
//
|
|
// tslint:disable-next-line:no-shadowed-variable
|
|
const lat = lonlat[1] as number;
|
|
|
|
//
|
|
// tslint:disable-next-line:no-shadowed-variable
|
|
const long = lonlat[0] as number;
|
|
|
|
//
|
|
// , this.IMPORTANT_ZOOM - 6
|
|
await this.addMarker(lat, long);
|
|
});
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Plugin Handlers ...
|
|
private async applyZoom(forceUpdate = true) {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyZoom(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const showZoom = await this.getValueAsync(this.showZoom);
|
|
if (showZoom) {
|
|
this.map.addControl(this.ZOOM_CONTROL);
|
|
} else {
|
|
this.map.removeControl(this.ZOOM_CONTROL);
|
|
}
|
|
|
|
//
|
|
if (forceUpdate) {
|
|
await this.updateMap();
|
|
}
|
|
}
|
|
|
|
private async applyRotate(forceUpdate = true) {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyRotate(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const showRotate = await this.getValueAsync(this.showRotate);
|
|
if (showRotate) {
|
|
this.map.addControl(this.ROTATE_CONTROL);
|
|
} else {
|
|
this.map.removeControl(this.ROTATE_CONTROL);
|
|
}
|
|
|
|
//
|
|
if (forceUpdate) {
|
|
await this.updateMap();
|
|
}
|
|
}
|
|
|
|
private async applyZoomSlider(forceUpdate = true) {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(
|
|
async () => await this.applyZoomSlider(),
|
|
this.ACTION_WAITIONG_DURATION
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const showZoomSlider = await this.getValueAsync(this.showZoomSlider);
|
|
if (showZoomSlider) {
|
|
this.map.addControl(this.ZOOM_SLIDER_CONTROL);
|
|
} else {
|
|
this.map.removeControl(this.ZOOM_SLIDER_CONTROL);
|
|
}
|
|
|
|
//
|
|
if (forceUpdate) {
|
|
await this.updateMap();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region SelectedLocation Plugin ...
|
|
private async updateSelectedLocation(
|
|
latitude?: number | XStandardType<number>,
|
|
longitude?: number | XStandardType<number>
|
|
) {
|
|
//
|
|
if (!this.isInitialized) {
|
|
//
|
|
setTimeout(async () => {
|
|
await this.updateSelectedLocation(latitude, longitude);
|
|
}, this.ACTION_WAITIONG_DURATION);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const message = await this.getSummarySelectedLocationMessage(
|
|
latitude,
|
|
longitude
|
|
);
|
|
this.positionProvider.next(message);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region SearchBar Plugin ...
|
|
private async handleSearchAction(query: string) {
|
|
//
|
|
const url = this.searchPlaceProvider(query);
|
|
|
|
//
|
|
this.searchResult = [];
|
|
this.searchPaneOpen = false;
|
|
this.searchResultListItems = [];
|
|
|
|
//
|
|
await this.setLoadingState(true);
|
|
applyFinally(this.getPlaceResults(url), async () => {
|
|
this.isSearching = false;
|
|
await this.setLoadingState(false);
|
|
}).subscribe(
|
|
async (res) => {
|
|
//
|
|
this.searchResult = res;
|
|
await this.prepareSearchListItems();
|
|
},
|
|
() => {
|
|
this.showError(XExceptionIDs.ActionFailed);
|
|
}
|
|
);
|
|
}
|
|
|
|
private getPlaceResults(url: string): Observable<XPlaceResult[]> {
|
|
//
|
|
const headers: HttpHeaders = new HttpHeaders();
|
|
headers.set(XHeader.Accept, XContentType.AppJson);
|
|
|
|
//
|
|
return applyFinally(
|
|
this.applyLoadingWrapper(
|
|
this.managerService.httpClient
|
|
.get<XPlaceResult[]>(url, { headers })
|
|
.pipe(
|
|
map((res) => {
|
|
return res.map((r) => {
|
|
//
|
|
const mPlace: XPlaceResult = {
|
|
display_name: r.display_name,
|
|
lat: +r.lat,
|
|
lon: +r.lon,
|
|
};
|
|
|
|
//
|
|
return mPlace;
|
|
});
|
|
}),
|
|
tap((res) => {
|
|
if (!this.hasChild(res)) {
|
|
this.searchPaneOpen = false;
|
|
}
|
|
})
|
|
)
|
|
),
|
|
() => this.setLoadingState(false)
|
|
);
|
|
}
|
|
|
|
private async prepareSearchListItems() {
|
|
//
|
|
if (!this.hasChild(this.searchResult)) {
|
|
//
|
|
this.searchPaneOpen = false;
|
|
await this.setLoadingState(false);
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.searchResultListItems = this.searchResult.map((r) => {
|
|
//
|
|
const li: XListItem<XPlaceResult> = {
|
|
data: r,
|
|
};
|
|
|
|
//
|
|
return li;
|
|
});
|
|
|
|
//
|
|
this.searchPaneOpen = true;
|
|
await this.setLoadingState(false);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XMapComponent } from './x-map.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XMapContainerComponent } from './x-map.typings';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XMapDialogService } from './x-map-dialog/x-map-dialog.service';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XMapDialogComponent } from './x-map-dialog/x-map-dialog.component';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
XListModule,
|
|
XCardModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XSlotterModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XListModule,
|
|
XCardModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XMapComponent,
|
|
XSlotterModule,
|
|
XMapDialogComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
providers: [XMapDialogService],
|
|
entryComponents: [XMapDialogComponent],
|
|
declarations: [XMapComponent, XMapDialogComponent, XMapContainerComponent],
|
|
})
|
|
export class XMapModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.tools.ts
|
|
|
|
import { XMapLocation } from './x-map.typings';
|
|
import { isNullOrEmptyString, hasChild, isString, isArray, countChild } from 'x-framework-core';
|
|
|
|
/**
|
|
* get given position link for open on Google Maps ...
|
|
*
|
|
* @param model map result model ...
|
|
*/
|
|
export function getGoogleMapLink(model: XMapLocation) {
|
|
return `https://maps.google.com/?q=${model.latitude},${model.longitude}`;
|
|
}
|
|
|
|
/**
|
|
* convert a point string to Map Result ...
|
|
*
|
|
* @param longLat the string which represent point ...
|
|
*/
|
|
export function fromLongLat(longLat: string) {
|
|
//
|
|
if (isNullOrEmptyString(longLat)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const longLatArr = longLat.toString().split(',');
|
|
if (!hasChild(longLatArr) || longLatArr.length !== 2) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result: XMapLocation = {
|
|
latitude: longLatArr[1],
|
|
longitude: longLatArr[0],
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export function toMapLocation(source: string | Array<number>) {
|
|
//
|
|
if (isString(source)) {
|
|
return fromLongLat(source as string);
|
|
}
|
|
|
|
//
|
|
if (!isArray(source) || countChild(source as Array<number>) < 2) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const longLatArr = source as Array<number>;
|
|
|
|
//
|
|
const result: XMapLocation = {
|
|
latitude: longLatArr[1].toString(),
|
|
longitude: longLatArr[0].toString(),
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* convert a point object to point string ...
|
|
*
|
|
* @param point the map selected object to convert it ...
|
|
*/
|
|
export function toLongLat(point: XMapLocation) {
|
|
return `${point.longitude},${point.latitude}`;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardContainer,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import {
|
|
XSearchBarActionModel,
|
|
XSearchBarTypeIdentifier,
|
|
XComponentSearchBarContainer,
|
|
IXComponentSearchBarContainer,
|
|
} from '../x-search-bar/x-search-bar.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { Style, Circle, Stroke, Fill } from 'ol/style';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { IXBaseContainer } from '../classes/i-x-base.container';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export interface XPlaceResult {
|
|
display_name: string;
|
|
lat: number;
|
|
lon: number;
|
|
}
|
|
|
|
export enum XMapItemPosition {
|
|
TOP = 'top',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XMapItemPositionIdentifier = XMapItemPosition | string;
|
|
|
|
export enum XMapAction {
|
|
//
|
|
Locate = 'locate',
|
|
|
|
//
|
|
AddMarker = 'add_marker',
|
|
HasMarker = 'has_marker',
|
|
ClearMarker = 'clear-marker',
|
|
HasNotMarker = 'has_not_marker',
|
|
GoMarkedPlace = 'go-marked-place',
|
|
|
|
//
|
|
SetCenter = 'set_center',
|
|
SetZoom = 'set_zoom',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XMapActionIdentifier = XMapAction | string;
|
|
|
|
export interface XMapActionModel
|
|
extends XBaseActionModel<XMapActionIdentifier> {}
|
|
|
|
export enum XMapCSSVar {
|
|
MapControlOffset = 'map-controls-offest',
|
|
}
|
|
|
|
export type XMapCSSVarIdentification = XMapCSSVar | string;
|
|
|
|
export interface XMapLocation {
|
|
zoom?: string;
|
|
latitude?: string;
|
|
longitude?: string;
|
|
}
|
|
|
|
export type XMapStyle = Style;
|
|
|
|
export const defaultMarkerStyle: XMapStyle = new Style({
|
|
image: new Circle({
|
|
radius: 10,
|
|
stroke: new Stroke({
|
|
color: 'rgb(255,0,0)',
|
|
width: 5,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'rgba(255,0,0,.3)',
|
|
}),
|
|
}),
|
|
stroke: new Stroke({
|
|
color: 'rgb(255,0,0)',
|
|
width: 5,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'rgba(255,165,0,.3)',
|
|
}),
|
|
});
|
|
|
|
export const defaultMapSearchPlaceProvider = (query: string) => {
|
|
return (
|
|
'https://nominatim.openstreetmap.org/search?q=' +
|
|
query +
|
|
'&format=json&limit=5'
|
|
);
|
|
};
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
type TXMapContainer = IXComponentCardContainer & IXComponentSearchBarContainer;
|
|
export interface IXMapContainer extends IXBaseContainer, TXMapContainer {
|
|
//
|
|
actionProvider: Subject<XMapActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
zoom: XStandardType<number>;
|
|
latitude: XStandardType<number>;
|
|
longitude: XStandardType<number>;
|
|
|
|
canSelect: XStandardType<boolean>;
|
|
addMarkerOnSelectedLocation: XStandardType<boolean>;
|
|
|
|
//
|
|
isReady: EventEmitter<void>;
|
|
viewChanged: EventEmitter<XMapLocation>;
|
|
locationSelected: EventEmitter<XMapLocation>;
|
|
// zoomChanged: EventEmitter<number>;
|
|
|
|
markerStyle: XStandardType<XMapStyle>;
|
|
|
|
showProgressBar: XStandardType<boolean>;
|
|
progressBarColor: XStandardType<XColorIdentifier>;
|
|
progressBarPosition: XStandardType<XMapItemPositionIdentifier>;
|
|
|
|
showSelectedLocation: XStandardType<boolean>;
|
|
selectedLocationPosition: XStandardType<XMapItemPositionIdentifier>;
|
|
|
|
showGoMarkedPlace: XStandardType<boolean>;
|
|
goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier>;
|
|
|
|
showClearMarker: XStandardType<boolean>;
|
|
clearMarkerPosition: XStandardType<XMapItemPositionIdentifier>;
|
|
|
|
showLocator: XStandardType<boolean>;
|
|
locatorPosition: XStandardType<XMapItemPositionIdentifier>;
|
|
|
|
showZoom: XStandardType<boolean>;
|
|
showRotate: XStandardType<boolean>;
|
|
showZoomSlider: XStandardType<boolean>;
|
|
|
|
//
|
|
searchBarPosition: XStandardType<XMapItemPositionIdentifier>;
|
|
searchPlaceProvider: (query: string) => string;
|
|
searchResultListColor: XStandardType<XColorIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMapContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXMapContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XMapActionModel> =
|
|
new Subject<XMapActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly zoom: XStandardType<number> = 0;
|
|
readonly latitude: XStandardType<number> = 0;
|
|
readonly longitude: XStandardType<number> = 0;
|
|
|
|
readonly canSelect: XStandardType<boolean> = true;
|
|
readonly addMarkerOnSelectedLocation: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly isReady: EventEmitter<void> = new EventEmitter();
|
|
readonly viewChanged: EventEmitter<XMapLocation> =
|
|
new EventEmitter<XMapLocation>();
|
|
readonly locationSelected: EventEmitter<XMapLocation> =
|
|
new EventEmitter<XMapLocation>();
|
|
// zoomChanged: EventEmitter<number>;
|
|
|
|
readonly markerStyle: XStandardType<XMapStyle> = defaultMarkerStyle;
|
|
|
|
readonly showProgressBar: XStandardType<boolean> = true;
|
|
readonly progressBarColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
readonly progressBarPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
|
|
readonly showSelectedLocation: XStandardType<boolean> = true;
|
|
readonly selectedLocationPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
|
|
readonly showGoMarkedPlace: XStandardType<boolean> = true;
|
|
readonly goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
|
|
readonly showClearMarker: XStandardType<boolean> = true;
|
|
readonly clearMarkerPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
|
|
readonly showLocator: XStandardType<boolean> = true;
|
|
readonly locatorPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
|
|
readonly showZoom: XStandardType<boolean> = true;
|
|
readonly showRotate: XStandardType<boolean> = true;
|
|
readonly showZoomSlider: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly searchBarPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
XMapItemPosition.TOP;
|
|
readonly searchPlaceProvider: (query: string) => string =
|
|
defaultMapSearchPlaceProvider;
|
|
readonly searchResultListColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
|
|
//
|
|
//#region ComponentSearchBar ...
|
|
//
|
|
readonly showSearchBar: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.showSearchBar;
|
|
|
|
//
|
|
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.searchBarPropertyProvider.searchBarActionProvider;
|
|
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.searchBarPropertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
readonly searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarColor;
|
|
readonly searchBarForegroundColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchInputColor;
|
|
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarType;
|
|
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarTitle;
|
|
readonly searchBarValue: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarValue;
|
|
readonly searchBarEnterKeyHint: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarEnterKeyHint;
|
|
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarKeyboardType;
|
|
readonly searchBarSpellcheck: XStandardType<boolean> =
|
|
this.searchBarPropertyProvider.searchBarSpellcheck;
|
|
readonly searchBarDebounce: XStandardType<number> =
|
|
this.searchBarPropertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
readonly searchBarShowCancelButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowCancelButton;
|
|
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
|
|
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
|
|
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarShowClearButton: XStandardType<string> =
|
|
this.searchBarPropertyProvider.searchBarShowClearButton;
|
|
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIcon;
|
|
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
|
|
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarQueryChange: EventEmitter<string> =
|
|
this.searchBarPropertyProvider.searchBarQueryChange;
|
|
readonly searchBarOnEvent: EventEmitter<string> =
|
|
this.searchBarPropertyProvider.searchBarOnEvent;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected propertyProvider: XCardContainer,
|
|
protected searchBarPropertyProvider: XComponentSearchBarContainer
|
|
) {
|
|
super(propertyProvider);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XMapContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXMapContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XMapActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
zoom: XStandardType<number> = this.propertyProvider.zoom;
|
|
|
|
@Input()
|
|
latitude: XStandardType<number> = this.propertyProvider.latitude;
|
|
|
|
@Input()
|
|
longitude: XStandardType<number> = this.propertyProvider.longitude;
|
|
|
|
@Input()
|
|
canSelect: XStandardType<boolean> = this.propertyProvider.canSelect;
|
|
|
|
@Input()
|
|
addMarkerOnSelectedLocation: XStandardType<boolean> =
|
|
this.propertyProvider.addMarkerOnSelectedLocation;
|
|
|
|
//
|
|
@Output()
|
|
isReady: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Output()
|
|
viewChanged: EventEmitter<XMapLocation> = new EventEmitter();
|
|
|
|
@Output()
|
|
locationSelected: EventEmitter<XMapLocation> = new EventEmitter();
|
|
// zoomChanged: EventEmitter<number>;
|
|
|
|
@Input()
|
|
markerStyle: XStandardType<XMapStyle> = this.propertyProvider.markerStyle;
|
|
|
|
@Input()
|
|
showProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.showProgressBar;
|
|
|
|
@Input()
|
|
progressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.progressBarColor;
|
|
|
|
@Input()
|
|
progressBarPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.progressBarPosition;
|
|
|
|
@Input()
|
|
showSelectedLocation: XStandardType<boolean> =
|
|
this.propertyProvider.showSelectedLocation;
|
|
|
|
@Input()
|
|
selectedLocationPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.selectedLocationPosition;
|
|
|
|
@Input()
|
|
showGoMarkedPlace: XStandardType<boolean> =
|
|
this.propertyProvider.showGoMarkedPlace;
|
|
|
|
@Input()
|
|
goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.goMarkedPlacePosition;
|
|
|
|
@Input()
|
|
showClearMarker: XStandardType<boolean> =
|
|
this.propertyProvider.showClearMarker;
|
|
|
|
@Input()
|
|
clearMarkerPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.clearMarkerPosition;
|
|
|
|
@Input()
|
|
showLocator: XStandardType<boolean> = this.propertyProvider.showLocator;
|
|
|
|
@Input()
|
|
locatorPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.locatorPosition;
|
|
|
|
@Input()
|
|
showZoom: XStandardType<boolean> = this.propertyProvider.showZoom;
|
|
|
|
@Input()
|
|
showRotate: XStandardType<boolean> = this.propertyProvider.showRotate;
|
|
|
|
@Input()
|
|
showZoomSlider: XStandardType<boolean> = this.propertyProvider.showZoomSlider;
|
|
|
|
//
|
|
@Input()
|
|
searchBarPosition: XStandardType<XMapItemPositionIdentifier> =
|
|
this.propertyProvider.searchBarPosition;
|
|
|
|
@Input()
|
|
searchPlaceProvider: (query: string) => string =
|
|
this.propertyProvider.searchPlaceProvider;
|
|
|
|
@Input()
|
|
searchResultListColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchResultListColor;
|
|
|
|
//
|
|
//#region ComponentSearchBar ...
|
|
//
|
|
@Input()
|
|
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
|
|
|
|
//
|
|
@Input()
|
|
searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.searchBarActionProvider;
|
|
|
|
@Input()
|
|
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
|
|
@Input()
|
|
searchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchInputColor;
|
|
|
|
@Input()
|
|
searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarType;
|
|
|
|
@Input()
|
|
searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarTitle;
|
|
|
|
@Input()
|
|
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
|
|
|
|
@Input()
|
|
searchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.searchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarKeyboardType;
|
|
|
|
@Input()
|
|
searchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarSpellcheck;
|
|
|
|
@Input()
|
|
searchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowCancelButton;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowClearButton;
|
|
|
|
@Input()
|
|
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
searchBarOnEvent: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XMapContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(container?: IXMapContainer): Observable<IXMapContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
zoom: this.getValue(container ? container.zoom : this.zoom),
|
|
latitude: this.getValue(
|
|
container ? container.latitude : this.latitude
|
|
),
|
|
longitude: this.getValue(
|
|
container ? container.longitude : this.longitude
|
|
),
|
|
canSelect: this.getValue(
|
|
container ? container.canSelect : this.canSelect
|
|
),
|
|
addMarkerOnSelectedLocation: this.getValue(
|
|
container
|
|
? container.addMarkerOnSelectedLocation
|
|
: this.addMarkerOnSelectedLocation
|
|
),
|
|
markerStyle: this.getValue(
|
|
container ? container.markerStyle : this.markerStyle
|
|
),
|
|
showProgressBar: this.getValue(
|
|
container ? container.showProgressBar : this.showProgressBar
|
|
),
|
|
progressBarColor: this.getValue(
|
|
container ? container.progressBarColor : this.progressBarColor
|
|
),
|
|
progressBarPosition: this.getValue(
|
|
container
|
|
? container.progressBarPosition
|
|
: this.progressBarPosition
|
|
),
|
|
showSelectedLocation: this.getValue(
|
|
container
|
|
? container.showSelectedLocation
|
|
: this.showSelectedLocation
|
|
),
|
|
selectedLocationPosition: this.getValue(
|
|
container
|
|
? container.selectedLocationPosition
|
|
: this.selectedLocationPosition
|
|
),
|
|
showGoMarkedPlace: this.getValue(
|
|
container ? container.showGoMarkedPlace : this.showGoMarkedPlace
|
|
),
|
|
goMarkedPlacePosition: this.getValue(
|
|
container
|
|
? container.goMarkedPlacePosition
|
|
: this.goMarkedPlacePosition
|
|
),
|
|
showClearMarker: this.getValue(
|
|
container ? container.showClearMarker : this.showClearMarker
|
|
),
|
|
clearMarkerPosition: this.getValue(
|
|
container
|
|
? container.clearMarkerPosition
|
|
: this.clearMarkerPosition
|
|
),
|
|
showLocator: this.getValue(
|
|
container ? container.showLocator : this.showLocator
|
|
),
|
|
locatorPosition: this.getValue(
|
|
container ? container.locatorPosition : this.locatorPosition
|
|
),
|
|
showZoom: this.getValue(
|
|
container ? container.showZoom : this.showZoom
|
|
),
|
|
showRotate: this.getValue(
|
|
container ? container.showRotate : this.showRotate
|
|
),
|
|
showZoomSlider: this.getValue(
|
|
container ? container.showZoomSlider : this.showZoomSlider
|
|
),
|
|
searchBarPosition: this.getValue(
|
|
container ? container.searchBarPosition : this.searchBarPosition
|
|
),
|
|
searchPlaceProvider: this.getValue(
|
|
container
|
|
? container.searchPlaceProvider
|
|
: this.searchPlaceProvider
|
|
),
|
|
searchResultListColor: this.getValue(
|
|
container
|
|
? container.searchResultListColor
|
|
: this.searchResultListColor
|
|
),
|
|
showSearchBar: this.getValue(
|
|
container ? container.showSearchBar : this.showSearchBar
|
|
),
|
|
searchBarCssClass: this.getValue(
|
|
container ? container.searchBarCssClass : this.searchBarCssClass
|
|
),
|
|
searchBarColor: this.getValue(
|
|
container ? container.searchBarColor : this.searchBarColor
|
|
),
|
|
searchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundColor
|
|
: this.searchBarForegroundColor
|
|
),
|
|
searchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchInputColor
|
|
: this.searchBarSearchInputColor
|
|
),
|
|
searchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundSearchInputColor
|
|
: this.searchBarForegroundSearchInputColor
|
|
),
|
|
searchBarType: this.getValue(
|
|
container ? container.searchBarType : this.searchBarType
|
|
),
|
|
searchBarTitle: this.getValue(
|
|
container ? container.searchBarTitle : this.searchBarTitle
|
|
),
|
|
searchBarValue: this.getValue(
|
|
container ? container.searchBarValue : this.searchBarValue
|
|
),
|
|
searchBarEnterKeyHint: this.getValue(
|
|
container
|
|
? container.searchBarEnterKeyHint
|
|
: this.searchBarEnterKeyHint
|
|
),
|
|
searchBarKeyboardType: this.getValue(
|
|
container
|
|
? container.searchBarKeyboardType
|
|
: this.searchBarKeyboardType
|
|
),
|
|
searchBarSpellcheck: this.getValue(
|
|
container
|
|
? container.searchBarSpellcheck
|
|
: this.searchBarSpellcheck
|
|
),
|
|
searchBarDebounce: this.getValue(
|
|
container ? container.searchBarDebounce : this.searchBarDebounce
|
|
),
|
|
searchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.searchBarShowCancelButton
|
|
: this.searchBarShowCancelButton
|
|
),
|
|
searchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIcon
|
|
: this.searchBarCancelButtonIcon
|
|
),
|
|
searchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonTitle
|
|
: this.searchBarCancelButtonTitle
|
|
),
|
|
searchBarCancelButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIconColor
|
|
: this.searchBarCancelButtonIconColor
|
|
),
|
|
searchBarShowClearButton: this.getValue(
|
|
container
|
|
? container.searchBarShowClearButton
|
|
: this.searchBarShowClearButton
|
|
),
|
|
searchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIcon
|
|
: this.searchBarClearButtonIcon
|
|
),
|
|
searchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIconColor
|
|
: this.searchBarClearButtonIconColor
|
|
),
|
|
searchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIcon
|
|
: this.searchBarSearchButtonIcon
|
|
),
|
|
searchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIconColor
|
|
: this.searchBarSearchButtonIconColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
isReady: this.isReady,
|
|
viewChanged: this.viewChanged,
|
|
locationSelected: this.locationSelected,
|
|
|
|
//
|
|
searchBarActionProvider: container
|
|
? container.searchBarActionProvider
|
|
: this.searchBarActionProvider,
|
|
|
|
//
|
|
searchBarQueryChange: this.searchBarQueryChange,
|
|
searchBarOnEvent: this.searchBarOnEvent,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.html
|
|
|
|
<section #mapDialogContainer class="x-map-dialog-container">
|
|
<!-- Title Toolbar -->
|
|
<section #mapDialogToolbar>
|
|
<ion-toolbar class="v-toolbar" [xColor]="'primary'">
|
|
<!-- Slots -->
|
|
<div class="toolbar-area">
|
|
<x-slotter>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'ion-float-start']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleBack()"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="backIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<ion-title class="toolbar-item center-vertical-flex">
|
|
<h3>
|
|
{{ getTitle() | async }}
|
|
</h3>
|
|
</ion-title>
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot
|
|
[name]="SlotNames.END"
|
|
[cssClass]="['ion-text-end', 'ion-float-end']"
|
|
>
|
|
<div
|
|
matRipple
|
|
(click)="handleSelect()"
|
|
*ngIf="dialogCanSelect() && (canSelect | async)"
|
|
class="toolbar-item toolbar-button center-vertical-flex"
|
|
>
|
|
<x-icon
|
|
[name]="selectIcon"
|
|
[loading]="loading"
|
|
[color]="'cb-inherit'"
|
|
[uiDisabled]="uiDisabled"
|
|
></x-icon>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</ion-toolbar>
|
|
</section>
|
|
|
|
<!-- Map Component -->
|
|
<x-map
|
|
[isInPage]="false"
|
|
[zoom]="zoom | async"
|
|
[loading]="loading"
|
|
[wrapWithCard]="false"
|
|
[showSearchBar]="true"
|
|
[uiDisabled]="uiDisabled"
|
|
[latitude]="latitude | async"
|
|
[cssClass]="cssClass | async"
|
|
[showZoom]="showZoom | async"
|
|
(isReady)="handleMapIsReady()"
|
|
[longitude]="longitude | async"
|
|
[canSelect]="canSelect | async"
|
|
[showRotate]="showRotate | async"
|
|
[actionProvider]="actionProvider"
|
|
[showLocator]="showLocator | async"
|
|
[markerStyle]="markerStyle | async"
|
|
[searchBarType]="searchBarType | async"
|
|
[searchBarValue]="searchBarValue | async"
|
|
[searchBarColor]="searchBarColor | async"
|
|
[searchBarTitle]="searchBarTitle | async"
|
|
[searchBarColor]="searchBarColor | async"
|
|
[showZoomSlider]="showZoomSlider | async"
|
|
[searchBarPosition]="MapItemPositions.TOP"
|
|
[showProgressBar]="showProgressBar | async"
|
|
[showClearMarker]="showClearMarker | async"
|
|
[locatorPosition]="locatorPosition | async"
|
|
[progressBarPosition]="MapItemPositions.TOP"
|
|
[progressBarColor]="progressBarColor | async"
|
|
[searchBarForegroundSearchInputColor]="
|
|
searchBarForegroundSearchInputColor | async
|
|
"
|
|
[searchBarForegroundSearchInputColor]="
|
|
searchBarForegroundSearchInputColor | async
|
|
"
|
|
[showGoMarkedPlace]="showGoMarkedPlace | async"
|
|
[searchBarDebounce]="searchBarDebounce | async"
|
|
[searchBarCssClass]="searchBarCssClass | async"
|
|
[searchBarSpellcheck]="searchBarSpellcheck | async"
|
|
[searchPlaceProvider]="searchPlaceProvider | async"
|
|
[clearMarkerPosition]="clearMarkerPosition | async"
|
|
[showSelectedLocation]="showSelectedLocation | async"
|
|
(locationSelected)="handleMapLocationSelected($event)"
|
|
[goMarkedPlacePosition]="goMarkedPlacePosition | async"
|
|
[searchBarKeyboardType]="searchBarKeyboardType | async"
|
|
[searchBarEnterKeyHint]="searchBarEnterKeyHint | async"
|
|
[searchResultListColor]="searchResultListColor | async"
|
|
(searchBarQueryChange)="handleSearchBarQueryChange($event)"
|
|
[searchBarActionProvider]="searchBarActionProvider | async"
|
|
[selectedLocationPosition]="selectedLocationPosition | async"
|
|
[searchBarClearButtonIcon]="searchBarClearButtonIcon | async"
|
|
[searchBarForegroundColor]="searchBarForegroundColor | async"
|
|
[searchBarSearchButtonIcon]="searchBarSearchButtonIcon | async"
|
|
[searchBarSearchInputColor]="searchBarSearchInputColor | async"
|
|
[searchBarShowCancelButton]="searchBarShowCancelButton | async"
|
|
[searchBarCancelButtonIcon]="searchBarCancelButtonIcon | async"
|
|
[searchBarClearButtonIconColor]="searchBarClearIconColor | async"
|
|
[searchBarCancelButtonTitle]="searchBarCancelButtonTitle | async"
|
|
[searchBarSearchButtonIconColor]="searchBarSearchButtonIconColor | async"
|
|
>
|
|
</x-map>
|
|
</section>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.scss
|
|
|
|
:host {
|
|
--x-map-height: 200px;
|
|
}
|
|
|
|
::ng-deep.fullscreen-dialog {
|
|
//
|
|
width: 80vw !important;
|
|
max-width: 80vw !important;
|
|
|
|
//
|
|
height: 80vh !important;
|
|
max-height: 80vh !important;
|
|
|
|
//
|
|
&.mobile {
|
|
//
|
|
width: 100vw !important;
|
|
max-width: 100vw !important;
|
|
|
|
//
|
|
height: 100vh !important;
|
|
max-height: 100vh !important;
|
|
}
|
|
|
|
//
|
|
.mat-dialog-container {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep x-map {
|
|
//
|
|
--map-height: var(--x-map-height);
|
|
}
|
|
|
|
.x-map-dialog-container {
|
|
height: 100%;
|
|
}
|
|
|
|
x-icon {
|
|
--size: 24px;
|
|
}
|
|
|
|
.toolbar-area {
|
|
margin: 8px;
|
|
}
|
|
|
|
.toolbar-item {
|
|
width: auto;
|
|
height: 48px;
|
|
}
|
|
|
|
.toolbar-button {
|
|
width: 32px;
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.ts
|
|
|
|
import {
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XColor,
|
|
isFunction,
|
|
XResourceIDs,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XMapAction,
|
|
XMapLocation,
|
|
XMapActionModel,
|
|
XMapItemPosition,
|
|
defaultMarkerStyle,
|
|
defaultMapSearchPlaceProvider,
|
|
} from '../x-map.typings';
|
|
import { ViewChild } from '@angular/core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XSearchBarType,
|
|
XSearchBarShowButton,
|
|
XSearchBarActionModel,
|
|
XSearchBarEnterKeyHint,
|
|
} from '../../x-search-bar/x-search-bar.typings';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XBasePage } from '../../classes/x-base-page';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconNames } from '../../x-icon/x-icon.typings';
|
|
import { XSlotName } from '../../x-slotter/x-slotter.typings';
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
import { XMapDialogConfig, XMapdialogCssVar } from './x-map-dialog.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-map-dialog',
|
|
templateUrl: './x-map-dialog.component.html',
|
|
styleUrls: ['./x-map-dialog.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XMapDialogComponent extends XBasePage {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly selectIcon = XIconNames.checked;
|
|
readonly backIcon = XIconNames.arrow_back;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly MapItemPositions = Object.assign({}, XMapItemPosition);
|
|
|
|
//
|
|
hasMarker: boolean;
|
|
selectedLocation: XMapLocation;
|
|
actionProvider = new Subject<XMapActionModel>();
|
|
|
|
//
|
|
@ViewChild('mapDialogContainer')
|
|
mapDialogContainer: ElementRef<HTMLElement>;
|
|
|
|
@ViewChild('mapDialogToolbar')
|
|
mapDialogToolbar: ElementRef<HTMLElement>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
|
public dialogRef: MatDialogRef<XMapDialogComponent>
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
this.preventBack = true;
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
await this.applyMapSize();
|
|
}
|
|
|
|
public registerViewHandlers(): void {
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider.subscribe(
|
|
(action) => {
|
|
switch (action.action) {
|
|
//
|
|
case XMapAction.HasMarker:
|
|
//
|
|
this.hasMarker = true;
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XMapAction.HasNotMarker:
|
|
this.hasMarker = false;
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
public onDestroy(): void {
|
|
//
|
|
if (!isNullOrUndefined(this.ACTION_PROVIDER_SUBSCRIPTION)) {
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
/**
|
|
* retrieve map dialog config ...
|
|
*/
|
|
getData() {
|
|
return this.getValue(this.data as XMapDialogConfig);
|
|
}
|
|
|
|
/**
|
|
* determines map dialog config exists or not ...
|
|
*/
|
|
hasData() {
|
|
return !isNullOrUndefined(this.getData());
|
|
}
|
|
|
|
/**
|
|
* determines dialog can select result or not ...
|
|
*/
|
|
dialogCanSelect() {
|
|
return (
|
|
this.hasMarker &&
|
|
!isNullOrUndefined(this.selectedLocation) &&
|
|
!isNullOrEmptyString(this.selectedLocation.latitude) &&
|
|
!isNullOrEmptyString(this.selectedLocation.longitude)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* retrieve dialog title ...
|
|
*/
|
|
getTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getResourceValue(config.title))
|
|
);
|
|
}
|
|
|
|
//
|
|
get markerStyle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.markerStyle)),
|
|
map((style) => (style ? style : defaultMarkerStyle))
|
|
);
|
|
}
|
|
|
|
get cssClass() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config.cssClass))
|
|
);
|
|
}
|
|
|
|
get progressBarColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.progressBarColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Warning))
|
|
);
|
|
}
|
|
|
|
get canSelect() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getValue(config.canSelect ? config.canSelect : true)
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
get latitude() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.latitude))
|
|
);
|
|
}
|
|
|
|
get longitude() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.longitude))
|
|
);
|
|
}
|
|
|
|
//
|
|
get zoom() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.zoom))
|
|
);
|
|
}
|
|
|
|
//
|
|
get showRotate() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showRotate)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showZoom() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showZoom)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showZoomSlider() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showZoomSlider)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? false : canShow))
|
|
);
|
|
}
|
|
|
|
get showLocator() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showLocator)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showClearMarker() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showClearMarker)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showGoMarkedPlace() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showGoMarkedPlace)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showSelectedLocation() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showSelectedLocation)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get showSearchBar() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showSearchBar)),
|
|
map((canShow) => (isNullOrUndefined(canShow) ? true : canShow))
|
|
);
|
|
}
|
|
|
|
get searchResultListColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getValue(config.searchResultListColor)),
|
|
map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light))
|
|
);
|
|
}
|
|
|
|
// //
|
|
// get isInPage() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.isInPage))
|
|
// );
|
|
// }
|
|
|
|
// get wrapWithCard() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.wrapWithCard))
|
|
// );
|
|
// }
|
|
|
|
// get cardColor() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getValue(config.progressBarColor)),
|
|
// map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light))
|
|
// );
|
|
// }
|
|
|
|
// get cardForegroundColor() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.cardForegroundColor))
|
|
// );
|
|
// }
|
|
|
|
// get cardTitle() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getResourceValue(config.cardTitle))
|
|
// );
|
|
// }
|
|
|
|
// get cardSubTitle() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getResourceValue(config.cardSubTitle))
|
|
// );
|
|
// }
|
|
|
|
// get cardShowFooter() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.cardShowFooter))
|
|
// );
|
|
// }
|
|
|
|
//
|
|
get showProgressBar() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.showProgressBar)),
|
|
map((result) => (isNullOrUndefined(result) ? true : result))
|
|
);
|
|
}
|
|
|
|
// get progressBarPosition() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.progressBarPosition)),
|
|
// map((result) =>
|
|
// isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
// )
|
|
// );
|
|
// }
|
|
|
|
get locatorPosition() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.locatorPosition)),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
)
|
|
);
|
|
}
|
|
|
|
get clearMarkerPosition() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.clearMarkerPosition)),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
)
|
|
);
|
|
}
|
|
|
|
get goMarkedPlacePosition() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.goMarkedPlacePosition)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
)
|
|
);
|
|
}
|
|
|
|
get selectedLocationPosition() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.selectedLocationPosition)
|
|
),
|
|
map((result) =>
|
|
isNullOrEmptyString(result) ? XMapItemPosition.TOP : result
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Search ...
|
|
get searchPlaceProvider() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchPlaceProvider)),
|
|
map((provider) =>
|
|
!provider || !isFunction(provider)
|
|
? defaultMapSearchPlaceProvider
|
|
: provider
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarType() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarType)),
|
|
map((data) => (isNullOrEmptyString(data) ? XSearchBarType.Search : data))
|
|
);
|
|
}
|
|
|
|
get searchBarValue() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarValue))
|
|
);
|
|
}
|
|
|
|
get searchBarColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarColor)),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XColorWithBrightness.Primary : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarTitle)),
|
|
map((data) =>
|
|
!data || isNullOrEmptyString(data.toString())
|
|
? XResourceIDs.search
|
|
: data
|
|
)
|
|
);
|
|
}
|
|
|
|
// get searchBarPosition() {
|
|
// return this.getData().pipe(
|
|
// concatMap((config) => this.getOptionalValue(config.searchBarPosition)),
|
|
// map((data) => (isNullOrEmptyString(data) ? XMapItemPosition.TOP : data))
|
|
// );
|
|
// }
|
|
|
|
get searchBarCssClass() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getArrayValue(config.searchBarCssClass))
|
|
);
|
|
}
|
|
|
|
get searchBarDebounce() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarDebounce)),
|
|
map((data) =>
|
|
isNullOrUndefined(data) ? this.config.defaultSearchDebounceTime : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarClearButtonIcon() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarClearButtonIcon)
|
|
),
|
|
map((data) =>
|
|
!data || isNullOrEmptyString(data.toString()) ? XIconNames.clear : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarSearchInputColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchInputColor)
|
|
),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XColorWithBrightness.Primary : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarSpellcheck() {
|
|
return this.getData().pipe(
|
|
concatMap((config) => this.getOptionalValue(config.searchBarSpellcheck))
|
|
);
|
|
}
|
|
|
|
get searchBarSearchButtonIcon() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchButtonIcon)
|
|
),
|
|
map((data) =>
|
|
!data || isNullOrEmptyString(data.toString()) ? XIconNames.search : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarKeyboardType() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarKeyboardType)
|
|
),
|
|
map((data) => (isNullOrEmptyString(data) ? XSearchBarType.Search : data))
|
|
);
|
|
}
|
|
|
|
get searchBarEnterKeyHint() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarEnterKeyHint)
|
|
),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XSearchBarEnterKeyHint.Search : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarClearIconColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarClearButtonIconColor)
|
|
),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XColorWithBrightness.Light : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarActionProvider() {
|
|
return this.getData().pipe(
|
|
map((data) =>
|
|
!isNullOrUndefined(data.searchBarActionProvider)
|
|
? data.searchBarActionProvider
|
|
: new Subject<XSearchBarActionModel>()
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarSearchButtonIconColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarSearchButtonIconColor)
|
|
),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XColorWithBrightness.Light : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarForegroundColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarForegroundColor)
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarShowCancelButton() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarShowCancelButton)
|
|
),
|
|
map((data) =>
|
|
isNullOrEmptyString(data) ? XSearchBarShowButton.Never : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarCancelButtonIcon() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarCancelButtonIcon)
|
|
),
|
|
map((data) =>
|
|
!data || isNullOrEmptyString(data.toString()) ? XIconNames.cancel : data
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarCancelButtonTitle() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getResourceValue(config.searchBarCancelButtonTitle)
|
|
)
|
|
);
|
|
}
|
|
|
|
get searchBarForegroundSearchInputColor() {
|
|
return this.getData().pipe(
|
|
concatMap((config) =>
|
|
this.getOptionalValue(config.searchBarForegroundSearchInputColor)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleBack() {
|
|
this.dialogRef.close();
|
|
}
|
|
|
|
async handleSelect() {
|
|
//
|
|
if (!this.dialogCanSelect()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dialogRef.close({
|
|
result: XDialogResult.Ok,
|
|
payload: this.selectedLocation,
|
|
});
|
|
}
|
|
|
|
async handleMapIsReady() {
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (!config || !config.isReady) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.isReady.emit();
|
|
}
|
|
|
|
async handleSearchBarQueryChange(event: string) {
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (!config || !config.searchBarQueryChange) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.searchBarQueryChange.emit(event);
|
|
}
|
|
|
|
async handleMapLocationSelected(event: XMapLocation) {
|
|
//
|
|
this.selectedLocation = event;
|
|
|
|
//
|
|
const config = await this.getValueAsync(this.getData());
|
|
if (!config || !config.locationSelected) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
config.locationSelected.emit(event);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
async applyMapSize() {
|
|
//
|
|
let result = 0;
|
|
|
|
//
|
|
//#region DialogHeight ...
|
|
//
|
|
if (!this.mapDialogContainer) {
|
|
//
|
|
setTimeout(async () => await this.applyMapSize(), 500);
|
|
return;
|
|
}
|
|
const height =
|
|
this.mapDialogContainer.nativeElement.getBoundingClientRect().height;
|
|
if (height === 0) {
|
|
//
|
|
setTimeout(async () => await this.applyMapSize(), 500);
|
|
return;
|
|
}
|
|
|
|
//
|
|
result += height;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ToolbarHeight ...
|
|
if (!this.mapDialogToolbar) {
|
|
//
|
|
setTimeout(async () => await this.applyMapSize(), 500);
|
|
return;
|
|
}
|
|
const toolbarHeight =
|
|
this.mapDialogToolbar.nativeElement.getBoundingClientRect().height;
|
|
if (toolbarHeight === 0) {
|
|
//
|
|
setTimeout(async () => await this.applyMapSize(), 500);
|
|
return;
|
|
}
|
|
|
|
//
|
|
result -= toolbarHeight;
|
|
//#endregion
|
|
|
|
//
|
|
this.setCssVar(XMapdialogCssVar.XMapHeight, `${result}px`);
|
|
this.detectChanges();
|
|
|
|
//
|
|
this.runTimedOut(() => {
|
|
this.managerService.dispatchResizeEvent();
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.service.ts
|
|
|
|
import {
|
|
XColor,
|
|
toPromise,
|
|
XBaseService,
|
|
XResourceIDs,
|
|
XDialogResult,
|
|
isNullOrUndefined,
|
|
} from 'x-framework-core';
|
|
import {
|
|
MatDialog,
|
|
MatDialogRef,
|
|
MatDialogConfig,
|
|
} from '@angular/material/dialog';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XMapLocation } from '../x-map.typings';
|
|
import { XMapDialogComponent } from './x-map-dialog.component';
|
|
import { Injectable, Output, EventEmitter, Inject } from '@angular/core';
|
|
import { XMapDialogResult, XMapDialogConfig } from './x-map-dialog.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMapDialogService extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
private MOBILE_CLASS_NAME = 'mobile';
|
|
private DIALOG_REF: MatDialogRef<XMapDialogComponent>;
|
|
|
|
//
|
|
isMobile$ = this.managerService.isMobileUi$;
|
|
|
|
// tslint:disable-next-line:no-output-on-prefix
|
|
@Output()
|
|
onResult = new EventEmitter<XMapDialogResult>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
private dialog: MatDialog,
|
|
private managerService: XManagerService
|
|
) {
|
|
super(config);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* Open Select Map Dialog ...
|
|
*/
|
|
async openDialog(config?: XMapDialogConfig) {
|
|
//
|
|
// Prevent Double Bubble ...
|
|
if (this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare Config ...
|
|
if (!config) {
|
|
config = {};
|
|
}
|
|
|
|
//
|
|
//#region Default Config for Map Component ...
|
|
//
|
|
// Zoom ...
|
|
if (config && !config.zoom) {
|
|
config.zoom = 6;
|
|
}
|
|
|
|
//
|
|
// canSelect ...
|
|
let selectable = false;
|
|
if (config && !isNullOrUndefined(config.canSelect)) {
|
|
//
|
|
selectable = await toPromise(config.canSelect);
|
|
config.canSelect = selectable;
|
|
}
|
|
|
|
//
|
|
// Set Default Title ...
|
|
if (config && !config.title) {
|
|
//
|
|
if (selectable) {
|
|
config.title = XResourceIDs.map_dialog_select_title;
|
|
} else {
|
|
config.title = XResourceIDs.map_dialog_title;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Search Bar Color ...
|
|
if (config && !config.searchBarColor) {
|
|
config.searchBarColor = XColor.Primary;
|
|
}
|
|
|
|
//
|
|
// Progress Bar Color ...
|
|
if (config && !config.progressBarColor) {
|
|
config.progressBarColor = XColor.Warning;
|
|
}
|
|
|
|
//
|
|
// Search Result List Color ...
|
|
if (config && !config.searchResultListColor) {
|
|
config.searchResultListColor = XColor.Medium;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Prepare Dialog Config ...
|
|
const data: MatDialogConfig = {
|
|
data: config,
|
|
};
|
|
|
|
//
|
|
data.panelClass = 'fullscreen-dialog';
|
|
|
|
//
|
|
// Show Cropper inside a Dialog ...
|
|
this.DIALOG_REF = this.dialog.open(XMapDialogComponent, data);
|
|
this.DIALOG_REF.disableClose = true;
|
|
|
|
//
|
|
// Attach Mobile Class ...
|
|
this.isMobile$.subscribe((isMobile) => {
|
|
//
|
|
if (isMobile) {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
} else {
|
|
if (this.DIALOG_REF) {
|
|
this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME);
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
// Handle Backdrop ...
|
|
this.DIALOG_REF.backdropClick().subscribe(() => {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
|
|
//
|
|
this.closeDialog();
|
|
});
|
|
|
|
//
|
|
// Handle Dialog Result ...
|
|
this.DIALOG_REF.afterClosed().subscribe((model: XMapDialogResult) => {
|
|
//
|
|
if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) {
|
|
//
|
|
// Cancel Dialog ...
|
|
this.onResult.emit({ result: XDialogResult.Cancel });
|
|
} else {
|
|
//
|
|
// Handle Results ...
|
|
this.onResult.emit(model);
|
|
}
|
|
|
|
//
|
|
this.closeDialog();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Close Select Map Dialog ...
|
|
*/
|
|
closeDialog() {
|
|
//
|
|
// Prevent Go Forward ...
|
|
if (!this.DIALOG_REF) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Close Dialog ...
|
|
this.DIALOG_REF.close();
|
|
this.DIALOG_REF = null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.typings.ts
|
|
|
|
import { XDialogResult } from 'x-framework-core';
|
|
import { XMapLocation, IXMapContainer } from '../x-map.typings';
|
|
import { XBaseDialogConfig } from '../../classes/i-x-base-dialog.container';
|
|
|
|
export interface XMapDialogResult {
|
|
payload?: XMapLocation;
|
|
result: XDialogResult;
|
|
}
|
|
|
|
export interface XMapDialogConfig
|
|
extends XBaseDialogConfig,
|
|
Pick<
|
|
Partial<IXMapContainer>,
|
|
| 'zoom'
|
|
| 'isReady'
|
|
| 'latitude'
|
|
| 'cssClass'
|
|
| 'showZoom'
|
|
| 'longitude'
|
|
| 'canSelect'
|
|
| 'showRotate'
|
|
| 'showLocator'
|
|
| 'markerStyle'
|
|
| 'showSearchBar'
|
|
| 'searchBarType'
|
|
| 'actionProvider'
|
|
| 'searchBarValue'
|
|
| 'searchBarColor'
|
|
| 'searchBarTitle'
|
|
| 'searchBarColor'
|
|
| 'showZoomSlider'
|
|
| 'showProgressBar'
|
|
| 'showClearMarker'
|
|
| 'locatorPosition'
|
|
| 'progressBarColor'
|
|
| 'locationSelected'
|
|
| 'searchBarCssClass'
|
|
| 'showGoMarkedPlace'
|
|
| 'searchBarDebounce'
|
|
| 'searchPlaceProvider'
|
|
| 'clearMarkerPosition'
|
|
| 'searchBarSpellcheck'
|
|
| 'searchBarQueryChange'
|
|
| 'showSelectedLocation'
|
|
| 'goMarkedPlacePosition'
|
|
| 'searchBarKeyboardType'
|
|
| 'searchBarEnterKeyHint'
|
|
| 'searchResultListColor'
|
|
| 'searchBarActionProvider'
|
|
| 'searchBarClearButtonIcon'
|
|
| 'searchBarForegroundColor'
|
|
| 'selectedLocationPosition'
|
|
| 'searchBarForegroundColor'
|
|
| 'searchBarSearchButtonIcon'
|
|
| 'searchBarSearchInputColor'
|
|
| 'searchBarSearchInputColor'
|
|
| 'searchBarShowCancelButton'
|
|
| 'searchBarCancelButtonIcon'
|
|
| 'searchBarCancelButtonTitle'
|
|
| 'searchBarClearButtonIconColor'
|
|
| 'searchBarSearchButtonIconColor'
|
|
| 'searchBarForegroundSearchInputColor'
|
|
> {}
|
|
|
|
export enum XMapdialogCssVar {
|
|
XMapHeight = 'x-map-height',
|
|
}
|
|
|
|
export type XMapdialogCssVarIdentifier = XMapdialogCssVar | string;
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.html
|
|
|
|
<!-- WrapWithCard Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[subTitle]="getResourceValue(cardSubTitle) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(getResourceValue(cardTitle) | async) | async) ||
|
|
(notEmptyValue(getResourceValue(cardSubTitle) | async) | async)
|
|
"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Template -->
|
|
<ng-template #componentRef>
|
|
<div
|
|
*ngIf="preparedMode"
|
|
class="x-markdown x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<!-- Toolbar -->
|
|
<div
|
|
class="x-toolbar-wrapper"
|
|
*ngIf="
|
|
(getValueStream(hasToolbar) | async) &&
|
|
((isEditMode() | async) || (isBothMode() | async))
|
|
"
|
|
>
|
|
<ion-toolbar
|
|
class="x-editor-toolbar"
|
|
[xColor]="getValue(toolbarColor) | async"
|
|
[ngClass]="getValue(toolbarCssClass) | async"
|
|
[isForeground]="getValue(toolbarForegroundColor) | async"
|
|
>
|
|
<!-- Start Slot -->
|
|
<ion-buttons slot="start" *ngIf="preparedToolbarConfig">
|
|
<ng-container
|
|
*ngTemplateOutlet="toolbarRef; context: { $implicit: 'start' }"
|
|
></ng-container>
|
|
</ion-buttons>
|
|
|
|
<!-- End Slot -->
|
|
<ion-buttons slot="end" *ngIf="preparedToolbarConfig">
|
|
<ng-container
|
|
*ngTemplateOutlet="toolbarRef; context: { $implicit: 'end' }"
|
|
></ng-container>
|
|
</ion-buttons>
|
|
</ion-toolbar>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[layout]="getSlotterLayout() | async"
|
|
[hasStartOrTopSlot]="(isEditMode() | async) || (isBothMode() | async)"
|
|
[hasEndOrBottomSlot]="(isPreviewMode() | async) || (isBothMode() | async)"
|
|
>
|
|
<!-- Edit Area -->
|
|
<x-slot [name]="'start'">
|
|
<div class="x-editor-wrapper">
|
|
<!-- Editor -->
|
|
<textarea
|
|
#markdownEditor
|
|
class="x-editor"
|
|
[(ngModel)]="innerContent"
|
|
(keyup)="handleContentChanged(innerContent)"
|
|
(change)="handleContentChanged(innerContent)"
|
|
(ngModelChange)="handleContentChanged(innerContent)"
|
|
[xColor]="(getValue(editorBoxColor) | async) || 'cb-inherit'"
|
|
></textarea>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<!-- Preview Area -->
|
|
<x-slot [name]="'end'">
|
|
<div
|
|
class="x-preview-wrapper"
|
|
[class.no-border]="isPreviewMode() | async"
|
|
[xColor]="(getValue(previewBoxColor) | async) || 'cb-inherit'"
|
|
>
|
|
<markdown class="x-preview" [data]="innerContent || ' '"> </markdown>
|
|
</div>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Toolbar Template Ref -->
|
|
<ng-template #toolbarRef let-slot>
|
|
<ng-container *ngIf="preparedToolbarConfig">
|
|
<ng-container *ngFor="let name of toolbarItems">
|
|
<ng-container
|
|
*ngIf="hasToolbarItem(name) && getToolbarItem(name).slot === slot"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
name === 'guide' ? guideToolbarItemRef : toolbarItemRef;
|
|
context: { $implicit: name }
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Toolbar Guide Item Template Ref -->
|
|
<ng-template #guideToolbarItemRef let-name>
|
|
<a
|
|
target="_blank"
|
|
style="text-decoration: none; color: unset"
|
|
href="https://guides.github.com/features/mastering-markdown/"
|
|
>
|
|
<x-icon
|
|
[clickable]="false"
|
|
[selectable]="true"
|
|
[loading]="loading"
|
|
class="x-toolbar-icon"
|
|
[color]="'transparent'"
|
|
[uiDisabled]="uiDisabled"
|
|
[foregroundColor]="false"
|
|
[name]="getValue(getToolbarItem(name).icon)"
|
|
[matTooltip]="getResourceValue(getToolbarItem(name).title) | async"
|
|
></x-icon>
|
|
</a>
|
|
</ng-template>
|
|
|
|
<!-- Toolbar Item Template Ref -->
|
|
<ng-template #toolbarItemRef let-name>
|
|
<x-icon
|
|
[clickable]="true"
|
|
[selectable]="true"
|
|
[loading]="loading"
|
|
class="x-toolbar-icon"
|
|
[color]="'transparent'"
|
|
[uiDisabled]="uiDisabled"
|
|
[foregroundColor]="false"
|
|
(clicked)="handleToolbarItemClicked(name)"
|
|
[name]="getValue(getToolbarItem(name).icon)"
|
|
[matTooltip]="getResourceValue(getToolbarItem(name).title) | async"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.scss
|
|
|
|
:host ::ng-deep a {
|
|
pointer-events: none;
|
|
}
|
|
|
|
:host {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
textarea {
|
|
resize: none;
|
|
}
|
|
|
|
.x-editor {
|
|
width: 100%;
|
|
min-height: 300px;
|
|
height: fit-content;
|
|
}
|
|
|
|
.x-toolbar-wrapper {
|
|
margin-bottom: 0px;
|
|
}
|
|
|
|
.x-preview {
|
|
text-align: justify;
|
|
}
|
|
|
|
.x-preview-wrapper {
|
|
height: fit-content;
|
|
min-height: 300px;
|
|
border: 1px solid gray;
|
|
padding: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.x-toolbar-icon {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.no-border {
|
|
border: 0;
|
|
min-height: unset;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.ts
|
|
|
|
import {
|
|
ViewChild,
|
|
Component,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
keys,
|
|
nameof,
|
|
insertText,
|
|
XStandardType,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XMarkdownMode,
|
|
XMarkdownAction,
|
|
XMarkdownActionModel,
|
|
XMarkdownToolbarItem,
|
|
XMarkdownModeIdentifier,
|
|
XMarkdownToolbarItemName,
|
|
XMarkdownToolbarConfigProps,
|
|
XMarkdownContainerComponent,
|
|
defaultXMarkdownToolbarConfig,
|
|
} from './x-markdown.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import 'node_modules/prismjs/prism.js';
|
|
import 'node_modules/marked/marked.min.js';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XSlotLayout } from '../x-slotter/x-slotter.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-markdown',
|
|
templateUrl: './x-markdown.component.html',
|
|
styleUrls: ['./x-markdown.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XMarkdownComponent extends XMarkdownContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private TOOLBAR_CONFIG: XMarkdownToolbarConfigProps;
|
|
|
|
//
|
|
readonly SlotterLayouts = Object.assign({}, XSlotLayout);
|
|
|
|
//
|
|
innerContent: string = this.content;
|
|
preparedMode: XMarkdownModeIdentifier;
|
|
toolbarItems = keys(defaultXMarkdownToolbarConfig);
|
|
|
|
//
|
|
get preparedToolbarConfig() {
|
|
return this.TOOLBAR_CONFIG;
|
|
}
|
|
|
|
//
|
|
@ViewChild('markdownEditor', { static: false })
|
|
editor: ElementRef;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareMode();
|
|
await this.prepareToolbarConfig(null);
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XMarkdownComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content Chaned ...
|
|
const isContentChanged = changeKeys.includes(
|
|
nameof<XMarkdownComponent>('content')
|
|
);
|
|
if (isContentChanged && this.content !== this.innerContent) {
|
|
this.innerContent = this.content;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Model Changed ...
|
|
const isModeChanged = changeKeys.includes(
|
|
nameof<XMarkdownComponent>('mode')
|
|
);
|
|
if (isModeChanged) {
|
|
await this.prepareMode();
|
|
await this.prepareToolbarConfig(null);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
// Register Action Provider ...
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
getSlotterLayout() {
|
|
return this.isMobileUi$.pipe(
|
|
map((isMobileUi) =>
|
|
isMobileUi ? XSlotLayout.VERTICAL : XSlotLayout.HORIZONTAL
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Mode Detectors ...
|
|
//
|
|
isEditMode() {
|
|
return this.getValueStream(this.mode).pipe(
|
|
map((preparedMode) => preparedMode === XMarkdownMode.EDIT)
|
|
);
|
|
}
|
|
|
|
//
|
|
isPreviewMode() {
|
|
return this.getValueStream(this.mode).pipe(
|
|
map((preparedMode) => preparedMode === XMarkdownMode.PREVIEW)
|
|
);
|
|
}
|
|
|
|
//
|
|
isBothMode() {
|
|
return this.getValueStream(this.mode).pipe(
|
|
map((preparedMode) => preparedMode === XMarkdownMode.BOTH)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Toolbar Providers ...
|
|
hasToolbarItem(name: XMarkdownToolbarItemName | any) {
|
|
//
|
|
if (!this.TOOLBAR_CONFIG) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const itesNamess = keys(this.TOOLBAR_CONFIG);
|
|
const result = itesNamess.includes(name);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getToolbarItem(name: XMarkdownToolbarItemName | any) {
|
|
//
|
|
if (!this.hasToolbarItem(name)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const item = this.TOOLBAR_CONFIG[name];
|
|
const defaultItem = this.getDefaultItemConfig(name);
|
|
|
|
//
|
|
const result: XMarkdownToolbarItem = {
|
|
...defaultItem,
|
|
...item,
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Handlers ...
|
|
handleContentChanged(content: string) {
|
|
//
|
|
if (!content) {
|
|
content = '';
|
|
}
|
|
|
|
//
|
|
this.innerContent = content;
|
|
this.contentChange.emit(content);
|
|
}
|
|
|
|
async handleToolbarItemClicked(name: XMarkdownToolbarItemName) {
|
|
//
|
|
switch (name) {
|
|
//
|
|
case 'preview':
|
|
await this.handleToggleMode();
|
|
break;
|
|
|
|
//
|
|
case 'bold':
|
|
await this.handleAddContent('**', true);
|
|
break;
|
|
|
|
//
|
|
case 'code':
|
|
await this.handleAddContent('`', true);
|
|
break;
|
|
|
|
//
|
|
case 'heading':
|
|
await this.handleAddContent('# ', false);
|
|
break;
|
|
|
|
//
|
|
case 'image':
|
|
await this.handleAddContent('', false);
|
|
break;
|
|
|
|
//
|
|
case 'italic':
|
|
await this.handleAddContent('*', true);
|
|
break;
|
|
|
|
//
|
|
case 'link':
|
|
await this.handleAddContent('[title](url)', false);
|
|
break;
|
|
|
|
//
|
|
case 'ol':
|
|
await this.handleAddContent('1. ', false);
|
|
break;
|
|
|
|
//
|
|
case 'ul':
|
|
await this.handleAddContent('- ', false);
|
|
break;
|
|
|
|
//
|
|
case 'quote':
|
|
await this.handleAddContent('> ', false);
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (this.editor) {
|
|
this.editor.nativeElement.focus();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XMarkdownActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XMarkdownAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XMarkdownAction.FireToolbarButtons:
|
|
//
|
|
if (!isNullOrEmptyString(model.payload)) {
|
|
await this.handleToolbarItemClicked(model.payload);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareMode() {
|
|
this.preparedMode = await this.getValueAsync(this.mode);
|
|
await this.changeMode(this.preparedMode);
|
|
}
|
|
|
|
private async prepareToolbarConfig(
|
|
config: XStandardType<XMarkdownToolbarConfigProps>
|
|
) {
|
|
//
|
|
if (!config) {
|
|
this.TOOLBAR_CONFIG = defaultXMarkdownToolbarConfig;
|
|
return;
|
|
}
|
|
|
|
//
|
|
const cfg = await this.getValueAsync(config);
|
|
|
|
//
|
|
this.TOOLBAR_CONFIG = {
|
|
...cfg,
|
|
};
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private getDefaultItemConfig(name: XMarkdownToolbarItemName) {
|
|
return defaultXMarkdownToolbarConfig[name];
|
|
}
|
|
|
|
private async changeMode(mode: XMarkdownModeIdentifier) {
|
|
//
|
|
this.mode = mode;
|
|
this.preparedMode = mode;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async handleToggleMode() {
|
|
//
|
|
const mode = await this.getValueAsync(this.mode);
|
|
|
|
//
|
|
switch (mode) {
|
|
case XMarkdownMode.BOTH:
|
|
await this.changeMode(XMarkdownMode.EDIT);
|
|
break;
|
|
|
|
case XMarkdownMode.EDIT:
|
|
await this.changeMode(XMarkdownMode.BOTH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private getCurrentPosition() {
|
|
//
|
|
if (!this.editor) {
|
|
return {
|
|
start: -1,
|
|
end: -1,
|
|
};
|
|
}
|
|
|
|
//
|
|
const start = this.editor.nativeElement.selectionStart;
|
|
const end = this.editor.nativeElement.selectionEnd;
|
|
|
|
//
|
|
const result = {
|
|
start: start ? +start : -1,
|
|
end: end ? +end : -1,
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private async handleAddContent(content: string, double: boolean = false) {
|
|
//
|
|
if (!content) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const pos = this.getCurrentPosition();
|
|
|
|
//
|
|
if (!pos) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let selectedContent: string;
|
|
if (pos.start === pos.end) {
|
|
selectedContent = '';
|
|
} else {
|
|
//
|
|
selectedContent = this.innerContent.substring(pos.start, pos.end);
|
|
this.innerContent = this.innerContent.replace(selectedContent, '');
|
|
}
|
|
|
|
//
|
|
let insertedContent: string;
|
|
if (isNullOrEmptyString(selectedContent)) {
|
|
insertedContent = double ? `${content}${content}` : `${content}`;
|
|
} else {
|
|
insertedContent = double
|
|
? `${content}${selectedContent}${content}`
|
|
: `${content}${selectedContent}`;
|
|
}
|
|
|
|
//
|
|
const startPos = pos.start > -1 ? pos.start : this.innerContent.length;
|
|
this.innerContent = insertText(
|
|
this.innerContent || '',
|
|
insertedContent,
|
|
startPos
|
|
);
|
|
this.contentChange.emit(this.innerContent);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { MarkdownModule } from 'ngx-markdown';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from './../x-icon/x-icon.module';
|
|
import { XMarkdownComponent } from './x-markdown.component';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XMarkdownComponent],
|
|
imports: [
|
|
CommonModule,
|
|
XIconModule,
|
|
XCardModule,
|
|
XSlotterModule,
|
|
XBaseComponentModule,
|
|
MarkdownModule.forRoot(),
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
MarkdownModule,
|
|
XSlotterModule,
|
|
XMarkdownComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XMarkdownModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XMarkdownMode {
|
|
EDIT = 'edit',
|
|
PREVIEW = 'preview',
|
|
BOTH = 'both',
|
|
}
|
|
|
|
export type XMarkdownModeIdentifier = XMarkdownMode | string;
|
|
|
|
export enum XMarkdownToolbarItemSlot {
|
|
START = 'start',
|
|
END = 'end',
|
|
}
|
|
|
|
export type XMarkdownToolbarItemSlotIdentifier =
|
|
| XMarkdownToolbarItemSlot
|
|
| string;
|
|
|
|
export type XMarkdownToolbarItemName =
|
|
| 'image'
|
|
| 'link'
|
|
| 'ul'
|
|
| 'ol'
|
|
| 'quote'
|
|
| 'code'
|
|
| 'bold'
|
|
| 'italic'
|
|
| 'heading'
|
|
| 'preview'
|
|
| 'guide';
|
|
|
|
export interface XMarkdownToolbarItem {
|
|
icon?: XIconIdentifier;
|
|
title?: XResourceIdentifier;
|
|
slot?: XMarkdownToolbarItemSlotIdentifier;
|
|
}
|
|
|
|
export type XMarkdownToolbarConfigProps = {
|
|
[key in XMarkdownToolbarItemName]?: XMarkdownToolbarItem;
|
|
};
|
|
|
|
export const defaultXMarkdownToolbarConfig: XMarkdownToolbarConfigProps = {
|
|
heading: {
|
|
icon: XIconNames.heading,
|
|
title: XResourceIDs.x_markdown_heading,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
bold: {
|
|
icon: XIconNames.bold,
|
|
title: XResourceIDs.x_markdown_bold,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
italic: {
|
|
icon: XIconNames.italic,
|
|
title: XResourceIDs.x_markdown_italic,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
quote: {
|
|
icon: XIconNames.quote,
|
|
title: XResourceIDs.x_markdown_quote,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
code: {
|
|
icon: XIconNames.code,
|
|
title: XResourceIDs.x_markdown_code,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
ol: {
|
|
icon: XIconNames.ol,
|
|
title: XResourceIDs.x_markdown_ol,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
ul: {
|
|
icon: XIconNames.ul,
|
|
title: XResourceIDs.x_markdown_ul,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
link: {
|
|
icon: XIconNames.link,
|
|
title: XResourceIDs.x_markdown_link,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
image: {
|
|
icon: XIconNames.image,
|
|
title: XResourceIDs.x_markdown_image,
|
|
slot: XMarkdownToolbarItemSlot.START,
|
|
},
|
|
preview: {
|
|
icon: XIconNames.preview,
|
|
title: XResourceIDs.x_markdown_preview,
|
|
slot: XMarkdownToolbarItemSlot.END,
|
|
},
|
|
guide: {
|
|
icon: XIconNames.guide,
|
|
title: XResourceIDs.x_markdown_guide,
|
|
slot: XMarkdownToolbarItemSlot.END,
|
|
},
|
|
};
|
|
|
|
export enum XMarkdownAction {
|
|
//
|
|
FireToolbarButtons = 'fire_toolbar_buttons',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XMarkdownActionIdentifier = XMarkdownAction | string;
|
|
|
|
export interface XMarkdownActionModel
|
|
extends XBaseActionModel<XMarkdownActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXMarkdownContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XMarkdownActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
content: string;
|
|
contentChange: EventEmitter<string>;
|
|
|
|
//
|
|
mode: XStandardType<XMarkdownModeIdentifier>;
|
|
|
|
//
|
|
editorBoxColor: XStandardType<XColorIdentifier>;
|
|
previewBoxColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
//#region Toolbar ...
|
|
hasToolbar: XStandardType<boolean>;
|
|
toolbarCssClass: XStandardType<XOneOrManyType<string>>;
|
|
toolbarColor: XStandardType<XColorIdentifier>;
|
|
toolbarForegroundColor: XStandardType<boolean>;
|
|
toolbarConfig: XStandardType<XMarkdownToolbarConfigProps>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XMarkdownContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXMarkdownContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XMarkdownActionModel> =
|
|
new Subject<XMarkdownActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly content: string = '';
|
|
readonly contentChange = new EventEmitter<string>();
|
|
|
|
//
|
|
readonly mode: XStandardType<XMarkdownModeIdentifier> = XMarkdownMode.BOTH;
|
|
|
|
//
|
|
readonly editorBoxColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Transparent;
|
|
readonly previewBoxColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Transparent;
|
|
|
|
//
|
|
//#region Toolbar ...
|
|
readonly hasToolbar: XStandardType<boolean> = true;
|
|
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly toolbarColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly toolbarForegroundColor: XStandardType<boolean> = false;
|
|
readonly toolbarConfig: XStandardType<XMarkdownToolbarConfigProps>;
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XMarkdownContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXMarkdownContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XMarkdownActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
content: string = this.propertyProvider.content;
|
|
|
|
@Output()
|
|
contentChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
mode: XStandardType<XMarkdownModeIdentifier> = this.propertyProvider.mode;
|
|
|
|
//
|
|
@Input()
|
|
editorBoxColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.editorBoxColor;
|
|
|
|
@Input()
|
|
previewBoxColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.previewBoxColor;
|
|
|
|
//
|
|
//#region Toolbar ...
|
|
@Input()
|
|
hasToolbar: XStandardType<boolean> = this.propertyProvider.hasToolbar;
|
|
|
|
@Input()
|
|
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.toolbarCssClass;
|
|
|
|
@Input()
|
|
toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarColor;
|
|
|
|
@Input()
|
|
toolbarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarForegroundColor;
|
|
|
|
@Input()
|
|
toolbarConfig: XStandardType<XMarkdownToolbarConfigProps> =
|
|
this.propertyProvider.toolbarConfig;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XMarkdownContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXMarkdownContainer
|
|
): Observable<IXMarkdownContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
content: this.getValue(
|
|
container ? container.content : this.content
|
|
),
|
|
|
|
//
|
|
mode: this.getValue(container ? container.mode : this.mode),
|
|
|
|
//
|
|
editorBoxColor: this.getValue(
|
|
container ? container.editorBoxColor : this.editorBoxColor
|
|
),
|
|
previewBoxColor: this.getValue(
|
|
container ? container.previewBoxColor : this.previewBoxColor
|
|
),
|
|
|
|
//
|
|
hasToolbar: this.getValue(
|
|
container ? container.hasToolbar : this.hasToolbar
|
|
),
|
|
toolbarCssClass: this.getArrayValue(
|
|
container ? container.toolbarCssClass : this.toolbarCssClass
|
|
),
|
|
toolbarColor: this.getValue(
|
|
container ? container.toolbarColor : this.toolbarColor
|
|
),
|
|
toolbarForegroundColor: this.getValue(
|
|
container
|
|
? container.toolbarForegroundColor
|
|
: this.toolbarForegroundColor
|
|
),
|
|
toolbarConfig: this.getValue(
|
|
container ? container.toolbarConfig : this.toolbarConfig
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
contentChange: this.contentChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component's itSelf Template -->
|
|
<ng-template #componentsRef>
|
|
<!-- Check Prepared Model Exists -->
|
|
<div
|
|
class="x-model-presenter x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
*ngIf="notNullOrUndefinedValue(preparedModel) | async"
|
|
>
|
|
<x-expandable-panel
|
|
[isAccordion]="false"
|
|
[applyColors]="false"
|
|
[multiExpanded]="true"
|
|
class="x-model-presenter-panel"
|
|
[actionProvider]="panelActionProvider"
|
|
[hideDescriptionOnSmallScreens]="false"
|
|
[cardColor]="getValue(cardColor) | async"
|
|
[wrapWithCard]="getValue(wrapWithCard) | async"
|
|
[cssClass]="getArrayValue(panelCssClass) | async"
|
|
[cardForegroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<ng-container *ngFor="let key of keys(preparedModel)">
|
|
<ng-container *ngIf="canShowKey(key) | async as canShowTheKey">
|
|
<x-panel
|
|
[id]="key"
|
|
[uiDisabled]="
|
|
!(hasContentItem(key) | async) &&
|
|
(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
[hideToggle]="
|
|
!(hasContentItem(key) | async) &&
|
|
(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
>
|
|
<!-- Title (Key) -->
|
|
<div
|
|
x-panel-title
|
|
[isForeground]="true"
|
|
class="x-model-presenter-title"
|
|
*ngIf="
|
|
canShowTheKey &&
|
|
(getValue(showLabels) | async) &&
|
|
(canShowLabelKey(key) | async)
|
|
"
|
|
[class.hasLabel]="
|
|
canShowTheKey &&
|
|
(getValue(showLabels) | async) &&
|
|
(canShowLabelKey(key) | async)
|
|
"
|
|
[xColor]="getValue(labelColor) | async"
|
|
[ngClass]="getModelPresenterTitleClasses(key)"
|
|
>
|
|
<span class="x-title-span text-truncate">
|
|
{{ getTitle(key) | async }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Content (Value) -->
|
|
<!-- if Has Not ContentItem and Descibeable -->
|
|
<div
|
|
x-panel-description
|
|
[isForeground]="true"
|
|
class="x-model-presenter-content"
|
|
[xColor]="getValue(valueColor) | async"
|
|
*ngIf="
|
|
!(hasContentItem(key) | async) &&
|
|
(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
[ngClass]="getModelPresenterContentClasses(key)"
|
|
>
|
|
<x-slotter
|
|
[hasCenterSlot]="false"
|
|
[cssClass]="'full-with'"
|
|
[layout]="SlotLayouts.HORIZONTAL"
|
|
[hasEndOrBottomSlot]="
|
|
notNullOrUndefinedValue(propertyActionTemplate) | async
|
|
"
|
|
>
|
|
<!-- Start -->
|
|
<x-slot
|
|
[name]="SlotNames.START"
|
|
[cssClass]="['ion-text-start', 'text-truncate']"
|
|
>
|
|
{{ getContent(key, preparedModel[key]) | async }}
|
|
</x-slot>
|
|
|
|
<!-- End -->
|
|
<x-slot [name]="SlotNames.END" [cssClass]="'ion-text-end'">
|
|
<!-- propertyActionTemplate -->
|
|
<ng-container
|
|
*ngIf="
|
|
notNullOrUndefinedValue(propertyActionTemplate) | async
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
propertyActionTemplate;
|
|
context: {
|
|
key: key,
|
|
prefix: prefix,
|
|
value: preparedModel[key]
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
|
|
<!-- if Has not ContentItem && not Describeable -->
|
|
<div
|
|
[isForeground]="true"
|
|
class="x-model-presenter-content"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getModelPresenterContentClasses(key)"
|
|
*ngIf="
|
|
!(hasContentItem(key) | async) &&
|
|
!(canDescribe(key, preparedModel[key]) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nestedRef;
|
|
context: {
|
|
key: key,
|
|
value: preparedModel[key],
|
|
prefix: getKeyPrefix(key),
|
|
hiddenModelKeys: (getHiddenModelKeys(key) | async),
|
|
availableModelKeys: (getAvailableModelKeys(key) | async),
|
|
sortOrderModelKeys: (getSortOrderModelKeys(key) | async),
|
|
hiddenLabelModelKeys: (getHiddenLabelModelKeys(key) | async)
|
|
}
|
|
"
|
|
>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- if Has ContentItem -->
|
|
<div
|
|
[isForeground]="true"
|
|
class="x-model-presenter-content"
|
|
*ngIf="hasContentItem(key) | async"
|
|
[xColor]="getValue(valueColor) | async"
|
|
[ngClass]="getModelPresenterContentClasses(key)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getContentItem(key, preparedModel[key]) | async).content
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</x-panel>
|
|
</ng-container>
|
|
</ng-container>
|
|
</x-expandable-panel>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- NestedRef -->
|
|
<ng-template
|
|
#nestedRef
|
|
let-key="key"
|
|
let-value="value"
|
|
let-prefix="prefix"
|
|
let-hiddenModelKeys="hiddenModelKeys"
|
|
let-availableModelKeys="availableModelKeys"
|
|
let-sortOrderModelKeys="sortOrderModelKeys"
|
|
let-hiddenLabelModelKeys="hiddenLabelModelKeys"
|
|
>
|
|
<x-model-presenter
|
|
[model]="value"
|
|
[attr.keyPrefix]="prefix"
|
|
[panelCssClass]="panelCssClass"
|
|
[actionProvider]="actionProvider"
|
|
[color]="getValue(color) | async"
|
|
[hiddenModelKeys]="hiddenModelKeys"
|
|
[modelKeyProvider]="modelKeyProvider"
|
|
[availableModelKeys]="availableModelKeys"
|
|
[sortOrderModelKeys]="sortOrderModelKeys"
|
|
[modelValueProvider]="modelValueProvider"
|
|
[panelActionProvider]="panelActionProvider"
|
|
[showLabels]="getValue(showLabels) | async"
|
|
[labelColor]="getValue(labelColor) | async"
|
|
[valueColor]="getValue(valueColor) | async"
|
|
[cssClass]="getArrayValue(cssClass) | async"
|
|
[hiddenLabelModelKeys]="hiddenLabelModelKeys"
|
|
[headerColor]="getValue(headerColor) | async"
|
|
(onModelChanged)="onModelChanged.emit($event)"
|
|
[contentColor]="getValue(contentColor) | async"
|
|
[startupState]="getValue(startupState) | async"
|
|
[propertyActionTemplate]="propertyActionTemplate"
|
|
[foregroundColor]="getValue(foregroundColor) | async"
|
|
[hideOptionalValues]="getValue(hideOptionalValues) | async"
|
|
[headerHighlightColor]="getValue(headerHighlightColor) | async"
|
|
*ngIf="
|
|
(notEmptyValue(key) | async) && (notNullOrUndefinedValue(value) | async)
|
|
"
|
|
>
|
|
</x-model-presenter>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.scss
|
|
|
|
:host {
|
|
//
|
|
--header-highlight-color: var(--x-color-light-shade);
|
|
|
|
//
|
|
--header-background-color: var(--x-color-light);
|
|
--header-foreground-color: var(--x-color-light-contrast);
|
|
|
|
//
|
|
--content-background-color: var(--x-color-light);
|
|
--content-foreground-color: var(--x-color-light-contrast);
|
|
|
|
//
|
|
--panel-background-color: var(--x-color-light);
|
|
--panel-foreground-color: var(--x-color-light-contrast);
|
|
}
|
|
|
|
:host ::ng-deep .x-card {
|
|
.x-actions {
|
|
display: none;
|
|
}
|
|
|
|
.x-content {
|
|
padding: 0px !important;
|
|
margin: 0px;
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep .x-expandable-panel {
|
|
//
|
|
&.mobile {
|
|
.mat-expansion-panel-header {
|
|
margin: {
|
|
top: 2px;
|
|
bottom: 6px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-expansion-panel {
|
|
//
|
|
box-shadow: unset;
|
|
color: var(--panel-foreground-color);
|
|
background-color: var(--panel-background-color);
|
|
|
|
//
|
|
.mat-expansion-panel-body {
|
|
color: var(--panel-foreground-color);
|
|
background-color: var(--panel-background-color);
|
|
}
|
|
|
|
//
|
|
.mat-expansion-panel-header {
|
|
//
|
|
color: var(--header-foreground-color);
|
|
background-color: var(--header-background-color);
|
|
|
|
//
|
|
// Header HighLight ...
|
|
&.cdk-keyboard-focused,
|
|
&.cdk-program-focused,
|
|
&:not(.mat-expanded):hover {
|
|
background-color: var(--header-highlight-color);
|
|
}
|
|
|
|
&.mobile {
|
|
.mat-content {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.x-model-presenter-title {
|
|
.x-title-span {
|
|
max-width: calc(80%);
|
|
}
|
|
}
|
|
}
|
|
|
|
.x-expandable-panel-header-title {
|
|
//
|
|
flex-grow: 0;
|
|
margin-left: 4px !important;
|
|
|
|
//
|
|
.x-model-presenter-title {
|
|
width: 100%;
|
|
word-wrap: unset;
|
|
white-space: pre;
|
|
}
|
|
|
|
//
|
|
.x-model-presenter-title.hasLabel {
|
|
.x-title-span::after {
|
|
content: " : ";
|
|
}
|
|
}
|
|
}
|
|
|
|
.x-expandable-panel-header-description {
|
|
//
|
|
overflow: hidden;
|
|
margin-left: 4px !important;
|
|
|
|
//
|
|
.x-model-presenter-content {
|
|
width: 100%;
|
|
}
|
|
|
|
.x-end-bottom-slot {
|
|
flex: 0 0 auto !important;
|
|
}
|
|
|
|
.x-start-top-slot {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.x-start-top-slot-inner-container {
|
|
max-width: calc(90%);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
.mat-expansion-panel-content {
|
|
color: var(--content-foreground-color);
|
|
background-color: var(--content-background-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.ts
|
|
|
|
import {
|
|
Component,
|
|
QueryList,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
tap,
|
|
map,
|
|
filter,
|
|
mergeMap,
|
|
switchMap,
|
|
concatMap,
|
|
} from 'rxjs/operators';
|
|
import {
|
|
keys,
|
|
nameof,
|
|
isDate,
|
|
isArray,
|
|
toArray,
|
|
isNumber,
|
|
isString,
|
|
isObject,
|
|
toXString,
|
|
isFunction,
|
|
parseXColor,
|
|
isSameObject,
|
|
XOneOrManyType,
|
|
XModelProperty,
|
|
toNormalString,
|
|
getPropertyValue,
|
|
setPropertyValue,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XModelPresenterAction,
|
|
XModelPresenterCssVars,
|
|
XModelPresenterActionModel,
|
|
XModelPresenterStartupState,
|
|
XModelPresenterContainerComponent,
|
|
} from './x-model-presenter.typings';
|
|
import {
|
|
XExpandablePanelAction,
|
|
XExpandablePanelActionModel,
|
|
} from '../x-expandable-panel/x-expandable-panel.typings';
|
|
import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { of, from, Subject, forkJoin, Observable, Subscription } from 'rxjs';
|
|
import { XModelPresenterItemComponent } from './x-model-presenter-item/x-model-presenter-item.component';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-model-presenter',
|
|
templateUrl: './x-model-presenter.component.html',
|
|
styleUrls: ['./x-model-presenter.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XModelPresenterComponent<
|
|
T = any
|
|
> extends XModelPresenterContainerComponent<T> {
|
|
//
|
|
//#region Props ...
|
|
private MODEL: T;
|
|
private keyPrefix = '';
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
|
|
//
|
|
get prefix() {
|
|
return this.keyPrefix;
|
|
}
|
|
|
|
get preparedModel() {
|
|
return this.MODEL;
|
|
}
|
|
|
|
//
|
|
@ContentChildren(XModelPresenterItemComponent)
|
|
items: QueryList<XModelPresenterItemComponent>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareModel();
|
|
await this.handleStartupState();
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// prepare KeyPrefix ...
|
|
const keyPrefix = this.element.nativeElement
|
|
? (this.element.nativeElement as HTMLElement).getAttribute('keyPrefix')
|
|
: '';
|
|
if (!isNullOrEmptyString(keyPrefix)) {
|
|
this.keyPrefix += `${keyPrefix}`;
|
|
}
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
//
|
|
//#region Model Changed ...
|
|
const isModelChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('model')
|
|
);
|
|
|
|
//
|
|
if (isModelChanged) {
|
|
await this.prepareModel();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('actionProvider')
|
|
);
|
|
const isPanelActionProviderChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('panelActionProvider')
|
|
);
|
|
if (isActionProviderChanged || isPanelActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Color Changes ...
|
|
//
|
|
//#region Color Changed ...
|
|
const isColorChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('color')
|
|
);
|
|
if (isColorChanged) {
|
|
await this.applyPanelColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Header Highlight Color Changed ...
|
|
const isHeaderHighlightColorChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('headerHighlightColor')
|
|
);
|
|
if (isHeaderHighlightColorChanged) {
|
|
await this.applyHeaderHighlightColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Header Color Changed ...
|
|
const isHeaderColorChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('headerColor')
|
|
);
|
|
if (isHeaderColorChanged) {
|
|
await this.applyHeaderColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content Color Changed ...
|
|
const isContentColorChanged = changeKeys.includes(
|
|
nameof<XModelPresenterComponent>('contentColor')
|
|
);
|
|
if (isContentColorChanged) {
|
|
await this.applyContentColor();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
keys(model: T) {
|
|
//
|
|
let modelKeys = keys(model);
|
|
|
|
//
|
|
if (!this.hasChild(this.sortOrderModelKeys)) {
|
|
return modelKeys;
|
|
}
|
|
|
|
//
|
|
const sortOrderArray = toArray(this.sortOrderModelKeys) as string[];
|
|
const result: string[] = [
|
|
...sortOrderArray.filter((k) => modelKeys.includes(k)),
|
|
...modelKeys.filter((k) => !sortOrderArray.includes(k)),
|
|
];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
canShowKey(key: string) {
|
|
//
|
|
return forkJoin({
|
|
key: this.getValue(key),
|
|
model: this.getValue(this.model),
|
|
prefix: this.getValue(this.keyPrefix),
|
|
hiddenModelKeys: this.getArrayValue(this.hiddenModelKeys),
|
|
hideOptionalValues: this.getValue(this.hideOptionalValues),
|
|
availableModelKeys: this.getArrayValue(this.availableModelKeys),
|
|
}).pipe(
|
|
map((provider) => {
|
|
//
|
|
const value = provider.model[provider.key];
|
|
|
|
//
|
|
const modelHasValue =
|
|
!isNullOrUndefined(provider.model) &&
|
|
!isNullOrUndefined(value) &&
|
|
!isNullOrEmptyString(toXString(provider.model[provider.key]));
|
|
const hasChildHiddens = this.hasChild(provider.hiddenModelKeys);
|
|
const hasChildAvailables = this.hasChild(provider.availableModelKeys);
|
|
|
|
//
|
|
if (!hasChildAvailables && !hasChildHiddens) {
|
|
//
|
|
if (!modelHasValue && provider.hideOptionalValues) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const isInHiddens = provider.hiddenModelKeys.includes(
|
|
provider.key as any
|
|
);
|
|
const isInAvailables = provider.availableModelKeys.includes(
|
|
provider.key as any
|
|
);
|
|
|
|
//
|
|
if (
|
|
(!hasChildAvailables && !isInHiddens) ||
|
|
(isInAvailables && !hasChildHiddens) ||
|
|
(isInAvailables && !isInHiddens) ||
|
|
(!isInAvailables &&
|
|
!isInHiddens &&
|
|
isNumber(provider.key) &&
|
|
!isNullOrEmptyString(provider.prefix))
|
|
) {
|
|
//
|
|
if (!modelHasValue && provider.hideOptionalValues) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
//
|
|
return false;
|
|
})
|
|
);
|
|
}
|
|
|
|
canShowLabelKey(key: string) {
|
|
return this.getArrayValue(this.hiddenLabelModelKeys).pipe(
|
|
map((hiddenLabelsModelKeys) => {
|
|
//
|
|
const hasChildHiddenLabels = this.hasChild(hiddenLabelsModelKeys);
|
|
|
|
//
|
|
if (!hasChildHiddenLabels) {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
const isInHiddens = hiddenLabelsModelKeys.includes(key as any);
|
|
return hasChildHiddenLabels && !isInHiddens;
|
|
})
|
|
);
|
|
}
|
|
|
|
getTitle(key: string): Observable<string> {
|
|
return this.getValue(this.modelKeyProvider).pipe(
|
|
concatMap((provider) => {
|
|
return isNullOrUndefined(provider) || !isFunction(provider)
|
|
? this.getValue(key)
|
|
: this.getValue(provider(key as any));
|
|
})
|
|
);
|
|
}
|
|
|
|
hasContentItem(key: string) {
|
|
return of(this.items).pipe(
|
|
concatMap((items) => {
|
|
return isNullOrUndefined(items)
|
|
? of(false)
|
|
: this.getArrayValue(items.toArray()).pipe(
|
|
switchMap((items) =>
|
|
from(items).pipe(
|
|
mergeMap((item) =>
|
|
this.getValue(item.name).pipe(
|
|
map((name) => ({ name, item }))
|
|
)
|
|
),
|
|
filter(
|
|
(itemData) =>
|
|
toNormalString(itemData.name) === toNormalString(key)
|
|
),
|
|
map((dataObject) => !isNullOrUndefined(dataObject))
|
|
)
|
|
)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
getContentItem(
|
|
key: string,
|
|
value: any
|
|
): Observable<XModelPresenterItemComponent> {
|
|
return this.hasContentItem(key).pipe(
|
|
concatMap((isExists) => {
|
|
return !isExists
|
|
? of(null)
|
|
: of(this.items).pipe(
|
|
concatMap((items) => {
|
|
return isNullOrUndefined(items)
|
|
? of(null)
|
|
: this.getArrayValue(items.toArray()).pipe(
|
|
switchMap((items) =>
|
|
from(items).pipe(
|
|
mergeMap((item) =>
|
|
this.getValue(item.name).pipe(
|
|
map((name) => ({ name, item }))
|
|
)
|
|
),
|
|
filter(
|
|
(itemData) =>
|
|
toNormalString(itemData.name) ===
|
|
toNormalString(key)
|
|
),
|
|
tap((dataObject) => (dataObject.item.value = value)),
|
|
map((dataObject) => dataObject.item)
|
|
)
|
|
)
|
|
);
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
getContent(key: string, value: any): Observable<string> {
|
|
return this.getValue(this.modelValueProvider).pipe(
|
|
concatMap((provider) => {
|
|
return isNullOrUndefined(provider) || !isFunction(provider)
|
|
? this.getValue(value)
|
|
: this.getValue(provider(key as any, value));
|
|
})
|
|
);
|
|
}
|
|
|
|
canDescribe(key: string, value: any) {
|
|
return of(value).pipe(
|
|
map(
|
|
(eVal) =>
|
|
isDate(eVal) ||
|
|
isFunction(eVal) ||
|
|
(!isArray(eVal) && !isObject(eVal))
|
|
)
|
|
);
|
|
}
|
|
|
|
getModelPresenterTitleClasses(key: string) {
|
|
return [`x-model-presenter-${key}-title`];
|
|
}
|
|
|
|
getModelPresenterContentClasses(key: string) {
|
|
return [`x-model-presenter-${key}-content`];
|
|
}
|
|
|
|
//
|
|
//#region Neste ...
|
|
getKeyPrefix(key: string) {
|
|
//
|
|
const result = isNullOrEmptyString(this.keyPrefix)
|
|
? `${key}`
|
|
: `${this.keyPrefix}.${key}`;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getHiddenModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.hiddenModelKeys);
|
|
}
|
|
|
|
getSortOrderModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.sortOrderModelKeys);
|
|
}
|
|
|
|
getAvailableModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.availableModelKeys);
|
|
}
|
|
|
|
getHiddenLabelModelKeys(key: string) {
|
|
return this.prepareNestedCollection(key, this.hiddenLabelModelKeys);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async expandAll() {
|
|
this.panelActionProvider.next({
|
|
action: XExpandablePanelAction.ExpandAll,
|
|
});
|
|
}
|
|
|
|
async collapseAll() {
|
|
this.panelActionProvider.next({
|
|
action: XExpandablePanelAction.CollapseAll,
|
|
});
|
|
}
|
|
|
|
async setModelProperty(property: XModelProperty) {
|
|
//
|
|
if (!property || isNullOrEmptyString(property.key)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const model = this.MODEL;
|
|
const nodeValue = getPropertyValue(model, property.prefix);
|
|
const modelKeys = isNullOrUndefined(nodeValue) ? [] : keys(nodeValue);
|
|
if (!this.hasChild(modelKeys)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(property.key as string);
|
|
if (!isExists) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// normalize value ...
|
|
const normalValue = isString(property.value)
|
|
? !isNullOrEmptyString(property.value) &&
|
|
!isNullOrUndefined(property.value)
|
|
? property.value.toString().trim()
|
|
: undefined
|
|
: isNullOrUndefined(property.value)
|
|
? undefined
|
|
: property.value;
|
|
|
|
//
|
|
if (nodeValue[property.key] === normalValue) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const setterPropertyPath = isNullOrEmptyString(property.prefix)
|
|
? `${property.key as string}`
|
|
: `${property.prefix}.${property.key as string}`;
|
|
|
|
//
|
|
setPropertyValue(model, setterPropertyPath, normalValue);
|
|
|
|
//
|
|
this.MODEL = {
|
|
...model,
|
|
};
|
|
this.detectChanges();
|
|
this.onModelChanged.emit(model);
|
|
}
|
|
|
|
async getModelProperty(key: keyof T | string) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const model = await this.getValueAsync(this.model);
|
|
const modelKeys = await this.getValueAsync(this.keys(model));
|
|
if (!this.hasChild(modelKeys)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(key);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = model[key as any];
|
|
return result;
|
|
}
|
|
|
|
async getModelViewProperty(key: keyof T | string) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const model = await this.getValueAsync(this.model);
|
|
const modelKeys = await this.getValueAsync(this.keys(model));
|
|
if (!this.hasChild(modelKeys)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isExists = modelKeys.includes(key);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = await this.getValueAsync(
|
|
this.getContent(key, model[key as any])
|
|
);
|
|
return result;
|
|
}
|
|
|
|
async setModel(model: T) {
|
|
//
|
|
if (!model || isSameObject(model as any, this.MODEL as any)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.model = {
|
|
...model,
|
|
};
|
|
this.MODEL = {
|
|
...model,
|
|
};
|
|
|
|
//
|
|
await this.prepareModel();
|
|
this.onModelChanged.emit(model);
|
|
}
|
|
|
|
async getModel() {
|
|
//
|
|
const result = await this.getValueAsync(this.model);
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XModelPresenterActionModel>();
|
|
}
|
|
|
|
//
|
|
if (!this.panelActionProvider) {
|
|
this.panelActionProvider = new Subject<XExpandablePanelActionModel>();
|
|
}
|
|
|
|
//
|
|
let modelProperty: XModelProperty = null;
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XModelPresenterAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterAction.ExpandAll:
|
|
await this.expandAll();
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterAction.CollapseAll:
|
|
await this.collapseAll();
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterAction.ClearProperty:
|
|
//
|
|
modelProperty = model.payload as XModelProperty;
|
|
if (
|
|
!model.payload ||
|
|
isNullOrUndefined(model) ||
|
|
isNullOrUndefined(model.payload) ||
|
|
isNullOrEmptyString(model.action)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
modelProperty.value = null;
|
|
|
|
//
|
|
await this.setModelProperty(modelProperty);
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterAction.SetProperty:
|
|
//
|
|
modelProperty = model.payload as XModelProperty;
|
|
if (
|
|
!model.payload ||
|
|
isNullOrUndefined(model) ||
|
|
isNullOrUndefined(model.payload) ||
|
|
isNullOrEmptyString(model.action)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setModelProperty(modelProperty);
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterAction.SetModel:
|
|
//
|
|
const resetModel = model.payload as T;
|
|
if (!model || !model.payload || !resetModel) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.setModel(resetModel);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareModel() {
|
|
//
|
|
this.MODEL = null;
|
|
this.detectChanges();
|
|
|
|
//
|
|
if (!this.model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.MODEL = await this.getValueAsync(this.model);
|
|
this.detectChanges();
|
|
}
|
|
|
|
private prepareNestedCollection(
|
|
key: string,
|
|
collection: XOneOrManyType<string>
|
|
) {
|
|
//
|
|
return forkJoin({
|
|
key: this.getValue(key),
|
|
prefix: this.getValue(this.getKeyPrefix(key)),
|
|
model: this.getValue(this.preparedModel[key]),
|
|
collection: this.getArrayValue(collection),
|
|
}).pipe(
|
|
map((provider) => {
|
|
//
|
|
const allAvailableCollectionItems = provider.collection;
|
|
|
|
//
|
|
const keySelector = isNullOrUndefined(provider.prefix)
|
|
? `${provider.key}.`
|
|
: `${provider.prefix}.`;
|
|
|
|
//
|
|
const canFilter =
|
|
!isNumber(provider.key) &&
|
|
!provider.prefix.includes(`${provider.key}.`);
|
|
const result = canFilter
|
|
? allAvailableCollectionItems
|
|
.filter((k) => k.includes(`${provider.key}.`))
|
|
.map((k) => k.replace(`${provider.key}.`, ''))
|
|
: allAvailableCollectionItems;
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
|
|
private async handleStartupState() {
|
|
//
|
|
const state = await this.getValueAsync(this.startupState);
|
|
if (isNullOrEmptyString(state)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (state) {
|
|
//
|
|
case XModelPresenterStartupState.CollapseAll:
|
|
await this.collapseAll();
|
|
break;
|
|
|
|
//
|
|
case XModelPresenterStartupState.ExpandAll:
|
|
await this.expandAll();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyPanelColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.color);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.PanelForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.PanelBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyHeaderColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.HeaderForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.HeaderBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyHeaderHighlightColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerHighlightColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.HeaderHighlighColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyContentColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.contentColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.ContentForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XModelPresenterCssVars.ContentBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XModelPresenterComponent } from './x-model-presenter.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module';
|
|
import { XModelPresenterItemComponent } from './x-model-presenter-item/x-model-presenter-item.component';
|
|
|
|
@NgModule({
|
|
declarations: [XModelPresenterComponent, XModelPresenterItemComponent],
|
|
imports: [
|
|
XCardModule,
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
XExpandablePanelModule,
|
|
],
|
|
exports: [
|
|
XCardModule,
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
XExpandablePanelModule,
|
|
XModelPresenterComponent,
|
|
XModelPresenterItemComponent,
|
|
],
|
|
})
|
|
export class XModelPresenterModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XModelFieldsType,
|
|
XColorIdentifier,
|
|
XModelKeyProvider,
|
|
XModelValueProvider,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
import { XExpandablePanelActionModel } from '../x-expandable-panel/x-expandable-panel.typings';
|
|
|
|
export enum XModelPresenterStartupState {
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XModelPresenterStartupStateIdentifier =
|
|
| XModelPresenterStartupState
|
|
| string;
|
|
|
|
export enum XModelPresenterAction {
|
|
//
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
|
|
//
|
|
ClearProperty = 'clear_property',
|
|
SetProperty = 'set_property',
|
|
|
|
//
|
|
SetModel = 'set_model',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XModelPresenterActionIdentifier = XModelPresenterAction | string;
|
|
|
|
export interface XModelPresenterActionModel
|
|
extends XBaseActionModel<XModelPresenterActionIdentifier> {}
|
|
|
|
export enum XModelPresenterCssVars {
|
|
//
|
|
HeaderHighlighColor = 'header-highlight-color',
|
|
|
|
//
|
|
HeaderForegroundColor = 'header-foreground-color',
|
|
HeaderBackgroundColor = 'header-background-color',
|
|
|
|
//
|
|
ContentForegroundColor = 'content-foreground-color',
|
|
ContentBackgroundColor = 'content-background-color',
|
|
|
|
//
|
|
PanelForegroundColor = 'panel-foreground-color',
|
|
PanelBackgroundColor = 'panel-background-color',
|
|
}
|
|
|
|
export type XModelPresenterCssVarsIdentifier = XModelPresenterCssVars | string;
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXModelPresenterContainer<T = any>
|
|
extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XModelPresenterActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
headerColor: XStandardType<XColorIdentifier>;
|
|
headerHighlightColor: XStandardType<XColorIdentifier>;
|
|
contentColor: XStandardType<XColorIdentifier>;
|
|
labelColor: XStandardType<XColorIdentifier>;
|
|
valueColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
showLabels: XStandardType<boolean>;
|
|
propertyActionTemplate: TemplateRef<any>;
|
|
startupState: XStandardType<XModelPresenterStartupStateIdentifier>;
|
|
|
|
//
|
|
panelCssClass: XStandardType<XOneOrManyType<string>>;
|
|
panelActionProvider: Subject<XExpandablePanelActionModel>;
|
|
|
|
//
|
|
model: XStandardType<T>;
|
|
|
|
//
|
|
hideOptionalValues: XStandardType<boolean>;
|
|
availableModelKeys: XModelFieldsType<T>;
|
|
hiddenModelKeys: XModelFieldsType<T>;
|
|
hiddenLabelModelKeys: XModelFieldsType<T>;
|
|
sortOrderModelKeys: XModelFieldsType<T>;
|
|
modelKeyProvider: XModelKeyProvider<T>;
|
|
modelValueProvider: XModelValueProvider<T>;
|
|
|
|
//
|
|
onModelChanged: EventEmitter<T>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XModelPresenterContainer<T = any>
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXModelPresenterContainer<T>>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XModelPresenterActionModel> =
|
|
new Subject<XModelPresenterActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly headerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly headerHighlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
readonly contentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly labelColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryShade;
|
|
readonly valueColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
//
|
|
readonly showLabels: XStandardType<boolean> = true;
|
|
readonly propertyActionTemplate: TemplateRef<any>;
|
|
readonly startupState: XStandardType<XModelPresenterStartupStateIdentifier> =
|
|
XModelPresenterStartupState.CollapseAll;
|
|
|
|
//
|
|
readonly panelCssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly panelActionProvider: Subject<XExpandablePanelActionModel> =
|
|
new Subject<XExpandablePanelActionModel>();
|
|
|
|
//
|
|
readonly model: XStandardType<T>;
|
|
|
|
//
|
|
readonly hideOptionalValues: XStandardType<boolean> = false;
|
|
readonly availableModelKeys: XModelFieldsType<T>;
|
|
readonly hiddenModelKeys: XModelFieldsType<T>;
|
|
readonly hiddenLabelModelKeys: XModelFieldsType<T>;
|
|
readonly sortOrderModelKeys: XModelFieldsType<T>;
|
|
readonly modelKeyProvider: XModelKeyProvider<T>;
|
|
readonly modelValueProvider: XModelValueProvider<T>;
|
|
|
|
//
|
|
readonly onModelChanged: EventEmitter<T> = new EventEmitter<T>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XModelPresenterContainerComponent<T = any>
|
|
extends XComponentCardContainerComponent
|
|
implements IXModelPresenterContainer<T>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XModelPresenterActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
headerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerColor;
|
|
|
|
@Input()
|
|
headerHighlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerHighlightColor;
|
|
|
|
@Input()
|
|
contentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.contentColor;
|
|
|
|
@Input()
|
|
labelColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.labelColor;
|
|
|
|
@Input()
|
|
valueColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.valueColor;
|
|
|
|
//
|
|
@Input()
|
|
showLabels: XStandardType<boolean> = this.propertyProvider.showLabels;
|
|
|
|
@Input()
|
|
propertyActionTemplate: TemplateRef<any> =
|
|
this.propertyProvider.propertyActionTemplate;
|
|
|
|
@Input()
|
|
startupState: XStandardType<XModelPresenterStartupStateIdentifier> =
|
|
this.propertyProvider.startupState;
|
|
|
|
//
|
|
@Input()
|
|
panelCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.panelCssClass;
|
|
|
|
@Input()
|
|
panelActionProvider: Subject<XExpandablePanelActionModel> =
|
|
this.propertyProvider.panelActionProvider;
|
|
|
|
//
|
|
@Input()
|
|
model: XStandardType<T> = this.propertyProvider.model;
|
|
|
|
//
|
|
@Input()
|
|
hideOptionalValues: XStandardType<boolean> =
|
|
this.propertyProvider.hideOptionalValues;
|
|
|
|
@Input()
|
|
availableModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.availableModelKeys;
|
|
|
|
@Input()
|
|
hiddenModelKeys: XModelFieldsType<T> = this.propertyProvider.hiddenModelKeys;
|
|
|
|
@Input()
|
|
hiddenLabelModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.hiddenLabelModelKeys;
|
|
|
|
@Input()
|
|
sortOrderModelKeys: XModelFieldsType<T> =
|
|
this.propertyProvider.sortOrderModelKeys;
|
|
|
|
@Input()
|
|
modelKeyProvider: XModelKeyProvider<T> =
|
|
this.propertyProvider.modelKeyProvider;
|
|
|
|
@Input()
|
|
modelValueProvider: XModelValueProvider<T> =
|
|
this.propertyProvider.modelValueProvider;
|
|
|
|
//
|
|
@Output()
|
|
onModelChanged: EventEmitter<T> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XModelPresenterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXModelPresenterContainer
|
|
): Observable<IXModelPresenterContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
headerColor: this.getValue(
|
|
container ? container.headerColor : this.headerColor
|
|
),
|
|
headerHighlightColor: this.getValue(
|
|
container
|
|
? container.headerHighlightColor
|
|
: this.headerHighlightColor
|
|
),
|
|
contentColor: this.getValue(
|
|
container ? container.contentColor : this.contentColor
|
|
),
|
|
labelColor: this.getValue(
|
|
container ? container.labelColor : this.labelColor
|
|
),
|
|
valueColor: this.getValue(
|
|
container ? container.valueColor : this.valueColor
|
|
),
|
|
showLabels: this.getValue(
|
|
container ? container.showLabels : this.showLabels
|
|
),
|
|
propertyActionTemplate: this.getValue(
|
|
container
|
|
? container.propertyActionTemplate
|
|
: this.propertyActionTemplate
|
|
),
|
|
startupState: this.getValue(
|
|
container ? container.startupState : this.startupState
|
|
),
|
|
panelCssClass: this.getValue(
|
|
container ? container.panelCssClass : this.panelCssClass
|
|
),
|
|
model: this.getValue(container ? container.model : this.model),
|
|
hideOptionalValues: this.getValue(
|
|
container ? container.hideOptionalValues : this.hideOptionalValues
|
|
),
|
|
availableModelKeys: this.getValue(
|
|
container ? container.availableModelKeys : this.availableModelKeys
|
|
),
|
|
hiddenModelKeys: this.getValue(
|
|
container ? container.hiddenModelKeys : this.hiddenModelKeys
|
|
),
|
|
hiddenLabelModelKeys: this.getValue(
|
|
container
|
|
? container.hiddenLabelModelKeys
|
|
: this.hiddenLabelModelKeys
|
|
),
|
|
sortOrderModelKeys: this.getValue(
|
|
container ? container.sortOrderModelKeys : this.sortOrderModelKeys
|
|
),
|
|
modelKeyProvider: this.getValue(
|
|
container ? container.modelKeyProvider : this.modelKeyProvider
|
|
),
|
|
modelValueProvider: this.getValue(
|
|
container ? container.modelValueProvider : this.modelValueProvider
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
panelActionProvider: container
|
|
? container.panelActionProvider
|
|
: this.panelActionProvider,
|
|
|
|
//
|
|
onModelChanged: this.onModelChanged,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.html
|
|
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Renderer2,
|
|
Component,
|
|
ViewChild,
|
|
ElementRef,
|
|
TemplateRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XModelPresenterItemAction,
|
|
XModelPresenterItemModel,
|
|
} from './x-model-presenter-item.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseComponent } from '../../classes/x-base-component';
|
|
import { XStandardType, XOneOrManyType, nameof } from 'x-framework-core';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-model-presenter-item',
|
|
templateUrl: './x-model-presenter-item.component.html',
|
|
styleUrls: ['./x-model-presenter-item.component.scss'],
|
|
// changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XModelPresenterItemComponent extends XBaseComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
content: TemplateRef<any>;
|
|
|
|
//
|
|
@Input()
|
|
name: XStandardType<string>;
|
|
|
|
@Input()
|
|
value: XStandardType<any>;
|
|
|
|
//
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
@Input()
|
|
actionProvider = new Subject<XModelPresenterItemModel>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XModelPresenterItemComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XModelPresenterItemModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XModelPresenterItemAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.typings.ts
|
|
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
|
|
export enum XModelPresenterItemAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
export type XModelPresenterItemActionIdentifier = XModelPresenterItemAction | string;
|
|
|
|
export interface XModelPresenterItemModel
|
|
extends XBaseActionModel<XModelPresenterItemActionIdentifier> {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.html
|
|
|
|
<!-- Component Content -->
|
|
<section
|
|
class="x-page x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<!-- Screen Capture -->
|
|
<x-screen-capture
|
|
[uiDisabled]="uiDisabled"
|
|
(imageCaptured)="imageCaptured.emit($event)"
|
|
[enable]="getValue(enableCaptureMode) | async"
|
|
[topOffset]="getValue(captureTopOffset) | async"
|
|
[bottomOffset]="getValue(captureBottomOffset) | async"
|
|
[downloadCapturedImage]="getValue(downloadCapturedImage) | async"
|
|
>
|
|
<!-- Toolbar -->
|
|
<x-toolbar
|
|
#toolbar
|
|
[uiDisabled]="uiDisabled"
|
|
*ngIf="getValue(showToolbar) | async"
|
|
[color]="getValue(toolbarColor) | async"
|
|
[title]="getValue(toolbarTitle) | async"
|
|
[contentTemplate]="toolbarContentTemplate"
|
|
[class.menu-opened]="isMenuOpen() | async"
|
|
[logoUrl]="getValue(toolbarLogoUrl) | async"
|
|
[hasMenu]="getValue(toolbarHasMenu) | async"
|
|
[hasBack]="getValue(toolbarHasBack) | async"
|
|
[logoSlot]="getValue(toolbarLogoSlot) | async"
|
|
[showLogo]="getValue(toolbarShowLogo) | async"
|
|
[showBack]="getValue(toolbarShowBack) | async"
|
|
[subTitle]="getValue(toolbarSubTitle) | async"
|
|
[showMenu]="getValue(toolbarShowMenu) | async"
|
|
[cssClass]="getValue(toolbarCssClass) | async"
|
|
[backSlot]="getValue(toolbarBackSlot) | async"
|
|
[menuSlot]="getValue(toolbarMenuSlot) | async"
|
|
[showTitle]="getValue(toolbarShowTitle) | async"
|
|
[titleSlot]="getValue(toolbarTitleSlot) | async"
|
|
[contentSlot]="getValue(toolbarContentSlot) | async"
|
|
[defaultHref]="getValue(toolbarDefaultHref) | async"
|
|
[backHandler]="getValue(toolbarBackHandler) | async"
|
|
[autoHideMenu]="getValue(toolbarAutoHideMenu) | async"
|
|
[showSubTitle]="getValue(toolbarShowSubTitle) | async"
|
|
[endSlotButtonsTemplate]="toolbarEndSlotButtonsTemplate"
|
|
[showProgressBar]="getValue(toolbarShowProgressBar) | async"
|
|
[startSlotButtonsTemplate]="toolbarStartSlotButtonsTemplate"
|
|
[progressBarColor]="getValue(toolbarProgressBarColor) | async"
|
|
>
|
|
</x-toolbar>
|
|
|
|
<!-- Split Pane -->
|
|
<ion-split-pane
|
|
contentId="x-menu-wrapper"
|
|
[when]="getValue(toggleMenuWhen) | async"
|
|
[disabled]="emptyValue(toggleMenuWhen) | async"
|
|
(ionSplitPaneVisible)="handleChangeSplitPane($event)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="insideContentRef"></ng-container>
|
|
</ion-split-pane>
|
|
|
|
<!-- Footer -->
|
|
<x-footer
|
|
#footer
|
|
[uiDisabled]="uiDisabled"
|
|
*ngIf="getValue(showFooter) | async"
|
|
[color]="getValue(footerColor) | async"
|
|
[contentTemplate]="footerContentTemplate"
|
|
></x-footer>
|
|
</x-screen-capture>
|
|
</section>
|
|
|
|
<!-- Page Inside Content Template -->
|
|
<ng-template #insideContentRef>
|
|
<!-- Ion Menu -->
|
|
<!-- [disabled]="uiDisabled" -->
|
|
<ion-menu
|
|
id="menu"
|
|
class="x-menu"
|
|
contentId="x-menu-wrapper"
|
|
*ngIf="getValue(hasSide) | async"
|
|
[side]="getValue(sideSlot) | async"
|
|
[type]="getValue(sideType) | async"
|
|
(ionDidOpen)="handleMenuStateChanged(MenuStates.Opened)"
|
|
(ionDidClose)="handleMenuStateChanged(MenuStates.Closed)"
|
|
(ionWillOpen)="handleMenuStateChanged(MenuStates.WillOpen)"
|
|
(ionWillClose)="handleMenuStateChanged(MenuStates.WillClose)"
|
|
>
|
|
<!-- Menu Content -->
|
|
<ion-content #menuContent [color]="getValue(sideColor) | async">
|
|
<!-- Content -->
|
|
<div class="x-page-side-wrapper">
|
|
<ng-content select="[side]"></ng-content>
|
|
</div>
|
|
</ion-content>
|
|
</ion-menu>
|
|
|
|
<!-- Page Content -->
|
|
<ion-content
|
|
#pageContent
|
|
id="x-menu-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
class="ion-no-margin ion-no-padding"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
(scrolling)="handleScrollingEvent($event)"
|
|
(scrollEnded)="scrolledEvent.emit($event)"
|
|
(scrollStarted)="handleScrollStarted($event)"
|
|
[scrollingActionProvider]="scrollEventActionProvider"
|
|
[scrollEvents]="getValue(provideScrollEvents) | async"
|
|
[xScrollBehaviour]="getValue(scrollBehaviour) | async"
|
|
[scrollEndClasses]="getValue(scrollEndClasses) | async"
|
|
[scrollStartClasses]="getValue(scrollStartClasses) | async"
|
|
>
|
|
<!-- Swipe Refresh -->
|
|
<ion-refresher
|
|
slot="fixed"
|
|
[disabled]="uiDisabled"
|
|
(ionRefresh)="handleRefresh($event)"
|
|
*ngIf="getValue(showPageRefresher) | async"
|
|
>
|
|
<ion-refresher-content
|
|
[refreshingText]="getValue(refreshingText) | async"
|
|
[pullingText]="getValue(refreshPullingText) | async"
|
|
[pullingIcon]="getValue(refreshPullingIcon) | async"
|
|
[refreshingSpinner]="getValue(refreshingSpinner) | async"
|
|
>
|
|
</ion-refresher-content>
|
|
</ion-refresher>
|
|
|
|
<!-- Page Content -->
|
|
<ng-content></ng-content>
|
|
|
|
<!-- Infinite Scroll -->
|
|
<ion-infinite-scroll
|
|
(ionInfinite)="handleLoadMore($event)"
|
|
*ngIf="getValue(showPageInfinityScroller) | async"
|
|
[disabled]="getValue(infinityScrollDisabled) | async"
|
|
[threshold]="getValue(infinityScrollThreshold) | async"
|
|
>
|
|
<ion-infinite-scroll-content
|
|
[loadingText]="getValue(infinityScrollerLoadingText) | async"
|
|
[loadingSpinner]="getValue(infinityScrollerLoadingSpinner) | async"
|
|
>
|
|
</ion-infinite-scroll-content>
|
|
</ion-infinite-scroll>
|
|
|
|
<!-- Fab Actions -->
|
|
<ng-container *ngIf="getValue(actions) | async">
|
|
<x-fab
|
|
pageFab
|
|
[loading]="loading"
|
|
[uiDisabled]="uiDisabled"
|
|
[item]="getValue(actions) | async"
|
|
(xOnOutsideClicked)="closeActions()"
|
|
[actionProvider]="actionsActionProvider"
|
|
>
|
|
</x-fab>
|
|
</ng-container>
|
|
</ion-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.scss
|
|
|
|
:host {
|
|
height: 100%;
|
|
|
|
--side-menu-width: 200px;
|
|
--side-menu-min-width: 100px;
|
|
--side-menu-max-width: 200px;
|
|
|
|
--side-menu-content-height-gutter: 0px;
|
|
--side-menu-content-offset-top: 0px;
|
|
--side-menu-content-offset-bottom: 0px;
|
|
|
|
--content-height-gutter: 0px;
|
|
--content-offset-top: 0px;
|
|
--content-offset-bottom: 0px;
|
|
|
|
ion-refresher {
|
|
padding-top: 90px;
|
|
}
|
|
|
|
ion-content {
|
|
//
|
|
height: calc(100% - var(--content-height-gutter));
|
|
overflow: auto;
|
|
|
|
//
|
|
--offset-top: var(--content-offset-top) !important;
|
|
--offset-bottom: var(--content-offset-bottom) !important;
|
|
|
|
//
|
|
--padding-top: 0;
|
|
--padding-end: 0;
|
|
--padding-start: 0;
|
|
--padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
:host::ng-deep {
|
|
ion-header,
|
|
ion-footer {
|
|
z-index: 10000 !important;
|
|
}
|
|
}
|
|
|
|
.x-menu {
|
|
//
|
|
--width: var(--side-menu-width) !important;
|
|
--min-width: var(--side-menu-min-width) !important;
|
|
--max-width: var(--side-menu-max-width) !important;
|
|
|
|
//
|
|
ion-content {
|
|
//
|
|
height: calc(100% - var(--side-menu-content-height-gutter)) !important;
|
|
overflow: auto !important;
|
|
|
|
//
|
|
--offset-top: var(--side-menu-content-offset-top) !important;
|
|
--offset-bottom: var(--side-menu-content-offset-bottom) !important;
|
|
|
|
//
|
|
--padding-top: 0;
|
|
--padding-end: 0;
|
|
--padding-start: 0;
|
|
--padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.split-pane-visible > .split-pane-side {
|
|
border: 0 !important;
|
|
width: var(--side-menu-width) !important;
|
|
min-width: var(--side-menu-min-width) !important;
|
|
max-width: var(--side-menu-max-width) !important;
|
|
}
|
|
|
|
.x-footer-offset,
|
|
.x-toolbar-offset {
|
|
visibility: hidden;
|
|
}
|
|
|
|
.x-page-side-wrapper {
|
|
touch-action: pan-y;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.ts
|
|
|
|
import {
|
|
XMenuState,
|
|
XMenuAction,
|
|
XPageCSSVars,
|
|
XPageLoadingEvent,
|
|
} from './x-page.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { IonContent } from '@ionic/angular';
|
|
import { XFabItem } from '../x-fab/x-fab.typings';
|
|
import { isNullOrUndefined, nameof, XBehaviourEvent } from 'x-framework-core';
|
|
import { XPageContainerComponent } from './x-page.container';
|
|
import { XFooterComponent } from './x-footer/x-footer.component';
|
|
import { XToolbarComponent } from './x-toolbar/x-toolbar.component';
|
|
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
|
|
import { XToolbarAction } from './x-toolbar/x-toolbar.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-page',
|
|
templateUrl: './x-page.component.html',
|
|
styleUrls: ['./x-page.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XPageComponent extends XPageContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly MenuStates = Object.assign({}, XMenuState);
|
|
|
|
//
|
|
scrollYOffset = 0;
|
|
scrollXOffset = 0;
|
|
|
|
//
|
|
//#region View Childs ...
|
|
//
|
|
//#region Toolbar ...
|
|
private TOOLBAR: XToolbarComponent;
|
|
|
|
@ViewChild('toolbar', { static: false })
|
|
set toolbar(v: XToolbarComponent) {
|
|
//
|
|
if (!isNullOrUndefined(v)) {
|
|
//
|
|
this.TOOLBAR = v;
|
|
this.applyContentSize();
|
|
}
|
|
}
|
|
|
|
get toolbar() {
|
|
return this.TOOLBAR;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
private FOOTER: XFooterComponent;
|
|
|
|
@ViewChild('footer', { static: false })
|
|
set footer(v: XFooterComponent) {
|
|
//
|
|
if (!isNullOrUndefined(v)) {
|
|
//
|
|
this.FOOTER = v;
|
|
this.applyContentSize();
|
|
}
|
|
}
|
|
|
|
get footer() {
|
|
return this.FOOTER;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Side Props ...
|
|
//
|
|
private IS_SIDE_OPENED = false;
|
|
|
|
get isSideOpened() {
|
|
return this.IS_SIDE_OPENED;
|
|
}
|
|
|
|
private CAN_CLOSE_MENU = true;
|
|
|
|
get canCloseMenu() {
|
|
return this.CAN_CLOSE_MENU;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region CssVars ...
|
|
//
|
|
//#region SideMenuWidth ...
|
|
const isSideMenuWidthChanged = changeKeys.includes(
|
|
nameof<XPageComponent>('sideMenuWidth')
|
|
);
|
|
const isSideMenuMinWidthChanged = changeKeys.includes(
|
|
nameof<XPageComponent>('sideMenuMinWidth')
|
|
);
|
|
const isSideMenuMaxWidthChanged = changeKeys.includes(
|
|
nameof<XPageComponent>('sideMenuMaxWidth')
|
|
);
|
|
if (
|
|
isSideMenuWidthChanged ||
|
|
isSideMenuMinWidthChanged ||
|
|
isSideMenuMaxWidthChanged
|
|
) {
|
|
await this.applySideMenuWidth();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
this.handleMenuStartState();
|
|
await this.applyContentSize();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerResizeHandler();
|
|
this.registerMenuActionProvider();
|
|
this.registerToolbarActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleChangeSplitPane(event: CustomEvent | any) {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isSideOpened = event.detail.visible;
|
|
this.IS_SIDE_OPENED = isSideOpened;
|
|
this.splitterStateChanged.emit(isSideOpened);
|
|
|
|
//
|
|
if (isSideOpened) {
|
|
//
|
|
this.CAN_CLOSE_MENU = false;
|
|
this.menuState = XMenuState.Opened;
|
|
await this.openMenu();
|
|
} else {
|
|
//
|
|
this.CAN_CLOSE_MENU = true;
|
|
this.menuState = XMenuState.Closed;
|
|
await this.closeMenu();
|
|
}
|
|
}
|
|
|
|
async handleMenuStateChanged(state: XMenuState) {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.menuState = state;
|
|
|
|
//
|
|
this.menuStateChange.emit(state);
|
|
}
|
|
|
|
async handleRefresh(event: any) {
|
|
//
|
|
const loaderEvent: XPageLoadingEvent = {
|
|
type: 'RefreshLoader',
|
|
event,
|
|
};
|
|
|
|
//
|
|
this.refreshPage.emit(loaderEvent);
|
|
}
|
|
|
|
async handleLoadMore(event: any) {
|
|
//
|
|
const loaderEvent: XPageLoadingEvent = {
|
|
type: 'InfinityScrollerLoader',
|
|
event,
|
|
};
|
|
|
|
//
|
|
this.loadMore.emit(loaderEvent);
|
|
}
|
|
|
|
async cancelLoading(event: any) {
|
|
//
|
|
if (!event) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
event.target.complete();
|
|
}
|
|
|
|
async handleScrollStarted(event: XBehaviourEvent) {
|
|
//
|
|
this.scrolledEvent.emit(event);
|
|
|
|
//
|
|
this.closeActions();
|
|
}
|
|
|
|
async handleScrollingEvent(event: XBehaviourEvent) {
|
|
//
|
|
this.scrolledEvent.emit(event);
|
|
|
|
//
|
|
this.scrollYOffset = event.event.detail.scrollTop as number;
|
|
this.scrollXOffset = event.event.detail.scrollLeft as number;
|
|
|
|
//
|
|
await this.applyCaptureOffsets();
|
|
}
|
|
|
|
isMenuOpen() {
|
|
//
|
|
return this.getValue(this.menuState).pipe(
|
|
map((menuState) => {
|
|
return (
|
|
menuState === XMenuState.WillOpen || menuState === XMenuState.Opened
|
|
);
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async openMenu() {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu || this.IS_SIDE_OPENED) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.menuController.open();
|
|
}
|
|
|
|
async closeMenu() {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu || !this.CAN_CLOSE_MENU) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.menuController.close();
|
|
}
|
|
|
|
async toggleMenu() {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (this.isMenuOpen()) {
|
|
await this.closeMenu();
|
|
} else {
|
|
await this.openMenu();
|
|
}
|
|
}
|
|
|
|
async scrollToTop(duration?: number) {
|
|
//
|
|
await this.waitForElement('ion-content[id="x-menu-wrapper"]').then(
|
|
(el: any) => {
|
|
el.scrollToTop(duration);
|
|
}
|
|
);
|
|
}
|
|
|
|
async scrollToBottom(duration?: number) {
|
|
//
|
|
await this.waitForElement('ion-content[id="x-menu-wrapper"]').then(
|
|
(el: any) => {
|
|
el.scrollToBottom(duration);
|
|
}
|
|
);
|
|
}
|
|
|
|
async scrollByPoint(x?: number, y?: number, duration?: number) {
|
|
//
|
|
await this.waitForElement('ion-content[id="x-menu-wrapper"]').then(
|
|
(el: any) => {
|
|
el.scrollByPoint(x, y, duration);
|
|
}
|
|
);
|
|
}
|
|
|
|
async scrollToPoint(x?: number, y?: number, duration?: number) {
|
|
//
|
|
await this.waitForElement('ion-content[id="x-menu-wrapper"]').then(
|
|
(el: any) => {
|
|
el.scrollToPoint(x, y, duration);
|
|
}
|
|
);
|
|
}
|
|
|
|
closeActions(delay: number = 1000) {
|
|
//
|
|
if (!this.actions) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
if (!this.actions) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actions = {
|
|
...this.actions,
|
|
activated: false,
|
|
} as XFabItem;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}, delay);
|
|
}
|
|
|
|
openActions(delay: number = 1000) {
|
|
//
|
|
if (!this.actions) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
setTimeout(() => {
|
|
//
|
|
if (!this.actions) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actions = {
|
|
...this.actions,
|
|
activated: true,
|
|
} as XFabItem;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}, delay);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async canUseMenu() {
|
|
//
|
|
if (!this.toolbarHasMenu || !this.toolbarShowMenu) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const hasMenu = await this.toPromise(this.getValue(this.toolbarHasMenu));
|
|
const showMenu = await this.toPromise(this.getValue(this.toolbarShowMenu));
|
|
|
|
//
|
|
if (!hasMenu || !showMenu) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
private async handleMenuStartState() {
|
|
//
|
|
const canUseMenu = await this.canUseMenu();
|
|
if (!canUseMenu || this.isSideOpened) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (this.menuState) {
|
|
//
|
|
case XMenuState.WillOpen:
|
|
case XMenuState.Opened:
|
|
await this.openMenu();
|
|
break;
|
|
|
|
//
|
|
case XMenuState.WillClose:
|
|
case XMenuState.Closed:
|
|
await this.closeMenu();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private registerMenuActionProvider() {
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.menuActionProvider.asObservable()
|
|
).subscribe((action) => {
|
|
//
|
|
switch (action) {
|
|
case XMenuAction.Open:
|
|
this.openMenu();
|
|
break;
|
|
|
|
case XMenuAction.Close:
|
|
this.closeMenu();
|
|
break;
|
|
|
|
case XMenuAction.Toggle:
|
|
this.toggleMenu();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private registerToolbarActionProvider() {
|
|
//
|
|
if (isNullOrUndefined(this.toolbarActionProvider)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.toolbarActionProvider.asObservable()
|
|
).subscribe(async (event) => {
|
|
//
|
|
if (isNullOrUndefined(event)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (event.action === XToolbarAction.ToggleMenu) {
|
|
await this.toggleMenu();
|
|
}
|
|
});
|
|
}
|
|
|
|
private async registerResizeHandler() {
|
|
//
|
|
this.applyTakeUntilWrapper(this.ruler.change()).subscribe(async () => {
|
|
await this.applyContentSize();
|
|
});
|
|
}
|
|
|
|
private async getToolbarHeight() {
|
|
//
|
|
if (!this.toolbar) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
const toolbarElm = this.toolbar.getElement();
|
|
|
|
//
|
|
if (!toolbarElm) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
return toolbarElm.getBoundingClientRect().height;
|
|
}
|
|
|
|
private async getFooterHeight() {
|
|
//
|
|
if (!this.footer) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
const footerElm = this.footer.getElement();
|
|
|
|
//
|
|
if (!footerElm) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
return footerElm.getBoundingClientRect().height;
|
|
}
|
|
|
|
private async applyContentSize() {
|
|
//
|
|
const showToolbar = await this.getValueAsync(this.showToolbar);
|
|
const toolbarHeight = await this.getToolbarHeight();
|
|
|
|
//
|
|
const showFooter = await this.getValueAsync(this.showFooter);
|
|
const footerHeight = await this.getFooterHeight();
|
|
|
|
//
|
|
if (
|
|
(showToolbar && toolbarHeight === 0) ||
|
|
(showFooter && footerHeight === 0)
|
|
) {
|
|
//
|
|
setTimeout(() => this.applyContentSize(), 100);
|
|
return;
|
|
}
|
|
|
|
//
|
|
const topValue = showToolbar ? `-${toolbarHeight}px` : '0px';
|
|
const bottomValue = showFooter ? `-${footerHeight}px` : '0px';
|
|
|
|
//
|
|
this.setCssVar(XPageCSSVars.ContentOffsetTop, topValue);
|
|
this.setCssVar(XPageCSSVars.SideMenuContentOffsetTop, topValue);
|
|
|
|
//
|
|
this.setCssVar(XPageCSSVars.ContentOffsetBottom, bottomValue);
|
|
this.setCssVar(XPageCSSVars.SideMenuContentOffsetBottom, bottomValue);
|
|
|
|
//
|
|
await this.applyCaptureOffsets();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applySideMenuWidth() {
|
|
//
|
|
const sideMenuWidth = (await this.getValueAsync(this.sideMenuWidth)) || 200;
|
|
const sideMenuMinWidth =
|
|
(await this.getValueAsync(this.sideMenuMinWidth)) || 100;
|
|
const sideMenuMaxWidth =
|
|
(await this.getValueAsync(this.sideMenuMaxWidth)) || 200;
|
|
|
|
//
|
|
this.setCssVar(XPageCSSVars.SideMenuWidth, `${sideMenuWidth}px`);
|
|
this.setCssVar(XPageCSSVars.SideMenuMinWidth, `${sideMenuMinWidth}px`);
|
|
this.setCssVar(XPageCSSVars.SideMenuMaxWidth, `${sideMenuMaxWidth}px`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyCaptureOffsets() {
|
|
//
|
|
const showToolbar = await this.getValueAsync(this.showToolbar);
|
|
const toolbarHeight = await this.getToolbarHeight();
|
|
|
|
//
|
|
const showFooter = await this.getValueAsync(this.showFooter);
|
|
const footerHeight = await this.getFooterHeight();
|
|
|
|
//
|
|
if (
|
|
(showToolbar && toolbarHeight === 0) ||
|
|
(showFooter && footerHeight === 0)
|
|
) {
|
|
//
|
|
setTimeout(() => this.applyCaptureOffsets(), 100);
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.captureTopOffset = -1 * this.scrollYOffset + -1 * toolbarHeight;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.container.ts
|
|
|
|
import {
|
|
Input,
|
|
NgZone,
|
|
Output,
|
|
Inject,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XSpinner,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XBehaviourEvent,
|
|
XColorIdentifier,
|
|
XSpinnerIdentifier,
|
|
XBehaviourEventType,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XPageSize,
|
|
XSideSlot,
|
|
XSideType,
|
|
XMenuState,
|
|
XMenuAction,
|
|
XPageLoadingEvent,
|
|
XMenuSlotIdentifier,
|
|
XLogoSlotIdentifier,
|
|
XPageSizeIdentifier,
|
|
XSideSlotIdentifier,
|
|
XSideTypeIdentifier,
|
|
XBackSlotIdentifier,
|
|
XTitleSlotIdentifier,
|
|
XContentSlotIdentifier,
|
|
} from './x-page.typings';
|
|
import { forkJoin } from 'rxjs';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XToolbarFooterContainer,
|
|
IXToolbarFooterContainer,
|
|
} from '../classes/i-x-toolbar-footer';
|
|
import { Observable, Subject } from 'rxjs';
|
|
import { MenuController } from '@ionic/angular';
|
|
import { XBasePage } from '../classes/x-base-page';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { IXBaseContainer } from '../classes/i-x-base.container';
|
|
import { XFooterActionModel } from './x-footer/x-footer.typings';
|
|
import { XFabActionModel, XFabItem } from '../x-fab/x-fab.typings';
|
|
import { XToolbarActionModel } from './x-toolbar/x-toolbar.typings';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXPageContainer
|
|
extends IXBaseContainer,
|
|
IXToolbarFooterContainer {
|
|
//
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
enableCaptureMode: XStandardType<boolean>;
|
|
downloadCapturedImage: XStandardType<boolean>;
|
|
captureTopOffset: XStandardType<number>;
|
|
captureBottomOffset: XStandardType<number>;
|
|
imageCaptured: EventEmitter<string | Blob>;
|
|
|
|
//
|
|
provideScrollEvents: XStandardType<boolean>;
|
|
scrollStartClasses: XOneOrManyType<string>;
|
|
scrollEndClasses: XOneOrManyType<string>;
|
|
scrollingClasses: XOneOrManyType<string>;
|
|
scrollBehaviour: XOneOrManyType<string>;
|
|
scrollEventActionProvider: Subject<XBehaviourEventType>;
|
|
scrolledEvent: EventEmitter<XBehaviourEvent>;
|
|
|
|
//
|
|
toggleMenuWhen: XStandardType<XPageSizeIdentifier>;
|
|
hasSide: XStandardType<boolean>;
|
|
sideSlot: XStandardType<XSideSlotIdentifier>;
|
|
sideType: XStandardType<XSideTypeIdentifier>;
|
|
sideColor: XStandardType<XColorIdentifier>;
|
|
sideMenuWidth: XStandardType<number>;
|
|
sideMenuMinWidth: XStandardType<number>;
|
|
sideMenuMaxWidth: XStandardType<number>;
|
|
menuState: XStandardType<XMenuState>;
|
|
menuActionProvider: Subject<XMenuAction>;
|
|
splitterStateChanged: EventEmitter<boolean>;
|
|
menuStateChange: EventEmitter<XMenuState>;
|
|
|
|
//
|
|
showPageRefresher: XStandardType<boolean>;
|
|
refreshPage: EventEmitter<XPageLoadingEvent>;
|
|
refreshingText: XStandardType<string>;
|
|
refreshPullingText: XStandardType<string>;
|
|
refreshPullingIcon: XStandardType<XIconIdentifier>;
|
|
refreshingSpinner: XStandardType<XSpinnerIdentifier>;
|
|
|
|
//
|
|
showPageInfinityScroller: XStandardType<boolean>;
|
|
infinityScrollDisabled: XStandardType<boolean>;
|
|
infinityScrollThreshold: XStandardType<string>;
|
|
infinityScrollerLoadingText: XStandardType<string>;
|
|
infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier>;
|
|
loadMore: EventEmitter<XPageLoadingEvent>;
|
|
|
|
//
|
|
actions: XStandardType<XFabItem>;
|
|
actionsActionProvider: Subject<XFabActionModel>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XPageContainer
|
|
extends XToolbarFooterContainer
|
|
implements Readonly<IXPageContainer>
|
|
{
|
|
//
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
|
|
//
|
|
readonly enableCaptureMode: XStandardType<boolean> = false;
|
|
readonly downloadCapturedImage: XStandardType<boolean> = true;
|
|
readonly captureTopOffset: XStandardType<number> = 0;
|
|
readonly captureBottomOffset: XStandardType<number> = 0;
|
|
readonly imageCaptured: EventEmitter<string | Blob> = new EventEmitter<
|
|
string | Blob
|
|
>();
|
|
|
|
//
|
|
readonly provideScrollEvents: XStandardType<boolean>;
|
|
readonly scrollStartClasses: XOneOrManyType<string>;
|
|
readonly scrollEndClasses: XOneOrManyType<string>;
|
|
readonly scrollingClasses: XOneOrManyType<string>;
|
|
readonly scrollBehaviour: XOneOrManyType<string>;
|
|
readonly scrollEventActionProvider: Subject<XBehaviourEventType> =
|
|
new Subject<XBehaviourEventType>();
|
|
readonly scrolledEvent: EventEmitter<XBehaviourEvent> =
|
|
new EventEmitter<XBehaviourEvent>();
|
|
|
|
//
|
|
readonly toggleMenuWhen: XStandardType<XPageSizeIdentifier> =
|
|
XPageSize.Medium;
|
|
readonly hasSide: XStandardType<boolean> = true;
|
|
readonly sideSlot: XStandardType<XSideSlotIdentifier> = XSideSlot.Start;
|
|
readonly sideType: XStandardType<XSideTypeIdentifier> = XSideType.Overlay;
|
|
readonly sideColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.PrimaryShade;
|
|
readonly sideMenuWidth: XStandardType<number> = 200;
|
|
readonly sideMenuMinWidth: XStandardType<number> = 100;
|
|
readonly sideMenuMaxWidth: XStandardType<number> = 200;
|
|
readonly menuState: XStandardType<XMenuState> = XMenuState.Opened;
|
|
readonly menuActionProvider = new Subject<XMenuAction>();
|
|
readonly splitterStateChanged = new EventEmitter<boolean>();
|
|
readonly menuStateChange = new EventEmitter<XMenuState>();
|
|
|
|
//
|
|
readonly showPageRefresher: XStandardType<boolean> = false;
|
|
readonly refreshPage: EventEmitter<XPageLoadingEvent> =
|
|
new EventEmitter<XPageLoadingEvent>();
|
|
readonly refreshingText: XStandardType<string>;
|
|
readonly refreshPullingText: XStandardType<string>;
|
|
readonly refreshPullingIcon: XStandardType<XIconIdentifier>;
|
|
readonly refreshingSpinner: XStandardType<XSpinnerIdentifier> =
|
|
XSpinner.Circular;
|
|
|
|
//
|
|
readonly showPageInfinityScroller: XStandardType<boolean> = false;
|
|
readonly infinityScrollDisabled: XStandardType<boolean> = false;
|
|
readonly infinityScrollThreshold: XStandardType<string> = '200px';
|
|
readonly infinityScrollerLoadingText: XStandardType<string>;
|
|
readonly infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier> =
|
|
XSpinner.Circular;
|
|
readonly loadMore: EventEmitter<XPageLoadingEvent> =
|
|
new EventEmitter<XPageLoadingEvent>();
|
|
|
|
//
|
|
readonly actions: XStandardType<XFabItem>;
|
|
readonly actionsActionProvider: Subject<XFabActionModel> =
|
|
new Subject<XFabActionModel>();
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XPageContainerComponent
|
|
extends XBasePage
|
|
implements IXPageContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Page ...
|
|
//
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
//
|
|
@Input()
|
|
enableCaptureMode: XStandardType<boolean> =
|
|
this.propertyProvider.enableCaptureMode;
|
|
|
|
@Input()
|
|
downloadCapturedImage: XStandardType<boolean> =
|
|
this.propertyProvider.downloadCapturedImage;
|
|
|
|
@Input()
|
|
captureTopOffset: XStandardType<number> =
|
|
this.propertyProvider.captureTopOffset;
|
|
|
|
@Input()
|
|
captureBottomOffset: XStandardType<number> =
|
|
this.propertyProvider.captureBottomOffset;
|
|
|
|
@Output()
|
|
imageCaptured: EventEmitter<string | Blob> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
provideScrollEvents: XStandardType<boolean> =
|
|
this.propertyProvider.provideScrollEvents;
|
|
|
|
@Input()
|
|
scrollStartClasses: XOneOrManyType<string> =
|
|
this.propertyProvider.scrollStartClasses;
|
|
|
|
@Input()
|
|
scrollEndClasses: XOneOrManyType<string> =
|
|
this.propertyProvider.scrollEndClasses;
|
|
|
|
@Input()
|
|
scrollingClasses: XOneOrManyType<string> =
|
|
this.propertyProvider.scrollingClasses;
|
|
|
|
@Input()
|
|
scrollBehaviour: XOneOrManyType<string> =
|
|
this.propertyProvider.scrollBehaviour;
|
|
|
|
@Input()
|
|
scrollEventActionProvider: Subject<XBehaviourEventType> =
|
|
this.propertyProvider.scrollEventActionProvider;
|
|
|
|
@Output()
|
|
scrolledEvent: EventEmitter<XBehaviourEvent> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
toggleMenuWhen: XStandardType<XPageSizeIdentifier> =
|
|
this.propertyProvider.toggleMenuWhen;
|
|
|
|
@Input()
|
|
hasSide: XStandardType<boolean> = this.propertyProvider.hasSide;
|
|
|
|
@Input()
|
|
sideSlot: XStandardType<XSideSlotIdentifier> = this.propertyProvider.sideSlot;
|
|
|
|
@Input()
|
|
sideType: XStandardType<XSideTypeIdentifier> = this.propertyProvider.sideType;
|
|
|
|
@Input()
|
|
sideColor: XStandardType<XColorIdentifier> = this.propertyProvider.sideColor;
|
|
|
|
@Input()
|
|
sideMenuWidth: XStandardType<number> = this.propertyProvider.sideMenuWidth;
|
|
|
|
@Input()
|
|
sideMenuMinWidth: XStandardType<number> =
|
|
this.propertyProvider.sideMenuMinWidth;
|
|
|
|
@Input()
|
|
sideMenuMaxWidth: XStandardType<number> =
|
|
this.propertyProvider.sideMenuMaxWidth;
|
|
|
|
@Input()
|
|
menuState: XStandardType<XMenuState> = this.propertyProvider.menuState;
|
|
|
|
@Input()
|
|
menuActionProvider: Subject<XMenuAction> =
|
|
this.propertyProvider.menuActionProvider;
|
|
|
|
@Output()
|
|
splitterStateChanged: EventEmitter<boolean> = new EventEmitter();
|
|
|
|
@Output()
|
|
menuStateChange: EventEmitter<XMenuState> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
showPageRefresher: XStandardType<boolean> =
|
|
this.propertyProvider.showPageRefresher;
|
|
|
|
@Output()
|
|
refreshPage: EventEmitter<XPageLoadingEvent> = new EventEmitter();
|
|
|
|
@Input()
|
|
refreshingText: XStandardType<string> = this.propertyProvider.refreshingText;
|
|
|
|
@Input()
|
|
refreshPullingText: XStandardType<string> =
|
|
this.propertyProvider.refreshPullingText;
|
|
|
|
@Input()
|
|
refreshPullingIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.refreshPullingIcon;
|
|
|
|
@Input()
|
|
refreshingSpinner: XStandardType<XSpinnerIdentifier> =
|
|
this.propertyProvider.refreshingSpinner;
|
|
|
|
//
|
|
@Input()
|
|
showPageInfinityScroller: XStandardType<boolean> =
|
|
this.propertyProvider.showPageInfinityScroller;
|
|
|
|
@Input()
|
|
infinityScrollDisabled: XStandardType<boolean> =
|
|
this.propertyProvider.infinityScrollDisabled;
|
|
|
|
@Input()
|
|
infinityScrollThreshold: XStandardType<string> =
|
|
this.propertyProvider.infinityScrollThreshold;
|
|
|
|
@Input()
|
|
infinityScrollerLoadingText: XStandardType<string> =
|
|
this.propertyProvider.infinityScrollerLoadingText;
|
|
|
|
@Input()
|
|
infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier> =
|
|
this.propertyProvider.infinityScrollerLoadingSpinner;
|
|
|
|
@Output()
|
|
loadMore: EventEmitter<XPageLoadingEvent> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
actions: XStandardType<XFabItem> = this.propertyProvider.actions;
|
|
|
|
@Input()
|
|
actionsActionProvider: Subject<XFabActionModel> =
|
|
this.propertyProvider.actionsActionProvider;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Toolbar ...
|
|
//
|
|
@Input()
|
|
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
|
|
|
|
//
|
|
@Input()
|
|
toolbarActionProvider: Subject<XToolbarActionModel> =
|
|
this.propertyProvider.toolbarActionProvider;
|
|
|
|
@Input()
|
|
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.toolbarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowProgressBar;
|
|
|
|
@Input()
|
|
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarProgressBarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowTitle;
|
|
|
|
@Input()
|
|
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.propertyProvider.toolbarTitleSlot;
|
|
|
|
@Input()
|
|
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowSubTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowSubTitle;
|
|
|
|
@Input()
|
|
toolbarSubTitle: XStandardType<string> =
|
|
this.propertyProvider.toolbarSubTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowLogo: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowLogo;
|
|
|
|
@Input()
|
|
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
|
|
this.propertyProvider.toolbarLogoSlot;
|
|
|
|
@Input()
|
|
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
|
|
|
|
@Input()
|
|
toolbarShowBack: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowBack;
|
|
|
|
@Input()
|
|
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
|
|
this.propertyProvider.toolbarBackSlot;
|
|
|
|
@Input()
|
|
toolbarBackHandler?: () => XStandardType<void> = () => {
|
|
this.managerService.historyService.back();
|
|
};
|
|
|
|
@Input()
|
|
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
|
|
|
|
@Input()
|
|
toolbarShowMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowMenu;
|
|
|
|
@Input()
|
|
toolbarAutoHideMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarAutoHideMenu;
|
|
|
|
@Input()
|
|
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
|
|
this.propertyProvider.toolbarMenuSlot;
|
|
|
|
//
|
|
@Input()
|
|
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarStartSlotButtonsTemplate;
|
|
|
|
@Input()
|
|
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarEndSlotButtonsTemplate;
|
|
|
|
//
|
|
@Input()
|
|
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.propertyProvider.toolbarContentSlot;
|
|
|
|
@Input()
|
|
toolbarContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarContentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
//
|
|
@Input()
|
|
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
|
|
|
|
//
|
|
@Input()
|
|
footerActionProvider: Subject<XFooterActionModel> =
|
|
this.propertyProvider.footerActionProvider;
|
|
|
|
@Input()
|
|
footerCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.footerCssClass;
|
|
|
|
//
|
|
@Input()
|
|
footerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.footerColor;
|
|
|
|
@Input()
|
|
footerContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.footerContentTemplate;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
public menuController: MenuController,
|
|
protected propertyProvider: XPageContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXPageContainer
|
|
): Observable<IXPageContainer> {
|
|
return forkJoin({
|
|
//
|
|
//#region Page ...
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
|
|
//
|
|
enableCaptureMode: this.getValue(
|
|
container ? container.enableCaptureMode : this.enableCaptureMode
|
|
),
|
|
downloadCapturedImage: this.getValue(
|
|
container ? container.downloadCapturedImage : this.downloadCapturedImage
|
|
),
|
|
captureTopOffset: this.getValue(
|
|
container ? container.captureTopOffset : this.captureTopOffset
|
|
),
|
|
captureBottomOffset: this.getValue(
|
|
container ? container.captureBottomOffset : this.captureBottomOffset
|
|
),
|
|
|
|
//
|
|
provideScrollEvents: this.getValue(
|
|
container ? container.provideScrollEvents : this.provideScrollEvents
|
|
),
|
|
scrollStartClasses: this.getValue(
|
|
container ? container.scrollStartClasses : this.scrollStartClasses
|
|
),
|
|
scrollEndClasses: this.getValue(
|
|
container ? container.scrollEndClasses : this.scrollEndClasses
|
|
),
|
|
scrollingClasses: this.getValue(
|
|
container ? container.scrollingClasses : this.scrollingClasses
|
|
),
|
|
scrollBehaviour: this.getValue(
|
|
container ? container.scrollBehaviour : this.scrollBehaviour
|
|
),
|
|
|
|
//
|
|
toggleMenuWhen: this.getValue(
|
|
container ? container.toggleMenuWhen : this.toggleMenuWhen
|
|
),
|
|
hasSide: this.getValue(container ? container.hasSide : this.hasSide),
|
|
sideSlot: this.getValue(container ? container.sideSlot : this.sideSlot),
|
|
sideType: this.getValue(container ? container.sideType : this.sideType),
|
|
sideColor: this.getValue(
|
|
container ? container.sideColor : this.sideColor
|
|
),
|
|
sideMenuWidth: this.getValue(
|
|
container ? container.sideMenuWidth : this.sideMenuWidth
|
|
),
|
|
sideMenuMinWidth: this.getValue(
|
|
container ? container.sideMenuMinWidth : this.sideMenuMinWidth
|
|
),
|
|
sideMenuMaxWidth: this.getValue(
|
|
container ? container.sideMenuMaxWidth : this.sideMenuMaxWidth
|
|
),
|
|
menuState: this.getValue(
|
|
container ? container.menuState : this.menuState
|
|
),
|
|
|
|
//
|
|
showPageRefresher: this.getValue(
|
|
container ? container.showPageRefresher : this.showPageRefresher
|
|
),
|
|
refreshingText: this.getValue(
|
|
container ? container.refreshingText : this.refreshingText
|
|
),
|
|
refreshPullingText: this.getValue(
|
|
container ? container.refreshPullingText : this.refreshPullingText
|
|
),
|
|
refreshPullingIcon: this.getValue(
|
|
container ? container.refreshPullingIcon : this.refreshPullingIcon
|
|
),
|
|
refreshingSpinner: this.getValue(
|
|
container ? container.refreshingSpinner : this.refreshingSpinner
|
|
),
|
|
|
|
//
|
|
showPageInfinityScroller: this.getValue(
|
|
container
|
|
? container.showPageInfinityScroller
|
|
: this.showPageInfinityScroller
|
|
),
|
|
infinityScrollDisabled: this.getValue(
|
|
container
|
|
? container.infinityScrollDisabled
|
|
: this.infinityScrollDisabled
|
|
),
|
|
infinityScrollThreshold: this.getValue(
|
|
container
|
|
? container.infinityScrollThreshold
|
|
: this.infinityScrollThreshold
|
|
),
|
|
infinityScrollerLoadingText: this.getValue(
|
|
container
|
|
? container.infinityScrollerLoadingText
|
|
: this.infinityScrollerLoadingText
|
|
),
|
|
infinityScrollerLoadingSpinner: this.getValue(
|
|
container
|
|
? container.infinityScrollerLoadingSpinner
|
|
: this.infinityScrollerLoadingSpinner
|
|
),
|
|
|
|
//
|
|
actions: this.getValue(container ? container.actions : this.actions),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Toolbar ...
|
|
showToolbar: this.getValue(
|
|
container ? container.showToolbar : this.showToolbar
|
|
),
|
|
toolbarCssClass: this.getValue(
|
|
container ? container.toolbarCssClass : this.toolbarCssClass
|
|
),
|
|
toolbarColor: this.getValue(
|
|
container ? container.toolbarColor : this.toolbarColor
|
|
),
|
|
toolbarShowProgressBar: this.getValue(
|
|
container
|
|
? container.toolbarShowProgressBar
|
|
: this.toolbarShowProgressBar
|
|
),
|
|
toolbarProgressBarColor: this.getValue(
|
|
container
|
|
? container.toolbarProgressBarColor
|
|
: this.toolbarProgressBarColor
|
|
),
|
|
toolbarShowTitle: this.getValue(
|
|
container ? container.toolbarShowTitle : this.toolbarShowTitle
|
|
),
|
|
toolbarTitleSlot: this.getValue(
|
|
container ? container.toolbarTitleSlot : this.toolbarTitleSlot
|
|
),
|
|
toolbarTitle: this.getValue(
|
|
container ? container.toolbarTitle : this.toolbarTitle
|
|
),
|
|
toolbarShowSubTitle: this.getValue(
|
|
container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle
|
|
),
|
|
toolbarSubTitle: this.getValue(
|
|
container ? container.toolbarSubTitle : this.toolbarSubTitle
|
|
),
|
|
toolbarShowLogo: this.getValue(
|
|
container ? container.toolbarShowLogo : this.toolbarShowLogo
|
|
),
|
|
toolbarLogoSlot: this.getValue(
|
|
container ? container.toolbarLogoSlot : this.toolbarLogoSlot
|
|
),
|
|
toolbarLogoUrl: this.getValue(
|
|
container ? container.toolbarLogoUrl : this.toolbarLogoUrl
|
|
),
|
|
toolbarHasBack: this.getValue(
|
|
container ? container.toolbarHasBack : this.toolbarHasBack
|
|
),
|
|
toolbarShowBack: this.getValue(
|
|
container ? container.toolbarShowBack : this.toolbarShowBack
|
|
),
|
|
toolbarBackSlot: this.getValue(
|
|
container ? container.toolbarBackSlot : this.toolbarBackSlot
|
|
),
|
|
toolbarBackHandler: this.getValue(
|
|
container ? container.toolbarBackHandler : this.toolbarBackHandler
|
|
),
|
|
toolbarDefaultHref: this.getValue(
|
|
container ? container.toolbarDefaultHref : this.toolbarDefaultHref
|
|
),
|
|
toolbarHasMenu: this.getValue(
|
|
container ? container.toolbarHasMenu : this.toolbarHasMenu
|
|
),
|
|
toolbarShowMenu: this.getValue(
|
|
container ? container.toolbarShowMenu : this.toolbarShowMenu
|
|
),
|
|
toolbarAutoHideMenu: this.getValue(
|
|
container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu
|
|
),
|
|
toolbarMenuSlot: this.getValue(
|
|
container ? container.toolbarMenuSlot : this.toolbarMenuSlot
|
|
),
|
|
toolbarStartSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarStartSlotButtonsTemplate
|
|
: this.toolbarStartSlotButtonsTemplate
|
|
),
|
|
toolbarEndSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarEndSlotButtonsTemplate
|
|
: this.toolbarEndSlotButtonsTemplate
|
|
),
|
|
toolbarContentSlot: this.getValue(
|
|
container ? container.toolbarContentSlot : this.toolbarContentSlot
|
|
),
|
|
toolbarContentTemplate: this.getValue(
|
|
container
|
|
? container.toolbarContentTemplate
|
|
: this.toolbarContentTemplate
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Footer ...
|
|
showFooter: this.getValue(
|
|
container ? container.showFooter : this.showFooter
|
|
),
|
|
footerCssClass: this.getValue(
|
|
container ? container.footerCssClass : this.footerCssClass
|
|
),
|
|
footerColor: this.getValue(
|
|
container ? container.footerColor : this.footerColor
|
|
),
|
|
footerContentTemplate: this.getValue(
|
|
container ? container.footerContentTemplate : this.footerContentTemplate
|
|
),
|
|
//#endregion
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
toolbarActionProvider: container
|
|
? container.toolbarActionProvider
|
|
: this.toolbarActionProvider,
|
|
|
|
//
|
|
footerActionProvider: container
|
|
? container.footerActionProvider
|
|
: this.footerActionProvider,
|
|
|
|
//
|
|
menuActionProvider: container
|
|
? container.menuActionProvider
|
|
: this.menuActionProvider,
|
|
|
|
//
|
|
scrollEventActionProvider: container
|
|
? container.scrollEventActionProvider
|
|
: this.scrollEventActionProvider,
|
|
|
|
//
|
|
actionsActionProvider: container
|
|
? container.actionsActionProvider
|
|
: this.actionsActionProvider,
|
|
|
|
//
|
|
imageCaptured: this.imageCaptured,
|
|
splitterStateChanged: this.splitterStateChanged,
|
|
menuStateChange: this.menuStateChange,
|
|
scrolledEvent: this.scrolledEvent,
|
|
refreshPage: this.refreshPage,
|
|
loadMore: this.loadMore,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XPageComponent } from './x-page.component';
|
|
import { XFabModule } from './../x-fab/x-fab.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XFooterComponent } from './x-footer/x-footer.component';
|
|
import { XToolbarComponent } from './x-toolbar/x-toolbar.component';
|
|
import { XNavigatorComponent } from './x-navigator/x-navigator.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XScreenCaptureModule } from '../x-screen-capture/x-screen-capture.module';
|
|
import { XExpandableListModule } from '../x-expandable-list/x-expandable-list.module';
|
|
import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module';
|
|
|
|
@NgModule({
|
|
imports: [
|
|
XFabModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XBaseComponentModule,
|
|
XScreenCaptureModule,
|
|
XExpandableListModule,
|
|
XExpandablePanelModule,
|
|
],
|
|
declarations: [
|
|
XPageComponent,
|
|
XFooterComponent,
|
|
XToolbarComponent,
|
|
XNavigatorComponent,
|
|
],
|
|
exports: [
|
|
XFabModule,
|
|
XIconModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XPageComponent,
|
|
XFooterComponent,
|
|
XToolbarComponent,
|
|
XNavigatorComponent,
|
|
XBaseComponentModule,
|
|
XScreenCaptureModule,
|
|
XExpandableListModule,
|
|
XExpandablePanelModule,
|
|
],
|
|
})
|
|
export class XPageModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.typings.ts
|
|
|
|
|
|
export enum XMenuState {
|
|
WillOpen,
|
|
Opened,
|
|
WillClose,
|
|
Closed,
|
|
}
|
|
|
|
export enum XMenuAction {
|
|
Open,
|
|
Close,
|
|
Toggle,
|
|
}
|
|
|
|
export enum XPageSize {
|
|
ExtraSmall = 'xs',
|
|
Small = 'sm',
|
|
Medium = 'md',
|
|
Large = 'lg',
|
|
ExtraLarge = 'xl',
|
|
}
|
|
|
|
export type XPageSizeIdentifier = XPageSize | string;
|
|
|
|
export enum XSideType {
|
|
Overlay = 'overlay',
|
|
Reveal = 'reveal',
|
|
Push = 'push',
|
|
}
|
|
|
|
export type XSideTypeIdentifier = XSideType | string;
|
|
|
|
export enum XBackSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XBackSlotIdentifier = XBackSlot | string;
|
|
|
|
export enum XMenuSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XMenuSlotIdentifier = XMenuSlot | string;
|
|
|
|
export enum XLogoSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XLogoSlotIdentifier = XLogoSlot | string;
|
|
|
|
export enum XTitleSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XTitleSlotIdentifier = XTitleSlot | string;
|
|
|
|
export enum XContentSlot {
|
|
Start = 'start',
|
|
Middle = 'middle',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XContentSlotIdentifier = XContentSlot | string;
|
|
|
|
export enum XSideSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XSideSlotIdentifier = XSideSlot | string;
|
|
|
|
export interface XPageLoadingEvent {
|
|
type: 'InfinityScrollerLoader' | 'RefreshLoader';
|
|
event: any;
|
|
}
|
|
|
|
export enum XPageCSSVars {
|
|
SideMenuWidth = 'side-menu-width',
|
|
SideMenuMinWidth = 'side-menu-min-width',
|
|
SideMenuMaxWidth = 'side-menu-max-width',
|
|
SideMenuContentHeightGutter = 'side-menu-content-height-gutter',
|
|
SideMenuContentOffsetTop = 'side-menu-content-offset-top',
|
|
SideMenuContentOffsetBottom = 'side-menu-content-offset-bottom',
|
|
ContentHeightGutter = 'content-height-gutter',
|
|
ContentOffsetTop = 'content-offset-top',
|
|
ContentOffsetBottom = 'content-offset-bottom',
|
|
}
|
|
|
|
export type XPageCSSVarsIdentifier = XPageCSSVars | string;
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.html
|
|
|
|
<ion-footer
|
|
class="x-footer x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<ion-toolbar [color]="getValue(color) | async">
|
|
<ion-title class="ion-text-center">
|
|
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
|
</ion-title>
|
|
</ion-toolbar>
|
|
</ion-footer>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.scss
|
|
|
|
:host {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.ts
|
|
|
|
import {
|
|
XFooterAction,
|
|
XFooterActionModel,
|
|
XFooterContainerComponent,
|
|
} from './x-footer.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-footer',
|
|
templateUrl: './x-footer.component.html',
|
|
styleUrls: ['./x-footer.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XFooterComponent extends XFooterContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XFooterComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XFooterActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XFooterAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
XBaseComponentContainer,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XFooterAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XFooterActionIdentifier = XFooterAction | string;
|
|
|
|
export interface XFooterActionModel
|
|
extends XBaseActionModel<XFooterActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXFooterContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XFooterActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
contentTemplate: TemplateRef<any>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XFooterContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXFooterContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XFooterActionModel> =
|
|
new Subject<XFooterActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly contentTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XFooterContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXFooterContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XFooterActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
contentTemplate: TemplateRef<any> = this.propertyProvider.contentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XFooterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXFooterContainer
|
|
): Observable<IXFooterContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
contentTemplate: this.getValue(
|
|
container ? container.contentTemplate : this.contentTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentFooterContainer = {
|
|
[TKey in keyof IXFooterContainer as `footer${Capitalize<
|
|
string & TKey
|
|
>}`]: IXFooterContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentFooterContainer
|
|
extends TXComponentFooterContainer,
|
|
IXBaseComponentContainer {
|
|
showFooter: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XComponentFooterContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentFooterContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showFooter: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly footerActionProvider: Subject<XFooterActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly footerCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly footerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly footerContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.contentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XFooterContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showFooter">
|
|
<x-footer
|
|
[footerColor]="props.footerColor"
|
|
[footerCssClass]="props.footerCssClass"
|
|
[footerActionProvider]="props.footerActionProvider"
|
|
[footerContentTemplate]="props.footerContentTemplate"
|
|
>
|
|
</x-footer>
|
|
</ng-container>
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XComponentFooterContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentFooterContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
|
|
|
|
//
|
|
@Input()
|
|
footerActionProvider: Subject<XFooterActionModel> =
|
|
this.propertyProvider.footerActionProvider;
|
|
|
|
@Input()
|
|
footerCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.footerCssClass;
|
|
|
|
//
|
|
@Input()
|
|
footerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.footerColor;
|
|
|
|
@Input()
|
|
footerContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.footerContentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentFooterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentFooterContainer
|
|
): Observable<IXComponentFooterContainer> {
|
|
return forkJoin({
|
|
//
|
|
showFooter: this.getValue(
|
|
container ? container.showFooter : this.showFooter
|
|
),
|
|
footerCssClass: this.getValue(
|
|
container ? container.footerCssClass : this.footerCssClass
|
|
),
|
|
footerColor: this.getValue(
|
|
container ? container.footerColor : this.footerColor
|
|
),
|
|
footerContentTemplate: this.getValue(
|
|
container ? container.footerContentTemplate : this.footerContentTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
footerActionProvider: container
|
|
? container.footerActionProvider
|
|
: this.footerActionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.html
|
|
|
|
<x-expandable-list
|
|
[loading]="loading"
|
|
[supportRouting]="true"
|
|
[uiDisabled]="uiDisabled"
|
|
class="x-navigator x-wrapper"
|
|
[childTemplate]="childTempRef"
|
|
[parentTemplate]="parentTempRef"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[cssClass]="getValue(cssClass) | async"
|
|
(itemSelected)="itemSelected.emit($event)"
|
|
[childColor]="getValue(childColor) | async"
|
|
[parentColor]="getValue(parentColor) | async"
|
|
[items]="getArrayValue(preparedItems) | async"
|
|
[startupState]="getValue(startupState) | async"
|
|
[itemCssClass]="getValue(itemCssClass) | async"
|
|
[dividerColor]="getValue(dividerColor) | async"
|
|
[closeSiblings]="getValue(closeSiblings) | async"
|
|
[highlightColor]="getValue(highlightColor) | async"
|
|
[childActiveColor]="getValue(childActiveColor) | async"
|
|
[parentActiveColor]="getValue(parentActiveColor) | async"
|
|
[showChildDetailIcon]="getValue(showChildDetailIcon) | async"
|
|
[showParentDetailIcon]="getValue(showParentDetailIcon) | async"
|
|
[disableParentRouting]="getValue(disableParentRouting) | async"
|
|
>
|
|
</x-expandable-list>
|
|
|
|
<ng-template #parentTempRef let-item>
|
|
<div
|
|
fxLayout="row"
|
|
fxLayoutAlign="start center"
|
|
class="nav-item nav-item-parent"
|
|
[ngClass]="getValue(itemCssClass) | async"
|
|
>
|
|
<div class="start">
|
|
<ng-container *ngIf="isStartSlotted() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
<div fxFill class="center">
|
|
<h4 class="x-nav-item-title ion-no-margin ion-no-padding text-truncate">
|
|
{{ getResourceValue(item.title) | async }}
|
|
</h4>
|
|
</div>
|
|
<div class="end">
|
|
<ng-container *ngIf="isEndSlotted() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #childTempRef let-item>
|
|
<div
|
|
fxLayout="row"
|
|
fxLayoutAlign="start center"
|
|
class="nav-item nav-item-child"
|
|
[ngClass]="getValue(itemCssClass) | async"
|
|
>
|
|
<div class="start" *ngIf="getValue(showChildIcon) | async">
|
|
<ng-container *ngIf="isStartSlotted() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
<div fxFill class="center">
|
|
<h4 class="x-nav-item-title ion-no-margin ion-no-padding text-truncate">
|
|
{{ getResourceValue(item.title) | async }}
|
|
</h4>
|
|
</div>
|
|
<div class="end" *ngIf="getValue(showChildIcon) | async">
|
|
<ng-container *ngIf="isEndSlotted() | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #iconRef let-item>
|
|
<x-icon [cssClass]="'cb-inherit'" [name]="getValue(item.icon) | async">
|
|
</x-icon>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.scss
|
|
|
|
.nav-item > * {
|
|
display: inline-block;
|
|
position: relative;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.x-nav-item-title {
|
|
max-width: 150px;
|
|
margin: 4px;
|
|
}
|
|
|
|
.nav-item-parent {
|
|
.x-nav-item-title {
|
|
font-size: 10pt;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
|
|
.nav-item-child {
|
|
.x-nav-item-title {
|
|
font-size: 9pt;
|
|
font-weight: normal;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.ts
|
|
|
|
import {
|
|
XNavigatorAction,
|
|
XNavigatorActionModel,
|
|
XNavigatorItemIconSlot,
|
|
XNavigatorContainerComponent,
|
|
XNavigatorListItem,
|
|
} from './x-navigator.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { Observable, Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { XStandardType, XOneOrManyType, nameof } from 'x-framework-core';
|
|
import { XExpandableListItem } from '../../x-expandable-list/x-expandable-list.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-navigator',
|
|
templateUrl: './x-navigator.component.html',
|
|
styleUrls: ['./x-navigator.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XNavigatorComponent extends XNavigatorContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private EXPANDABLE_LIST_ITEMS: XOneOrManyType<XExpandableListItem<any>>;
|
|
|
|
get preparedItems() {
|
|
return this.EXPANDABLE_LIST_ITEMS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareItems();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XNavigatorComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Items Changed ...
|
|
const isItemsChanged = changeKeys.includes(
|
|
nameof<XNavigatorComponent>('items')
|
|
);
|
|
if (isItemsChanged) {
|
|
await this.prepareItems();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
isEndSlotted() {
|
|
return this.getValue(this.iconSlot).pipe(
|
|
map((iconSlot) => iconSlot === XNavigatorItemIconSlot.End)
|
|
);
|
|
}
|
|
|
|
isStartSlotted() {
|
|
return this.getValue(this.iconSlot).pipe(
|
|
map((iconSlot) => iconSlot === XNavigatorItemIconSlot.Start)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XNavigatorActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XNavigatorAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareItems() {
|
|
//
|
|
this.EXPANDABLE_LIST_ITEMS = null;
|
|
this.detectChanges();
|
|
|
|
//
|
|
const items = await this.getArrayValueAsync(this.items);
|
|
const preparedItems = await Promise.all(
|
|
items.map(async (i) => await this.toExpandableListItem(i))
|
|
);
|
|
|
|
//
|
|
this.EXPANDABLE_LIST_ITEMS = [
|
|
...preparedItems
|
|
];
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async toExpandableListItem(item: XNavigatorListItem) {
|
|
//
|
|
const result: XExpandableListItem<any> = {
|
|
//
|
|
...item,
|
|
data: '',
|
|
childs: [
|
|
...(await Promise.all(
|
|
(item.childs ? await this.getArrayValueAsync(item.childs) : []).map(
|
|
async (c) => await this.toExpandableListItem(c)
|
|
)
|
|
)),
|
|
],
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.tools.ts
|
|
|
|
import {
|
|
XPage,
|
|
isArray,
|
|
toArray,
|
|
hasChild,
|
|
mergeRoutes,
|
|
XOneOrManyType,
|
|
} from 'x-framework-core';
|
|
import { XNavigatorListItem } from './x-navigator.typings';
|
|
|
|
export function extractParent(source: XOneOrManyType<XPage>): any {
|
|
//
|
|
if (!source) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isArrayOfPages = isArray(source);
|
|
const page = source as XPage;
|
|
const pages = source as XPage[];
|
|
|
|
//
|
|
if (isArrayOfPages) {
|
|
//
|
|
// Handle Array of Pages ...
|
|
return pages.filter((p) => hasChild(p.childs));
|
|
} else {
|
|
//
|
|
// Handle On Page ...
|
|
return extractParent(page.childs);
|
|
}
|
|
}
|
|
|
|
export function extractChilds(source: XOneOrManyType<XPage>) {
|
|
//
|
|
if (!source) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const isArrayOfPages = isArray(source);
|
|
const page = source as XPage;
|
|
const pages = source as XPage[];
|
|
|
|
//
|
|
if (isArrayOfPages) {
|
|
//
|
|
// Handle Array of Pages ...
|
|
return pages.filter((p) => !hasChild(p.childs));
|
|
} else {
|
|
//
|
|
// Handle On Page ...
|
|
return extractParent(page.childs);
|
|
}
|
|
}
|
|
|
|
export function toFlat(pages: XOneOrManyType<XPage>) {
|
|
//
|
|
if (!pages || !hasChild(pages)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
let result: XPage[] = [];
|
|
|
|
//
|
|
const pPages = toArray(pages);
|
|
pPages.forEach((p) => {
|
|
//
|
|
result.push(p);
|
|
|
|
//
|
|
if (p.childs && hasChild(p.childs)) {
|
|
//
|
|
const childsFlat = toFlat(p.childs);
|
|
result = result.concat(childsFlat);
|
|
}
|
|
});
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
export function toNavigatiorListItem(page: XPage) {
|
|
//
|
|
if (!page) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const pageRoute = mergeRoutes(page.route);
|
|
|
|
//
|
|
const result: XNavigatorListItem = {
|
|
id: page.id ? `${page.id}_(${pageRoute})` : `${page.name}_(${pageRoute})`,
|
|
opened: false,
|
|
hidden: false,
|
|
disabled: false,
|
|
icon: page.icon,
|
|
href: page.route,
|
|
replaceUrl: true,
|
|
title: page.title,
|
|
description: page.description,
|
|
childs: hasChild(page.childs)
|
|
? toArray(page.childs).map((c) => toNavigatiorListItem(c))
|
|
: null,
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
import { XExpandableListItem } from '../../x-expandable-list/x-expandable-list.typings';
|
|
|
|
export type XNavigatorListItemBase = Pick<
|
|
XExpandableListItem<any>,
|
|
| 'id'
|
|
| 'href'
|
|
| 'title'
|
|
| 'opened'
|
|
| 'hidden'
|
|
| 'disabled'
|
|
| 'replaceUrl'
|
|
| 'description'
|
|
>;
|
|
export interface XNavigatorListItem extends XNavigatorListItemBase {
|
|
icon?: XStandardType<XIconIdentifier>;
|
|
childs?: XStandardType<XOneOrManyType<XNavigatorListItem>>;
|
|
}
|
|
|
|
export enum XNavigatorItemIconSlot {
|
|
Start = 'start',
|
|
End = 'end',
|
|
}
|
|
|
|
export type XNavigatorItemIconSlotIdentifier = XNavigatorItemIconSlot | string;
|
|
|
|
export enum XNavigatorStartupState {
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XNavigatorStartupStateIdentifier = XNavigatorStartupState | string;
|
|
|
|
export enum XNavigatorAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XNavigatorActionIdentifier = XNavigatorAction | string;
|
|
|
|
export interface XNavigatorActionModel
|
|
extends XBaseActionModel<XNavigatorActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXNavigatorContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XNavigatorActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
itemCssClass: XStandardType<XOneOrManyType<string>>;
|
|
items: XStandardType<XOneOrManyType<XNavigatorListItem>>;
|
|
|
|
//
|
|
closeSiblings: XStandardType<boolean>;
|
|
iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier>;
|
|
startupState: XStandardType<XNavigatorStartupStateIdentifier>;
|
|
|
|
//
|
|
showChildIcon: XStandardType<boolean>;
|
|
showChildDetailIcon: XStandardType<boolean>;
|
|
showParentIcon: XStandardType<boolean>;
|
|
showParentDetailIcon: XStandardType<boolean>;
|
|
disableParentRouting: XStandardType<boolean>;
|
|
|
|
//
|
|
childColor: XStandardType<XColorIdentifier>;
|
|
childActiveColor: XStandardType<XColorIdentifier>;
|
|
parentColor: XStandardType<XColorIdentifier>;
|
|
parentActiveColor: XStandardType<XColorIdentifier>;
|
|
highlightColor: XStandardType<XColorIdentifier>;
|
|
dividerColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
itemSelected: EventEmitter<XNavigatorListItem>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XNavigatorContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXNavigatorContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XNavigatorActionModel> =
|
|
new Subject<XNavigatorActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly itemCssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly items: XStandardType<XOneOrManyType<XNavigatorListItem>>;
|
|
|
|
//
|
|
readonly closeSiblings: XStandardType<boolean> = true;
|
|
readonly iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier> =
|
|
XNavigatorItemIconSlot.Start;
|
|
readonly startupState: XStandardType<XNavigatorStartupStateIdentifier> =
|
|
XNavigatorStartupState.ExpandAll;
|
|
|
|
//
|
|
readonly showChildIcon: XStandardType<boolean> = true;
|
|
readonly showChildDetailIcon: XStandardType<boolean> = true;
|
|
readonly showParentIcon: XStandardType<boolean> = true;
|
|
readonly showParentDetailIcon: XStandardType<boolean> = true;
|
|
readonly disableParentRouting: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly childColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.PrimaryShade;
|
|
readonly childActiveColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly parentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryTint;
|
|
readonly parentActiveColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly highlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
readonly dividerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
//
|
|
readonly itemSelected: EventEmitter<XNavigatorListItem> =
|
|
new EventEmitter<XNavigatorListItem>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XNavigatorContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXNavigatorContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XNavigatorActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
itemCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.itemCssClass;
|
|
|
|
@Input()
|
|
items: XStandardType<XOneOrManyType<XNavigatorListItem>> =
|
|
this.propertyProvider.items;
|
|
|
|
//
|
|
@Input()
|
|
closeSiblings: XStandardType<boolean> = this.propertyProvider.closeSiblings;
|
|
|
|
@Input()
|
|
iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier> =
|
|
this.propertyProvider.iconSlot;
|
|
|
|
@Input()
|
|
startupState: XStandardType<XNavigatorStartupStateIdentifier> =
|
|
this.propertyProvider.startupState;
|
|
|
|
//
|
|
@Input()
|
|
showChildIcon: XStandardType<boolean> = this.propertyProvider.showChildIcon;
|
|
|
|
@Input()
|
|
showChildDetailIcon: XStandardType<boolean> =
|
|
this.propertyProvider.showChildDetailIcon;
|
|
|
|
@Input()
|
|
showParentIcon: XStandardType<boolean> = this.propertyProvider.showParentIcon;
|
|
|
|
@Input()
|
|
showParentDetailIcon: XStandardType<boolean> =
|
|
this.propertyProvider.showParentDetailIcon;
|
|
|
|
@Input()
|
|
disableParentRouting: XStandardType<boolean> =
|
|
this.propertyProvider.disableParentRouting;
|
|
|
|
//
|
|
@Input()
|
|
childColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.childColor;
|
|
|
|
@Input()
|
|
childActiveColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.childActiveColor;
|
|
|
|
@Input()
|
|
parentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.parentColor;
|
|
|
|
@Input()
|
|
parentActiveColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.parentActiveColor;
|
|
|
|
@Input()
|
|
highlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.highlightColor;
|
|
|
|
@Input()
|
|
dividerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.dividerColor;
|
|
|
|
//
|
|
@Output()
|
|
itemSelected: EventEmitter<XNavigatorListItem> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XNavigatorContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXNavigatorContainer
|
|
): Observable<IXNavigatorContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
itemCssClass: this.getValue(
|
|
container ? container.itemCssClass : this.itemCssClass
|
|
),
|
|
items: this.getValue(container ? container.items : this.items),
|
|
closeSiblings: this.getValue(
|
|
container ? container.closeSiblings : this.closeSiblings
|
|
),
|
|
iconSlot: this.getValue(container ? container.iconSlot : this.iconSlot),
|
|
startupState: this.getValue(
|
|
container ? container.startupState : this.startupState
|
|
),
|
|
showChildIcon: this.getValue(
|
|
container ? container.showChildIcon : this.showChildIcon
|
|
),
|
|
showChildDetailIcon: this.getValue(
|
|
container ? container.showChildDetailIcon : this.showChildDetailIcon
|
|
),
|
|
showParentIcon: this.getValue(
|
|
container ? container.showParentIcon : this.showParentIcon
|
|
),
|
|
showParentDetailIcon: this.getValue(
|
|
container ? container.showParentDetailIcon : this.showParentDetailIcon
|
|
),
|
|
disableParentRouting: this.getValue(
|
|
container ? container.disableParentRouting : this.disableParentRouting
|
|
),
|
|
childColor: this.getValue(
|
|
container ? container.childColor : this.childColor
|
|
),
|
|
childActiveColor: this.getValue(
|
|
container ? container.childActiveColor : this.childActiveColor
|
|
),
|
|
parentColor: this.getValue(
|
|
container ? container.parentColor : this.parentColor
|
|
),
|
|
parentActiveColor: this.getValue(
|
|
container ? container.parentActiveColor : this.parentActiveColor
|
|
),
|
|
highlightColor: this.getValue(
|
|
container ? container.highlightColor : this.highlightColor
|
|
),
|
|
dividerColor: this.getValue(
|
|
container ? container.dividerColor : this.dividerColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
itemSelected: this.itemSelected,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.html
|
|
|
|
<ion-header>
|
|
<!-- Toolbar -->
|
|
<ion-toolbar
|
|
matRipple
|
|
[color]="getValue(color) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<div class="x-toolbar-slot-container">
|
|
<!-- Start Slot Content -->
|
|
<div slot="start" class="x-toolbar-slot x-toolbar-start-slot">
|
|
<!-- Start Slot Buttons -->
|
|
<ion-buttons>
|
|
<!-- Back Button -->
|
|
<ng-container
|
|
*ngIf="(getValue(showBack) | async) && (isStartSlotBack() | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="backButtonRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Menu Button -->
|
|
<ng-container
|
|
*ngIf="(getValue(showMenu) | async) && (isStartSlotMenu() | async)"
|
|
>
|
|
<ion-menu-button
|
|
*ngIf="getValue(hasMenu) | async"
|
|
(click)="handleMenuButtonClicked()"
|
|
[autoHide]="getValue(autoHideMenu) | async"
|
|
></ion-menu-button>
|
|
</ng-container>
|
|
|
|
<!-- Custom Start Buttons -->
|
|
<ng-container *ngIf="startSlotButtonsTemplate">
|
|
<ng-container
|
|
*ngTemplateOutlet="startSlotButtonsTemplate"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
|
|
<!-- Logo -->
|
|
<ion-thumbnail
|
|
class="x-toolbar-thumbnail"
|
|
*ngIf="(getValue(showLogo) | async) && (isStartSlotLogo() | async)"
|
|
>
|
|
<ion-img [src]="getValue(logoUrl) | async"></ion-img>
|
|
</ion-thumbnail>
|
|
|
|
<!-- Title and SubTitle -->
|
|
<span
|
|
class="x-toolbar-title-wrapper ion-text-start"
|
|
*ngIf="(getValue(showTitle) | async) && (isStartSlotTitle() | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="titleSubTitleRef"></ng-container>
|
|
</span>
|
|
|
|
<!-- Custom Content -->
|
|
<ng-container *ngIf="contentTemplate && (isStartSlotContent() | async)">
|
|
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Middle Content -->
|
|
<div
|
|
class="x-toolbar-slot x-toolbar-middle-slot"
|
|
*ngIf="contentTemplate && (isMiddleSlotContent() | async)"
|
|
>
|
|
<!-- Custom Content -->
|
|
<ng-container
|
|
*ngIf="contentTemplate && (isMiddleSlotContent() | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- End Slot Content -->
|
|
<div class="x-toolbar-slot x-toolbar-end-slot" slot="end">
|
|
<!-- Custom Content -->
|
|
<ng-container *ngIf="contentTemplate && (isEndSlotContent() | async)">
|
|
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Title and SubTitle -->
|
|
<span
|
|
class="x-toolbar-title-wrapper ion-text-end"
|
|
*ngIf="(getValue(showTitle) | async) && (isEndSlotTitle() | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="titleSubTitleRef"></ng-container>
|
|
</span>
|
|
|
|
<!-- Logo -->
|
|
<ion-thumbnail
|
|
class="x-toolbar-thumbnail"
|
|
*ngIf="(getValue(showLogo) | async) && (isEndSlotLogo() | async)"
|
|
>
|
|
<ion-img [src]="getValue(logoUrl) | async"></ion-img>
|
|
</ion-thumbnail>
|
|
|
|
<!-- End Slot Buttons -->
|
|
<ion-buttons>
|
|
<!-- Custom Start Buttons -->
|
|
<ng-container *ngIf="endSlotButtonsTemplate">
|
|
<ng-container
|
|
*ngTemplateOutlet="endSlotButtonsTemplate"
|
|
></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Menu Button -->
|
|
<ng-container
|
|
*ngIf="(getValue(showMenu) | async) && (isEndSlotMenu() | async)"
|
|
>
|
|
<ion-menu-button
|
|
*ngIf="getValue(hasMenu) | async"
|
|
(click)="handleMenuButtonClicked()"
|
|
[autoHide]="getValue(autoHideMenu) | async"
|
|
></ion-menu-button>
|
|
</ng-container>
|
|
|
|
<!-- Back Button -->
|
|
<ng-container
|
|
*ngIf="(getValue(showBack) | async) && (isEndSlotBack() | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="backButtonRef"></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
</div>
|
|
</div>
|
|
</ion-toolbar>
|
|
|
|
<!-- Progressbar for Loading -->
|
|
<ion-progress-bar
|
|
type="indeterminate"
|
|
*ngIf="getValue(showProgressBar) | async"
|
|
[color]="getValue(progressBarColor) | async"
|
|
></ion-progress-bar>
|
|
</ion-header>
|
|
|
|
<!-- Back Bottun Template -->
|
|
<ng-template #backButtonRef>
|
|
<x-button
|
|
class="x-toolbar-back"
|
|
[type]="ButtonTypes.Icon"
|
|
[title]="ResourceIDs.back"
|
|
[color]="getValue(color) | async"
|
|
(clicked)="handleBackButtonClicked($event)"
|
|
>
|
|
<x-icon
|
|
[foregroundColor]="false"
|
|
[name]="IconNames.arrow_back"
|
|
[color]="getValue(color) | async"
|
|
></x-icon>
|
|
</x-button>
|
|
</ng-template>
|
|
|
|
<!-- Title/SubTitle Template -->
|
|
<ng-template #titleSubTitleRef>
|
|
<!-- Title -->
|
|
<h3
|
|
[class.mobile]="managerService.isMobileUi$ | async"
|
|
class="x-toolbar-title ion-no-padding ion-no-margin"
|
|
[class.text-truncate]="managerService.isMobileUi$ | async"
|
|
>
|
|
{{ getValue(title) | async }}
|
|
</h3>
|
|
|
|
<!-- SubTitle -->
|
|
<h5
|
|
*ngIf="getValue(showSubTitle) | async"
|
|
[matTooltip]="getValue(subTitle) | async"
|
|
[class.mobile]="managerService.isMobileUi$ | async"
|
|
class="x-toolbar-sub-title ion-no-margin ion-no-padding"
|
|
[class.text-truncate]="managerService.isMobileUi$ | async"
|
|
>
|
|
{{ getValue(subTitle) | async }}
|
|
</h5>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.scss
|
|
|
|
.x-toolbar-slot,
|
|
.x-toolbar-start-slot,
|
|
.x-toolbar-middle-slot,
|
|
.x-toolbar-end-slot {
|
|
visibility: inherit;
|
|
}
|
|
|
|
.x-toolbar-start-slot,
|
|
.x-toolbar-middle-slot,
|
|
.x-toolbar-end-slot {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.x-toolbar-slot-container {
|
|
display: flex;
|
|
}
|
|
|
|
.x-toolbar-slot {
|
|
display: flex;
|
|
flex: 1;
|
|
}
|
|
|
|
.x-toolbar-slot > *,
|
|
.x-toolbar-slot-container > * {
|
|
margin: {
|
|
left: 2px;
|
|
right: 2px;
|
|
}
|
|
|
|
width: max-content;
|
|
}
|
|
|
|
ion-thumbnail {
|
|
width: 48px !important;
|
|
height: 48px !important;
|
|
}
|
|
|
|
ion-img {
|
|
object-fit: contain !important;
|
|
}
|
|
|
|
:host {
|
|
--menu-button-transform: rotate(90deg);
|
|
--menu-button-transform-duration: 500ms;
|
|
}
|
|
|
|
:host.menu-opened {
|
|
ion-menu-button {
|
|
//
|
|
transform: var(--menu-button-transform);
|
|
-ms-transform: var(--menu-button-transform);
|
|
-webkit-transform: var(--menu-button-transform);
|
|
|
|
//
|
|
transition: transform;
|
|
-webkit-transition: transform;
|
|
|
|
//
|
|
transition-duration: var(--menu-button-transform-duration);
|
|
-webkit-transition-duration: var(--menu-button-transform-duration);
|
|
}
|
|
}
|
|
|
|
ion-menu-button {
|
|
//
|
|
transition-duration: var(--menu-button-transform-duration);
|
|
-webkit-transition-duration: var(--menu-button-transform-duration);
|
|
}
|
|
|
|
.x-toolbar-title-wrapper {
|
|
padding-inline-end: 16px;
|
|
padding-inline-start: 0;
|
|
|
|
display: block;
|
|
margin: {
|
|
top: auto;
|
|
bottom: auto;
|
|
}
|
|
}
|
|
|
|
.x-toolbar-title,
|
|
.x-toolbar-sub-title {
|
|
display: block !important;
|
|
}
|
|
|
|
.x-toolbar-back {
|
|
}
|
|
|
|
.mobile {
|
|
max-width: 150px;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.ts
|
|
|
|
import {
|
|
XParam,
|
|
nameof,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XToolbarAction,
|
|
XToolbarActionModel,
|
|
XToolbarContainerComponent,
|
|
} from './x-toolbar.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XIconNames } from '../../x-icon/x-icon.typings';
|
|
import { XMenuSlot, XBackSlot } from './../x-page.typings';
|
|
import { XButtonType } from '../../x-button/x-button.typings';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { XLogoSlot, XTitleSlot, XContentSlot } from '../x-page.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-toolbar',
|
|
templateUrl: './x-toolbar.component.html',
|
|
styleUrls: ['./x-toolbar.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XToolbarComponent extends XToolbarContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly IconNames = Object.assign({}, XIconNames);
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
readonly ColorNames = Object.assign({}, XColorWithBrightness);
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XToolbarComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reading Query Params ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Providers ...
|
|
getBackHref() {
|
|
//
|
|
const isContainReturnUrl = this.managerService.isContainQueryParam(
|
|
XParam.ReturnUrl
|
|
);
|
|
|
|
//
|
|
return !isNullOrEmptyString(this.defaultHref)
|
|
? this.defaultHref
|
|
: !isContainReturnUrl
|
|
? null
|
|
: this.managerService.getQueryParamValOfType<string>(XParam.ReturnUrl);
|
|
}
|
|
|
|
canBack() {
|
|
//
|
|
return this.getValue(this.hasBack).pipe(
|
|
map((hasBack) => {
|
|
//
|
|
if (
|
|
!hasBack &&
|
|
this.managerService.isContainQueryParam(XParam.HasBack)
|
|
) {
|
|
hasBack =
|
|
hasBack ||
|
|
this.managerService.getQueryParamValOfType<boolean>(XParam.HasBack);
|
|
}
|
|
|
|
//
|
|
return hasBack;
|
|
})
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Slot Providers ...
|
|
isEndSlotBack() {
|
|
return this.getValue(this.backSlot).pipe(
|
|
map((slot) => slot === XBackSlot.End)
|
|
);
|
|
}
|
|
|
|
isStartSlotBack() {
|
|
return this.getValue(this.backSlot).pipe(
|
|
map((slot) => slot === XBackSlot.Start)
|
|
);
|
|
}
|
|
|
|
isEndSlotMenu() {
|
|
return this.getValue(this.menuSlot).pipe(
|
|
map((slot) => slot === XMenuSlot.End)
|
|
);
|
|
}
|
|
|
|
isStartSlotMenu() {
|
|
return this.getValue(this.menuSlot).pipe(
|
|
map((slot) => slot === XMenuSlot.Start)
|
|
);
|
|
}
|
|
|
|
isEndSlotLogo() {
|
|
return this.getValue(this.logoSlot).pipe(
|
|
map((slot) => slot === XLogoSlot.End)
|
|
);
|
|
}
|
|
|
|
isStartSlotLogo() {
|
|
return this.getValue(this.logoSlot).pipe(
|
|
map((slot) => slot === XLogoSlot.Start)
|
|
);
|
|
}
|
|
|
|
isEndSlotTitle() {
|
|
return this.getValue(this.titleSlot).pipe(
|
|
map((slot) => slot === XTitleSlot.End)
|
|
);
|
|
}
|
|
|
|
isStartSlotTitle() {
|
|
return this.getValue(this.titleSlot).pipe(
|
|
map((slot) => slot === XTitleSlot.Start)
|
|
);
|
|
}
|
|
|
|
isEndSlotContent() {
|
|
return this.getValue(this.contentSlot).pipe(
|
|
map((slot) => slot === XContentSlot.End)
|
|
);
|
|
}
|
|
|
|
isMiddleSlotContent() {
|
|
return this.getValue(this.contentSlot).pipe(
|
|
map((slot) => slot === XContentSlot.Middle)
|
|
);
|
|
}
|
|
|
|
isStartSlotContent() {
|
|
return this.getValue(this.contentSlot).pipe(
|
|
map((slot) => slot === XContentSlot.Start)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handlers ...
|
|
handleMenuButtonClicked() {
|
|
this.actionProvider.next({ action: XToolbarAction.ToggleMenu });
|
|
}
|
|
|
|
async handleBackButtonClicked(event: any) {
|
|
//
|
|
if (this.backHandler) {
|
|
//
|
|
if (event && event.preventDefault) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
//
|
|
await this.getValueAsync(this.backHandler());
|
|
return;
|
|
}
|
|
|
|
//
|
|
const hasReturnUrl = this.managerService.isContainQueryParam(
|
|
XParam.ReturnUrl
|
|
);
|
|
const hasDefaultHref = !isNullOrEmptyString(this.defaultHref);
|
|
const returnUrl = hasReturnUrl
|
|
? this.managerService.getQueryParamValOfType<string>(XParam.ReturnUrl)
|
|
: hasDefaultHref
|
|
? this.defaultHref
|
|
: '';
|
|
|
|
//
|
|
if (!isNullOrEmptyString(returnUrl)) {
|
|
//
|
|
await this.managerService.navigateByUrl(returnUrl);
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.managerService.historyService.back();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XToolbarActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XToolbarAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XBackSlot,
|
|
XLogoSlot,
|
|
XMenuSlot,
|
|
XTitleSlot,
|
|
XContentSlot,
|
|
XBackSlotIdentifier,
|
|
XLogoSlotIdentifier,
|
|
XMenuSlotIdentifier,
|
|
XTitleSlotIdentifier,
|
|
XContentSlotIdentifier,
|
|
} from '../x-page.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
XBaseComponentContainer,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XToolbarAction {
|
|
Refresh = 'refresh',
|
|
ToggleMenu = 'ToggleMenu',
|
|
}
|
|
|
|
export type XToolbarActionIdentifier = XToolbarAction | string;
|
|
|
|
export interface XToolbarActionModel
|
|
extends XBaseActionModel<XToolbarActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXToolbarContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XToolbarActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
showProgressBar: XStandardType<boolean>;
|
|
progressBarColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
showTitle: XStandardType<boolean>;
|
|
titleSlot: XStandardType<XTitleSlotIdentifier>;
|
|
title: XStandardType<string>;
|
|
|
|
//
|
|
showSubTitle: XStandardType<boolean>;
|
|
subTitle: XStandardType<string>;
|
|
|
|
//
|
|
showLogo: XStandardType<boolean>;
|
|
logoSlot: XStandardType<XLogoSlotIdentifier>;
|
|
logoUrl: XStandardType<string>;
|
|
|
|
//
|
|
hasBack: XStandardType<boolean>;
|
|
showBack: XStandardType<boolean>;
|
|
backSlot: XStandardType<XBackSlotIdentifier>;
|
|
backHandler?: () => XStandardType<void>;
|
|
defaultHref: string;
|
|
|
|
//
|
|
hasMenu: XStandardType<boolean>;
|
|
showMenu: XStandardType<boolean>;
|
|
autoHideMenu: XStandardType<boolean>;
|
|
menuSlot: XStandardType<XMenuSlotIdentifier>;
|
|
|
|
//
|
|
startSlotButtonsTemplate: TemplateRef<any>;
|
|
endSlotButtonsTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
contentSlot: XStandardType<XContentSlotIdentifier>;
|
|
contentTemplate: TemplateRef<any>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XToolbarContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXToolbarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XToolbarActionModel> =
|
|
new Subject<XToolbarActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Primary;
|
|
|
|
//
|
|
readonly showProgressBar: XStandardType<boolean> = false;
|
|
readonly progressBarColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Warning;
|
|
|
|
//
|
|
readonly showTitle: XStandardType<boolean> = true;
|
|
readonly titleSlot: XStandardType<XTitleSlotIdentifier> = XTitleSlot.End;
|
|
readonly title: XStandardType<string>;
|
|
|
|
//
|
|
readonly showSubTitle: XStandardType<boolean> = false;
|
|
readonly subTitle: XStandardType<string>;
|
|
|
|
//
|
|
readonly showLogo: XStandardType<boolean> = false;
|
|
readonly logoSlot: XStandardType<XLogoSlotIdentifier> = XLogoSlot.Start;
|
|
readonly logoUrl: XStandardType<string>;
|
|
|
|
//
|
|
readonly hasBack: XStandardType<boolean> = true;
|
|
readonly showBack: XStandardType<boolean> = false;
|
|
readonly backSlot: XStandardType<XBackSlotIdentifier> = XBackSlot.Start;
|
|
readonly backHandler?: () => XStandardType<void>;
|
|
readonly defaultHref: string;
|
|
|
|
//
|
|
readonly hasMenu: XStandardType<boolean> = true;
|
|
readonly showMenu: XStandardType<boolean> = false;
|
|
readonly autoHideMenu: XStandardType<boolean> = true;
|
|
readonly menuSlot: XStandardType<XMenuSlotIdentifier> = XMenuSlot.Start;
|
|
|
|
//
|
|
readonly startSlotButtonsTemplate: TemplateRef<any>;
|
|
readonly endSlotButtonsTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly contentSlot: XStandardType<XContentSlotIdentifier> =
|
|
XContentSlot.End;
|
|
readonly contentTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XToolbarContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXToolbarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XToolbarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
//
|
|
@Input()
|
|
showProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.showProgressBar;
|
|
|
|
@Input()
|
|
progressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.progressBarColor;
|
|
|
|
//
|
|
@Input()
|
|
showTitle: XStandardType<boolean> = this.propertyProvider.showTitle;
|
|
|
|
@Input()
|
|
titleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.propertyProvider.titleSlot;
|
|
|
|
@Input()
|
|
title: XStandardType<string> = this.propertyProvider.title;
|
|
|
|
//
|
|
@Input()
|
|
showSubTitle: XStandardType<boolean> = this.propertyProvider.showSubTitle;
|
|
|
|
@Input()
|
|
subTitle: XStandardType<string> = this.propertyProvider.subTitle;
|
|
|
|
//
|
|
@Input()
|
|
showLogo: XStandardType<boolean> = this.propertyProvider.showLogo;
|
|
|
|
@Input()
|
|
logoSlot: XStandardType<XLogoSlotIdentifier> = this.propertyProvider.logoSlot;
|
|
|
|
@Input()
|
|
logoUrl: XStandardType<string> = this.propertyProvider.logoUrl;
|
|
|
|
//
|
|
@Input()
|
|
hasBack: XStandardType<boolean> = this.propertyProvider.hasBack;
|
|
|
|
@Input()
|
|
showBack: XStandardType<boolean> = this.propertyProvider.showBack;
|
|
|
|
@Input()
|
|
backSlot: XStandardType<XBackSlotIdentifier> = this.propertyProvider.backSlot;
|
|
|
|
@Input()
|
|
backHandler?: () => XStandardType<void> = this.propertyProvider.backHandler;
|
|
|
|
@Input()
|
|
defaultHref: string = this.propertyProvider.defaultHref;
|
|
|
|
//
|
|
@Input()
|
|
hasMenu: XStandardType<boolean> = this.propertyProvider.hasMenu;
|
|
|
|
@Input()
|
|
showMenu: XStandardType<boolean> = this.propertyProvider.showMenu;
|
|
|
|
@Input()
|
|
autoHideMenu: XStandardType<boolean> = this.propertyProvider.autoHideMenu;
|
|
|
|
@Input()
|
|
menuSlot: XStandardType<XMenuSlotIdentifier> = this.propertyProvider.menuSlot;
|
|
|
|
//
|
|
@Input()
|
|
startSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.startSlotButtonsTemplate;
|
|
|
|
@Input()
|
|
endSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.endSlotButtonsTemplate;
|
|
|
|
//
|
|
@Input()
|
|
contentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.propertyProvider.contentSlot;
|
|
|
|
@Input()
|
|
contentTemplate: TemplateRef<any> = this.propertyProvider.contentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XToolbarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXToolbarContainer
|
|
): Observable<IXToolbarContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
showProgressBar: this.getValue(
|
|
container ? container.showProgressBar : this.showProgressBar
|
|
),
|
|
progressBarColor: this.getValue(
|
|
container ? container.progressBarColor : this.progressBarColor
|
|
),
|
|
showTitle: this.getValue(
|
|
container ? container.showTitle : this.showTitle
|
|
),
|
|
titleSlot: this.getValue(
|
|
container ? container.titleSlot : this.titleSlot
|
|
),
|
|
title: this.getValue(container ? container.title : this.title),
|
|
showSubTitle: this.getValue(
|
|
container ? container.showSubTitle : this.showSubTitle
|
|
),
|
|
subTitle: this.getValue(container ? container.subTitle : this.subTitle),
|
|
showLogo: this.getValue(container ? container.showLogo : this.showLogo),
|
|
logoSlot: this.getValue(container ? container.logoSlot : this.logoSlot),
|
|
logoUrl: this.getValue(container ? container.logoUrl : this.logoUrl),
|
|
hasBack: this.getValue(container ? container.hasBack : this.hasBack),
|
|
showBack: this.getValue(container ? container.showBack : this.showBack),
|
|
backSlot: this.getValue(container ? container.backSlot : this.backSlot),
|
|
backHandler: this.getValue(
|
|
container ? container.backHandler : this.backHandler
|
|
),
|
|
defaultHref: this.getValue(
|
|
container ? container.defaultHref : this.defaultHref
|
|
),
|
|
hasMenu: this.getValue(container ? container.hasMenu : this.hasMenu),
|
|
showMenu: this.getValue(container ? container.showMenu : this.showMenu),
|
|
autoHideMenu: this.getValue(
|
|
container ? container.autoHideMenu : this.autoHideMenu
|
|
),
|
|
menuSlot: this.getValue(container ? container.menuSlot : this.menuSlot),
|
|
startSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.startSlotButtonsTemplate
|
|
: this.startSlotButtonsTemplate
|
|
),
|
|
endSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.endSlotButtonsTemplate
|
|
: this.endSlotButtonsTemplate
|
|
),
|
|
contentSlot: this.getValue(
|
|
container ? container.contentSlot : this.contentSlot
|
|
),
|
|
contentTemplate: this.getValue(
|
|
container ? container.contentTemplate : this.contentTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentToolbarContainer = {
|
|
[TKey in keyof IXToolbarContainer as `toolbar${Capitalize<
|
|
string & TKey
|
|
>}`]: IXToolbarContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentToolbarContainer
|
|
extends TXComponentToolbarContainer,
|
|
IXBaseComponentContainer {
|
|
showToolbar: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentToolbarContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentToolbarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showToolbar: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly toolbarActionProvider: Subject<XToolbarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
|
|
//
|
|
readonly toolbarShowProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.showProgressBar;
|
|
readonly toolbarProgressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.progressBarColor;
|
|
|
|
//
|
|
readonly toolbarShowTitle: XStandardType<boolean> =
|
|
this.propertyProvider.showTitle;
|
|
readonly toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.propertyProvider.titleSlot;
|
|
readonly toolbarTitle: XStandardType<string> = this.propertyProvider.title;
|
|
|
|
//
|
|
readonly toolbarShowSubTitle: XStandardType<boolean> =
|
|
this.propertyProvider.showSubTitle;
|
|
readonly toolbarSubTitle: XStandardType<string> =
|
|
this.propertyProvider.subTitle;
|
|
|
|
//
|
|
readonly toolbarShowLogo: XStandardType<boolean> =
|
|
this.propertyProvider.showLogo;
|
|
readonly toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
|
|
this.propertyProvider.logoSlot;
|
|
readonly toolbarLogoUrl: XStandardType<string> =
|
|
this.propertyProvider.logoUrl;
|
|
|
|
//
|
|
readonly toolbarHasBack: XStandardType<boolean> =
|
|
this.propertyProvider.hasBack;
|
|
readonly toolbarShowBack: XStandardType<boolean> =
|
|
this.propertyProvider.showBack;
|
|
readonly toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
|
|
this.propertyProvider.backSlot;
|
|
readonly toolbarBackHandler?: () => XStandardType<void> =
|
|
this.propertyProvider.backHandler;
|
|
readonly toolbarDefaultHref: string = this.propertyProvider.defaultHref;
|
|
|
|
//
|
|
readonly toolbarHasMenu: XStandardType<boolean> =
|
|
this.propertyProvider.hasMenu;
|
|
readonly toolbarShowMenu: XStandardType<boolean> =
|
|
this.propertyProvider.showMenu;
|
|
readonly toolbarAutoHideMenu: XStandardType<boolean> =
|
|
this.propertyProvider.autoHideMenu;
|
|
readonly toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
|
|
this.propertyProvider.menuSlot;
|
|
|
|
//
|
|
readonly toolbarStartSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.startSlotButtonsTemplate;
|
|
readonly toolbarEndSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.endSlotButtonsTemplate;
|
|
|
|
//
|
|
readonly toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.propertyProvider.contentSlot;
|
|
readonly toolbarContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.contentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XToolbarContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
<ng-container *ngIf="props.showToolbar">
|
|
<x-toolbar
|
|
[toolbarTitle]="props.toolbarTitle"
|
|
[toolbarColor]="props.toolbarColor"
|
|
[toolbarLogoUrl]="props.toolbarLogoUrl"
|
|
[toolbarHasBack]="props.toolbarHasBack"
|
|
[toolbarHasMenu]="props.toolbarHasMenu"
|
|
[toolbarSubTitle]="props.toolbarSubTitle"
|
|
[toolbarShowLogo]="props.toolbarShowLogo"
|
|
[toolbarLogoSlot]="props.toolbarLogoSlot"
|
|
[toolbarShowBack]="props.toolbarShowBack"
|
|
[toolbarBackSlot]="props.toolbarBackSlot"
|
|
[toolbarShowMenu]="props.toolbarShowMenu"
|
|
[toolbarAutoHideMenu]="props.toolbarAutoHideMenu"
|
|
[toolbarMenuSlot]="props.toolbarMenuSlot"
|
|
[toolbarCssClass]="props.toolbarCssClass"
|
|
[toolbarShowTitle]="props.toolbarShowTitle"
|
|
[toolbarTitleSlot]="props.toolbarTitleSlot"
|
|
[toolbarBackHandler]="props.toolbarBackHandler"
|
|
[toolbarDefaultHref]="props.toolbarDefaultHref"
|
|
[toolbarContentSlot]="props.toolbarContentSlot"
|
|
[toolbarShowSubTitle]="props.toolbarShowSubTitle"
|
|
[toolbarActionProvider]="props.toolbarActionProvider"
|
|
[toolbarShowProgressBar]="props.toolbarShowProgressBar"
|
|
[toolbarContentTemplate]="props.toolbarContentTemplate"
|
|
[toolbarProgressBarColor]="props.toolbarProgressBarColor"
|
|
[toolbarEndSlotButtonsTemplate]="props.toolbarEndSlotButtonsTemplate"
|
|
[toolbarStartSlotButtonsTemplate]="props.toolbarStartSlotButtonsTemplate"
|
|
>
|
|
</x-toolbar>
|
|
</ng-container>
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XComponentToolbarContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentToolbarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
|
|
|
|
//
|
|
@Input()
|
|
toolbarActionProvider: Subject<XToolbarActionModel> =
|
|
this.propertyProvider.toolbarActionProvider;
|
|
|
|
@Input()
|
|
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.toolbarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
toolbarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowProgressBar: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowProgressBar;
|
|
|
|
@Input()
|
|
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.toolbarProgressBarColor;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowTitle;
|
|
|
|
@Input()
|
|
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
|
|
this.propertyProvider.toolbarTitleSlot;
|
|
|
|
@Input()
|
|
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowSubTitle: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowSubTitle;
|
|
|
|
@Input()
|
|
toolbarSubTitle: XStandardType<string> =
|
|
this.propertyProvider.toolbarSubTitle;
|
|
|
|
//
|
|
@Input()
|
|
toolbarShowLogo: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowLogo;
|
|
|
|
@Input()
|
|
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
|
|
this.propertyProvider.toolbarLogoSlot;
|
|
|
|
@Input()
|
|
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
|
|
|
|
@Input()
|
|
toolbarShowBack: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowBack;
|
|
|
|
@Input()
|
|
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
|
|
this.propertyProvider.toolbarBackSlot;
|
|
|
|
@Input()
|
|
toolbarBackHandler?: () => XStandardType<void> =
|
|
this.propertyProvider.toolbarBackHandler;
|
|
|
|
@Input()
|
|
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
|
|
|
|
//
|
|
@Input()
|
|
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
|
|
|
|
@Input()
|
|
toolbarShowMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarShowMenu;
|
|
|
|
@Input()
|
|
toolbarAutoHideMenu: XStandardType<boolean> =
|
|
this.propertyProvider.toolbarAutoHideMenu;
|
|
|
|
@Input()
|
|
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
|
|
this.propertyProvider.toolbarMenuSlot;
|
|
|
|
//
|
|
@Input()
|
|
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarStartSlotButtonsTemplate;
|
|
|
|
@Input()
|
|
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarEndSlotButtonsTemplate;
|
|
|
|
//
|
|
@Input()
|
|
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
|
|
this.propertyProvider.toolbarContentSlot;
|
|
|
|
@Input()
|
|
toolbarContentTemplate: TemplateRef<any> =
|
|
this.propertyProvider.toolbarContentTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentToolbarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentToolbarContainer
|
|
): Observable<IXComponentToolbarContainer> {
|
|
return forkJoin({
|
|
//
|
|
showToolbar: this.getValue(
|
|
container ? container.showToolbar : this.showToolbar
|
|
),
|
|
//
|
|
toolbarCssClass: this.getValue(
|
|
container ? container.toolbarCssClass : this.toolbarCssClass
|
|
),
|
|
toolbarColor: this.getValue(
|
|
container ? container.toolbarColor : this.toolbarColor
|
|
),
|
|
toolbarShowProgressBar: this.getValue(
|
|
container
|
|
? container.toolbarShowProgressBar
|
|
: this.toolbarShowProgressBar
|
|
),
|
|
toolbarProgressBarColor: this.getValue(
|
|
container
|
|
? container.toolbarProgressBarColor
|
|
: this.toolbarProgressBarColor
|
|
),
|
|
toolbarShowTitle: this.getValue(
|
|
container ? container.toolbarShowTitle : this.toolbarShowTitle
|
|
),
|
|
toolbarTitleSlot: this.getValue(
|
|
container ? container.toolbarTitleSlot : this.toolbarTitleSlot
|
|
),
|
|
toolbarTitle: this.getValue(
|
|
container ? container.toolbarTitle : this.toolbarTitle
|
|
),
|
|
toolbarShowSubTitle: this.getValue(
|
|
container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle
|
|
),
|
|
toolbarSubTitle: this.getValue(
|
|
container ? container.toolbarSubTitle : this.toolbarSubTitle
|
|
),
|
|
toolbarShowLogo: this.getValue(
|
|
container ? container.toolbarShowLogo : this.toolbarShowLogo
|
|
),
|
|
toolbarLogoSlot: this.getValue(
|
|
container ? container.toolbarLogoSlot : this.toolbarLogoSlot
|
|
),
|
|
toolbarLogoUrl: this.getValue(
|
|
container ? container.toolbarLogoUrl : this.toolbarLogoUrl
|
|
),
|
|
toolbarHasBack: this.getValue(
|
|
container ? container.toolbarHasBack : this.toolbarHasBack
|
|
),
|
|
toolbarShowBack: this.getValue(
|
|
container ? container.toolbarShowBack : this.toolbarShowBack
|
|
),
|
|
toolbarBackSlot: this.getValue(
|
|
container ? container.toolbarBackSlot : this.toolbarBackSlot
|
|
),
|
|
toolbarBackHandler: this.getValue(
|
|
container ? container.toolbarBackHandler : this.toolbarBackHandler
|
|
),
|
|
toolbarDefaultHref: this.getValue(
|
|
container ? container.toolbarDefaultHref : this.toolbarDefaultHref
|
|
),
|
|
toolbarHasMenu: this.getValue(
|
|
container ? container.toolbarHasMenu : this.toolbarHasMenu
|
|
),
|
|
toolbarShowMenu: this.getValue(
|
|
container ? container.toolbarShowMenu : this.toolbarShowMenu
|
|
),
|
|
toolbarAutoHideMenu: this.getValue(
|
|
container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu
|
|
),
|
|
toolbarMenuSlot: this.getValue(
|
|
container ? container.toolbarMenuSlot : this.toolbarMenuSlot
|
|
),
|
|
toolbarStartSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarStartSlotButtonsTemplate
|
|
: this.toolbarStartSlotButtonsTemplate
|
|
),
|
|
toolbarEndSlotButtonsTemplate: this.getValue(
|
|
container
|
|
? container.toolbarEndSlotButtonsTemplate
|
|
: this.toolbarEndSlotButtonsTemplate
|
|
),
|
|
toolbarContentSlot: this.getValue(
|
|
container ? container.toolbarContentSlot : this.toolbarContentSlot
|
|
),
|
|
toolbarContentTemplate: this.getValue(
|
|
container
|
|
? container.toolbarContentTemplate
|
|
: this.toolbarContentTemplate
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
toolbarActionProvider: container
|
|
? container.toolbarActionProvider
|
|
: this.toolbarActionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.html
|
|
|
|
<section class="x-progress-bar x-wrapper">
|
|
<ion-progress-bar
|
|
class="x-progress-bar-spinner"
|
|
[type]="getValue(type) | async"
|
|
[color]="getValue(color) | async"
|
|
[value]="getValue(value) | async"
|
|
[buffer]="getValue(buffer) | async"
|
|
></ion-progress-bar>
|
|
</section>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.ts
|
|
|
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
import { XProgressBarAction, XProgressBarActionModel, XProgressBarContainerComponent, XProgressBarType } from './x-progress-bar.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { nameof } from 'x-framework-core';
|
|
|
|
@Component({
|
|
selector: 'x-progress-bar',
|
|
templateUrl: './x-progress-bar.component.html',
|
|
styleUrls: ['./x-progress-bar.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XProgressBarComponent extends XProgressBarContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly PresentTypes = Object.assign({}, XProgressBarType);
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycle ...
|
|
onChange (changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XProgressBarComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy () {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handlers ...
|
|
registerViewHandlers () {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Reading Query Params ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider () {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XProgressBarActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.actionProvider.asObservable()
|
|
).subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XProgressBarAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider () {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XProgressBarComponent } from './x-progress-bar.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XProgressBarComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XProgressBarComponent],
|
|
})
|
|
export class XProgressBarModule { }
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.typings.ts
|
|
|
|
import {
|
|
Subject,
|
|
forkJoin,
|
|
Observable,
|
|
} from 'rxjs';
|
|
import {
|
|
Input,
|
|
NgZone,
|
|
Inject,
|
|
Renderer2,
|
|
Component,
|
|
Injectable,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseComponentContainer,
|
|
XBaseContainerComponent,
|
|
IXBaseComponentContainer,
|
|
} from '../classes/i-x-base.container';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { ViewportRuler } from '@angular/cdk/scrolling';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Prop Definitions ...
|
|
export enum XProgressBarType {
|
|
Buffer = 'buffer',
|
|
Determinate = 'determinate',
|
|
Indeterminate = 'indeterminate',
|
|
}
|
|
|
|
export type XProgressBarTypeIdentifier = XProgressBarType | string;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Provider
|
|
export enum XProgressBarAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XProgressBarActionIdentifier = XProgressBarAction | string;
|
|
|
|
|
|
export interface XProgressBarActionModel
|
|
extends XBaseActionModel<XProgressBarActionIdentifier> { }
|
|
//#endregion
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXProgressBarContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XProgressBarActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
type: XStandardType<XProgressBarTypeIdentifier>;
|
|
|
|
//
|
|
value: XStandardType<number>;
|
|
buffer: XStandardType<number>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XProgressBarContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXProgressBarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XProgressBarActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Warning;
|
|
|
|
//
|
|
readonly type: XStandardType<XProgressBarTypeIdentifier> = XProgressBarType.Indeterminate;
|
|
|
|
//
|
|
readonly value: XStandardType<number>;
|
|
readonly buffer: XStandardType<number>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XProgressBarContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXProgressBarContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XProgressBarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
|
|
//
|
|
@Input()
|
|
type: XStandardType<XProgressBarTypeIdentifier> =
|
|
this.propertyProvider.type;
|
|
|
|
//
|
|
@Input()
|
|
value: XStandardType<number> =
|
|
this.propertyProvider.value;
|
|
|
|
@Input()
|
|
buffer: XStandardType<number> =
|
|
this.propertyProvider.buffer;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XProgressBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps (
|
|
container?: IXProgressBarContainer
|
|
): Observable<IXProgressBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
|
|
//
|
|
type: this.getValue(container ? container.type : this.type),
|
|
|
|
//
|
|
value: this.getValue(container ? container.value : this.value),
|
|
buffer: this.getValue(container ? container.buffer : this.buffer),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentProgressBarContainer = {
|
|
[TKey in keyof IXProgressBarContainer as `progressBar${Capitalize<
|
|
string & TKey
|
|
>}`]: IXProgressBarContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentProgressBarContainer
|
|
extends TXComponentProgressBarContainer,
|
|
IXBaseComponentContainer {
|
|
showProgressBar: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentProgressBarContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentProgressBarContainer> {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showProgressBar: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly progressBarActionProvider =
|
|
this.propertyProvider.actionProvider;
|
|
readonly progressBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly progressBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
|
|
//
|
|
readonly progressBarType: XStandardType<XProgressBarTypeIdentifier> =
|
|
this.propertyProvider.type;
|
|
|
|
//
|
|
readonly progressBarValue: XStandardType<number> =
|
|
this.propertyProvider.value;
|
|
readonly progressBarBuffer: XStandardType<number> =
|
|
this.propertyProvider.buffer;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XProgressBarContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.html
|
|
|
|
<div class="x-screen-capture x-wrapper" [class.mobile]="isMobileUi$ | async">
|
|
<!-- Content -->
|
|
<div #content class="x-content">
|
|
<ng-content></ng-content>
|
|
</div>
|
|
|
|
<!-- Overlay -->
|
|
<div
|
|
#over
|
|
xMouseHandler
|
|
class="x-overlay"
|
|
[class.enabled]="false"
|
|
(moved)="handleMouseMoved($event)"
|
|
(started)="handleMouseStarted($event)"
|
|
[hidden]="!(getValue(enable) | async)"
|
|
(finished)="handleMouseFinished($event)"
|
|
[enableHandler]="getValue(enable) | async"
|
|
>
|
|
<div #rect class="x-rectangle" [class.drawing]="isDrawing"></div>
|
|
</div>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.scss
|
|
|
|
.x-overlay {
|
|
top: 0px;
|
|
left: 0px;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
position: absolute;
|
|
|
|
&.enabled {
|
|
background-color: rgba(204, 204, 204, 0.6);
|
|
}
|
|
}
|
|
|
|
.x-rectangle {
|
|
position: absolute;
|
|
|
|
&.drawing {
|
|
border: 1px solid #ff0000;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.ts
|
|
|
|
import {
|
|
ViewChild,
|
|
Component,
|
|
ElementRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import { nameof } from 'x-framework-core';
|
|
import { XScreenCaptureDimensions } from './x-screen-capture.typings';
|
|
import { XScreenCaptureContainerComponent } from './x-screen-capture.container';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-screen-capture',
|
|
templateUrl: './x-screen-capture.component.html',
|
|
styleUrls: ['./x-screen-capture.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XScreenCaptureComponent extends XScreenCaptureContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
rect: HTMLElement;
|
|
captureZone: HTMLElement;
|
|
|
|
//
|
|
isDrawing = false;
|
|
|
|
//
|
|
clippingDimensions: XScreenCaptureDimensions = {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
|
|
//
|
|
mouse = {
|
|
x: 0,
|
|
y: 0,
|
|
startX: 0,
|
|
startY: 0,
|
|
};
|
|
|
|
//
|
|
//#region View Childs ...
|
|
//
|
|
private RECT: ElementRef;
|
|
|
|
//
|
|
@ViewChild('rect', { static: false })
|
|
set rectangle(v: ElementRef) {
|
|
//
|
|
this.RECT = v;
|
|
this.rect = v.nativeElement;
|
|
}
|
|
|
|
//
|
|
get rectangle() {
|
|
return this.RECT;
|
|
}
|
|
|
|
//
|
|
private OVERLAY: ElementRef;
|
|
|
|
//
|
|
@ViewChild('over', { static: false })
|
|
set overlay(v: ElementRef) {
|
|
//
|
|
this.OVERLAY = v;
|
|
this.captureZone = v.nativeElement;
|
|
}
|
|
|
|
//
|
|
get overlay() {
|
|
return this.OVERLAY;
|
|
}
|
|
|
|
//
|
|
private CONTENT: ElementRef;
|
|
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
set content(v: ElementRef) {
|
|
this.CONTENT = v;
|
|
}
|
|
|
|
//
|
|
get content() {
|
|
return this.CONTENT;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isEnableChanged = changeKeys.includes(
|
|
nameof<XScreenCaptureComponent>('enable')
|
|
);
|
|
if (isEnableChanged) {
|
|
//
|
|
const enable = await this.getValueAsync(this.enable);
|
|
this.reAssignElements(enable);
|
|
this.detectChanges();
|
|
}
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
this.reAssignElements();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleMouseMoved(event: MouseEvent) {
|
|
this.drawRect(event);
|
|
}
|
|
|
|
async handleMouseStarted(event: MouseEvent) {
|
|
this.startCapture(event);
|
|
}
|
|
|
|
async handleMouseFinished(event: MouseEvent) {
|
|
this.endCapture(event);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private reAssignElements(enabled?: boolean) {
|
|
//
|
|
if (!this.OVERLAY || !this.RECT || !this.CONTENT) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.rect = this.RECT.nativeElement;
|
|
this.captureZone = this.OVERLAY.nativeElement;
|
|
|
|
//
|
|
if (enabled === true) {
|
|
this.captureZone.style.cursor = 'crosshair';
|
|
} else {
|
|
this.captureZone.style.cursor = 'default';
|
|
}
|
|
}
|
|
|
|
private setRectangle() {
|
|
//
|
|
this.rect.style.left = this.clippingDimensions.x + 'px';
|
|
this.rect.style.top = this.clippingDimensions.y + 'px';
|
|
this.rect.style.width = this.clippingDimensions.width + 'px';
|
|
this.rect.style.height = this.clippingDimensions.height + 'px';
|
|
}
|
|
|
|
private startCapture(e: any) {
|
|
//
|
|
if (!this.captureZone) {
|
|
//
|
|
this.reAssignElements();
|
|
}
|
|
|
|
//
|
|
this.setMousePosition(e);
|
|
|
|
//
|
|
this.isDrawing = true;
|
|
this.detectChanges();
|
|
|
|
//
|
|
this.mouse.startX = this.mouse.x;
|
|
this.mouse.startY = this.mouse.y;
|
|
this.clippingDimensions = {
|
|
x: this.mouse.x,
|
|
y: this.mouse.y,
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
|
|
//
|
|
this.setRectangle();
|
|
this.captureZone.style.cursor = 'crosshair';
|
|
this.detectChanges();
|
|
}
|
|
|
|
private drawRect(e: any) {
|
|
//
|
|
if (!this.captureZone) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (this.isDrawing) {
|
|
//
|
|
this.setMousePosition(e);
|
|
|
|
//
|
|
this.clippingDimensions = {
|
|
x:
|
|
this.mouse.x - this.mouse.startX < 0
|
|
? this.mouse.x
|
|
: this.mouse.startX,
|
|
y:
|
|
this.mouse.y - this.mouse.startY < 0
|
|
? this.mouse.y
|
|
: this.mouse.startY,
|
|
width: Math.abs(this.mouse.x - this.mouse.startX),
|
|
height: Math.abs(this.mouse.y - this.mouse.startY),
|
|
};
|
|
|
|
//
|
|
this.setRectangle();
|
|
}
|
|
}
|
|
|
|
private setMousePosition(e: any) {
|
|
//
|
|
if (!this.captureZone) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// tslint:disable-next-line: deprecation
|
|
const ev = e || window.event; // Moz || IE
|
|
if (ev.pageX) {
|
|
// Moz
|
|
//
|
|
this.mouse.x = ev.pageX + window.pageXOffset;
|
|
this.mouse.y = ev.pageY + window.pageYOffset;
|
|
} else if (ev.clientX) {
|
|
// IE
|
|
//
|
|
this.mouse.x = ev.clientX + document.body.scrollLeft;
|
|
this.mouse.y = ev.clientY + document.body.scrollTop;
|
|
}
|
|
}
|
|
|
|
private async endCapture(ev: MouseEvent) {
|
|
//
|
|
if (!ev || !this.captureZone) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.captureZone.style.cursor = 'default';
|
|
this.isDrawing = false;
|
|
this.detectChanges();
|
|
|
|
//
|
|
const captureDocument = document.body;
|
|
|
|
//
|
|
const topOffset = await this.getValueAsync(this.topOffset);
|
|
if (topOffset !== 0) {
|
|
this.clippingDimensions = {
|
|
...this.clippingDimensions,
|
|
y: this.clippingDimensions.y + topOffset,
|
|
};
|
|
}
|
|
|
|
//
|
|
const bottomOffset = await this.getValueAsync(this.bottomOffset);
|
|
if (bottomOffset !== 0) {
|
|
this.clippingDimensions = {
|
|
...this.clippingDimensions,
|
|
y: this.clippingDimensions.y + bottomOffset,
|
|
};
|
|
}
|
|
|
|
//
|
|
const canDownload = await this.getOptionalValueAsync(
|
|
this.downloadCapturedImage
|
|
);
|
|
if (canDownload === true) {
|
|
//
|
|
const blob = await this.screenCaptureService.captureAndDownload(
|
|
captureDocument,
|
|
null,
|
|
this.clippingDimensions
|
|
);
|
|
|
|
//
|
|
this.imageCaptured.emit(blob);
|
|
} else {
|
|
//
|
|
const blob = await this.screenCaptureService.capture(
|
|
captureDocument,
|
|
null,
|
|
this.clippingDimensions
|
|
);
|
|
|
|
//
|
|
this.imageCaptured.emit(blob);
|
|
}
|
|
|
|
//
|
|
this.clippingDimensions = {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
};
|
|
|
|
//
|
|
this.setRectangle();
|
|
|
|
//
|
|
this.reAssignElements();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.container.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { forkJoin, Observable } from 'rxjs';
|
|
import { XStandardType } from 'x-framework-core';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XScreenCaptureService } from './x-screen-capture.service';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXScreenCaptureContainer extends IXBaseContainer {
|
|
enable: XStandardType<boolean>;
|
|
topOffset: XStandardType<number>;
|
|
bottomOffset: XStandardType<number>;
|
|
downloadCapturedImage: XStandardType<boolean>;
|
|
imageCaptured: EventEmitter<string | Blob>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XScreenCaptureContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXScreenCaptureContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly enable: XStandardType<boolean> = false;
|
|
readonly topOffset: XStandardType<number> = 0;
|
|
readonly bottomOffset: XStandardType<number> = 0;
|
|
readonly downloadCapturedImage: XStandardType<boolean> = true;
|
|
readonly imageCaptured: EventEmitter<string | Blob> = new EventEmitter<
|
|
string | Blob
|
|
>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
@Component({
|
|
template: `
|
|
<!--
|
|
<ng-container *ngIf="extractProps() | async as props">
|
|
</ng-container>
|
|
-->
|
|
`,
|
|
})
|
|
export abstract class XScreenCaptureContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXScreenCaptureContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
enable: XStandardType<boolean> = this.propertyProvider.enable;
|
|
|
|
@Input()
|
|
topOffset: XStandardType<number> = this.propertyProvider.topOffset;
|
|
|
|
@Input()
|
|
bottomOffset: XStandardType<number> = this.propertyProvider.bottomOffset;
|
|
|
|
@Input()
|
|
downloadCapturedImage: XStandardType<boolean> =
|
|
this.propertyProvider.downloadCapturedImage;
|
|
|
|
@Output()
|
|
imageCaptured: EventEmitter<string | Blob> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
public screenCaptureService: XScreenCaptureService,
|
|
protected propertyProvider: XScreenCaptureContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXScreenCaptureContainer
|
|
): Observable<IXScreenCaptureContainer> {
|
|
return forkJoin({
|
|
//
|
|
enable: this.getValue(container ? container.enable : this.enable),
|
|
topOffset: this.getValue(
|
|
container ? container.topOffset : this.topOffset
|
|
),
|
|
bottomOffset: this.getValue(
|
|
container ? container.bottomOffset : this.bottomOffset
|
|
),
|
|
downloadCapturedImage: this.getValue(
|
|
container ? container.downloadCapturedImage : this.downloadCapturedImage
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
imageCaptured: this.imageCaptured,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XScreenCaptureComponent } from './x-screen-capture.component';
|
|
|
|
@NgModule({
|
|
declarations: [XScreenCaptureComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XScreenCaptureComponent],
|
|
})
|
|
export class XScreenCaptureModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.service.ts
|
|
|
|
import {
|
|
XMimeType,
|
|
blobToImage,
|
|
XBaseService,
|
|
generateUuid,
|
|
canvasToBlob,
|
|
dataUrlToImage,
|
|
canvasToDataUrl,
|
|
clipImageToCanvas,
|
|
downloadArrayBufferedFile,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XScreenCaptureType,
|
|
XScreenCaptureOptions,
|
|
XScreenCaptureDimensions,
|
|
XScreenCaptureTypeIdentifier,
|
|
} from './x-screen-capture.typings';
|
|
import * as domToImage from 'dom-to-image';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { XNotificationService } from 'x-framework-services';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XScreenCaptureService extends XBaseService {
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
private notificationService: XNotificationService
|
|
) {
|
|
super(config);
|
|
}
|
|
//#endregion
|
|
|
|
/**
|
|
* Capture Element with Options as specified type ...
|
|
*
|
|
* @param screen an instance of HTMLElement ...
|
|
*/
|
|
async capture(
|
|
screen: HTMLElement,
|
|
type?: XScreenCaptureTypeIdentifier,
|
|
options?: XScreenCaptureOptions,
|
|
clippingDimensions?: XScreenCaptureDimensions
|
|
) {
|
|
//
|
|
if (!screen) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!type) {
|
|
type = XScreenCaptureType.PNG;
|
|
}
|
|
|
|
//
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
|
|
//
|
|
this.playCaptureNotification();
|
|
|
|
//
|
|
try {
|
|
//
|
|
switch (type) {
|
|
//
|
|
// PNG ...
|
|
case XScreenCaptureType.PNG:
|
|
//
|
|
const pngDataUrl = await domToImage.default.toPng(screen, options);
|
|
if (!clippingDimensions) {
|
|
return pngDataUrl;
|
|
} else {
|
|
//
|
|
const pngImage = await dataUrlToImage(pngDataUrl);
|
|
if (!pngImage) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const pngClippedCanvas = await clipImageToCanvas(
|
|
pngImage,
|
|
clippingDimensions.x,
|
|
clippingDimensions.y,
|
|
clippingDimensions.width,
|
|
clippingDimensions.height
|
|
);
|
|
if (!pngClippedCanvas) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return canvasToDataUrl(pngClippedCanvas, XMimeType.ImagePNG);
|
|
}
|
|
|
|
//
|
|
// JPeg ...
|
|
case XScreenCaptureType.JPeg:
|
|
//
|
|
const jPegDataUrl = await domToImage.default.toJpeg(screen, options);
|
|
if (!clippingDimensions) {
|
|
return jPegDataUrl;
|
|
} else {
|
|
//
|
|
const jPegImage = await dataUrlToImage(jPegDataUrl);
|
|
if (!jPegImage) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const jPegClippedCanvas = await clipImageToCanvas(
|
|
jPegImage,
|
|
clippingDimensions.x,
|
|
clippingDimensions.y,
|
|
clippingDimensions.width,
|
|
clippingDimensions.height
|
|
);
|
|
if (!jPegClippedCanvas) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return canvasToDataUrl(jPegClippedCanvas, XMimeType.ImageJPEG);
|
|
}
|
|
|
|
//
|
|
// SVG ...
|
|
case XScreenCaptureType.SVG:
|
|
//
|
|
const svgDataUrl = await domToImage.default.toSvg(screen, options);
|
|
if (!clippingDimensions) {
|
|
return svgDataUrl;
|
|
} else {
|
|
//
|
|
const svgImage = await dataUrlToImage(svgDataUrl);
|
|
if (!svgImage) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const svgClippedCanvas = await clipImageToCanvas(
|
|
svgImage,
|
|
clippingDimensions.x,
|
|
clippingDimensions.y,
|
|
clippingDimensions.width,
|
|
clippingDimensions.height
|
|
);
|
|
if (!svgClippedCanvas) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return canvasToDataUrl(svgClippedCanvas, XMimeType.ImageSVG);
|
|
}
|
|
|
|
//
|
|
// To Blob ...
|
|
case XScreenCaptureType.Blob:
|
|
//
|
|
const blob = await domToImage.default.toBlob(screen, options);
|
|
if (!clippingDimensions) {
|
|
return blob;
|
|
} else {
|
|
//
|
|
const blobImage = await blobToImage(blob);
|
|
if (!blobImage) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const blobClippedCanvas = await clipImageToCanvas(
|
|
blobImage,
|
|
clippingDimensions.x,
|
|
clippingDimensions.y,
|
|
clippingDimensions.width,
|
|
clippingDimensions.height
|
|
);
|
|
if (!blobClippedCanvas) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return await canvasToBlob(blobClippedCanvas);
|
|
}
|
|
}
|
|
} catch {}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Capture Element with Options as Blob object and Download it ...
|
|
*
|
|
* @param screen an instance of HTMLElement ...
|
|
* @param fileName downloaded file name ...
|
|
*/
|
|
async captureAndDownload(
|
|
screen: HTMLElement,
|
|
options?: XScreenCaptureOptions,
|
|
clippingDimensions?: XScreenCaptureDimensions,
|
|
fileName?: string
|
|
) {
|
|
//
|
|
this.playCaptureNotification();
|
|
|
|
//
|
|
const fName = fileName ? fileName : `${generateUuid()}.png`;
|
|
|
|
//
|
|
try {
|
|
//
|
|
const blob = await domToImage.default.toBlob(screen, options);
|
|
|
|
//
|
|
if (!blob) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!clippingDimensions) {
|
|
//
|
|
downloadArrayBufferedFile(fName, blob);
|
|
return blob;
|
|
} else {
|
|
//
|
|
const blobImage = await blobToImage(blob);
|
|
if (!blobImage) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const blobClippedCanvas = await clipImageToCanvas(
|
|
blobImage,
|
|
clippingDimensions.x,
|
|
clippingDimensions.y,
|
|
clippingDimensions.width,
|
|
clippingDimensions.height
|
|
);
|
|
if (!blobClippedCanvas) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const clippedBlob = await canvasToBlob(blobClippedCanvas);
|
|
if (!clippedBlob) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
downloadArrayBufferedFile(fName, clippedBlob);
|
|
return clippedBlob;
|
|
}
|
|
} catch {}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* play Capture Notification Sound ...
|
|
*/
|
|
playCaptureNotification() {
|
|
this.notificationService.playCaptureNotification();
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.typings.ts
|
|
|
|
import { Options } from 'dom-to-image';
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XScreenCaptureOptions extends Options {}
|
|
|
|
export enum XScreenCaptureType {
|
|
SVG = 'svg',
|
|
PNG = 'png',
|
|
Blob = 'blob',
|
|
JPeg = 'jpeg',
|
|
}
|
|
|
|
export type XScreenCaptureTypeIdentifier = XScreenCaptureType | string;
|
|
|
|
export interface XScreenCaptureDimensions {
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.html
|
|
|
|
<ion-toolbar
|
|
class="x-search-bar x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<ion-searchbar
|
|
class="x-search-bar"
|
|
[type]="getValue(type) | async"
|
|
[value]="getValue(value) | async"
|
|
[disabled]="uiDisabled || loading"
|
|
[debounce]="getValue(debounce) | async"
|
|
[spellcheck]="getValue(spellcheck) | async"
|
|
[inputmode]="getValue(keyboardType) | async"
|
|
[xColor]="getValue(searchInputColor) | async"
|
|
(ionBlur)="onEvent.emit(SearchBarEvents.BLUR)"
|
|
[clearIcon]="getValue(clearButtonIcon) | async"
|
|
[enterkeyhint]="getValue(enterKeyHint) | async"
|
|
[placeholder]="getResourceValue(title) | async"
|
|
(ionFocus)="onEvent.emit(SearchBarEvents.FOCUS)"
|
|
(ionClear)="onEvent.emit(SearchBarEvents.CLEAR)"
|
|
(ionInput)="onEvent.emit(SearchBarEvents.INPUT)"
|
|
[searchIcon]="getValue(searchButtonIcon) | async"
|
|
(ionCancel)="onEvent.emit(SearchBarEvents.CANCEL)"
|
|
(ionChange)="handleSearchQueryValueChange($event)"
|
|
[showCancelButton]="getValue(showCancelButton) | async"
|
|
[showClearButton]="getValue(showClearButton) | async"
|
|
[cancelButtonIcon]="getValue(cancelButtonIcon) | async"
|
|
[isForeground]="getValue(foregroundSearchInputColor) | async"
|
|
[cancelButtonText]="getResourceValue(cancelButtonTitle) | async"
|
|
></ion-searchbar>
|
|
</ion-toolbar>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.scss
|
|
|
|
:host {
|
|
--clear-icon-color: var(--x-color-danger);
|
|
--cancel-icon-color: var(--x-color-primary);
|
|
--search-icon-color: var(--x-color-primary);
|
|
}
|
|
|
|
:host::ng-deep {
|
|
.searchbar-clear-icon {
|
|
color: var(--clear-icon-color) !important;
|
|
}
|
|
|
|
.searchbar-search-icon {
|
|
color: var(--search-icon-color) !important;
|
|
}
|
|
|
|
.searchbar-cancel-button {
|
|
color: var(--cancel-icon-color) !important;
|
|
}
|
|
}
|
|
|
|
.x-search-bar {
|
|
padding: {
|
|
left: 3px;
|
|
right: 3px;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XSearchBarEvent,
|
|
XSearchBarAction,
|
|
XSearchBarCssVars,
|
|
XSearchBarActionModel,
|
|
XSearchBarContainerComponent,
|
|
} from './x-search-bar.typings';
|
|
import { filter } from 'rxjs/operators';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-search-bar',
|
|
templateUrl: './x-search-bar.component.html',
|
|
styleUrls: ['./x-search-bar.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSearchBarComponent extends XSearchBarContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
protected applyThemeColors: boolean = true;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
readonly SearchBarEvents = Object.assign({}, XSearchBarEvent);
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
// Handle Start Value for start searching ...
|
|
this.getValue(this.value)
|
|
.pipe(filter((query) => !isNullOrEmptyString(query)))
|
|
.subscribe((query) => {
|
|
this.queryChange.emit(query);
|
|
});
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region Action Provider ...
|
|
const isActionProviderChaged = changeKeys.includes(
|
|
nameof<XSearchBarComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChaged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Colors ...
|
|
//
|
|
const isCancelButtonIconColorChanged = changeKeys.includes(
|
|
nameof<XSearchBarComponent>('cancelButtonIconColor')
|
|
);
|
|
if (isCancelButtonIconColorChanged) {
|
|
await this.applyCancelButtonIconColor();
|
|
}
|
|
|
|
//
|
|
const isClearButtonIconColorChanged = changeKeys.includes(
|
|
nameof<XSearchBarComponent>('clearButtonIconColor')
|
|
);
|
|
if (isClearButtonIconColorChanged) {
|
|
await this.applyClearButtonIconColor();
|
|
}
|
|
|
|
//
|
|
const isSearchButtonIconColorChanged = changeKeys.includes(
|
|
nameof<XSearchBarComponent>('searchButtonIconColor')
|
|
);
|
|
if (isSearchButtonIconColorChanged) {
|
|
await this.applySearchButtonIconColor();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
//
|
|
handleSearchQueryValueChange(event: CustomEvent | any) {
|
|
//
|
|
const query =
|
|
event && event.detail && event.detail.value
|
|
? event.detail.value.toString().trim().toLowerCase()
|
|
: '';
|
|
|
|
//
|
|
this.queryChange.emit(query);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSearchBarActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSearchBarAction.ClearValue:
|
|
//
|
|
this.value = '';
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XSearchBarAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyCancelButtonIconColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.cancelButtonIconColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XSearchBarCssVars.CancelIconColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XSearchBarCssVars.CancelIconColor,
|
|
`var(${bgColor})`,
|
|
document.body
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyClearButtonIconColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.clearButtonIconColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XSearchBarCssVars.ClearIconColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XSearchBarCssVars.ClearIconColor,
|
|
`var(${bgColor})`,
|
|
document.body
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applySearchButtonIconColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.searchButtonIconColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XSearchBarCssVars.SearchIconColor, `var(${bgColor})`);
|
|
this.setCssVar(
|
|
XSearchBarCssVars.SearchIconColor,
|
|
`var(${bgColor})`,
|
|
document.body
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XSearchBarComponent } from './x-search-bar.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XSearchBarComponent],
|
|
imports: [
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
CommonModule,
|
|
XSearchBarComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XSearchBarModule { }
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.typings.ts
|
|
|
|
import {
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseComponentContainer,
|
|
XBaseContainerComponent,
|
|
IXBaseComponentContainer,
|
|
XBaseComponentContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XSearchBarAction {
|
|
ClearValue = 'clear_value',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSearchBarActionIdentifier = XSearchBarAction | string;
|
|
|
|
export interface XSearchBarActionModel
|
|
extends XBaseActionModel<XSearchBarActionIdentifier> {}
|
|
|
|
export enum XSearchBarType {
|
|
None = 'none',
|
|
Text = 'text',
|
|
Tel = 'tel',
|
|
Url = 'url',
|
|
Email = 'email',
|
|
Numeric = 'numeric',
|
|
Decimal = 'decimal',
|
|
Search = 'search',
|
|
}
|
|
|
|
export type XSearchBarTypeIdentifier = XSearchBarType | string;
|
|
|
|
export enum XSearchBarEnterKeyHint {
|
|
Done = 'done',
|
|
Go = 'go',
|
|
Next = 'next',
|
|
Previous = 'previous',
|
|
Search = 'search',
|
|
Send = 'send',
|
|
Enter = 'enter',
|
|
}
|
|
|
|
export type XSearchBarEnterKeyHintIdentifier = XSearchBarEnterKeyHint | string;
|
|
|
|
export enum XSearchBarShowButton {
|
|
Always = 'always',
|
|
Focus = 'focus',
|
|
Never = 'never',
|
|
}
|
|
|
|
export type XSearchBarShowButtonIdentifier = XSearchBarShowButton | string;
|
|
|
|
export enum XSearchBarCssVars {
|
|
//
|
|
ClearIconColor = 'clear-icon-color',
|
|
CancelIconColor = 'cancel-icon-color',
|
|
SearchIconColor = 'search-icon-color',
|
|
}
|
|
|
|
export type XSearchBarCssVarsIdentifier = XSearchBarCssVars | string;
|
|
|
|
export enum XSearchBarEvent {
|
|
FOCUS = 'focus',
|
|
BLUR = 'blur',
|
|
CANCEL = 'cancel',
|
|
CLEAR = 'clear',
|
|
INPUT = 'input',
|
|
}
|
|
|
|
export type XSearchBarEventIdentifier = XSearchBarEvent | string;
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXSearchBarContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XSearchBarActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
searchInputColor: XStandardType<XColorIdentifier>;
|
|
foregroundSearchInputColor: XStandardType<boolean>;
|
|
|
|
//
|
|
type: XStandardType<XSearchBarTypeIdentifier>;
|
|
title: XStandardType<XResourceIdentifier>;
|
|
value: XStandardType<string>;
|
|
enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier>;
|
|
keyboardType: XStandardType<XSearchBarTypeIdentifier>;
|
|
spellcheck: XStandardType<boolean>;
|
|
debounce: XStandardType<number>;
|
|
|
|
//
|
|
showCancelButton: XStandardType<XSearchBarShowButtonIdentifier>;
|
|
cancelButtonIcon: XStandardType<XIconIdentifier>;
|
|
cancelButtonTitle: XStandardType<XResourceIdentifier>;
|
|
cancelButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
showClearButton: XStandardType<XSearchBarShowButtonIdentifier>;
|
|
clearButtonIcon: XStandardType<XIconIdentifier>;
|
|
clearButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
searchButtonIcon: XStandardType<XIconIdentifier>;
|
|
searchButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
queryChange: EventEmitter<string>;
|
|
onEvent: EventEmitter<XSearchBarEventIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XSearchBarContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXSearchBarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XSearchBarActionModel> =
|
|
new Subject<XSearchBarActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly searchInputColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly foregroundSearchInputColor: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly type: XStandardType<XSearchBarTypeIdentifier> =
|
|
XSearchBarType.Search;
|
|
readonly title: XStandardType<XResourceIdentifier> = XResourceIDs.search;
|
|
readonly value: XStandardType<string>;
|
|
readonly enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier> =
|
|
XSearchBarEnterKeyHint.Search;
|
|
readonly keyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
XSearchBarType.Search;
|
|
readonly spellcheck: XStandardType<boolean> = false;
|
|
readonly debounce: XStandardType<number> =
|
|
this.config.defaultSearchDebounceTime || 500;
|
|
|
|
//
|
|
readonly showCancelButton: XStandardType<XSearchBarShowButtonIdentifier> =
|
|
XSearchBarShowButton.Never;
|
|
readonly cancelButtonIcon: XStandardType<XIconIdentifier>;
|
|
readonly cancelButtonTitle: XStandardType<XResourceIdentifier>;
|
|
readonly cancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Primary;
|
|
|
|
//
|
|
readonly showClearButton: XStandardType<XSearchBarShowButtonIdentifier> =
|
|
XSearchBarShowButton.Always;
|
|
readonly clearButtonIcon: XStandardType<XIconIdentifier>;
|
|
readonly clearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
|
|
//
|
|
readonly searchButtonIcon: XStandardType<XIconIdentifier>;
|
|
readonly searchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Primary;
|
|
|
|
//
|
|
readonly queryChange: EventEmitter<string> = new EventEmitter<string>();
|
|
readonly onEvent: EventEmitter<XSearchBarEventIdentifier> =
|
|
new EventEmitter<XSearchBarEventIdentifier>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig
|
|
) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSearchBarContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXSearchBarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
@Input()
|
|
searchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchInputColor;
|
|
|
|
@Input()
|
|
foregroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
type: XStandardType<XSearchBarTypeIdentifier> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
|
|
|
|
@Input()
|
|
value: XStandardType<string> = this.propertyProvider.value;
|
|
|
|
@Input()
|
|
enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier> =
|
|
this.propertyProvider.enterKeyHint;
|
|
|
|
@Input()
|
|
keyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.keyboardType;
|
|
|
|
@Input()
|
|
spellcheck: XStandardType<boolean> = this.propertyProvider.spellcheck;
|
|
|
|
@Input()
|
|
debounce: XStandardType<number> = this.propertyProvider.debounce;
|
|
|
|
//
|
|
@Input()
|
|
showCancelButton: XStandardType<XSearchBarShowButtonIdentifier> =
|
|
this.propertyProvider.showCancelButton;
|
|
|
|
@Input()
|
|
cancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.cancelButtonIcon;
|
|
|
|
@Input()
|
|
cancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cancelButtonTitle;
|
|
|
|
@Input()
|
|
cancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.cancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
showClearButton: XStandardType<XSearchBarShowButtonIdentifier> =
|
|
this.propertyProvider.showClearButton;
|
|
|
|
@Input()
|
|
clearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.clearButtonIcon;
|
|
|
|
@Input()
|
|
clearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.clearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchButtonIcon;
|
|
|
|
@Input()
|
|
searchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
queryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
onEvent: EventEmitter<XSearchBarEventIdentifier> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSearchBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSearchBarContainer
|
|
): Observable<IXSearchBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
searchInputColor: this.getValue(
|
|
container ? container.searchInputColor : this.searchInputColor
|
|
),
|
|
foregroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.foregroundSearchInputColor
|
|
: this.foregroundSearchInputColor
|
|
),
|
|
type: this.getValue(container ? container.type : this.type),
|
|
title: this.getValue(container ? container.title : this.title),
|
|
value: this.getValue(container ? container.value : this.value),
|
|
enterKeyHint: this.getValue(
|
|
container ? container.enterKeyHint : this.enterKeyHint
|
|
),
|
|
keyboardType: this.getValue(
|
|
container ? container.keyboardType : this.keyboardType
|
|
),
|
|
spellcheck: this.getValue(
|
|
container ? container.spellcheck : this.spellcheck
|
|
),
|
|
debounce: this.getValue(container ? container.debounce : this.debounce),
|
|
showCancelButton: this.getValue(
|
|
container ? container.showCancelButton : this.showCancelButton
|
|
),
|
|
cancelButtonIcon: this.getValue(
|
|
container ? container.cancelButtonIcon : this.cancelButtonIcon
|
|
),
|
|
cancelButtonTitle: this.getValue(
|
|
container ? container.cancelButtonTitle : this.cancelButtonTitle
|
|
),
|
|
cancelButtonIconColor: this.getValue(
|
|
container ? container.cancelButtonIconColor : this.cancelButtonIconColor
|
|
),
|
|
showClearButton: this.getValue(
|
|
container ? container.showCancelButton : this.showCancelButton
|
|
),
|
|
clearButtonIcon: this.getValue(
|
|
container ? container.clearButtonIcon : this.clearButtonIcon
|
|
),
|
|
clearButtonIconColor: this.getValue(
|
|
container ? container.clearButtonIconColor : this.clearButtonIconColor
|
|
),
|
|
searchButtonIcon: this.getValue(
|
|
container ? container.searchButtonIcon : this.searchButtonIcon
|
|
),
|
|
searchButtonIconColor: this.getValue(
|
|
container ? container.searchButtonIconColor : this.searchButtonIconColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
onEvent: this.onEvent,
|
|
queryChange: this.queryChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ComponentContainer ...
|
|
type TXComponentSearchBarContainer = {
|
|
[TKey in keyof IXSearchBarContainer as `searchBar${Capitalize<
|
|
string & TKey
|
|
>}`]: IXSearchBarContainer[TKey];
|
|
};
|
|
|
|
export interface IXComponentSearchBarContainer
|
|
extends TXComponentSearchBarContainer,
|
|
IXBaseComponentContainer {
|
|
//
|
|
showSearchBar: XStandardType<boolean>;
|
|
|
|
//
|
|
searchBarActionProvider: Subject<XSearchBarActionModel>;
|
|
searchBarCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
searchBarColor: XStandardType<XColorIdentifier>;
|
|
searchBarForegroundColor: XStandardType<boolean>;
|
|
|
|
//
|
|
searchBarSearchInputColor: XStandardType<XColorIdentifier>;
|
|
searchBarForegroundSearchInputColor: XStandardType<boolean>;
|
|
|
|
//
|
|
searchBarType: XStandardType<XSearchBarTypeIdentifier>;
|
|
searchBarTitle: XStandardType<XResourceIdentifier>;
|
|
searchBarValue: XStandardType<string>;
|
|
searchBarEnterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier>;
|
|
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier>;
|
|
searchBarSpellcheck: XStandardType<boolean>;
|
|
searchBarDebounce: XStandardType<number>;
|
|
|
|
//
|
|
searchBarShowCancelButton: XStandardType<XSearchBarShowButtonIdentifier>;
|
|
searchBarCancelButtonIcon: XStandardType<XIconIdentifier>;
|
|
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier>;
|
|
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
searchBarShowClearButton: XStandardType<XSearchBarShowButtonIdentifier>;
|
|
searchBarClearButtonIcon: XStandardType<XIconIdentifier>;
|
|
searchBarClearButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
searchBarSearchButtonIcon: XStandardType<XIconIdentifier>;
|
|
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
searchBarQueryChange: EventEmitter<string>;
|
|
searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XComponentSearchBarContainer
|
|
extends XBaseComponentContainer
|
|
implements Readonly<IXComponentSearchBarContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly showSearchBar: XStandardType<boolean> = true;
|
|
|
|
//
|
|
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
readonly searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.color;
|
|
readonly searchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
//
|
|
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchInputColor;
|
|
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundSearchInputColor;
|
|
|
|
//
|
|
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.type;
|
|
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.title;
|
|
readonly searchBarValue: XStandardType<string> = this.propertyProvider.value;
|
|
readonly searchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.enterKeyHint;
|
|
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.keyboardType;
|
|
readonly searchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.spellcheck;
|
|
readonly searchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.debounce;
|
|
|
|
//
|
|
readonly searchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.showCancelButton;
|
|
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.cancelButtonIcon;
|
|
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.cancelButtonTitle;
|
|
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.cancelButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.showClearButton;
|
|
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.clearButtonIcon;
|
|
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.clearButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchButtonIcon;
|
|
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchButtonIconColor;
|
|
|
|
//
|
|
readonly searchBarQueryChange: EventEmitter<string> =
|
|
this.propertyProvider.queryChange;
|
|
readonly searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
|
|
this.propertyProvider.onEvent;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(protected propertyProvider: XSearchBarContainer) {
|
|
super();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XComponentSearchBarContainerComponent
|
|
extends XBaseComponentContainerComponent
|
|
implements IXComponentSearchBarContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
|
|
|
|
//
|
|
@Input()
|
|
searchBarActionProvider: Subject<XSearchBarActionModel> =
|
|
this.propertyProvider.searchBarActionProvider;
|
|
|
|
@Input()
|
|
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.searchBarCssClass;
|
|
|
|
//
|
|
@Input()
|
|
searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
|
|
@Input()
|
|
searchBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchInputColor;
|
|
|
|
@Input()
|
|
searchBarForegroundSearchInputColor: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarForegroundSearchInputColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarType;
|
|
|
|
@Input()
|
|
searchBarTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarTitle;
|
|
|
|
@Input()
|
|
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
|
|
|
|
@Input()
|
|
searchBarEnterKeyHint: XStandardType<string> =
|
|
this.propertyProvider.searchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
|
|
this.propertyProvider.searchBarKeyboardType;
|
|
|
|
@Input()
|
|
searchBarSpellcheck: XStandardType<boolean> =
|
|
this.propertyProvider.searchBarSpellcheck;
|
|
|
|
@Input()
|
|
searchBarDebounce: XStandardType<number> =
|
|
this.propertyProvider.searchBarDebounce;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowCancelButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowCancelButton;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarCancelButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarShowClearButton: XStandardType<string> =
|
|
this.propertyProvider.searchBarShowClearButton;
|
|
|
|
@Input()
|
|
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarClearButtonIconColor;
|
|
|
|
//
|
|
@Input()
|
|
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarSearchButtonIconColor;
|
|
|
|
//
|
|
@Output()
|
|
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Output()
|
|
searchBarOnEvent: EventEmitter<string> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XComponentSearchBarContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXComponentSearchBarContainer
|
|
): Observable<IXComponentSearchBarContainer> {
|
|
return forkJoin({
|
|
//
|
|
showSearchBar: this.getValue(
|
|
container ? container.showSearchBar : this.showSearchBar
|
|
),
|
|
|
|
//
|
|
searchBarCssClass: this.getArrayValue(
|
|
container ? container.searchBarCssClass : this.searchBarCssClass
|
|
),
|
|
|
|
//
|
|
searchBarColor: this.getValue(
|
|
container ? container.searchBarColor : this.searchBarColor
|
|
),
|
|
searchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundColor
|
|
: this.searchBarForegroundColor
|
|
),
|
|
searchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchInputColor
|
|
: this.searchBarSearchInputColor
|
|
),
|
|
searchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.searchBarForegroundSearchInputColor
|
|
: this.searchBarForegroundSearchInputColor
|
|
),
|
|
searchBarType: this.getValue(
|
|
container ? container.searchBarType : this.searchBarType
|
|
),
|
|
searchBarTitle: this.getValue(
|
|
container ? container.searchBarTitle : this.searchBarTitle
|
|
),
|
|
searchBarValue: this.getValue(
|
|
container ? container.searchBarValue : this.searchBarValue
|
|
),
|
|
searchBarEnterKeyHint: this.getValue(
|
|
container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint
|
|
),
|
|
searchBarKeyboardType: this.getValue(
|
|
container ? container.searchBarKeyboardType : this.searchBarKeyboardType
|
|
),
|
|
searchBarSpellcheck: this.getValue(
|
|
container ? container.searchBarSpellcheck : this.searchBarSpellcheck
|
|
),
|
|
searchBarDebounce: this.getValue(
|
|
container ? container.searchBarDebounce : this.searchBarDebounce
|
|
),
|
|
searchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.searchBarShowCancelButton
|
|
: this.searchBarShowCancelButton
|
|
),
|
|
searchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIcon
|
|
: this.searchBarCancelButtonIcon
|
|
),
|
|
searchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonTitle
|
|
: this.searchBarCancelButtonTitle
|
|
),
|
|
searchBarCancelButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarCancelButtonIconColor
|
|
: this.searchBarCancelButtonIconColor
|
|
),
|
|
searchBarShowClearButton: this.getValue(
|
|
container
|
|
? container.searchBarShowClearButton
|
|
: this.searchBarShowClearButton
|
|
),
|
|
searchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIcon
|
|
: this.searchBarClearButtonIcon
|
|
),
|
|
searchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarClearButtonIconColor
|
|
: this.searchBarClearButtonIconColor
|
|
),
|
|
searchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIcon
|
|
: this.searchBarSearchButtonIcon
|
|
),
|
|
searchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.searchBarSearchButtonIconColor
|
|
: this.searchBarSearchButtonIconColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
searchBarActionProvider: container
|
|
? container.searchBarActionProvider
|
|
: this.searchBarActionProvider,
|
|
|
|
//
|
|
searchBarOnEvent: this.searchBarOnEvent,
|
|
searchBarQueryChange: this.searchBarQueryChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide.animation.providers.ts
|
|
|
|
import { XSlideAnimationProvider } from './x-slider.typings';
|
|
|
|
//
|
|
//#region Animations ...
|
|
export const Coverflow: XSlideAnimationProvider = {
|
|
coverflowEffect: {
|
|
rotate: 50,
|
|
stretch: 0,
|
|
depth: 100,
|
|
modifier: 1,
|
|
slideShadows: true
|
|
},
|
|
on: {
|
|
beforeInit() {
|
|
const swiper = this;
|
|
swiper.classNames.push(
|
|
`${swiper.params.containerModifierClass}coverflow`
|
|
);
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
|
|
|
|
swiper.params.watchSlidesProgress = true;
|
|
swiper.originalParams.watchSlidesProgress = true;
|
|
},
|
|
setTranslate() {
|
|
const swiper = this;
|
|
const {
|
|
width: swiperWidth,
|
|
height: swiperHeight,
|
|
slides,
|
|
$wrapperEl,
|
|
slidesSizesGrid
|
|
} = swiper;
|
|
const params = swiper.params.coverflowEffect;
|
|
const isHorizontal = swiper.isHorizontal();
|
|
const transform$$1 = swiper.translate;
|
|
const center = isHorizontal
|
|
? -transform$$1 + swiperWidth / 2
|
|
: -transform$$1 + swiperHeight / 2;
|
|
const rotate = isHorizontal ? params.rotate : -params.rotate;
|
|
const translate = params.depth;
|
|
// Each slide offset from center
|
|
for (let i = 0, length = slides.length; i < length; i += 1) {
|
|
const $slideEl = slides.eq(i);
|
|
const slideSize = slidesSizesGrid[i];
|
|
const slideOffset = $slideEl[0].swiperSlideOffset;
|
|
const offsetMultiplier =
|
|
((center - slideOffset - slideSize / 2) / slideSize) *
|
|
params.modifier;
|
|
|
|
let rotateY = isHorizontal ? rotate * offsetMultiplier : 0;
|
|
let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier;
|
|
// var rotateZ = 0
|
|
let translateZ = -translate * Math.abs(offsetMultiplier);
|
|
|
|
let translateY = isHorizontal ? 0 : params.stretch * offsetMultiplier;
|
|
let translateX = isHorizontal ? params.stretch * offsetMultiplier : 0;
|
|
|
|
// Fix for ultra small values
|
|
if (Math.abs(translateX) < 0.001) {
|
|
translateX = 0;
|
|
}
|
|
if (Math.abs(translateY) < 0.001) {
|
|
translateY = 0;
|
|
}
|
|
if (Math.abs(translateZ) < 0.001) {
|
|
translateZ = 0;
|
|
}
|
|
if (Math.abs(rotateY) < 0.001) {
|
|
rotateY = 0;
|
|
}
|
|
if (Math.abs(rotateX) < 0.001) {
|
|
rotateX = 0;
|
|
}
|
|
|
|
const slideTransform =
|
|
`translate3d(${translateX}px,${translateY}px,${translateZ}px)` +
|
|
` rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
|
|
|
|
$slideEl.transform(slideTransform);
|
|
$slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
|
|
if (params.slideShadows) {
|
|
// Set shadows
|
|
let $shadowBeforeEl = isHorizontal
|
|
? $slideEl.find('.swiper-slide-shadow-left')
|
|
: $slideEl.find('.swiper-slide-shadow-top');
|
|
let $shadowAfterEl = isHorizontal
|
|
? $slideEl.find('.swiper-slide-shadow-right')
|
|
: $slideEl.find('.swiper-slide-shadow-bottom');
|
|
if ($shadowBeforeEl.length === 0) {
|
|
$shadowBeforeEl = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
isHorizontal ? 'left' : 'top'
|
|
}"></div>`
|
|
);
|
|
// $slideEl.append($shadowBeforeEl);
|
|
}
|
|
if ($shadowAfterEl.length === 0) {
|
|
$shadowAfterEl = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
isHorizontal ? 'right' : 'bottom'
|
|
}"></div>`
|
|
);
|
|
// $slideEl.append($shadowAfterEl);
|
|
}
|
|
if ($shadowBeforeEl.length) {
|
|
$shadowBeforeEl[0].style.opacity =
|
|
offsetMultiplier > 0 ? offsetMultiplier : 0;
|
|
}
|
|
if ($shadowAfterEl.length) {
|
|
$shadowAfterEl[0].style.opacity =
|
|
-offsetMultiplier > 0 ? -offsetMultiplier : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set correct perspective for IE10
|
|
if (
|
|
swiper.support.pointerEvents ||
|
|
swiper.support.prefixedPointerEvents
|
|
) {
|
|
const ws = $wrapperEl[0].style;
|
|
ws.perspectiveOrigin = `${center}px 50%`;
|
|
}
|
|
},
|
|
setTransition(duration) {
|
|
const swiper = this;
|
|
swiper.slides
|
|
.transition(duration)
|
|
.find(
|
|
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
|
|
)
|
|
.transition(duration);
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
export const Cube: XSlideAnimationProvider = {
|
|
cubeEffect: {
|
|
shadow: true,
|
|
slideShadows: true,
|
|
shadowOffset: 20,
|
|
shadowScale: 0.94
|
|
},
|
|
on: {
|
|
beforeInit() {
|
|
const swiper = this;
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}cube`);
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
|
|
|
|
const overwriteParams = {
|
|
slidesPerView: 1,
|
|
slidesPerColumn: 1,
|
|
slidesPerGroup: 1,
|
|
watchSlidesProgress: true,
|
|
resistanceRatio: 0,
|
|
spaceBetween: 0,
|
|
centeredSlides: false,
|
|
virtualTranslate: true
|
|
};
|
|
|
|
this.params = Object.assign(this.params, overwriteParams);
|
|
this.originalParams = Object.assign(this.originalParams, overwriteParams);
|
|
},
|
|
setTranslate() {
|
|
const swiper = this;
|
|
const {
|
|
$el,
|
|
$wrapperEl,
|
|
slides,
|
|
width: swiperWidth,
|
|
height: swiperHeight,
|
|
rtlTranslate: rtl,
|
|
size: swiperSize
|
|
} = swiper;
|
|
const params = swiper.params.cubeEffect;
|
|
const isHorizontal = swiper.isHorizontal();
|
|
const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
|
|
let wrapperRotate = 0;
|
|
let $cubeShadowEl;
|
|
if (params.shadow) {
|
|
if (isHorizontal) {
|
|
$cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow');
|
|
if ($cubeShadowEl.length === 0) {
|
|
$cubeShadowEl = swiper.$('<div class="swiper-cube-shadow"></div>');
|
|
$wrapperEl.append($cubeShadowEl);
|
|
}
|
|
$cubeShadowEl.css({ height: `${swiperWidth}px` });
|
|
} else {
|
|
$cubeShadowEl = $el.find('.swiper-cube-shadow');
|
|
if ($cubeShadowEl.length === 0) {
|
|
$cubeShadowEl = swiper.$('<div class="swiper-cube-shadow"></div>');
|
|
$el.append($cubeShadowEl);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < slides.length; i += 1) {
|
|
const $slideEl = slides.eq(i);
|
|
let slideIndex = i;
|
|
if (isVirtual) {
|
|
slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10);
|
|
}
|
|
let slideAngle = slideIndex * 90;
|
|
let round = Math.floor(slideAngle / 360);
|
|
if (rtl) {
|
|
slideAngle = -slideAngle;
|
|
round = Math.floor(-slideAngle / 360);
|
|
}
|
|
const progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
|
|
let tx = 0;
|
|
let ty = 0;
|
|
let tz = 0;
|
|
if (slideIndex % 4 === 0) {
|
|
tx = -round * 4 * swiperSize;
|
|
tz = 0;
|
|
} else if ((slideIndex - 1) % 4 === 0) {
|
|
tx = 0;
|
|
tz = -round * 4 * swiperSize;
|
|
} else if ((slideIndex - 2) % 4 === 0) {
|
|
tx = swiperSize + round * 4 * swiperSize;
|
|
tz = swiperSize;
|
|
} else if ((slideIndex - 3) % 4 === 0) {
|
|
tx = -swiperSize;
|
|
tz = 3 * swiperSize + swiperSize * 4 * round;
|
|
}
|
|
if (rtl) {
|
|
tx = -tx;
|
|
}
|
|
|
|
if (!isHorizontal) {
|
|
ty = tx;
|
|
tx = 0;
|
|
}
|
|
|
|
const transform$$1 = `rotateX(${
|
|
isHorizontal ? 0 : -slideAngle
|
|
}deg) rotateY(${
|
|
isHorizontal ? slideAngle : 0
|
|
}deg) translate3d(${tx}px, ${ty}px, ${tz}px)`;
|
|
if (progress <= 1 && progress > -1) {
|
|
wrapperRotate = slideIndex * 90 + progress * 90;
|
|
if (rtl) {
|
|
wrapperRotate = -slideIndex * 90 - progress * 90;
|
|
}
|
|
}
|
|
$slideEl.transform(transform$$1);
|
|
if (params.slideShadows) {
|
|
// Set shadows
|
|
let shadowBefore = isHorizontal
|
|
? $slideEl.find('.swiper-slide-shadow-left')
|
|
: $slideEl.find('.swiper-slide-shadow-top');
|
|
let shadowAfter = isHorizontal
|
|
? $slideEl.find('.swiper-slide-shadow-right')
|
|
: $slideEl.find('.swiper-slide-shadow-bottom');
|
|
if (shadowBefore.length === 0) {
|
|
shadowBefore = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
isHorizontal ? 'left' : 'top'
|
|
}"></div>`
|
|
);
|
|
$slideEl.append(shadowBefore);
|
|
}
|
|
if (shadowAfter.length === 0) {
|
|
shadowAfter = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
isHorizontal ? 'right' : 'bottom'
|
|
}"></div>`
|
|
);
|
|
$slideEl.append(shadowAfter);
|
|
}
|
|
if (shadowBefore.length) {
|
|
shadowBefore[0].style.opacity = Math.max(-progress, 0);
|
|
}
|
|
if (shadowAfter.length) {
|
|
shadowAfter[0].style.opacity = Math.max(progress, 0);
|
|
}
|
|
}
|
|
}
|
|
$wrapperEl.css({
|
|
'-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`,
|
|
'-moz-transform-origin': `50% 50% -${swiperSize / 2}px`,
|
|
'-ms-transform-origin': `50% 50% -${swiperSize / 2}px`,
|
|
'transform-origin': `50% 50% -${swiperSize / 2}px`
|
|
});
|
|
|
|
if (params.shadow) {
|
|
if (isHorizontal) {
|
|
$cubeShadowEl.transform(
|
|
`translate3d(0px, ${swiperWidth / 2 +
|
|
params.shadowOffset}px, ${-swiperWidth /
|
|
2}px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})`
|
|
);
|
|
} else {
|
|
const shadowAngle =
|
|
Math.abs(wrapperRotate) -
|
|
Math.floor(Math.abs(wrapperRotate) / 90) * 90;
|
|
const multiplier =
|
|
1.5 -
|
|
(Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2 +
|
|
Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2);
|
|
const scale1 = params.shadowScale;
|
|
const scale2 = params.shadowScale / multiplier;
|
|
const offset$$1 = params.shadowOffset;
|
|
$cubeShadowEl.transform(
|
|
`scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight /
|
|
2 +
|
|
offset$$1}px, ${-swiperHeight / 2 / scale2}px) rotateX(-90deg)`
|
|
);
|
|
}
|
|
}
|
|
|
|
const zFactor =
|
|
swiper.browser.isSafari || swiper.browser.isUiWebView
|
|
? -swiperSize / 2
|
|
: 0;
|
|
$wrapperEl.transform(
|
|
`translate3d(0px,0,${zFactor}px) rotateX(${
|
|
swiper.isHorizontal() ? 0 : wrapperRotate
|
|
}deg) rotateY(${swiper.isHorizontal() ? -wrapperRotate : 0}deg)`
|
|
);
|
|
},
|
|
setTransition(duration) {
|
|
const swiper = this;
|
|
const { $el, slides } = swiper;
|
|
slides
|
|
.transition(duration)
|
|
.find(
|
|
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
|
|
)
|
|
.transition(duration);
|
|
if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) {
|
|
$el.find('.swiper-cube-shadow').transition(duration);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
export const Fade: XSlideAnimationProvider = {
|
|
on: {
|
|
beforeInit() {
|
|
const swiper = this;
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}fade`);
|
|
const overwriteParams = {
|
|
slidesPerView: 1,
|
|
slidesPerColumn: 1,
|
|
slidesPerGroup: 1,
|
|
watchSlidesProgress: true,
|
|
spaceBetween: 0,
|
|
virtualTranslate: true
|
|
};
|
|
swiper.params = Object.assign(swiper.params, overwriteParams);
|
|
swiper.params = Object.assign(swiper.originalParams, overwriteParams);
|
|
},
|
|
setTranslate() {
|
|
const swiper = this;
|
|
const { slides } = swiper;
|
|
for (let i = 0; i < slides.length; i += 1) {
|
|
const $slideEl = swiper.slides.eq(i);
|
|
const offset$$1 = $slideEl[0].swiperSlideOffset;
|
|
let tx = -offset$$1;
|
|
if (!swiper.params.virtualTranslate) {
|
|
tx -= swiper.translate;
|
|
}
|
|
let ty = 0;
|
|
if (!swiper.isHorizontal()) {
|
|
ty = tx;
|
|
tx = 0;
|
|
}
|
|
const slideOpacity = swiper.params.fadeEffect.crossFade
|
|
? Math.max(1 - Math.abs($slideEl[0].progress), 0)
|
|
: 1 + Math.min(Math.max($slideEl[0].progress, -1), 0);
|
|
$slideEl
|
|
.css({
|
|
opacity: slideOpacity
|
|
})
|
|
.transform(`translate3d(${tx}px, ${ty}px, 0px)`);
|
|
}
|
|
},
|
|
setTransition(duration) {
|
|
const swiper = this;
|
|
const { slides, $wrapperEl } = swiper;
|
|
slides.transition(duration);
|
|
if (swiper.params.virtualTranslate && duration !== 0) {
|
|
let eventTriggered = false;
|
|
slides.transitionEnd(() => {
|
|
if (eventTriggered) {
|
|
return;
|
|
}
|
|
if (!swiper || swiper.destroyed) {
|
|
return;
|
|
}
|
|
eventTriggered = true;
|
|
swiper.animating = false;
|
|
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
|
|
// tslint:disable-next-line:prefer-for-of
|
|
for (let i = 0; i < triggerEvents.length; i += 1) {
|
|
$wrapperEl.trigger(triggerEvents[i]);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
export const Flip: XSlideAnimationProvider = {
|
|
on: {
|
|
beforeInit() {
|
|
const swiper = this;
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}flip`);
|
|
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
|
|
const overwriteParams = {
|
|
slidesPerView: 1,
|
|
slidesPerColumn: 1,
|
|
slidesPerGroup: 1,
|
|
watchSlidesProgress: true,
|
|
spaceBetween: 0,
|
|
virtualTranslate: true
|
|
};
|
|
swiper.params = Object.assign(swiper.params, overwriteParams);
|
|
swiper.originalParams = Object.assign(
|
|
swiper.originalParams,
|
|
overwriteParams
|
|
);
|
|
},
|
|
setTranslate() {
|
|
const swiper = this;
|
|
const { $, slides, rtlTranslate: rtl } = swiper;
|
|
for (let i = 0; i < slides.length; i += 1) {
|
|
const $slideEl = slides.eq(i);
|
|
let progress = $slideEl[0].progress;
|
|
if (swiper.params.flipEffect.limitRotation) {
|
|
progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
|
|
}
|
|
const offset$$1 = $slideEl[0].swiperSlideOffset;
|
|
const rotate = -180 * progress;
|
|
let rotateY = rotate;
|
|
let rotateX = 0;
|
|
let tx = -offset$$1;
|
|
let ty = 0;
|
|
if (!swiper.isHorizontal()) {
|
|
ty = tx;
|
|
tx = 0;
|
|
rotateX = -rotateY;
|
|
rotateY = 0;
|
|
} else if (rtl) {
|
|
rotateY = -rotateY;
|
|
}
|
|
|
|
$slideEl[0].style.zIndex =
|
|
-Math.abs(Math.round(progress)) + slides.length;
|
|
|
|
if (swiper.params.flipEffect.slideShadows) {
|
|
// Set shadows
|
|
let shadowBefore = swiper.isHorizontal()
|
|
? $slideEl.find('.swiper-slide-shadow-left')
|
|
: $slideEl.find('.swiper-slide-shadow-top');
|
|
let shadowAfter = swiper.isHorizontal()
|
|
? $slideEl.find('.swiper-slide-shadow-right')
|
|
: $slideEl.find('.swiper-slide-shadow-bottom');
|
|
if (shadowBefore.length === 0) {
|
|
shadowBefore = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
swiper.isHorizontal() ? 'left' : 'top'
|
|
}"></div>`
|
|
);
|
|
$slideEl.append(shadowBefore);
|
|
}
|
|
if (shadowAfter.length === 0) {
|
|
shadowAfter = swiper.$(
|
|
`<div class="swiper-slide-shadow-${
|
|
swiper.isHorizontal() ? 'right' : 'bottom'
|
|
}"></div>`
|
|
);
|
|
$slideEl.append(shadowAfter);
|
|
}
|
|
if (shadowBefore.length) {
|
|
shadowBefore[0].style.opacity = Math.max(-progress, 0);
|
|
}
|
|
if (shadowAfter.length) {
|
|
shadowAfter[0].style.opacity = Math.max(progress, 0);
|
|
}
|
|
}
|
|
$slideEl.transform(
|
|
`translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
|
|
);
|
|
}
|
|
},
|
|
setTransition(duration) {
|
|
const swiper = this;
|
|
const { slides, activeIndex, $wrapperEl } = swiper;
|
|
slides
|
|
.transition(duration)
|
|
.find(
|
|
'.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left'
|
|
)
|
|
.transition(duration);
|
|
if (swiper.params.virtualTranslate && duration !== 0) {
|
|
let eventTriggered = false;
|
|
// eslint-disable-next-line
|
|
slides.eq(activeIndex).transitionEnd(function onTransitionEnd() {
|
|
if (eventTriggered) {
|
|
return;
|
|
}
|
|
if (!swiper || swiper.destroyed) {
|
|
return;
|
|
}
|
|
|
|
eventTriggered = true;
|
|
swiper.animating = false;
|
|
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
|
|
// tslint:disable-next-line:prefer-for-of
|
|
for (let i = 0; i < triggerEvents.length; i += 1) {
|
|
$wrapperEl.trigger(triggerEvents[i]);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.html
|
|
|
|
<!-- WrapWithCard Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Template -->
|
|
<ng-template #componentRef>
|
|
<section
|
|
class="x-slider x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<ion-slides
|
|
#slider
|
|
class="slider"
|
|
[options]="sliderConfig"
|
|
[pager]="hasPager() | async"
|
|
[class.no-pager]="hasPager() | async"
|
|
(ionSlideTap)="handleSlideChanged()"
|
|
(ionSlideNextEnd)="handleSlideChanged()"
|
|
(ionSlidePrevEnd)="handleSlideChanged()"
|
|
(ionSlideTouchEnd)="handleSlideChanged()"
|
|
(ionSlideDidChange)="handleSlideChanged()"
|
|
(ionSlideTransitionEnd)="handleSlideChanged()"
|
|
>
|
|
<ng-container *ngFor="let slide of slides">
|
|
<ng-container *ngTemplateOutlet="slide.template"></ng-container>
|
|
</ng-container>
|
|
</ion-slides>
|
|
</section>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.scss
|
|
|
|
:host {
|
|
--paginator: var(--x-color-dark-tint);
|
|
--paginator-active: var(--x-color-secondary);
|
|
}
|
|
|
|
ion-slides {
|
|
--bullet-background: var(--paginator);
|
|
--bullet-background-active: var(--paginator-active);
|
|
}
|
|
|
|
.no-pager {
|
|
padding-bottom: 0 !important;
|
|
}
|
|
|
|
.slider {
|
|
padding-bottom: 30px !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.ts
|
|
|
|
import {
|
|
Component,
|
|
QueryList,
|
|
ViewChild,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XSliderAction,
|
|
XSliderConfig,
|
|
XSliderAnimation,
|
|
XSliderActionModel,
|
|
defaultXSliderConfig,
|
|
XSliderContainerComponent,
|
|
XSliderAnimationIdentifier,
|
|
defaultXSliderPaginationConfig,
|
|
} from './x-slider.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { IonSlides } from '@ionic/angular';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XSlideComponent } from './x-slide/x-slide.component';
|
|
import { Coverflow, Cube, Fade, Flip } from './x-slide.animation.providers';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-slider',
|
|
templateUrl: './x-slider.component.html',
|
|
styleUrls: ['./x-slider.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSliderComponent extends XSliderContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private LAST_ACTIVE_INDEX = 0;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
//#region Slider Config ...
|
|
//
|
|
private SLIDER_CONFIG: any;
|
|
|
|
//
|
|
get sliderConfig() {
|
|
//
|
|
if (!this.SLIDER_CONFIG) {
|
|
this.SLIDER_CONFIG = this.getConfiguration();
|
|
}
|
|
|
|
//
|
|
return this.SLIDER_CONFIG;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Slider ...
|
|
//
|
|
private SLIDER: IonSlides;
|
|
|
|
//
|
|
@ViewChild('slider', { static: false })
|
|
set slider(s: IonSlides) {
|
|
this.SLIDER = s;
|
|
this.handleConfigurationChanged();
|
|
}
|
|
|
|
//
|
|
get slider() {
|
|
return this.SLIDER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Slides ...
|
|
//
|
|
private SLIDES: QueryList<XSlideComponent>;
|
|
|
|
//
|
|
@ContentChildren(XSlideComponent)
|
|
set slides(s: QueryList<XSlideComponent>) {
|
|
this.SLIDES = s;
|
|
this.handleConfigurationChanged();
|
|
}
|
|
|
|
//
|
|
get slides() {
|
|
return this.SLIDES;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XSliderComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
const isConfigChanged = changeKeys.includes(
|
|
nameof<XSliderComponent>('options')
|
|
);
|
|
const isAnimationChanged = changeKeys.includes(
|
|
nameof<XSliderComponent>('animation')
|
|
);
|
|
|
|
//
|
|
if (isConfigChanged || isAnimationChanged) {
|
|
await this.handleConfigurationChanged();
|
|
}
|
|
}
|
|
|
|
afterContentInit() {
|
|
super.afterContentInit();
|
|
|
|
//
|
|
if (this.slider) {
|
|
this.update();
|
|
}
|
|
|
|
//
|
|
this.managerService.dispatchResizeEvent();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Action Providers ...
|
|
hasPager() {
|
|
return this.getValue(this.options).pipe(
|
|
map((options) => options.pagination)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleSlideChanged() {
|
|
//
|
|
if (isNullOrUndefined(this.slider)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const index = await this.slider.getActiveIndex();
|
|
if (index === this.LAST_ACTIVE_INDEX) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.LAST_ACTIVE_INDEX = index;
|
|
this.onSlideChange.emit(index);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Provided Actions ...
|
|
length() {
|
|
return this.slider.length();
|
|
}
|
|
|
|
getActiveIndex() {
|
|
return this.slider.getActiveIndex();
|
|
}
|
|
|
|
getPreviousIndex() {
|
|
return this.slider.getPreviousIndex();
|
|
}
|
|
|
|
getSwiper() {
|
|
return this.slider.getSwiper();
|
|
}
|
|
|
|
isBeginning() {
|
|
return this.slider.isBeginning();
|
|
}
|
|
|
|
isEnd() {
|
|
return this.slider.isEnd();
|
|
}
|
|
|
|
lockSwipeToNext(lock: boolean) {
|
|
return this.slider.lockSwipeToNext(lock);
|
|
}
|
|
|
|
lockSwipeToPrev(lock: boolean) {
|
|
return this.slider.lockSwipeToPrev(lock);
|
|
}
|
|
|
|
lockSwipes(lock: boolean) {
|
|
return this.slider.lockSwipes(lock);
|
|
}
|
|
|
|
slideNext(speed?: number, runCallbacks?: boolean) {
|
|
return this.slider.slideNext(speed, runCallbacks);
|
|
}
|
|
|
|
slidePrev(speed?: number, runCallbacks?: boolean) {
|
|
return this.slider.slidePrev(speed, runCallbacks);
|
|
}
|
|
|
|
slideTo(index: number, speed?: number, runCallbacks?: boolean) {
|
|
return this.slider.slideTo(index, speed, runCallbacks);
|
|
}
|
|
|
|
startAutoplay() {
|
|
return this.slider.startAutoplay();
|
|
}
|
|
|
|
stopAutoplay() {
|
|
return this.slider.stopAutoplay();
|
|
}
|
|
|
|
update() {
|
|
return this.slider.update();
|
|
}
|
|
|
|
updateAutoHeight() {
|
|
return this.slider.updateAutoHeight();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSliderActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSliderAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async handleConfigurationChanged() {
|
|
//
|
|
const anim = await this.getValueAsync(this.animation);
|
|
const options = await this.getValueAsync(this.options);
|
|
|
|
//
|
|
this.SLIDER_CONFIG = this.getConfiguration(anim, options);
|
|
}
|
|
|
|
private getConfiguration(
|
|
animation?: XSliderAnimationIdentifier,
|
|
config?: XSliderConfig
|
|
) {
|
|
//
|
|
let result: XSliderConfig;
|
|
|
|
//
|
|
if (isNullOrEmptyString(animation)) {
|
|
animation = XSliderAnimation.Coverflow;
|
|
}
|
|
|
|
//
|
|
if (!config) {
|
|
config = defaultXSliderConfig;
|
|
}
|
|
|
|
//
|
|
result = {
|
|
...defaultXSliderConfig,
|
|
...config,
|
|
speed:
|
|
config.speed && config.speed <= 15000 && config.speed >= 500
|
|
? config.speed
|
|
: defaultXSliderConfig.speed,
|
|
initialSlide:
|
|
this.slides &&
|
|
config.initialSlide <= this.slides.length &&
|
|
config.initialSlide >= 0
|
|
? config.initialSlide
|
|
: defaultXSliderConfig.initialSlide,
|
|
};
|
|
|
|
//
|
|
switch (animation) {
|
|
case XSliderAnimation.Coverflow:
|
|
result = {
|
|
...result,
|
|
...Coverflow,
|
|
};
|
|
break;
|
|
|
|
case XSliderAnimation.Cube:
|
|
result = {
|
|
...result,
|
|
...Cube,
|
|
};
|
|
break;
|
|
|
|
case XSliderAnimation.Fade:
|
|
result = {
|
|
...result,
|
|
...Fade,
|
|
};
|
|
break;
|
|
|
|
case XSliderAnimation.Flip:
|
|
result = {
|
|
...result,
|
|
...Flip,
|
|
};
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (result.pagination) {
|
|
result.pagination = defaultXSliderPaginationConfig;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XSliderComponent } from './x-slider.component';
|
|
import { XSlideComponent } from './x-slide/x-slide.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XSliderComponent, XSlideComponent],
|
|
imports: [XCardModule, CommonModule, XBaseComponentModule, XIconModule],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XSlideComponent,
|
|
XSliderComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XSliderModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XSliderAnimation {
|
|
Coverflow = 'coverflow',
|
|
Cube = 'cube',
|
|
Fade = 'fade',
|
|
Flip = 'flip',
|
|
}
|
|
|
|
export type XSliderAnimationIdentifier = XSliderAnimation | string;
|
|
|
|
export interface XSlideAnimationProvider {
|
|
[key: string]: any;
|
|
on: {
|
|
[key: string]: any;
|
|
beforeInit?: () => void;
|
|
setTranslate?: () => void;
|
|
setTransition?: (duration?: number) => void;
|
|
};
|
|
}
|
|
|
|
export interface XSliderPaginationConfig {
|
|
el: string;
|
|
type: string;
|
|
clickable: boolean;
|
|
}
|
|
|
|
export type XSliderPagination = XSliderPaginationConfig | boolean;
|
|
|
|
export const defaultXSliderPaginationConfig: XSliderPaginationConfig = {
|
|
el: '.swiper-pagination',
|
|
type: 'bullets',
|
|
clickable: true,
|
|
};
|
|
|
|
export interface XSliderConfig {
|
|
lazy: boolean;
|
|
zoom: boolean;
|
|
autoplay: boolean;
|
|
initialSlide: number;
|
|
grabCursor: boolean;
|
|
autoHeight: boolean;
|
|
slidesPerView: number;
|
|
loadPrevNext: boolean;
|
|
preventClicks: boolean;
|
|
pagination: XSliderPagination;
|
|
speed: number;
|
|
on?: any;
|
|
}
|
|
|
|
export const defaultXSliderConfig: XSliderConfig = {
|
|
lazy: true,
|
|
zoom: true,
|
|
autoplay: true,
|
|
initialSlide: 0,
|
|
grabCursor: true,
|
|
autoHeight: true,
|
|
slidesPerView: 1,
|
|
loadPrevNext: true,
|
|
preventClicks: false,
|
|
speed: 400,
|
|
pagination: true,
|
|
};
|
|
|
|
export enum XSliderAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSliderActionIdentifier = XSliderAction | string;
|
|
|
|
export interface XSliderActionModel
|
|
extends XBaseActionModel<XSliderActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXSliderContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XSliderActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
options: XStandardType<XSliderConfig>;
|
|
animation: XStandardType<XSliderAnimationIdentifier>;
|
|
|
|
//
|
|
onSlideChange: EventEmitter<number>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XSliderContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXSliderContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XSliderActionModel> =
|
|
new Subject<XSliderActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly options: XStandardType<XSliderConfig> = defaultXSliderConfig;
|
|
readonly animation: XStandardType<XSliderAnimationIdentifier> =
|
|
XSliderAnimation.Coverflow;
|
|
|
|
//
|
|
readonly onSlideChange = new EventEmitter<number>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSliderContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXSliderContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XSliderActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
options: XStandardType<XSliderConfig> = this.propertyProvider.options;
|
|
|
|
@Input()
|
|
animation: XStandardType<XSliderAnimationIdentifier> =
|
|
this.propertyProvider.animation;
|
|
|
|
//
|
|
@Output()
|
|
onSlideChange: EventEmitter<number> = this.propertyProvider.onSlideChange;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSliderContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSliderContainer
|
|
): Observable<IXSliderContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
options: this.getValue(
|
|
container ? container.options : this.options
|
|
),
|
|
animation: this.getValue(
|
|
container ? container.animation : this.animation
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
onSlideChange: container
|
|
? container.onSlideChange
|
|
: this.onSlideChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.html
|
|
|
|
<ng-template #content>
|
|
<ion-slide>
|
|
<div class="full-width">
|
|
<ng-content></ng-content>
|
|
</div>
|
|
</ion-slide>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.scss
|
|
|
|
.full-width {
|
|
width: 100%;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
TemplateRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XSlideAction,
|
|
XSlideActionModel,
|
|
XSlideContainerComponent,
|
|
} from './x-slide.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-slide',
|
|
templateUrl: './x-slide.component.html',
|
|
styleUrls: ['./x-slide.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSlideComponent extends XSlideContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
@ViewChild('content', { static: true })
|
|
template!: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XSlideComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSlideActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSlideAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
NgZone,
|
|
Inject,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XSlideAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSlideActionIdentifier = XSlideAction | string;
|
|
|
|
export interface XSlideActionModel
|
|
extends XBaseActionModel<XSlideActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXSlideContainer extends IXBaseContainer {
|
|
actionProvider: Subject<XSlideActionModel>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XSlideContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXSlideContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
actionProvider: Subject<XSlideActionModel> = new Subject<XSlideActionModel>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSlideContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXSlideContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XSlideActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSlideContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSlideContainer
|
|
): Observable<IXSlideContainer> {
|
|
return forkJoin({
|
|
//
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
// //
|
|
// ...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.html
|
|
|
|
<div
|
|
class="x-slotter x-wrapper"
|
|
[fxLayout]="getLayout() | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<!-- Chack Has Slots -->
|
|
<ng-container *ngIf="hasSlots()">
|
|
<div
|
|
fxFlex
|
|
class="x-start-top-slot"
|
|
*ngIf="getHasStartOrTopSlot() | async"
|
|
[ngClass]="getValue(startTopSlotCssClass) | async"
|
|
>
|
|
<!-- Start / Top -->
|
|
<ng-container *ngFor="let slot of startOrTopSlots">
|
|
<div
|
|
class="x-start-top-slot-inner-container"
|
|
[ngClass]="getValue(slot.cssClass) | async"
|
|
*ngIf="notNullOrUndefinedValue(slot.content) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- Center -->
|
|
<div
|
|
fxFlex
|
|
class="x-center-slot"
|
|
*ngIf="getHasCenterSlot() | async"
|
|
[ngClass]="getValue(centerSlotCssClass) | async"
|
|
>
|
|
<ng-container *ngFor="let slot of cneterSlots">
|
|
<div
|
|
class="x-center-slot-inner-container"
|
|
[ngClass]="getValue(slot.cssClass) | async"
|
|
*ngIf="notNullOrUndefinedValue(slot.content) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
|
|
<!-- end / Bottom -->
|
|
<div
|
|
fxFlex
|
|
class="x-end-bottom-slot"
|
|
*ngIf="getHasEndOrBottomSlot() | async"
|
|
[ngClass]="getValue(endBottomSlotCssClass) | async"
|
|
>
|
|
<ng-container *ngFor="let slot of endOrBottomSlots">
|
|
<div
|
|
class="x-end-bottom-slot-inner-container"
|
|
[ngClass]="getValue(slot.cssClass) | async"
|
|
*ngIf="notNullOrUndefinedValue(slot.content) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
</ng-container>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.ts
|
|
|
|
import {
|
|
Component,
|
|
QueryList,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XSlotName,
|
|
XSlotLayout,
|
|
XSlotterAction,
|
|
XSlotterActionModel,
|
|
XSlotterContainerComponent,
|
|
} from './x-slotter.typings';
|
|
import { map } from 'rxjs/operators';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XSlotComponent } from './x-slot/x-slot.component';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-slotter',
|
|
templateUrl: './x-slotter.component.html',
|
|
styleUrls: ['./x-slotter.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSlotterComponent extends XSlotterContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
//#region Slots Props ...
|
|
//
|
|
private SLOTS: QueryList<XSlotComponent>;
|
|
|
|
//
|
|
@ContentChildren(XSlotComponent)
|
|
set slots(s: QueryList<XSlotComponent>) {
|
|
//
|
|
this.SLOTS = s;
|
|
this.prepareSlots();
|
|
}
|
|
|
|
//
|
|
get slots() {
|
|
return this.SLOTS;
|
|
}
|
|
|
|
//
|
|
startOrTopSlots: XSlotComponent[] = [];
|
|
cneterSlots: XSlotComponent[] = [];
|
|
endOrBottomSlots: XSlotComponent[] = [];
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XSlotterComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Providers ...
|
|
hasSlots() {
|
|
return this.slots && this.slots.length > 0;
|
|
}
|
|
|
|
getHasCenterSlot() {
|
|
return this.applyTakeUntilWrapper(this.getValue(this.hasCenterSlot));
|
|
}
|
|
|
|
getHasStartOrTopSlot() {
|
|
return this.applyTakeUntilWrapper(this.getValue(this.hasStartOrTopSlot));
|
|
}
|
|
|
|
getHasEndOrBottomSlot() {
|
|
return this.applyTakeUntilWrapper(this.getValue(this.hasEndOrBottomSlot));
|
|
}
|
|
|
|
isLayoutHorizontal() {
|
|
return this.getValue(this.layout).pipe(
|
|
map((layout) => layout === XSlotLayout.HORIZONTAL)
|
|
);
|
|
}
|
|
|
|
isLayoutVertical() {
|
|
return this.getValue(this.layout).pipe(
|
|
map((layout) => layout === XSlotLayout.VERTICAL)
|
|
);
|
|
}
|
|
|
|
getLayout() {
|
|
return this.getValue(this.layout).pipe(
|
|
map((layout) => {
|
|
return layout === XSlotLayout.VERTICAL ? 'column' : 'row';
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSlotterActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSlotterAction.Refresh:
|
|
await this.prepareSlots();
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareSlots() {
|
|
//
|
|
this.startOrTopSlots = [];
|
|
this.cneterSlots = [];
|
|
this.endOrBottomSlots = [];
|
|
|
|
//
|
|
this.detectChanges();
|
|
|
|
//
|
|
if (!this.hasSlots()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.slots.forEach(async (slot) => {
|
|
//
|
|
const name = await this.getValueAsync(slot.name);
|
|
switch (name) {
|
|
case XSlotName.START:
|
|
this.startOrTopSlots.push(slot);
|
|
break;
|
|
|
|
case XSlotName.TOP:
|
|
this.startOrTopSlots.push(slot);
|
|
break;
|
|
|
|
case XSlotName.CENTER:
|
|
this.cneterSlots.push(slot);
|
|
break;
|
|
|
|
case XSlotName.END:
|
|
this.endOrBottomSlots.push(slot);
|
|
break;
|
|
|
|
case XSlotName.BOTTOM:
|
|
this.endOrBottomSlots.push(slot);
|
|
break;
|
|
}
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XSlotterComponent } from './x-slotter.component';
|
|
import { XSlotComponent } from './x-slot/x-slot.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XSlotterComponent, XSlotComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XSlotterComponent, XSlotComponent]
|
|
})
|
|
export class XSlotterModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XSlotName {
|
|
START = 'start',
|
|
END = 'end',
|
|
CENTER = 'center',
|
|
TOP = 'top',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XSlotNameIdentifier = XSlotName | string;
|
|
|
|
export enum XSlotLayout {
|
|
HORIZONTAL = 'horizontal',
|
|
VERTICAL = 'vertical',
|
|
}
|
|
|
|
export type XSlotLayoutIdentifier = XSlotLayout | string;
|
|
|
|
export enum XSlotterAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSlotterActionIdentifier = XSlotterAction | string;
|
|
|
|
export interface XSlotterActionModel
|
|
extends XBaseActionModel<XSlotterActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXSlotterContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XSlotterActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
layout: XStandardType<XSlotLayoutIdentifier>;
|
|
|
|
//
|
|
hasStartOrTopSlot: XStandardType<boolean>;
|
|
startTopSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
hasCenterSlot: XStandardType<boolean>;
|
|
centerSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
hasEndOrBottomSlot: XStandardType<boolean>;
|
|
endBottomSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XSlotterContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXSlotterContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XSlotterActionModel>;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly layout: XStandardType<XSlotLayoutIdentifier> =
|
|
XSlotLayout.HORIZONTAL;
|
|
|
|
//
|
|
readonly hasStartOrTopSlot: XStandardType<boolean> = true;
|
|
readonly startTopSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly hasCenterSlot: XStandardType<boolean> = true;
|
|
readonly centerSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly hasEndOrBottomSlot: XStandardType<boolean> = true;
|
|
readonly endBottomSlotCssClass: XStandardType<XOneOrManyType<string>>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSlotterContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXSlotterContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XSlotterActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
layout: XStandardType<XSlotLayoutIdentifier> = this.propertyProvider.layout;
|
|
|
|
//
|
|
@Input()
|
|
hasStartOrTopSlot: XStandardType<boolean> =
|
|
this.propertyProvider.hasStartOrTopSlot;
|
|
|
|
@Input()
|
|
startTopSlotCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.startTopSlotCssClass;
|
|
|
|
//
|
|
@Input()
|
|
hasCenterSlot: XStandardType<boolean> = this.propertyProvider.hasCenterSlot;
|
|
|
|
@Input()
|
|
centerSlotCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.centerSlotCssClass;
|
|
|
|
//
|
|
@Input()
|
|
hasEndOrBottomSlot: XStandardType<boolean> =
|
|
this.propertyProvider.hasEndOrBottomSlot;
|
|
|
|
@Input()
|
|
endBottomSlotCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.endBottomSlotCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSlotterContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSlotterContainer
|
|
): Observable<IXSlotterContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
layout: this.getValue(container ? container.layout : this.layout),
|
|
hasStartOrTopSlot: this.getValue(
|
|
container ? container.hasStartOrTopSlot : this.hasStartOrTopSlot
|
|
),
|
|
startTopSlotCssClass: this.getValue(
|
|
container ? container.startTopSlotCssClass : this.startTopSlotCssClass
|
|
),
|
|
hasCenterSlot: this.getValue(
|
|
container ? container.hasCenterSlot : this.hasCenterSlot
|
|
),
|
|
centerSlotCssClass: this.getValue(
|
|
container ? container.centerSlotCssClass : this.centerSlotCssClass
|
|
),
|
|
hasEndOrBottomSlot: this.getValue(
|
|
container ? container.hasEndOrBottomSlot : this.hasEndOrBottomSlot
|
|
),
|
|
endBottomSlotCssClass: this.getValue(
|
|
container ? container.endBottomSlotCssClass : this.endBottomSlotCssClass
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.html
|
|
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.ts
|
|
|
|
import {
|
|
XSlotAction,
|
|
XSlotActionModel,
|
|
XSlotContainerComponent,
|
|
} from './x-slot.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ViewChild, TemplateRef } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-slot',
|
|
templateUrl: './x-slot.component.html',
|
|
styleUrls: ['./x-slot.component.scss'],
|
|
// changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSlotComponent extends XSlotContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
content: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XSlotComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSlotActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSlotAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XSlotNameIdentifier } from '../x-slotter.typings';
|
|
import { XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XSlotAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSlotActionIdentifier = XSlotAction | string;
|
|
|
|
export interface XSlotActionModel
|
|
extends XBaseActionModel<XSlotActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXSlotContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XSlotActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
name: XStandardType<XSlotNameIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XSlotContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXSlotContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider = new Subject<XSlotActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly name: XStandardType<XSlotNameIdentifier>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSlotContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXSlotContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XSlotActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
name: XStandardType<XSlotNameIdentifier> = this.propertyProvider.name;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSlotContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSlotContainer
|
|
): Observable<IXSlotContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
name: this.getValue(container ? container.name : this.name),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.html
|
|
|
|
<ion-spinner
|
|
[isForeground]="true"
|
|
[name]="getValue(name) | async"
|
|
[xColor]="getValue(color) | async"
|
|
[paused]="getValue(paused) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[duration]="getValue(duration) | async"
|
|
class="x-spinner x-wrapper ion-no-margin ion-no-padding ion-no-border"
|
|
></ion-spinner>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.scss
|
|
|
|
:host {
|
|
display: inline-block;
|
|
position: relative;
|
|
width: 28px;
|
|
height: 28px;
|
|
}
|
|
|
|
ion-spinner {
|
|
display: inline-block;
|
|
position: relative;
|
|
width: 28px;
|
|
height: 28px;
|
|
}
|
|
|
|
.x-spinner {
|
|
direction: ltr !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.ts
|
|
|
|
import {
|
|
XSpinnerAction,
|
|
XSpinnerActionModel,
|
|
XSpinnerContainerComponent,
|
|
} from './x-spinner.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-spinner',
|
|
templateUrl: './x-spinner.component.html',
|
|
styleUrls: ['./x-spinner.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XSpinnerComponent extends XSpinnerContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XSpinnerComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XSpinnerActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XSpinnerAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XSpinnerComponent } from './x-spinner.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XSpinnerComponent],
|
|
imports: [CommonModule, XBaseComponentModule],
|
|
exports: [XBaseComponentModule, XSpinnerComponent]
|
|
})
|
|
export class XSpinnerModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XSpinner,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XSpinnerIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XSpinnerAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XSpinnerActionIdentifier = XSpinnerAction | string;
|
|
|
|
export interface XSpinnerActionModel
|
|
extends XBaseActionModel<XSpinnerActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXSpinnerContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XSpinnerActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
name: XStandardType<XSpinnerIdentifier>;
|
|
duration: XStandardType<number>;
|
|
color: XStandardType<XColorIdentifier>;
|
|
paused: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XSpinnerContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXSpinnerContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XSpinnerActionModel>;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly name: XStandardType<XSpinnerIdentifier> = XSpinner.Circular;
|
|
readonly duration: XStandardType<number> = undefined;
|
|
readonly color: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.SecondaryShade;
|
|
readonly paused: XStandardType<boolean> = false;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XSpinnerContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXSpinnerContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XSpinnerActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
name: XStandardType<XSpinnerIdentifier> = this.propertyProvider.name;
|
|
|
|
@Input()
|
|
duration: XStandardType<number> = this.propertyProvider.duration;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
paused: XStandardType<boolean> = this.propertyProvider.paused;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XSpinnerContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXSpinnerContainer
|
|
): Observable<IXSpinnerContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
|
|
//
|
|
name: this.getValue(container ? container.name : this.name),
|
|
duration: this.getValue(container ? container.duration : this.duration),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
paused: this.getValue(container ? container.paused : this.paused),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else wrapperRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="wrapperRef"></ng-container>
|
|
|
|
<!-- Actions -->
|
|
<div class="x-actions" actions>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Components itSelf Template -->
|
|
<ng-template #wrapperRef>
|
|
<!-- Stepper Element -->
|
|
<div
|
|
class="x-stepper x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[class.disableHeader]="!(getValue(selectableHeaders) | async)"
|
|
>
|
|
<!-- Mat Stepper -->
|
|
<mat-stepper
|
|
#stepper
|
|
[orientation]="getOrientation() | async"
|
|
[selectedIndex]="getValue(selectedIndex) | async"
|
|
[labelPosition]="getLabelPositionValue() | async"
|
|
(selectionChange)="handleSelectionChanged($event)"
|
|
>
|
|
<!-- Icons Templates -->
|
|
<ng-template matStepperIcon="number" let-index="index">
|
|
{{ applyLocale(index + 1) }}
|
|
</ng-template>
|
|
<ng-template matStepperIcon="edit" let-index="index">
|
|
{{ applyLocale(index + 1) }}
|
|
</ng-template>
|
|
|
|
<!-- Steps -->
|
|
<!-- Check Has Steps -->
|
|
<ng-container *ngIf="hasSteps()">
|
|
<ng-container *ngFor="let step of steps">
|
|
<!-- Step Implementation -->
|
|
<mat-step [attr.stepperId]="step.id">
|
|
<!-- Step Label -->
|
|
<ng-template matStepLabel *ngIf="getValue(showLabel) | async">
|
|
<ng-container *ngTemplateOutlet="step.label"></ng-container>
|
|
</ng-template>
|
|
|
|
<!-- Step Content Representation -->
|
|
<ng-container *ngTemplateOutlet="step.content"></ng-container>
|
|
|
|
<!-- Step Buttons -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
stepperActionsRef;
|
|
context: { stepper: stepper, step: step }
|
|
"
|
|
></ng-container>
|
|
</mat-step>
|
|
</ng-container>
|
|
</ng-container>
|
|
</mat-stepper>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Actions Template -->
|
|
<ng-template #stepperActionsRef let-stepper="stepper" let-step="step">
|
|
<!-- Step Buttons -->
|
|
<div class="x-step-actions">
|
|
<x-slotter *ngIf="hasActions(step) | async">
|
|
<!-- Next -->
|
|
<x-slot
|
|
[name]="getValue(step.nextPosition) | async"
|
|
[cssClass]="getValue(step.nextCssClass) | async"
|
|
>
|
|
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Next) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
stepper: stepper,
|
|
step: step,
|
|
type: NPRButtonTypes.Next
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Reset -->
|
|
<x-slot
|
|
[name]="getValue(step.resetPosition) | async"
|
|
[cssClass]="getValue(step.resetCssClass) | async"
|
|
>
|
|
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Reset) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
stepper: stepper,
|
|
step: step,
|
|
type: NPRButtonTypes.Reset
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
|
|
<!-- Prev -->
|
|
<x-slot
|
|
[name]="getValue(step.prevPosition) | async"
|
|
[cssClass]="getValue(step.prevCssClass) | async"
|
|
>
|
|
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Prev) | async">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
buttonRef;
|
|
context: {
|
|
stepper: stepper,
|
|
step: step,
|
|
type: NPRButtonTypes.Prev
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ng-container>
|
|
</x-slot>
|
|
</x-slotter>
|
|
|
|
<!-- Specified Actions -->
|
|
<div
|
|
class="x-step-custom-actions-wrapper"
|
|
*ngIf="getValue(step.hasCustomActions) | async"
|
|
>
|
|
<ng-container *ngTemplateOutlet="step.actions"></ng-container>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Button Template -->
|
|
<ng-template #buttonRef let-stepper="stepper" let-step="step" let-type="type">
|
|
<x-button
|
|
[icon]="getButtonIcon(step, type) | async"
|
|
[type]="getButtonType(step, type) | async"
|
|
[title]="getButtonTitle(step, type) | async"
|
|
[color]="getButtonColor(step, type) | async"
|
|
(clicked)="handleNPRStep(stepper, step, type)"
|
|
[cssClass]="getButtonCssClass(step, type) | async"
|
|
[uiDisabled]="getButtonDisabled(step, type) | async"
|
|
[iconColor]="getButtonIconColor(step, type) | async"
|
|
[class.disabled]="getButtonDisabled(step, type) | async"
|
|
[iconPosition]="getButtonIconPosition(step, type) | async"
|
|
[foregroundColor]="getButtonForegroundColor(step, type) | async"
|
|
></x-button>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.scss
|
|
|
|
:host {
|
|
//
|
|
// TODO: add and handle cssVariable and color applier ...
|
|
--icon-background-color: var(--x-color-tertiary);
|
|
--icon-foreground-color: var(--x-color-tertiary-contrast);
|
|
--title-foreground-color: var(--x-color-secondary);
|
|
--header-background-color: var(--x-color-light);
|
|
--header-foreground-color: var(--x-color-light-contrast);
|
|
}
|
|
|
|
:host(::ng-deep.disableHeader) {
|
|
.mat-step-header {
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep .mat-step-header,
|
|
:host ::ng-deep .mat-stepper-vertical,
|
|
:host ::ng-deep .mat-stepper-horizontal,
|
|
:host ::ng-deep .mat-horizontal-stepper-header-container {
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
:host ::ng-deep .mat-step-icon {
|
|
color: var(--icon-foreground-color) !important;
|
|
background-color: var(--icon-background-color) !important;
|
|
}
|
|
|
|
:host ::ng-deep .mat-step-label,
|
|
:host ::ng-deep .mat-step-header {
|
|
color: var(--header-foreground-color) !important;
|
|
background-color: var(--header-background-color) !important;
|
|
}
|
|
|
|
:host ::ng-deep .mat-step-label {
|
|
color: var(--title-foreground-color) !important;
|
|
}
|
|
|
|
:host ::ng-deep .mat-vertical-stepper-header {
|
|
padding: {
|
|
top: 4px;
|
|
bottom: 4px;
|
|
}
|
|
}
|
|
|
|
//
|
|
$transition: opacity;
|
|
$duration: 500ms;
|
|
$delay: 0;
|
|
button {
|
|
//
|
|
transition: $transition;
|
|
-webkit-transition: $transition;
|
|
|
|
//
|
|
transition-delay: $delay;
|
|
-webkit-transition-delay: $delay;
|
|
|
|
//
|
|
transition-duration: $duration;
|
|
-webkit-transition-duration: $duration;
|
|
}
|
|
|
|
.x-step-actions {
|
|
button {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.ts
|
|
|
|
import {
|
|
ViewChild,
|
|
Component,
|
|
QueryList,
|
|
ContentChildren,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
mergeList,
|
|
parseXColor,
|
|
XStandardType,
|
|
isNullOrEmptyString,
|
|
XColorWithBrightness,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XStepperType,
|
|
XStepperAction,
|
|
XStepperCssVars,
|
|
XStepperActionModel,
|
|
XStepperLabelPosition,
|
|
XStepperContainerComponent,
|
|
} from './x-stepper.typings';
|
|
import {
|
|
StepperOrientation,
|
|
StepperSelectionEvent,
|
|
STEPPER_GLOBAL_OPTIONS,
|
|
} from '@angular/cdk/stepper';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { MatStepper } from '@angular/material/stepper';
|
|
import { Observable, Subject, Subscription } from 'rxjs';
|
|
import { XStepComponent } from './x-step/x-step.component';
|
|
import { XButtonType } from '../x-button/x-button.typings';
|
|
import { XSlotName } from '../x-slotter/x-slotter.typings';
|
|
import { XNPRButtonType } from '../classes/i-x-next-prev-reset.container';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-stepper',
|
|
templateUrl: './x-stepper.component.html',
|
|
styleUrls: ['./x-stepper.component.scss'],
|
|
providers: [
|
|
{
|
|
provide: STEPPER_GLOBAL_OPTIONS,
|
|
useValue: { showError: true },
|
|
},
|
|
],
|
|
})
|
|
export class XStepperComponent extends XStepperContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly NPRButtonTypes = Object.assign({}, XNPRButtonType);
|
|
|
|
//
|
|
@ViewChild('stepper', { static: false })
|
|
private stepper: MatStepper;
|
|
|
|
//
|
|
selected: string;
|
|
// applyThemeColors = true;
|
|
|
|
//
|
|
//#region Steps Props ...
|
|
//
|
|
private STEPS: QueryList<XStepComponent>;
|
|
|
|
//
|
|
@ContentChildren(XStepComponent)
|
|
set steps(s: QueryList<XStepComponent>) {
|
|
//
|
|
if (!s) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.STEPS = s;
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
get steps() {
|
|
return this.STEPS;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XStepperComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Colors Changed ...
|
|
//
|
|
const isIconColorChanged = changeKeys.includes(
|
|
nameof<XStepperComponent>('iconColor')
|
|
);
|
|
if (isIconColorChanged) {
|
|
await this.applyIconColor();
|
|
}
|
|
|
|
//
|
|
const isTitleColorChanged = changeKeys.includes(
|
|
nameof<XStepperComponent>('titleColor')
|
|
);
|
|
if (isTitleColorChanged) {
|
|
await this.applyTitleColor();
|
|
}
|
|
|
|
//
|
|
const isHeaderColorChanged = changeKeys.includes(
|
|
nameof<XStepperComponent>('headerColor')
|
|
);
|
|
if (isHeaderColorChanged) {
|
|
await this.applyeaderColor();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerInstanceHandlers() {
|
|
super.registerInstanceHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
//#region TypeDetectors ...
|
|
getOrientation() {
|
|
return this.getValue(this.type).pipe(
|
|
map((result) => result as StepperOrientation)
|
|
);
|
|
}
|
|
|
|
isTypeHorizontal() {
|
|
return this.getValue(this.type).pipe(
|
|
map((type) => type === XStepperType.HORIZONTAL)
|
|
);
|
|
}
|
|
|
|
isTypeVertical() {
|
|
return this.getValue(this.type).pipe(
|
|
map((type) => type === XStepperType.VERTICAL)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
getLabelPositionValue(): Observable<'bottom' | 'end'> {
|
|
return this.getValue(this.labelPosition).pipe(
|
|
map((position) =>
|
|
position === XStepperLabelPosition.END ? 'end' : 'bottom'
|
|
)
|
|
);
|
|
}
|
|
|
|
//
|
|
hasSteps() {
|
|
return this.steps && this.steps.length > 0 ? true : false;
|
|
}
|
|
|
|
hasActions(step: XStepComponent) {
|
|
return this.getValue(step.hasNext).pipe(
|
|
concatMap((hasNext) =>
|
|
this.getValue(step.hasPrev).pipe(
|
|
map((hasPrev) => {
|
|
return {
|
|
hasNext,
|
|
hasPrev,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
concatMap((hasNextPrev) =>
|
|
this.getValue(step.hasReset).pipe(
|
|
map((hasReset) => {
|
|
return {
|
|
...hasNextPrev,
|
|
hasReset,
|
|
};
|
|
})
|
|
)
|
|
),
|
|
map((info) => info.hasNext || info.hasPrev || info.hasReset)
|
|
);
|
|
}
|
|
|
|
//
|
|
//#region Button Providers ...
|
|
hasStepAction(step: XStepComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getOptionalValue(this.hasNext).pipe(
|
|
concatMap((cHas) =>
|
|
this.getOptionalValue(step.hasNext).pipe(
|
|
map((sHas) => cHas || sHas)
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getOptionalValue(this.hasPrev).pipe(
|
|
concatMap((cHas) =>
|
|
this.getOptionalValue(step.hasPrev).pipe(
|
|
map((sHas) => cHas || sHas)
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getOptionalValue(this.hasReset).pipe(
|
|
concatMap((cHas) =>
|
|
this.getOptionalValue(step.hasReset).pipe(
|
|
map((sHas) => cHas || sHas)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
getButtonIcon(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.icon
|
|
? this.getValue(btns.s.icon)
|
|
: this.getValue(btns.c.icon)
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonType(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.type
|
|
? this.getValue(btns.s.type)
|
|
: this.getValue(btns.c.type)
|
|
),
|
|
map((btnType) =>
|
|
!isNullOrEmptyString(btnType) ? btnType : XButtonType.Raised
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonTitle(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.title
|
|
? this.getResourceValue(btns.s.title)
|
|
: this.getResourceValue(btns.c.title)
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonColor(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.color
|
|
? this.getValue(btns.s.color)
|
|
: this.getValue(btns.c.color)
|
|
),
|
|
map((btnColor) =>
|
|
!isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonIconColor(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.iconColor
|
|
? this.getValue(btns.s.iconColor)
|
|
: this.getValue(btns.c.iconColor)
|
|
),
|
|
map((btnColor) =>
|
|
!isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonDisabled(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtonDisabled(step, type);
|
|
}
|
|
|
|
getButtonCssClass(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
this.getArrayValue(btns.s.cssClass).pipe(
|
|
concatMap((sCss) =>
|
|
this.getArrayValue(btns.c.cssClass).pipe(
|
|
map((cCss) => mergeList(sCss, cCss))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonIconPosition(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.iconPosition
|
|
? this.getValue(btns.s.iconPosition)
|
|
: this.getValue(btns.c.iconPosition)
|
|
)
|
|
);
|
|
}
|
|
|
|
getButtonForegroundColor(step: XStepComponent, type: XNPRButtonType) {
|
|
return this.getActionButtons(step, type).pipe(
|
|
concatMap((btns) =>
|
|
btns.s && btns.s.foregroundColor
|
|
? this.getOptionalValue(btns.s.foregroundColor)
|
|
: this.getOptionalValue(btns.c.foregroundColor)
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleSelectionChanged(event: StepperSelectionEvent) {
|
|
//
|
|
if (this.uiDisabled || this.loading || !this.hasSteps()) {
|
|
return;
|
|
}
|
|
|
|
const index = event.selectedIndex;
|
|
const stepId = await this.getValueAsync(this.steps.toArray()[index].id);
|
|
this.selectedChange.emit(stepId);
|
|
}
|
|
|
|
async handleNPRStep(
|
|
stepper: MatStepper,
|
|
step: XStepComponent,
|
|
type: XNPRButtonType
|
|
) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
await this.handleNextStep(stepper, step);
|
|
break;
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
await this.handlePrevStep(stepper, step);
|
|
break;
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
await this.handleReset(stepper, step);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleNextStep(
|
|
stepper: MatStepper,
|
|
step: XStepComponent,
|
|
force?: boolean
|
|
) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!stepper ||
|
|
!step ||
|
|
step.loading ||
|
|
step.uiDisabled ||
|
|
!this.hasSteps()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let nextId: string;
|
|
const stepId = await this.getValueAsync(step.id);
|
|
const stepIndex = await this.getStepIndex(stepId);
|
|
if (stepIndex === -1) {
|
|
return;
|
|
}
|
|
if (stepIndex < this.steps.length - 1) {
|
|
nextId = await this.getValueAsync(this.steps.toArray()[stepIndex + 1].id);
|
|
}
|
|
|
|
//
|
|
const button = await this.getValueAsync(step.nextButton);
|
|
if (button.clicked) {
|
|
button.clicked.emit();
|
|
}
|
|
|
|
if (isNullOrEmptyString(nextId)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!force) {
|
|
//
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canNextStep = await this.getValueAsync(this.canNext);
|
|
const disableNextStep = await this.getValueAsync(step.disableNext);
|
|
|
|
//
|
|
if (isUiBusy || disableNextStep || !canNextStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isConfirmedType = this.nextConfirmer
|
|
? this.nextConfirmer()
|
|
: this.getValue(true);
|
|
const isConfirmed = await this.getValueAsync(isConfirmedType);
|
|
|
|
//
|
|
if (!isConfirmed) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepNextConfitmedType = step.nextConfirmer
|
|
? step.nextConfirmer()
|
|
: this.getValue(true);
|
|
const isStepNextConfirmed = await this.getValueAsync(
|
|
isStepNextConfitmedType
|
|
);
|
|
if (!isStepNextConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = nextId;
|
|
this.selectedChange.emit(nextId);
|
|
stepper.next();
|
|
this.onNext.emit(stepId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handlePrevStep(
|
|
stepper: MatStepper,
|
|
step: XStepComponent,
|
|
force?: boolean
|
|
) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!stepper ||
|
|
!step ||
|
|
step.loading ||
|
|
step.uiDisabled ||
|
|
!this.hasSteps()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let prevId: string;
|
|
const stepId = await this.getValueAsync(step.id);
|
|
const stepIndex = await this.getStepIndex(stepId);
|
|
if (stepIndex === -1) {
|
|
return;
|
|
}
|
|
prevId = await this.getValueAsync(this.steps.toArray()[stepIndex].id);
|
|
|
|
//
|
|
const button = await this.getValueAsync(step.prevButton);
|
|
if (button.clicked) {
|
|
button.clicked.emit();
|
|
}
|
|
|
|
if (isNullOrEmptyString(prevId)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canPrevStep = await this.getValueAsync(this.canPrev);
|
|
const disablePrevStep = await this.getValueAsync(step.disablePrev);
|
|
if (isUiBusy || disablePrevStep || !canPrevStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isConfirmedType = this.prevConfirmer
|
|
? this.prevConfirmer()
|
|
: this.getValue(true);
|
|
const isConfirmed = await this.getValueAsync(isConfirmedType);
|
|
|
|
//
|
|
if (!isConfirmed) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepPrevConfitmedType = step.prevConfirmer
|
|
? step.prevConfirmer()
|
|
: this.getValue(true);
|
|
const isStepPrevConfirmed = await this.getValueAsync(
|
|
isStepPrevConfitmedType
|
|
);
|
|
if (!isStepPrevConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = prevId;
|
|
this.selectedChange.emit(prevId);
|
|
stepper.previous();
|
|
this.onPrev.emit(stepId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleReset(
|
|
stepper: MatStepper,
|
|
step: XStepComponent,
|
|
force?: boolean
|
|
) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!stepper ||
|
|
!step ||
|
|
step.loading ||
|
|
step.uiDisabled ||
|
|
!this.hasSteps()
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(step.id);
|
|
const firstId = await this.getValueAsync(this.steps.toArray()[0].id);
|
|
|
|
//
|
|
const button = await this.getValueAsync(step.resetButton);
|
|
if (button.clicked) {
|
|
button.clicked.emit();
|
|
}
|
|
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canResetStep = await this.getValueAsync(this.canReset);
|
|
const disableResetStep = await this.getValueAsync(step.disableReset);
|
|
if (isUiBusy || disableResetStep || !canResetStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isConfirmedType = this.resetConfirmer
|
|
? this.resetConfirmer()
|
|
: this.getValue(true);
|
|
const isConfirmed = await this.getValueAsync(isConfirmedType);
|
|
|
|
//
|
|
if (!isConfirmed) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepResetConfitmedType = step.resetConfirmer
|
|
? step.resetConfirmer()
|
|
: this.getValue(true);
|
|
const isStepResetConfirmed = await this.getValueAsync(
|
|
isStepResetConfitmedType
|
|
);
|
|
if (!isStepResetConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = firstId;
|
|
this.selectedChange.emit(firstId);
|
|
stepper.reset();
|
|
this.onReset.emit(stepId);
|
|
this.detectChanges();
|
|
}
|
|
|
|
async handleToStep(stepper: MatStepper, step: XStepComponent) {
|
|
//
|
|
if (
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!step ||
|
|
step.loading ||
|
|
step.uiDisabled ||
|
|
!this.hasSteps() ||
|
|
this.selected === (await this.getValueAsync(step.id))
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(step.id);
|
|
const stepIndex = await this.getStepIndex(stepId);
|
|
|
|
//
|
|
this.selected = stepId;
|
|
this.selectedChange.emit(stepId);
|
|
stepper.selectedIndex = stepIndex;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async next(force?: boolean) {
|
|
//
|
|
if (!this.selected || !this.stepper || !this.hasSteps()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(this.selected);
|
|
if (!stepId) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const step = await this.getStep(stepId);
|
|
if (!step) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleNextStep(this.stepper, step, force);
|
|
}
|
|
|
|
async prev(force?: boolean) {
|
|
//
|
|
if (!this.selected || !this.stepper || !this.hasSteps()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(this.selected);
|
|
if (!stepId) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const step = await this.getStep(stepId);
|
|
if (!step) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handlePrevStep(this.stepper, step, force);
|
|
}
|
|
|
|
async reset(force?: boolean) {
|
|
//
|
|
if (!this.selected || !this.stepper || !this.hasSteps()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(this.selected);
|
|
if (!stepId) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const step = await this.getStep(stepId);
|
|
if (!step) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.handleReset(this.stepper, step, force);
|
|
}
|
|
|
|
async to(id: XStandardType<string>, force?: boolean) {
|
|
//
|
|
if (!id || !this.hasSteps() || !this.stepper) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepId = await this.getValueAsync(id);
|
|
if (!stepId) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const stepIndex = await this.getStepIndex(stepId);
|
|
if (stepIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const step = await this.getStep(stepId);
|
|
if (!step) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const selectedIndex = await this.getStepIndex(this.selected);
|
|
if (selectedIndex === -1 || selectedIndex === stepIndex) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (stepIndex > selectedIndex) {
|
|
//
|
|
// next confirm ...
|
|
//
|
|
if (!force) {
|
|
//
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canNextStep = await this.getValueAsync(this.canNext);
|
|
const disableNextStep = await this.getValueAsync(step.disableNext);
|
|
|
|
//
|
|
if (isUiBusy || disableNextStep || !canNextStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepNextConfitmedType = step.nextConfirmer
|
|
? step.nextConfirmer()
|
|
: this.getValue(true);
|
|
const isStepNextConfirmed = await this.getValueAsync(
|
|
isStepNextConfitmedType
|
|
);
|
|
if (!isStepNextConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = stepId;
|
|
this.selectedChange.emit(stepId);
|
|
} else if (stepIndex < selectedIndex) {
|
|
//
|
|
// prev Confirm ...
|
|
//
|
|
if (!force) {
|
|
const isUiBusy = this.uiDisabled || this.loading;
|
|
const canPrevStep = await this.getValueAsync(this.canPrev);
|
|
const disablePrevStep = await this.getValueAsync(step.disablePrev);
|
|
if (isUiBusy || disablePrevStep || !canPrevStep) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isStepPrevConfitmedType = step.prevConfirmer
|
|
? step.prevConfirmer()
|
|
: this.getValue(true);
|
|
const isStepPrevConfirmed = await this.getValueAsync(
|
|
isStepPrevConfitmedType
|
|
);
|
|
if (!isStepPrevConfirmed) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
this.selected = stepId;
|
|
this.selectedChange.emit(stepId);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XStepperActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XStepperAction.NEXT:
|
|
await this.next(model.force);
|
|
break;
|
|
|
|
//
|
|
case XStepperAction.PREV:
|
|
await this.prev(model.force);
|
|
break;
|
|
|
|
//
|
|
case XStepperAction.RESET:
|
|
await this.reset(model.force);
|
|
break;
|
|
|
|
//
|
|
case XStepperAction.TO:
|
|
if (model.payload) {
|
|
await this.to(model.payload, model.force);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XStepperAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private getActionButtons(step: XStepComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getValue(this.nextButton).pipe(
|
|
concatMap((cButton) =>
|
|
this.getValue(step.nextButton).pipe(
|
|
map((sButton) => ({ c: cButton, s: sButton }))
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getValue(this.prevButton).pipe(
|
|
concatMap((cButton) =>
|
|
this.getValue(step.prevButton).pipe(
|
|
map((sButton) => ({ c: cButton, s: sButton }))
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getValue(this.resetButton).pipe(
|
|
concatMap((cButton) =>
|
|
this.getValue(step.resetButton).pipe(
|
|
map((sButton) => ({ c: cButton, s: sButton }))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private getActionButtonDisabled(step: XStepComponent, type: XNPRButtonType) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case this.NPRButtonTypes.Next:
|
|
return this.getOptionalValue(this.disableNext).pipe(
|
|
concatMap((cDisable) =>
|
|
this.getOptionalValue(step.disableNext).pipe(
|
|
map(
|
|
(sDisable) =>
|
|
this.uiDisabled || cDisable || step.uiDisabled || sDisable
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Prev:
|
|
return this.getOptionalValue(this.disablePrev).pipe(
|
|
concatMap((cDisable) =>
|
|
this.getOptionalValue(step.disablePrev).pipe(
|
|
map(
|
|
(sDisable) =>
|
|
this.uiDisabled || cDisable || step.uiDisabled || sDisable
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
case this.NPRButtonTypes.Reset:
|
|
return this.getOptionalValue(this.disableReset).pipe(
|
|
concatMap((cDisable) =>
|
|
this.getOptionalValue(step.disableReset).pipe(
|
|
map(
|
|
(sDisable) =>
|
|
this.uiDisabled || cDisable || step.uiDisabled || sDisable
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private async getStep(id: string) {
|
|
//
|
|
if (!id || !this.hasSteps()) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.steps.toArray().find(async (p) => {
|
|
const pId = await this.getValueAsync(p.id);
|
|
return pId === id;
|
|
});
|
|
}
|
|
|
|
private async getStepIndex(id: string) {
|
|
//
|
|
if (!id || !this.hasSteps()) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
let result = -1;
|
|
const steps = this.steps.toArray();
|
|
if (!this.hasChild(steps)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (let i = 0; i < steps.length; i++) {
|
|
//
|
|
const step = steps[i];
|
|
const stepId = await this.getValueAsync(step.id);
|
|
if (stepId === id) {
|
|
result = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyIconColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.iconColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XStepperCssVars.IconForegroundColor, `var(${fgColor})`);
|
|
this.setCssVar(XStepperCssVars.IconBackgroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyTitleColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.titleColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XStepperCssVars.TitleForegroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyeaderColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XStepperCssVars.HeaderForegroundColor, `var(${fgColor})`);
|
|
this.setCssVar(XStepperCssVars.HeaderBackgroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ReactiveFormsModule } from '@angular/forms';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XFormModule } from './../x-form/x-form.module';
|
|
import { XStepperComponent } from './x-stepper.component';
|
|
import { XStepComponent } from './x-step/x-step.component';
|
|
import { XButtonModule } from '../x-button/x-button.module';
|
|
import { XSlotterModule } from '../x-slotter/x-slotter.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XStepperComponent, XStepComponent],
|
|
imports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XFormModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XSlotterModule,
|
|
ReactiveFormsModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XFormModule,
|
|
CommonModule,
|
|
XButtonModule,
|
|
XStepComponent,
|
|
XSlotterModule,
|
|
XStepperComponent,
|
|
ReactiveFormsModule,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XStepperModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
NgZone,
|
|
Inject,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XNextPrevResetAndHostContainer,
|
|
IXNextPrevResetAndHostContainer,
|
|
XNextPrevResetAndHostContainerComponent,
|
|
} from '../classes/i-x-next-prev-reset.container';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XStepperType {
|
|
HORIZONTAL = 'horizontal',
|
|
VERTICAL = 'vertical',
|
|
}
|
|
|
|
export type XStepperTypeIdentifier = XStepperType | string;
|
|
|
|
export enum XStepperLabelPosition {
|
|
END = 'end',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XStepperLabelPositionIdentifier = XStepperLabelPosition | string;
|
|
|
|
export enum XStepperAction {
|
|
NEXT = 'next',
|
|
PREV = 'prev',
|
|
RESET = 'reset',
|
|
TO = 'to',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XStepperActionIdentifier = XStepperAction | string;
|
|
|
|
export interface XStepperActionModel
|
|
extends XBaseActionModel<XStepperActionIdentifier> {
|
|
force?: boolean;
|
|
}
|
|
|
|
export enum XStepperCssVars {
|
|
//
|
|
IconForegroundColor = 'icon-foreground-color',
|
|
IconBackgroundColor = 'icon-background-color',
|
|
|
|
//
|
|
TitleForegroundColor = 'title-foreground-color',
|
|
|
|
//
|
|
HeaderForegroundColor = 'header-foreground-color',
|
|
HeaderBackgroundColor = 'header-background-color',
|
|
}
|
|
|
|
export type XStepperCssVarsIdentifier = XStepperCssVars | string;
|
|
|
|
export function defaultActionConfirmer() {
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXStepperContainer extends IXNextPrevResetAndHostContainer {
|
|
//
|
|
actionProvider: Subject<XStepperActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
type: XStandardType<XStepperTypeIdentifier>;
|
|
showLabel: XStandardType<boolean>;
|
|
labelPosition: XStandardType<XStepperLabelPositionIdentifier>;
|
|
|
|
//
|
|
selectableHeaders: XStandardType<boolean>;
|
|
|
|
//
|
|
selectedIndex: XStandardType<number>;
|
|
selectedChange: EventEmitter<string>;
|
|
|
|
//
|
|
iconColor: XStandardType<XColorIdentifier>;
|
|
titleColor: XStandardType<XColorIdentifier>;
|
|
headerColor: XStandardType<XColorIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XStepperContainer
|
|
extends XNextPrevResetAndHostContainer
|
|
implements Readonly<IXStepperContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XStepperActionModel> =
|
|
new Subject<XStepperActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly type: XStandardType<XStepperTypeIdentifier> =
|
|
XStepperType.HORIZONTAL;
|
|
readonly showLabel: XStandardType<boolean> = true;
|
|
readonly labelPosition: XStandardType<XStepperLabelPositionIdentifier> =
|
|
XStepperLabelPosition.END;
|
|
|
|
//
|
|
readonly selectableHeaders: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly selectedIndex: XStandardType<number>;
|
|
readonly selectedChange: EventEmitter<string> = new EventEmitter<string>();
|
|
|
|
//
|
|
readonly iconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly titleColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Secondary;
|
|
readonly headerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XStepperContainerComponent
|
|
extends XNextPrevResetAndHostContainerComponent
|
|
implements IXStepperContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XStepperActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
type: XStandardType<XStepperTypeIdentifier> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
showLabel: XStandardType<boolean> = this.propertyProvider.showLabel;
|
|
|
|
@Input()
|
|
labelPosition: XStandardType<XStepperLabelPositionIdentifier> =
|
|
this.propertyProvider.labelPosition;
|
|
|
|
//
|
|
@Input()
|
|
selectableHeaders: XStandardType<boolean> =
|
|
this.propertyProvider.selectableHeaders;
|
|
|
|
//
|
|
@Input()
|
|
selectedIndex: XStandardType<number> = this.propertyProvider.selectedIndex;
|
|
|
|
@Output()
|
|
selectedChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
|
|
|
|
@Input()
|
|
titleColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.titleColor;
|
|
|
|
@Input()
|
|
headerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XStepperContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXStepperContainer
|
|
): Observable<IXStepperContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
type: this.getValue(container ? container.type : this.type),
|
|
showLabel: this.getValue(
|
|
container ? container.showLabel : this.showLabel
|
|
),
|
|
labelPosition: this.getValue(
|
|
container ? container.labelPosition : this.labelPosition
|
|
),
|
|
selectableHeaders: this.getValue(
|
|
container ? container.selectableHeaders : this.selectableHeaders
|
|
),
|
|
selectedIndex: this.getValue(
|
|
container ? container.selectedIndex : this.selectedIndex
|
|
),
|
|
iconColor: this.getValue(
|
|
container ? container.iconColor : this.iconColor
|
|
),
|
|
titleColor: this.getValue(
|
|
container ? container.titleColor : this.titleColor
|
|
),
|
|
headerColor: this.getValue(
|
|
container ? container.headerColor : this.headerColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
selectedChange: this.selectedChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.html
|
|
|
|
<!-- Label -->
|
|
<ng-template #label>
|
|
<ng-content select="[x-step-label]"></ng-content>
|
|
</ng-template>
|
|
|
|
<!-- Content -->
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
<!-- Actions -->
|
|
<ng-template #actions>
|
|
<ng-content select="[x-step-actions]"></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.scss
|
|
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.ts
|
|
|
|
import {
|
|
XStepAction,
|
|
XStepActionModel,
|
|
XStepContainerComponent,
|
|
} from './x-step.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XModalButtonRole, nameof } from 'x-framework-core';
|
|
import { Component, ViewChild, TemplateRef } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-step',
|
|
templateUrl: './x-step.component.html',
|
|
styleUrls: ['./x-step.component.scss'],
|
|
})
|
|
export class XStepComponent extends XStepContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
//#region ViewChilds ...
|
|
//
|
|
@ViewChild('label', { static: false })
|
|
label!: TemplateRef<any>;
|
|
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
content!: TemplateRef<any>;
|
|
|
|
//
|
|
@ViewChild('actions', { static: false })
|
|
actions!: TemplateRef<any>;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XStepComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerInstanceHandlers() {
|
|
super.registerInstanceHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XStepActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XStepAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private defaultStepperResetConfirmer() {
|
|
//
|
|
return new Promise<boolean>((resolver) => {
|
|
//
|
|
this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
() => resolver(true),
|
|
XModalButtonRole.Destructive,
|
|
() => resolver(false)
|
|
);
|
|
});
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XNextPrevResetContainer,
|
|
IXNextPrevResetContainer,
|
|
XNextPrevResetContainerComponent,
|
|
} from '../../classes/i-x-next-prev-reset.container';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Subject, Observable } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { generateUuid, XStandardType } from 'x-framework-core';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XStepAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XStepActionIdentifier = XStepAction | string;
|
|
|
|
export interface XStepActionModel
|
|
extends XBaseActionModel<XStepActionIdentifier> {
|
|
force?: boolean;
|
|
}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXStepContainer extends IXNextPrevResetContainer {
|
|
actionProvider: Subject<XStepActionModel>;
|
|
id: XStandardType<string>;
|
|
hasCustomActions: XStandardType<boolean>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XStepContainer
|
|
extends XNextPrevResetContainer
|
|
implements Readonly<IXStepContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XStepActionModel> =
|
|
new Subject<XStepActionModel>();
|
|
readonly id: XStandardType<string>; // = generateUuid('XStepComponent');
|
|
readonly hasCustomActions: XStandardType<boolean> = false;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XStepContainerComponent
|
|
extends XNextPrevResetContainerComponent
|
|
implements IXStepContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XStepActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
id: XStandardType<string> = generateUuid('XStepComponent');
|
|
|
|
@Input()
|
|
hasCustomActions: XStandardType<boolean> =
|
|
this.propertyProvider.hasCustomActions;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XStepContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXStepContainer
|
|
): Observable<IXStepContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
id: this.getValue(container ? container.id : this.id),
|
|
hasCustomActions: this.getValue(
|
|
container ? container.hasCustomActions : this.hasCustomActions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.html
|
|
|
|
<div
|
|
class="x-tab-navigator x-wrapper"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<ion-tabs>
|
|
<ion-tab-bar
|
|
[xColor]="getValue(color) | async"
|
|
[slot]="getValue(navigatorSlot) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
>
|
|
<ng-container *ngFor="let item of preparedItems">
|
|
<ion-tab-button
|
|
*ngIf="item"
|
|
class="x-nav-button"
|
|
[tab]="getItemRoute(item) | async"
|
|
[href]="getItemRoute(item) | async"
|
|
[disabled]="isDisabled(item) | async"
|
|
[layout]="getValue(item.layout) | async"
|
|
[matTooltip]="getItemTooltip(item) | async"
|
|
[download]="getOptionalValue(item.download) | async"
|
|
[target]="getOptionalValue(item.routerTarget) | async"
|
|
>
|
|
<!-- Icon -->
|
|
<x-icon
|
|
class="x-icon"
|
|
[color]="'cb-inherit'"
|
|
[name]="getValue(item.icon) | async"
|
|
*ngIf="notEmptyValue(item.icon) | async"
|
|
[cssClass]="'ion-no-padding ion-no-margin'"
|
|
>
|
|
</x-icon>
|
|
|
|
<!-- Label -->
|
|
<ion-label class="x-tab-label" *ngIf="!(hideTabTitle(item) | async)">
|
|
{{ getResourceValue(item.title) | async }}
|
|
</ion-label>
|
|
|
|
<!-- Badge Number -->
|
|
<ion-badge *ngIf="hasBadgeNumber(item) | async">
|
|
{{ getItemBadgeNumber(item) | async }}
|
|
</ion-badge>
|
|
</ion-tab-button>
|
|
</ng-container>
|
|
</ion-tab-bar>
|
|
</ion-tabs>
|
|
</div>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.scss
|
|
|
|
:host {
|
|
//
|
|
--highlight-foreground-color: var(--x-color-success-contrast);
|
|
--highlight-background-color: var(--x-color-success);
|
|
|
|
//
|
|
--selected-foreground-color: var(--x-color-secondary-contrast);
|
|
--selected-background-color: var(--x-color-secondary);
|
|
|
|
//
|
|
--badge-foreground-color: var(--x-color-dark-contrast);
|
|
--badge-background-color: var(--x-color-dark);
|
|
|
|
//
|
|
--icon-color: var(--x-color-dark);
|
|
|
|
//
|
|
--foreground-color: var(--x-color-light-contrast);
|
|
--background-color: var(--x-color-light);
|
|
}
|
|
|
|
x-icon {
|
|
font-size: 12px;
|
|
color: var(--icon-color);
|
|
}
|
|
|
|
ion-tab-button {
|
|
--color: var(--foreground-color);
|
|
--color-focused: var(--highlight-foreground-color);
|
|
--color-selected: var(--selected-foreground-color);
|
|
}
|
|
|
|
ion-tab-button::part(native) {
|
|
color: var(--foreground-color);
|
|
|
|
&:hover {
|
|
color: var(--highlight-foreground-color);
|
|
}
|
|
}
|
|
|
|
ion-badge {
|
|
color: var(--badge-foreground-color);
|
|
background-color: var(--badge-background-color);
|
|
}
|
|
|
|
.tab-selected {
|
|
background-color: var(--selected-background-color) !important;
|
|
|
|
x-icon {
|
|
color: var(--selected-foreground-color) !important;
|
|
}
|
|
}
|
|
|
|
.x-tab-label {
|
|
font-size: 9px !important;
|
|
|
|
&:hover {
|
|
color: var(--highlight-foreground-color);
|
|
}
|
|
}
|
|
|
|
.x-nav-button:hover {
|
|
color: var(--highlight-foreground-color);
|
|
background-color: var(--highlight-background-color);
|
|
|
|
x-icon {
|
|
color: var(--highlight-foreground-color) !important;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XTabNavigatorItem,
|
|
XTabNavigatorAction,
|
|
XTabNavigatorCssVars,
|
|
XTabNavigatorItemLayout,
|
|
XTabNavigatorActionModel,
|
|
XTabNavigatorContainerComponent,
|
|
} from './x-tab-navigator.typings';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { of, Observable, Subject, Subscription } from 'rxjs';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-tab-navigator',
|
|
templateUrl: './x-tab-navigator.component.html',
|
|
styleUrls: ['./x-tab-navigator.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XTabNavigatorComponent extends XTabNavigatorContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private PREPARED_ITEMS: XTabNavigatorItem[];
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
get preparedItems() {
|
|
return this.PREPARED_ITEMS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.prepareItems();
|
|
await this.applyDefaultColors();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Items Changed ...
|
|
const isItemsChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('items')
|
|
);
|
|
if (isItemsChanged) {
|
|
await this.prepareItems();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Colors Changed ...
|
|
//
|
|
// Color ...
|
|
const isColorChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('color')
|
|
);
|
|
if (isColorChanged) {
|
|
await this.applyColor();
|
|
}
|
|
|
|
//
|
|
// Icon Color ...
|
|
const isIconColorChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('iconColor')
|
|
);
|
|
if (isIconColorChanged) {
|
|
await this.applyIconColor();
|
|
}
|
|
|
|
//
|
|
// HighLight Color ...
|
|
const isHighLightColorChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('highlightColor')
|
|
);
|
|
if (isHighLightColorChanged) {
|
|
await this.applyHighLightedColor();
|
|
}
|
|
|
|
//
|
|
// Selected Color ...
|
|
const isSelectedColorChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('selectedColor')
|
|
);
|
|
if (isSelectedColorChanged) {
|
|
await this.applySelectedColor();
|
|
}
|
|
|
|
//
|
|
// Badge Color ...
|
|
const isBadgeColorChanged = changeKeys.includes(
|
|
nameof<XTabNavigatorComponent>('badgeColor')
|
|
);
|
|
if (isBadgeColorChanged) {
|
|
await this.applyBadgeColor();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Ui Providers ...
|
|
isDisabled(item: XTabNavigatorItem) {
|
|
return (this.getOptionalValue(item.disabled) as Observable<boolean>).pipe(
|
|
map((disabled) => disabled || this.uiDisabled)
|
|
);
|
|
}
|
|
|
|
getItemRoute(item: XTabNavigatorItem) {
|
|
return this.getArrayValue(item.href).pipe(
|
|
map((href) => {
|
|
//
|
|
if (!this.hasChild(href)) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
if (href.length === 1) {
|
|
return href[0];
|
|
}
|
|
|
|
//
|
|
const result = href.join('/').replace('//', '/');
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
|
|
getItemTooltip(item: XTabNavigatorItem) {
|
|
return this.getResourceValue(item.description).pipe(
|
|
concatMap((val) => {
|
|
if (isNullOrEmptyString(val.toString())) {
|
|
return this.getResourceValue(item.title);
|
|
} else {
|
|
return of(val);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
hideTabTitle(item: XTabNavigatorItem) {
|
|
return this.getValue(this.hideTabLabelsOnSmallScreens).pipe(
|
|
concatMap((hideOnMobile) => {
|
|
return hideOnMobile
|
|
? this.isMobileUi$
|
|
: this.getValue(item.layout).pipe(
|
|
map((layout) => layout === XTabNavigatorItemLayout.LABEL_HIDE)
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
hasBadgeNumber(item: XTabNavigatorItem) {
|
|
return this.getValue(item.badge).pipe(map((badge) => badge > 0));
|
|
}
|
|
|
|
getItemBadgeNumber(item: XTabNavigatorItem) {
|
|
return (this.getOptionalValue(item.badge) as Observable<number>).pipe(
|
|
map((badge) => {
|
|
if (!badge) {
|
|
return this.applyLocale(0);
|
|
} else {
|
|
return this.applyLocale(badge);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async prepareItems() {
|
|
//
|
|
const items = await this.getValueAsync(this.items);
|
|
this.PREPARED_ITEMS = items;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XTabNavigatorActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XTabNavigatorAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyDefaultColors() {
|
|
//
|
|
await this.applyColor();
|
|
await this.applyIconColor();
|
|
await this.applyBadgeColor();
|
|
await this.applySelectedColor();
|
|
await this.applyHighLightedColor();
|
|
}
|
|
|
|
//
|
|
// Color ...
|
|
private async applyColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.color);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabNavigatorCssVars.ForegroundColor, `var(${fgColor})`);
|
|
this.setCssVar(XTabNavigatorCssVars.BackgroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
// Icon Color ...
|
|
private async applyIconColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.iconColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabNavigatorCssVars.IconColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
// HighLight Color ...
|
|
private async applyHighLightedColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.highlightColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.HighlightedForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.HighlightedBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
// Selected Color ...
|
|
private async applySelectedColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.selectedColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.SelectedForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.SelectedBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
//
|
|
// Badge Color ...
|
|
private async applyBadgeColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.badgeColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.BadgeForegroundColor,
|
|
`var(${fgColor})`
|
|
);
|
|
this.setCssVar(
|
|
XTabNavigatorCssVars.BadgeBackgroundColor,
|
|
`var(${bgColor})`
|
|
);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XTabNavigatorComponent } from './x-tab-navigator.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XTabNavigatorComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XIconModule],
|
|
exports: [XIconModule, XBaseComponentModule, XTabNavigatorComponent]
|
|
})
|
|
export class XTabNavigatorModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.tools.ts
|
|
|
|
import {
|
|
XTabNavigatorItem,
|
|
XTabNavigatorItemLayout,
|
|
} from './x-tab-navigator.typings';
|
|
import { XPage } from 'x-framework-core';
|
|
|
|
export function toTabNavigatiorItem(page: XPage) {
|
|
//
|
|
if (!page) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result: XTabNavigatorItem = {
|
|
id: page.id ? page.id : page.name,
|
|
title: page.title,
|
|
description: page.description,
|
|
href: page.baseRoute,
|
|
disabled: false,
|
|
icon: page.icon,
|
|
badge: 0,
|
|
layout: XTabNavigatorItemLayout.ICON_TOP,
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
XRouterTargetIdentifier,
|
|
} from 'x-framework-core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XNavigatorListItem } from '../x-page/x-navigator/x-navigator.typings';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export interface XTabNavigatorItem
|
|
extends Pick<
|
|
XNavigatorListItem,
|
|
'id' | 'title' | 'description' | 'href' | 'disabled'
|
|
> {
|
|
//
|
|
icon: XStandardType<XIconIdentifier>;
|
|
badge?: XStandardType<number>;
|
|
//
|
|
download?: XStandardType<string>;
|
|
routerTarget?: XStandardType<XRouterTargetIdentifier>;
|
|
//
|
|
layout: XStandardType<XTabNavigatorItemLayout>;
|
|
}
|
|
|
|
export enum XTabNavigatorItemLayout {
|
|
ICON_TOP = 'icon-top',
|
|
ICON_END = 'icon-end',
|
|
ICON_HIDE = 'icon-hide',
|
|
ICON_START = 'icon-start',
|
|
LABEL_HIDE = 'label-hide',
|
|
ICON_BOTTOM = 'icon-bottom',
|
|
}
|
|
|
|
export type XTabNavigatorItemLayoutIdentifier =
|
|
| XTabNavigatorItemLayout
|
|
| string;
|
|
|
|
export enum XTabNavigatorNavigatorSlot {
|
|
TOP = 'top',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XTabNavigatorNavigatorSlotIdentifier =
|
|
| XTabNavigatorNavigatorSlot
|
|
| string;
|
|
|
|
export enum XTabNavigatorAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XTabNavigatorActionIdentifier = XTabNavigatorAction | string;
|
|
|
|
export interface XTabNavigatorActionModel
|
|
extends XBaseActionModel<XTabNavigatorActionIdentifier> {}
|
|
|
|
export enum XTabNavigatorCssVars {
|
|
//
|
|
HighlightedForegroundColor = 'highlight-foreground-color',
|
|
HighlightedBackgroundColor = 'highlight-background-color',
|
|
|
|
//
|
|
SelectedForegroundColor = 'selected-foreground-color',
|
|
SelectedBackgroundColor = 'selected-background-color',
|
|
|
|
//
|
|
BadgeForegroundColor = 'badge-foreground-color',
|
|
BadgeBackgroundColor = 'badge-background-color',
|
|
|
|
//
|
|
IconColor = 'icon-color',
|
|
|
|
//
|
|
ForegroundColor = 'foreground-color',
|
|
BackgroundColor = 'background-color',
|
|
}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXTabNavigatorContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XTabNavigatorActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier>;
|
|
hideTabLabelsOnSmallScreens: XStandardType<boolean>;
|
|
items: XStandardType<XTabNavigatorItem[]>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
iconColor: XStandardType<XColorIdentifier>;
|
|
badgeColor: XStandardType<XColorIdentifier>;
|
|
highlightColor: XStandardType<XColorIdentifier>;
|
|
selectedColor: XStandardType<XColorIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XTabNavigatorContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXTabNavigatorContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XTabNavigatorActionModel> =
|
|
new Subject<XTabNavigatorActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier> =
|
|
XTabNavigatorNavigatorSlot.BOTTOM;
|
|
readonly hideTabLabelsOnSmallScreens: XStandardType<boolean> = true;
|
|
readonly items: XStandardType<XTabNavigatorItem[]> = [];
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
readonly iconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly badgeColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.WarningTint;
|
|
readonly highlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.WarningShade;
|
|
readonly selectedColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.TertiaryShade;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XTabNavigatorContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXTabNavigatorContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XTabNavigatorActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier> =
|
|
this.propertyProvider.navigatorSlot;
|
|
|
|
@Input()
|
|
hideTabLabelsOnSmallScreens: XStandardType<boolean> =
|
|
this.propertyProvider.hideTabLabelsOnSmallScreens;
|
|
|
|
@Input()
|
|
items: XStandardType<XTabNavigatorItem[]> = this.propertyProvider.items;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
|
|
|
|
@Input()
|
|
badgeColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.badgeColor;
|
|
|
|
@Input()
|
|
highlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.highlightColor;
|
|
|
|
@Input()
|
|
selectedColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.selectedColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XTabNavigatorContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXTabNavigatorContainer
|
|
): Observable<IXTabNavigatorContainer> {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(container ? container.cssClass : this.cssClass),
|
|
navigatorSlot: this.getValue(
|
|
container ? container.navigatorSlot : this.navigatorSlot
|
|
),
|
|
hideTabLabelsOnSmallScreens: this.getValue(
|
|
container
|
|
? container.hideTabLabelsOnSmallScreens
|
|
: this.hideTabLabelsOnSmallScreens
|
|
),
|
|
items: this.getValue(container ? container.items : this.items),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
iconColor: this.getValue(
|
|
container ? container.iconColor : this.iconColor
|
|
),
|
|
badgeColor: this.getValue(
|
|
container ? container.badgeColor : this.badgeColor
|
|
),
|
|
highlightColor: this.getValue(
|
|
container ? container.highlightColor : this.highlightColor
|
|
),
|
|
selectedColor: this.getValue(
|
|
container ? container.selectedColor : this.selectedColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else tableRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="tableRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Table ItSelf Template -->
|
|
<ng-template #tableRef>
|
|
<!-- Wrapper -->
|
|
<div class="x-table x-wrapper" [class.mobile]="isMobileUi$ | async">
|
|
<!-- SearchBar -->
|
|
<ng-container *ngIf="isSearchbarTopPositioned() | async">
|
|
<ng-container *ngTemplateOutlet="searchBarRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Table Actions -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(showActionBar) | async) &&
|
|
(isActionBarTopPositioned() | async)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="actionsRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Table Paginator -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasChildValue(data) | async) &&
|
|
(getValue(showPaginator) | async) &&
|
|
(isPaginatorTopPositioned() | async)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Table if there is Data -->
|
|
<mat-table
|
|
matSort
|
|
class="x-table"
|
|
[dataSource]="dataSource"
|
|
[xColor]="getValue(color) | async"
|
|
*ngIf="hasChildValue(data) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
[matSortDisableClear]="!(getValue(canClearSort) | async)"
|
|
>
|
|
<!-- Columns -->
|
|
<ng-container *ngFor="let col of columnsData">
|
|
<!-- Selection Column -->
|
|
<ng-container
|
|
[sticky]="true"
|
|
*ngIf="isSelectionRow(col) | async"
|
|
[matColumnDef]="getColumnName(col) | async"
|
|
>
|
|
<!-- Selection Header Cell -->
|
|
<mat-header-cell
|
|
*matHeaderCellDef
|
|
[ngClass]="getHeaderClass(col) | async"
|
|
class="x-table-header x-table-selection"
|
|
[xColor]="getValue(headerColor) | async"
|
|
[isForeground]="getValue(headerForegroundColor) | async"
|
|
>
|
|
<ion-checkbox
|
|
[disabled]="!selection"
|
|
[class.hydrated]="false"
|
|
[hidden]="!(getValue(allowMultiSelect) | async)"
|
|
class="x-check-box x-selection-master ion-margin-end"
|
|
>
|
|
</ion-checkbox>
|
|
</mat-header-cell>
|
|
|
|
<!-- Selection Table Cell -->
|
|
<mat-cell
|
|
*matCellDef="let row"
|
|
[ngClass]="getCellClass(col) | async"
|
|
class="x-table-cell x-table-selection"
|
|
>
|
|
<ion-checkbox
|
|
[checked]="isSelected(row)"
|
|
class="x-check-box ion-margin-end"
|
|
[disabled]="!isRowsSelectable || !selection"
|
|
(ionChange)="handleRowSelected($event, row)"
|
|
>
|
|
</ion-checkbox>
|
|
</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Model Displayed Columns -->
|
|
<ng-container
|
|
*ngIf="!(isSelectionRow(col) | async)"
|
|
[matColumnDef]="getColumnName(col) | async"
|
|
>
|
|
<!-- Header Cell -->
|
|
<mat-header-cell
|
|
mat-sort-header
|
|
*matHeaderCellDef
|
|
class="x-table-header"
|
|
[ngClass]="getHeaderClass(col) | async"
|
|
[xColor]="getValue(headerColor) | async"
|
|
[hidden]="getOptionalValue(col.hidden) | async"
|
|
[disabled]="!(getOptionalValue(col.sortable) | async)"
|
|
[isForeground]="getValue(headerForegroundColor) | async"
|
|
[matTooltip]="getResourceValue(col.description) | async"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
headerCellRef;
|
|
context: { $implicit: getResourceValue(col.title) | async }
|
|
"
|
|
></ng-container>
|
|
</mat-header-cell>
|
|
|
|
<!-- Table Cell -->
|
|
<mat-cell
|
|
class="x-table-cell"
|
|
*matCellDef="let element"
|
|
[ngClass]="getCellClass(col) | async"
|
|
[hidden]="getOptionalValue(col.hidden) | async"
|
|
>
|
|
<!-- Determine which Template to used based on Custom Column or Displayed Columns and pass Proper Data to it -->
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(getOptionalValue(col.customColumn) | async)
|
|
? customCellTemplate || defaultCustomCellRef
|
|
: cellTemplate || defaultCellRef;
|
|
context: {
|
|
$implicit:
|
|
(getOptionalValue(col.customColumn) | async)
|
|
? element
|
|
: element[col.name],
|
|
name: col.name
|
|
}
|
|
"
|
|
></ng-container>
|
|
</mat-cell>
|
|
</ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Header Rows -->
|
|
<ng-container *ngIf="getValue(showHeader) | async">
|
|
<!-- Header Row -->
|
|
<mat-header-row
|
|
mat-header-row
|
|
class="x-table-header-row"
|
|
*matHeaderRowDef="
|
|
displayedColumns;
|
|
sticky: getValue(stickyHeader) | async
|
|
"
|
|
></mat-header-row>
|
|
</ng-container>
|
|
|
|
<!-- Items Row -->
|
|
<mat-row
|
|
matRipple
|
|
class="x-table-row"
|
|
(click)="handleRowClicked(row)"
|
|
[xColor]="getValue(color) | async"
|
|
[matRippleDisabled]="
|
|
!(getValue(clickableRows) | async) &&
|
|
!(getValue(selectableRows) | async)
|
|
"
|
|
*matRowDef="let row; columns: displayedColumns"
|
|
[isForeground]="getValue(foregroundColor) | async"
|
|
></mat-row>
|
|
</mat-table>
|
|
|
|
<!-- SearchBar -->
|
|
<ng-container *ngIf="!(isSearchbarTopPositioned() | async)">
|
|
<ng-container *ngTemplateOutlet="searchBarRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Table Actions -->
|
|
<ng-container
|
|
*ngIf="
|
|
(getValue(showActionBar) | async) &&
|
|
!(isActionBarTopPositioned() | async)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="actionsRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Table Paginator -->
|
|
<ng-container
|
|
*ngIf="
|
|
(hasChildValue(data) | async) &&
|
|
(getValue(showPaginator) | async) &&
|
|
!(isPaginatorTopPositioned() | async)
|
|
"
|
|
>
|
|
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Empty -->
|
|
<ng-container
|
|
*ngIf="(getValue(showEmpty) | async) && !(hasChildValue(data) | async)"
|
|
>
|
|
<ng-container *ngTemplateOutlet="defaultEmptyListRef"></ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Header Cell Ref -->
|
|
<ng-template #headerCellRef let-title>
|
|
<div class="x-header-title text-truncate">
|
|
{{ title }}
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Default Empty Content -->
|
|
<ng-template #defaultEmptyListRef>
|
|
<x-empty
|
|
(refresh)="emptyRefresh.emit($event)"
|
|
[color]="getValue(emptyColor) | async"
|
|
[message]="getResourceValue(emptyMessage) | async"
|
|
[refreshIcon]="getValue(emptyRefreshIcon) | async"
|
|
[messageColor]="getValue(emptyMessageColor) | async"
|
|
[hasRefresh]="getValue(emptyHasRefresh) | async"
|
|
[foregroundRefreshButtonColor]="
|
|
getValue(emptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[foregroundColor]="getValue(emptyForegroundColor) | async"
|
|
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
|
|
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
|
|
></x-empty>
|
|
</ng-template>
|
|
|
|
<!-- Default Element Template -->
|
|
<ng-template #defaultCellRef let-value let-name="name">
|
|
<div class="text-truncate">
|
|
{{ value }}
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- Default Custom Template -->
|
|
<ng-template #defaultCustomCellRef let-item> </ng-template>
|
|
|
|
<!-- SearchBar Ref -->
|
|
<ng-template #searchBarRef>
|
|
<ion-toolbar
|
|
class="x-search-bar"
|
|
*ngIf="getValue(showSearchBar) | async"
|
|
[xColor]="getValue(searchBarColor) | async"
|
|
>
|
|
<ion-searchbar
|
|
class="x-list-actions"
|
|
[xColor]="getValue(searchBarColor) | async"
|
|
[placeholder]="getResourceValue(searchTitle) | async"
|
|
(ionChange)="handleFilterData($event)"
|
|
></ion-searchbar>
|
|
</ion-toolbar>
|
|
</ng-template>
|
|
|
|
<!-- PaginatorRef -->
|
|
<ng-template #paginatorRef>
|
|
<ion-toolbar
|
|
class="x-paginator-bar"
|
|
*ngIf="getValue(showPaginator) | async"
|
|
[xColor]="getValue(paginatorColor) | async"
|
|
>
|
|
<!-- Mat Paginator Component -->
|
|
<mat-paginator
|
|
#matPaginator
|
|
[hidden]="true"
|
|
*ngIf="preparedPaginatorOptions"
|
|
[pageSize]="getValue(preparedPaginatorOptions.pageSize) | async"
|
|
></mat-paginator>
|
|
|
|
<!-- Start Slot Contents -->
|
|
<ion-buttons slot="start" *ngIf="preparedPaginatorOptions">
|
|
<!-- First -->
|
|
<ion-button
|
|
#first
|
|
(click)="firstPage()"
|
|
*ngIf="preparedPaginatorOptions.first"
|
|
[hidden]="getValue(preparedPaginatorOptions.first.hidden) | async"
|
|
[disabled]="
|
|
uiDisabled ||
|
|
loading ||
|
|
(getValue(preparedPaginatorOptions.first.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.first.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.first.title) | async,
|
|
color: getValue(preparedPaginatorOptions.first.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
|
|
<!-- Previous -->
|
|
<ion-button
|
|
#previous
|
|
(click)="previousPage()"
|
|
*ngIf="preparedPaginatorOptions.prev"
|
|
[hidden]="getValue(preparedPaginatorOptions.prev.hidden) | async"
|
|
[disabled]="
|
|
uiDisabled ||
|
|
loading ||
|
|
(getValue(preparedPaginatorOptions.prev.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.prev.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.prev.title) | async,
|
|
color: getValue(preparedPaginatorOptions.prev.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
|
|
<!-- Pagination Info -->
|
|
<div class="x-table-paginator-wrapper">
|
|
<div fxLayout="row" fxLayoutAlign="center stretch">
|
|
<!-- Current Page -->
|
|
<div fxFlex="auto" *ngIf="currentPage">
|
|
<ion-button
|
|
fill="clear"
|
|
expand="full"
|
|
class="cb-inherit"
|
|
*ngIf="!pageNumberInput"
|
|
[disabled]="uiDisabled || loading"
|
|
(click)="pageNumberInput = true"
|
|
>
|
|
{{
|
|
preparedPaginatorOptions.pageInfoProvider(
|
|
managerService.currentLocale,
|
|
currentPage,
|
|
pageSize,
|
|
totalPages,
|
|
totalItems
|
|
)
|
|
}}
|
|
</ion-button>
|
|
|
|
<!-- Change Current Page -->
|
|
<ion-input
|
|
step="1"
|
|
[min]="1"
|
|
type="number"
|
|
debounce="500"
|
|
required="true"
|
|
autofocus="true"
|
|
[max]="totalPages"
|
|
class="cb-inherit"
|
|
inputmode="numeric"
|
|
[value]="currentPage"
|
|
*ngIf="pageNumberInput"
|
|
(ionBlur)="pageNumberInput = false"
|
|
[disabled]="uiDisabled || loading"
|
|
(ionChange)="handlePageChange($event)"
|
|
></ion-input>
|
|
</div>
|
|
|
|
<!-- Page Size -->
|
|
<div fxFlex="auto">
|
|
<ion-button
|
|
fill="clear"
|
|
expand="full"
|
|
*ngIf="pageSize"
|
|
class="cb-inherit"
|
|
(click)="handlePageSizeChange()"
|
|
[disabled]="uiDisabled || loading"
|
|
>
|
|
{{ applyLocale(pageSize) }}
|
|
</ion-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- End Slot Content -->
|
|
<ion-buttons slot="end" *ngIf="preparedPaginatorOptions">
|
|
<!-- Noxt -->
|
|
<ion-button
|
|
#next
|
|
(click)="nextPage()"
|
|
*ngIf="preparedPaginatorOptions.next"
|
|
[hidden]="getValue(preparedPaginatorOptions.next.hidden) | async"
|
|
[disabled]="
|
|
uiDisabled ||
|
|
loading ||
|
|
(getValue(preparedPaginatorOptions.next.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.next.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.next.title) | async,
|
|
color: getValue(preparedPaginatorOptions.next.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
|
|
<!-- Last -->
|
|
<ion-button
|
|
#last
|
|
(click)="lastPage()"
|
|
*ngIf="preparedPaginatorOptions.last"
|
|
[hidden]="getValue(preparedPaginatorOptions.last.hidden) | async"
|
|
[disabled]="
|
|
uiDisabled ||
|
|
loading ||
|
|
(getValue(preparedPaginatorOptions.last.disabled) | async)
|
|
"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(preparedPaginatorOptions.last.icon) | async,
|
|
tooltip:
|
|
getResourceValue(preparedPaginatorOptions.last.title) | async,
|
|
color: getValue(preparedPaginatorOptions.prev.color) | async,
|
|
applyDirection: true
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ion-buttons>
|
|
</ion-toolbar>
|
|
</ng-template>
|
|
|
|
<!-- ActionsRef -->
|
|
<ng-template #actionsRef>
|
|
<ion-toolbar
|
|
class="x-actions-bar"
|
|
[xColor]="getValue(actionBarColor) | async"
|
|
*ngIf="preparedActionOptions && getValue(showActionBar) | async"
|
|
>
|
|
<!-- Start Slot Content -->
|
|
<ion-buttons slot="start">
|
|
<ng-container *ngFor="let action of preparedActionOptions.start">
|
|
<ng-container
|
|
*ngTemplateOutlet="actionButtonRef; context: { $implicit: action }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
|
|
<!-- Custom Content -->
|
|
<div
|
|
fxLayout="row"
|
|
class="x-table-paginator-wrapper"
|
|
fxLayoutAlign="center stretch"
|
|
>
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
|
|
<!-- End Slot Content -->
|
|
<ion-buttons slot="end">
|
|
<ng-container *ngFor="let action of preparedActionOptions.end">
|
|
<ng-container
|
|
*ngTemplateOutlet="actionButtonRef; context: { $implicit: action }"
|
|
></ng-container>
|
|
</ng-container>
|
|
</ion-buttons>
|
|
</ion-toolbar>
|
|
</ng-template>
|
|
|
|
<!-- Icon Template -->
|
|
<ng-template
|
|
#iconRef
|
|
let-name="name"
|
|
let-tooltip="tooltip"
|
|
let-color="color"
|
|
let-applyDirection="applyDirection"
|
|
>
|
|
<x-icon
|
|
[name]="name"
|
|
[color]="color"
|
|
[matTooltip]="tooltip"
|
|
[applyDirection]="applyDirection"
|
|
[foregroundColor]="true"
|
|
[cssClass]="!color ? 'cb-inherit' : null"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
<!-- Action Button Ref -->
|
|
<ng-template #actionButtonRef let-action>
|
|
<ion-button
|
|
*ngIf="action"
|
|
[hidden]="getValue(action.hidden) | async"
|
|
[disabled]="getValue(action.disabled) | async"
|
|
(click)="handleActionBarItemClick(action, selection.selected)"
|
|
>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
iconRef;
|
|
context: {
|
|
name: getValue(action.icon) | async,
|
|
tooltip: getResourceValue(action.title) | async,
|
|
color: getValue(action.color) | async,
|
|
applyDirection: false
|
|
}
|
|
"
|
|
></ng-container>
|
|
</ion-button>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.scss
|
|
|
|
::ng-deep :root,
|
|
:host {
|
|
//
|
|
--divider-color: var(--x-color-dark);
|
|
|
|
//
|
|
--highlight-color: var(--x-color-warning-shade-contrast);
|
|
--highlight-background-color: var(--x-color-warning-shade);
|
|
|
|
//
|
|
--odd-rows-background-color: inherit;
|
|
--even-rows-background-color: inherit;
|
|
|
|
//
|
|
--check-box-border-color: var(--x-color-dark);
|
|
--check-box-check-mark-color: var(--x-color-dark);
|
|
}
|
|
|
|
x-card {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
.x-table {
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
mat-row,
|
|
td.mat-cell,
|
|
mat-header-row,
|
|
mat-footer-row,
|
|
th.mat-header-cell,
|
|
td.mat-footer-cell {
|
|
border-bottom-color: var(--divider-color) !important;
|
|
}
|
|
|
|
.mat-paginator,
|
|
.mat-paginator-page-size .mat-select-trigger {
|
|
color: unset !important;
|
|
}
|
|
|
|
.mat-paginator {
|
|
background-color: unset !important;
|
|
}
|
|
|
|
.x-table-paginator-wrapper {
|
|
width: 100%;
|
|
}
|
|
|
|
.x-page-select-icon {
|
|
margin: {
|
|
left: 4px;
|
|
right: 4px;
|
|
}
|
|
}
|
|
|
|
.x-table-cell,
|
|
.x-table-header {
|
|
flex: 1 !important;
|
|
}
|
|
|
|
.x-header-title {
|
|
width: fit-content;
|
|
}
|
|
|
|
.x-table-selection {
|
|
flex: none !important;
|
|
}
|
|
|
|
.x-table-cell {
|
|
color: inherit !important;
|
|
background-color: inherit !important;
|
|
}
|
|
|
|
.x-table-row {
|
|
&:hover {
|
|
color: var(--highlight-color) !important;
|
|
background-color: var(--highlight-background-color) !important;
|
|
}
|
|
|
|
&:not(:hover):nth-child(odd) {
|
|
background-color: var(--odd-rows-background-color) !important;
|
|
}
|
|
|
|
&:not(:hover):nth-child(even) {
|
|
background-color: var(--even-rows-background-color) !important;
|
|
}
|
|
}
|
|
|
|
.x-check-box {
|
|
--border-color: var(--check-box-border-color, inherit) !important;
|
|
--checkmark-color: var(--check-box-check-mark-color, inherit) !important;
|
|
--background-checked: auto !important;
|
|
--border-color-checked: auto !important;
|
|
}
|
|
|
|
.x-selection-master {
|
|
visibility: hidden !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
XColor,
|
|
toArray,
|
|
XLocale,
|
|
isNumber,
|
|
hasChild,
|
|
isFunction,
|
|
applyLocale,
|
|
XResourceIDs,
|
|
XModalButtonRole,
|
|
XPickerColumnOption,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XTableAction,
|
|
XTableActionModel,
|
|
XTableColumnOption,
|
|
XTableItemPosition,
|
|
XTableActionButton,
|
|
XTableActionOptions,
|
|
XTablePaginatorOptions,
|
|
XTableContainerComponent,
|
|
X_TABLE_SELECTION_HEADER_IDENTIFIER,
|
|
} from './x-table.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { MatSort } from '@angular/material/sort';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { SelectionModel } from '@angular/cdk/collections';
|
|
import { MatPaginator } from '@angular/material/paginator';
|
|
import { MatTableDataSource } from '@angular/material/table';
|
|
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-table',
|
|
templateUrl: './x-table.component.html',
|
|
styleUrls: ['./x-table.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XTableComponent extends XTableContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
private MODAL: any;
|
|
private SORT: MatSort;
|
|
private DATA: any[] = [];
|
|
private PAGE_SIZE: number;
|
|
private TOTAL_PAGES: number;
|
|
private TOTAL_ITEMS: number;
|
|
private CURRENT_PAGE: number;
|
|
private PAGINATOR: MatPaginator;
|
|
private IS_ROWS_SELECTABLE: boolean;
|
|
private DISPLAYED_COLUMNS: string[] = [];
|
|
private ACTION_OPTIONS: XTableActionOptions;
|
|
private SELECTION_SUBSCRIPTION: Subscription;
|
|
private SELECTION = new SelectionModel<any>();
|
|
private COLUMNS_DATA: XTableColumnOption<any>[];
|
|
private PAGINATOR_OPTIONS: XTablePaginatorOptions;
|
|
private PAGINATOR_INIT_SUBSCRIPTION: Subscription;
|
|
private PAGINATOR_PAGE_SUBSCRIPTION: Subscription;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private DATA_SOURCE = new MatTableDataSource(this.DATA);
|
|
|
|
//
|
|
pageNumberInput = false;
|
|
selectionRowTitle = X_TABLE_SELECTION_HEADER_IDENTIFIER;
|
|
|
|
//
|
|
//#region Getters ...
|
|
get data() {
|
|
return this.DATA;
|
|
}
|
|
|
|
get isRowsSelectable() {
|
|
return this.IS_ROWS_SELECTABLE;
|
|
}
|
|
|
|
get columnsData() {
|
|
return this.COLUMNS_DATA;
|
|
}
|
|
|
|
get dataSource() {
|
|
return this.DATA_SOURCE;
|
|
}
|
|
|
|
get displayedColumns() {
|
|
return this.DISPLAYED_COLUMNS;
|
|
}
|
|
|
|
get selection() {
|
|
return this.SELECTION;
|
|
}
|
|
|
|
get preparedPaginatorOptions() {
|
|
return this.PAGINATOR_OPTIONS;
|
|
}
|
|
|
|
get pageSize() {
|
|
return this.PAGE_SIZE;
|
|
}
|
|
|
|
get currentPage() {
|
|
return this.CURRENT_PAGE;
|
|
}
|
|
|
|
get totalPages() {
|
|
return this.TOTAL_PAGES;
|
|
}
|
|
|
|
get totalItems() {
|
|
return this.TOTAL_ITEMS;
|
|
}
|
|
|
|
get selectedItems() {
|
|
return this.isRowsSelectable && this.selection
|
|
? this.selection.selected
|
|
: [];
|
|
}
|
|
|
|
get preparedActionOptions() {
|
|
return this.ACTION_OPTIONS;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Sort Props ...
|
|
@ViewChild(MatSort, { static: false })
|
|
set sort(v: MatSort) {
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.SORT = v;
|
|
this.DATA_SOURCE.sort = v;
|
|
}
|
|
|
|
get sort() {
|
|
return this.SORT;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Paginator Props ...
|
|
@ViewChild(MatPaginator, { static: false })
|
|
set paginator(v: MatPaginator) {
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.PAGINATOR = v;
|
|
this.DATA_SOURCE.paginator = v;
|
|
this.registerPaginatorHandlers();
|
|
}
|
|
|
|
get paginator() {
|
|
return this.PAGINATOR;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.preparePaginatorOptions();
|
|
}
|
|
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
await this.prepareUIData();
|
|
await this.prepareSelection();
|
|
await this.prepareActionOptions();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
let isLoadingChanged = changeKeys.includes(
|
|
nameof<XTableComponent>('loading')
|
|
);
|
|
let isUiDisabledChanged = changeKeys.includes(
|
|
nameof<XTableComponent>('uiDisabled')
|
|
);
|
|
if (isLoadingChanged || isUiDisabledChanged) {
|
|
await this.prepareActionOptions();
|
|
}
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XTableComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Handle Prepare Data Source ...
|
|
if (
|
|
changeKeys.includes(nameof<XTableComponent>('properties')) ||
|
|
changeKeys.includes(nameof<XTableComponent>('selectableRows'))
|
|
) {
|
|
await this.prepareDataSource();
|
|
}
|
|
|
|
//
|
|
// Handle Prepare Selection ...
|
|
if (
|
|
changeKeys.includes(nameof<XTableComponent>('allowMultiSelect')) ||
|
|
changeKeys.includes(nameof<XTableComponent>('initialSelectedValues'))
|
|
) {
|
|
await this.prepareSelection();
|
|
}
|
|
|
|
//
|
|
// Handle Paginator Options ...
|
|
if (changeKeys.includes(nameof<XTableComponent>('paginatorOptions'))) {
|
|
await this.preparePaginatorOptions();
|
|
}
|
|
|
|
//
|
|
// Handle Action Options ...
|
|
if (changeKeys.includes(nameof<XTableComponent>('actionOptions'))) {
|
|
await this.prepareActionOptions();
|
|
}
|
|
|
|
//
|
|
// Handle UI Data ...
|
|
if (changeKeys.includes(nameof<XTableComponent>('selectableRows'))) {
|
|
await this.prepareUIData();
|
|
}
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
isSelectionRow(col: XTableColumnOption<any>) {
|
|
return this.getValue(col.name).pipe(
|
|
map((colName) => colName === X_TABLE_SELECTION_HEADER_IDENTIFIER)
|
|
);
|
|
}
|
|
|
|
isSearchbarTopPositioned() {
|
|
return this.getValue(this.searchBarPosition).pipe(
|
|
map((pos) => pos === XTableItemPosition.TOP)
|
|
);
|
|
}
|
|
|
|
isPaginatorTopPositioned() {
|
|
return this.getValue(this.paginatorPosition).pipe(
|
|
map((pos) => pos === XTableItemPosition.TOP)
|
|
);
|
|
}
|
|
|
|
isActionBarTopPositioned() {
|
|
return this.getValue(this.actionBarPosition).pipe(
|
|
map((pos) => pos === XTableItemPosition.TOP)
|
|
);
|
|
}
|
|
|
|
getHeaderClass(col: XTableColumnOption<any>) {
|
|
return this.getValue(col.name).pipe(
|
|
concatMap((colName) =>
|
|
this.getValue(this.headerCellCssClass).pipe(
|
|
map((cssClass) => {
|
|
return { colName, cssClass };
|
|
})
|
|
)
|
|
),
|
|
map((info) => {
|
|
//
|
|
let result: string[] = [];
|
|
|
|
//
|
|
const className = `x-table-header-${info.colName.toString()}`;
|
|
const cssClasses = toArray(info.cssClass);
|
|
|
|
//
|
|
result = [className].concat(cssClasses);
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
|
|
getCellClass(col: XTableColumnOption<any>) {
|
|
return this.getValue(col.name).pipe(
|
|
concatMap((colName) =>
|
|
this.getValue(this.cellCssClass).pipe(
|
|
map((cssClass) => {
|
|
return { colName, cssClass };
|
|
})
|
|
)
|
|
),
|
|
map((info) => {
|
|
//
|
|
let result: string[] = [];
|
|
|
|
//
|
|
const className = `x-table-cell-${info.colName.toString()}`;
|
|
const cssClasses = toArray(info.cssClass);
|
|
|
|
//
|
|
result = [className].concat(cssClasses);
|
|
|
|
//
|
|
return result;
|
|
})
|
|
);
|
|
}
|
|
|
|
getColumnName(col: XTableColumnOption<any>) {
|
|
return this.getValue(col.name).pipe(map(name => name.toString()));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleRowClicked(row: any) {
|
|
//
|
|
const isClickable = await this.getValueAsync(this.clickableRows);
|
|
const isSelectable = await this.getValueAsync(this.selectableRows);
|
|
|
|
//
|
|
if (!isClickable && !this.selectableRows) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (isSelectable && this.selection) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selection.toggle(row);
|
|
}
|
|
|
|
//
|
|
if (isClickable) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.rowClicked.emit(row);
|
|
}
|
|
}
|
|
|
|
async handleRowSelected(event: CustomEvent | any, row: any) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isSelectable = await this.getValueAsync(this.selectableRows);
|
|
if (!isSelectable) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const selected = event.detail.checked as boolean;
|
|
|
|
//
|
|
if (!selected) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.rowSelected.emit(row);
|
|
}
|
|
|
|
async handleFilterData(event: CustomEvent | any) {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const query =
|
|
event && event.detail && event.detail.value
|
|
? event.detail.value.toString().trim().toLowerCase()
|
|
: '';
|
|
|
|
//
|
|
await this.filterData(query);
|
|
}
|
|
|
|
async handlePageChange(event: CustomEvent | any) {
|
|
//
|
|
const selectedPage = (event.detail.value as number) || undefined;
|
|
if (!selectedPage) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.toPage(selectedPage);
|
|
}
|
|
|
|
async handlePageSizeChange() {
|
|
//
|
|
if (!this.preparedPaginatorOptions || !this.pageSize) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const pageSizes = await this.getValueAsync(
|
|
this.preparedPaginatorOptions.pageSizes
|
|
);
|
|
if (!hasChild(pageSizes)) {
|
|
return;
|
|
}
|
|
|
|
const options: XPickerColumnOption[] = pageSizes.map((ps) => {
|
|
//
|
|
const opt: XPickerColumnOption = {
|
|
text: this.applyLocale(ps.toString()),
|
|
value: ps,
|
|
disabled: ps === this.pageSize,
|
|
};
|
|
|
|
//
|
|
return opt;
|
|
});
|
|
|
|
//
|
|
if (this.MODAL) {
|
|
await this.managerService.dialogService.pickerController.dismiss();
|
|
this.MODAL = null;
|
|
}
|
|
|
|
//
|
|
this.MODAL = await this.managerService.dialogService.presentPicker({
|
|
buttons: [
|
|
{
|
|
text: this.resourceProvider('accept'),
|
|
role: XModalButtonRole.Selected,
|
|
handler: (value) => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const pageSize = value.pageSize.value;
|
|
this.changePageSize(pageSize);
|
|
this.detectChanges();
|
|
},
|
|
},
|
|
{
|
|
text: this.resourceProvider('cancel'),
|
|
role: XModalButtonRole.Cancel,
|
|
},
|
|
],
|
|
columns: [{ name: 'pageSize', options }],
|
|
});
|
|
|
|
//
|
|
await this.MODAL.onWillDismiss();
|
|
this.MODAL = null;
|
|
}
|
|
|
|
async handleActionBarItemClick(
|
|
action: XTableActionButton,
|
|
selectedItems: any[]
|
|
) {
|
|
//
|
|
if (action && action.handler && isFunction(action.handler)) {
|
|
await this.getValueAsync(action.handler(selectedItems));
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
isAllSelected() {
|
|
const numSelected = this.selection.selected.length;
|
|
const numRows = this.dataSource.data.length;
|
|
return numSelected === numRows;
|
|
}
|
|
|
|
isAllFilteredSelected() {
|
|
//
|
|
if (
|
|
!this.dataSource ||
|
|
!hasChild(this.dataSource.filteredData) ||
|
|
this.selection.isEmpty() ||
|
|
!hasChild(this.selection.selected)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const filteredData = this.dataSource.filteredData;
|
|
const result = this.selection.selected.every((s) =>
|
|
filteredData.includes(s)
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
isSelected(item: any) {
|
|
//
|
|
if (
|
|
!item ||
|
|
!this.data ||
|
|
!this.selection ||
|
|
!this.isRowsSelectable ||
|
|
!this.data.includes(item)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return this.selection.isSelected(item);
|
|
}
|
|
|
|
toggleSelectAll() {
|
|
this.isAllSelected()
|
|
? this.selection.clear()
|
|
: this.dataSource.data.forEach((row) => this.selection.select(row));
|
|
}
|
|
|
|
selectAll() {
|
|
//
|
|
if (
|
|
!this.isRowsSelectable ||
|
|
!this.selection ||
|
|
!this.dataSource ||
|
|
!this.dataSource.data
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataSource.data.forEach((i) => this.selection.select(i));
|
|
}
|
|
|
|
selectAllFilteredData() {
|
|
//
|
|
if (
|
|
!this.isRowsSelectable ||
|
|
!this.selection ||
|
|
!this.dataSource ||
|
|
!this.dataSource.data ||
|
|
!this.dataSource.filteredData
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataSource.filteredData.forEach((i) => this.selection.select(i));
|
|
}
|
|
|
|
deselectAll() {
|
|
//
|
|
if (
|
|
!this.isRowsSelectable ||
|
|
!this.selection ||
|
|
!this.dataSource ||
|
|
!this.dataSource.data ||
|
|
!this.dataSource.filteredData
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataSource.filteredData.forEach((i) => this.selection.deselect(i));
|
|
}
|
|
|
|
deselectAllFilteredData() {
|
|
//
|
|
if (!this.isRowsSelectable || !this.selection) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selection.clear();
|
|
}
|
|
|
|
inverseSelection() {
|
|
//
|
|
if (
|
|
!this.isRowsSelectable ||
|
|
!this.selection ||
|
|
!this.dataSource ||
|
|
!this.dataSource.data
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.dataSource.data.forEach((i) => this.selection.toggle(i));
|
|
}
|
|
|
|
async filterData(query: string) {
|
|
//
|
|
this.dataSource.filter = query.trim().toLowerCase();
|
|
this.prepareActionOptions();
|
|
|
|
//
|
|
await this.firstPage();
|
|
}
|
|
|
|
async firstPage() {
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.firstPage();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async lastPage() {
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.lastPage();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async nextPage() {
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.nextPage();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async previousPage() {
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.previousPage();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async toPage(index: number) {
|
|
//
|
|
const hasPaginator = await this.getValueAsync(this.showPaginator);
|
|
if (!hasPaginator || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
index = index === 0 ? 1 : index;
|
|
|
|
//
|
|
this.paginator.pageIndex = index - 1;
|
|
this.paginator.page.next({
|
|
pageIndex: index - 1,
|
|
pageSize: this.pageSize,
|
|
length: this.totalItems,
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
async changePageSize(size: number) {
|
|
//
|
|
if (!size || !this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.paginator.pageSize = size;
|
|
this.paginator.page.emit({
|
|
pageIndex: 0,
|
|
pageSize: size,
|
|
length: this.totalItems,
|
|
});
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Action Provider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XTableActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XTableAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.DE_SELECT_ALL:
|
|
this.deselectAll();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.INVERSE_SELECTION:
|
|
this.inverseSelection();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.SELECT_ALL:
|
|
this.selectAll();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.TOGGLE_SELECT_ALL:
|
|
this.toggleSelectAll();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.FIRST_PAGE:
|
|
await this.firstPage();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.LAST_PAGE:
|
|
await this.lastPage();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.NEXT_PAGE:
|
|
await this.nextPage();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.PREVIOUS_PAGE:
|
|
await this.previousPage();
|
|
break;
|
|
|
|
//
|
|
case XTableAction.TO_PAGE:
|
|
if (model.payload && isNumber(model.payload)) {
|
|
await this.toPage(model.payload as number);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private async prepareUIData() {
|
|
//
|
|
this.IS_ROWS_SELECTABLE = await this.getValueAsync(this.selectableRows);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async prepareDataSource() {
|
|
//
|
|
this.DATA = [];
|
|
this.COLUMNS_DATA = [];
|
|
this.DISPLAYED_COLUMNS = [];
|
|
if (!this.properties) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const dataSource = await this.getValueAsync(this.properties.items);
|
|
this.DATA = dataSource;
|
|
|
|
//
|
|
const isSelectableRows = await this.getValueAsync(this.selectableRows);
|
|
const baseColumnsData = !isSelectableRows
|
|
? []
|
|
: [
|
|
{
|
|
name: X_TABLE_SELECTION_HEADER_IDENTIFIER,
|
|
} as XTableColumnOption<any>,
|
|
];
|
|
this.COLUMNS_DATA = baseColumnsData.concat(this.properties.columns);
|
|
|
|
//
|
|
const displayedColumns = await Promise.all(
|
|
this.COLUMNS_DATA.map(
|
|
async (cd) => (await this.getValueAsync(cd.name)) as string
|
|
)
|
|
);
|
|
this.DISPLAYED_COLUMNS = displayedColumns;
|
|
|
|
//
|
|
this.DATA_SOURCE.data = this.DATA;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async prepareSelection() {
|
|
//
|
|
const isMultipleSelection = await this.getValueAsync(this.allowMultiSelect);
|
|
const initialSelectedValues = await this.getValueAsync(
|
|
this.initialSelectedValues
|
|
);
|
|
|
|
//
|
|
this.SELECTION = new SelectionModel<any>(
|
|
isMultipleSelection,
|
|
initialSelectedValues
|
|
);
|
|
|
|
//
|
|
// notify event emitter when has initial selected values ...
|
|
if (hasChild(initialSelectedValues)) {
|
|
this.rowSelectionChanged.emit(initialSelectedValues);
|
|
}
|
|
|
|
//
|
|
this.registerSelectionChangeHandler();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private registerSelectionChangeHandler() {
|
|
//
|
|
// Unsubscribe Last ...
|
|
if (this.SELECTION_SUBSCRIPTION) {
|
|
this.SELECTION_SUBSCRIPTION.unsubscribe();
|
|
this.SELECTION_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
// Subscribe New ...
|
|
this.SELECTION_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.SELECTION.changed.asObservable()
|
|
).subscribe(async () => {
|
|
//
|
|
await this.prepareActionOptions();
|
|
this.rowSelectionChanged.emit(this.SELECTION.selected);
|
|
});
|
|
}
|
|
|
|
private async preparePaginatorOptions() {
|
|
//
|
|
const options = await this.getValueAsync(this.paginatorOptions);
|
|
const defaultOptions = this.defaultPaginatorOptions();
|
|
const preparedOptions: XTablePaginatorOptions = {
|
|
...defaultOptions,
|
|
...options,
|
|
};
|
|
|
|
//
|
|
if (options) {
|
|
//
|
|
if (!options.first) {
|
|
preparedOptions.first = undefined;
|
|
} else {
|
|
//
|
|
const first = options.first;
|
|
|
|
//
|
|
if (first.disabled) {
|
|
const firstDisabled = await this.getValueAsync(first.disabled);
|
|
preparedOptions.first.disabled =
|
|
defaultOptions.first.disabled && firstDisabled;
|
|
} else {
|
|
preparedOptions.first.disabled = defaultOptions.first.disabled;
|
|
}
|
|
|
|
//
|
|
if (!first.icon) {
|
|
preparedOptions.first.icon = defaultOptions.first.icon;
|
|
}
|
|
|
|
//
|
|
if (!first.title) {
|
|
preparedOptions.first.title = defaultOptions.first.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.last) {
|
|
preparedOptions.last = undefined;
|
|
} else {
|
|
//
|
|
const last = options.last;
|
|
|
|
//
|
|
if (last.disabled) {
|
|
const lastDisabled = await this.getValueAsync(last.disabled);
|
|
preparedOptions.last.disabled =
|
|
defaultOptions.last.disabled && lastDisabled;
|
|
} else {
|
|
preparedOptions.last.disabled = defaultOptions.last.disabled;
|
|
}
|
|
|
|
//
|
|
if (!last.icon) {
|
|
preparedOptions.last.icon = defaultOptions.last.icon;
|
|
}
|
|
|
|
//
|
|
if (!last.title) {
|
|
preparedOptions.last.title = defaultOptions.last.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.next) {
|
|
preparedOptions.next = undefined;
|
|
} else {
|
|
//
|
|
const next = options.next;
|
|
|
|
//
|
|
if (next.disabled) {
|
|
const nextDisabled = await this.getValueAsync(next.disabled);
|
|
preparedOptions.next.disabled =
|
|
defaultOptions.next.disabled && nextDisabled;
|
|
} else {
|
|
preparedOptions.next.disabled = defaultOptions.next.disabled;
|
|
}
|
|
|
|
//
|
|
if (!next.icon) {
|
|
preparedOptions.next.icon = defaultOptions.next.icon;
|
|
}
|
|
|
|
//
|
|
if (!next.title) {
|
|
preparedOptions.next.title = defaultOptions.next.title;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!options.prev) {
|
|
preparedOptions.prev = undefined;
|
|
} else {
|
|
//
|
|
const prev = options.prev;
|
|
|
|
//
|
|
if (prev.disabled) {
|
|
const prevDisabled = await this.getValueAsync(prev.disabled);
|
|
preparedOptions.prev.disabled =
|
|
defaultOptions.prev.disabled && prevDisabled;
|
|
} else {
|
|
preparedOptions.prev.disabled = defaultOptions.prev.disabled;
|
|
}
|
|
|
|
//
|
|
if (!prev.icon) {
|
|
preparedOptions.prev.icon = defaultOptions.prev.icon;
|
|
}
|
|
|
|
//
|
|
if (!prev.title) {
|
|
preparedOptions.prev.title = defaultOptions.prev.title;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
this.PAGINATOR_OPTIONS = preparedOptions;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async registerPaginatorHandlers() {
|
|
//
|
|
if (!this.paginator) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Handle Paginator Ready ...
|
|
//
|
|
// Unsubscribe Last ...
|
|
if (this.PAGINATOR_INIT_SUBSCRIPTION) {
|
|
this.PAGINATOR_INIT_SUBSCRIPTION.unsubscribe();
|
|
this.PAGINATOR_INIT_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
// Subscribe New ...
|
|
this.PAGINATOR_INIT_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.paginator.initialized
|
|
).subscribe(async () => {
|
|
//
|
|
await this.preparePaginatorOptions();
|
|
|
|
//
|
|
//#region Initial Page Info Reciever ...
|
|
//
|
|
this.PAGE_SIZE = this.paginator.pageSize;
|
|
this.TOTAL_ITEMS = this.paginator.length;
|
|
this.PAGE_SIZE = this.paginator.pageSize;
|
|
this.CURRENT_PAGE = this.paginator.pageIndex + 1;
|
|
|
|
//
|
|
const totalPagesFloat = this.paginator.length / this.paginator.pageSize;
|
|
this.TOTAL_PAGES = Math.floor(totalPagesFloat);
|
|
|
|
//
|
|
if (
|
|
totalPagesFloat > this.TOTAL_PAGES &&
|
|
totalPagesFloat < this.TOTAL_PAGES + 1
|
|
) {
|
|
this.TOTAL_PAGES++;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handle Page Changes ...
|
|
//
|
|
// Unsubscribe last ...
|
|
if (this.PAGINATOR_PAGE_SUBSCRIPTION) {
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION.unsubscribe();
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION = null;
|
|
}
|
|
|
|
//
|
|
// Subscribe New ...
|
|
this.PAGINATOR_PAGE_SUBSCRIPTION = this.applyTakeUntilWrapper(
|
|
this.paginator.page.asObservable()
|
|
).subscribe(async (res) => {
|
|
//
|
|
// ReNew Pagination Options ...
|
|
await this.preparePaginatorOptions();
|
|
|
|
//
|
|
// Handle Current Page ...
|
|
this.PAGE_SIZE = res.pageSize;
|
|
this.TOTAL_ITEMS = res.length;
|
|
this.PAGE_SIZE = res.pageSize;
|
|
this.CURRENT_PAGE = res.pageIndex + 1;
|
|
this.pageChanged.emit(this.CURRENT_PAGE);
|
|
|
|
//
|
|
//#region Handle Calculation of Total pages ...
|
|
const totalPagesFloat = res.length / res.pageSize;
|
|
this.TOTAL_PAGES = Math.floor(totalPagesFloat);
|
|
|
|
//
|
|
if (
|
|
totalPagesFloat > this.TOTAL_PAGES &&
|
|
totalPagesFloat < this.TOTAL_PAGES + 1
|
|
) {
|
|
this.TOTAL_PAGES++;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.detectChanges();
|
|
});
|
|
//#endregion
|
|
}
|
|
|
|
private defaultPaginatorOptions() {
|
|
//
|
|
const options: XTablePaginatorOptions = {
|
|
pageSizes: this.config.pageSizes,
|
|
pageSize: this.config.defaultPageSize,
|
|
first: {
|
|
title: 'first',
|
|
icon: XIconNames.first,
|
|
disabled: !this.paginator || !this.paginator.hasPreviousPage(),
|
|
},
|
|
last: {
|
|
title: 'last',
|
|
icon: XIconNames.last,
|
|
disabled: !this.paginator || !this.paginator.hasNextPage(),
|
|
},
|
|
prev: {
|
|
title: 'previous',
|
|
icon: XIconNames.previous,
|
|
disabled: !this.paginator || !this.paginator.hasPreviousPage(),
|
|
},
|
|
next: {
|
|
title: 'next',
|
|
icon: XIconNames.next,
|
|
disabled: !this.paginator || !this.paginator.hasNextPage(),
|
|
},
|
|
pageInfoProvider: (
|
|
locale: XLocale,
|
|
currentPage: number,
|
|
pageSize: number,
|
|
totalPages: number
|
|
) => {
|
|
//
|
|
const info = `${currentPage}/${totalPages}`;
|
|
return applyLocale(info, locale);
|
|
},
|
|
};
|
|
|
|
//
|
|
return options;
|
|
}
|
|
|
|
private async prepareActionOptions() {
|
|
//
|
|
let preparedOptions: XTableActionOptions = {};
|
|
const options = await this.getValueAsync(this.actionOptions);
|
|
const defaultOptions = this.defaultActionOptions();
|
|
|
|
//
|
|
if (!options) {
|
|
preparedOptions = defaultOptions;
|
|
} else {
|
|
//
|
|
if (options.start) {
|
|
preparedOptions.start = [...options.start, ...defaultOptions.start];
|
|
} else {
|
|
preparedOptions.start = [...defaultOptions.start];
|
|
}
|
|
|
|
//
|
|
if (options.end) {
|
|
preparedOptions.end = [...defaultOptions.end, ...options.end];
|
|
} else {
|
|
preparedOptions.end = [...defaultOptions.end];
|
|
}
|
|
}
|
|
|
|
//
|
|
this.ACTION_OPTIONS = preparedOptions;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private defaultActionOptions() {
|
|
//
|
|
const options: XTableActionOptions = {
|
|
start: [
|
|
{
|
|
title: XResourceIDs.delete,
|
|
icon: XIconNames.remove,
|
|
color: XColor.Danger,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!this.selection ||
|
|
!hasChild(this.data) ||
|
|
!hasChild(this.selection.selected),
|
|
hidden: !this.isRowsSelectable,
|
|
handler: (items: any) => {
|
|
//
|
|
this.managerService.dialogService.presentActionModal({
|
|
header: XResourceIDs.are_you_sure,
|
|
buttons: [],
|
|
keyboardClose: true,
|
|
backdropDismiss: true,
|
|
hasOk: true,
|
|
okHandler: () => {
|
|
this.removeItems.emit(items);
|
|
},
|
|
hasCancel: true,
|
|
});
|
|
},
|
|
},
|
|
],
|
|
end: [
|
|
{
|
|
title: XResourceIDs.select_all,
|
|
icon: XIconNames.select_all,
|
|
color: XColor.Tertiary,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!this.selection ||
|
|
!hasChild(this.data) ||
|
|
this.isAllSelected(),
|
|
hidden: !this.isRowsSelectable,
|
|
handler: () => {
|
|
this.selectAll();
|
|
},
|
|
},
|
|
{
|
|
title: XResourceIDs.select_all_group,
|
|
icon: XIconNames.select_all_group,
|
|
color: XColor.Tertiary,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!hasChild(this.dataSource.filteredData) ||
|
|
this.isAllFilteredSelected(),
|
|
hidden:
|
|
!this.dataSource ||
|
|
!this.isRowsSelectable ||
|
|
!this.dataSource.filter,
|
|
handler: () => {
|
|
this.selectAllFilteredData();
|
|
},
|
|
},
|
|
{
|
|
title: XResourceIDs.deselect_all,
|
|
icon: XIconNames.deselect_all,
|
|
color: XColor.Tertiary,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!this.selection ||
|
|
!hasChild(this.data) ||
|
|
!hasChild(this.selection.selected),
|
|
hidden: !this.isRowsSelectable,
|
|
handler: () => {
|
|
this.deselectAll();
|
|
},
|
|
},
|
|
{
|
|
title: XResourceIDs.deselect_all_group,
|
|
icon: XIconNames.deselect_all_group,
|
|
color: XColor.Tertiary,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!this.selection ||
|
|
!hasChild(this.data) ||
|
|
!this.isAllFilteredSelected() ||
|
|
!hasChild(this.selection.selected),
|
|
hidden:
|
|
!this.isRowsSelectable ||
|
|
!this.dataSource.filter ||
|
|
!hasChild(this.dataSource.filteredData),
|
|
handler: () => {
|
|
this.deselectAllFilteredData();
|
|
},
|
|
},
|
|
{
|
|
title: XResourceIDs.inverse_selection,
|
|
icon: XIconNames.inverse_selection,
|
|
color: XColor.Tertiary,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
!this.selection ||
|
|
!hasChild(this.data) ||
|
|
!hasChild(this.selection.selected),
|
|
hidden: !this.isRowsSelectable,
|
|
handler: () => {
|
|
this.inverseSelection();
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
//
|
|
return options;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XTableComponent } from './x-table.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XEmptyModule } from '../x-empty/x-empty.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XTableComponent],
|
|
imports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
XEmptyModule,
|
|
CommonModule,
|
|
XBaseComponentModule,
|
|
],
|
|
exports: [
|
|
XCardModule,
|
|
XIconModule,
|
|
XEmptyModule,
|
|
XTableComponent,
|
|
XBaseComponentModule,
|
|
],
|
|
})
|
|
export class XTableModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.typings.ts
|
|
|
|
import {
|
|
Inject,
|
|
Input,
|
|
NgZone,
|
|
Output,
|
|
Component,
|
|
Renderer2,
|
|
Injectable,
|
|
ElementRef,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XLocale,
|
|
XResourceIDs,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardEmptyContainer,
|
|
IXCardEmptyContainer,
|
|
XCardEmptyContainerComponent,
|
|
} from '../classes/i-x-card-empty.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XIconIdentifier } from '../x-icon/x-icon.typings';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export type XTableColumn<T> = keyof T;
|
|
|
|
export type XTableColumnIdentifier<T> = XTableColumn<T> | string;
|
|
|
|
export interface XTableColumnOption<T> {
|
|
//
|
|
hidden?: XStandardType<boolean>;
|
|
name: XTableColumnIdentifier<T>;
|
|
sortable?: XStandardType<boolean>;
|
|
icon?: XStandardType<XIconIdentifier>;
|
|
customColumn?: XStandardType<boolean>;
|
|
title: XStandardType<XResourceIdentifier>;
|
|
description?: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
export interface XTableConfig<T> {
|
|
//
|
|
items: XStandardType<T[]>;
|
|
columns: XTableColumnOption<T>[];
|
|
}
|
|
|
|
export type XSortDirection = 'asc' | 'desc';
|
|
|
|
export enum XTableItemPosition {
|
|
TOP = 'top',
|
|
BOTTOM = 'bottom',
|
|
}
|
|
|
|
export type XTableItemPositionIdentifier = XTableItemPosition | string;
|
|
|
|
export const X_TABLE_SELECTION_HEADER_IDENTIFIER = 'selection';
|
|
|
|
export interface XTableActionButton {
|
|
hidden?: XStandardType<boolean>;
|
|
disabled?: XStandardType<boolean>;
|
|
icon?: XStandardType<XIconIdentifier>;
|
|
color?: XStandardType<XColorIdentifier>;
|
|
title?: XStandardType<XResourceIdentifier>;
|
|
handler?: (item?: any) => XStandardType<void>;
|
|
}
|
|
|
|
export interface XTablePaginatorOptions {
|
|
pageSizes?: XStandardType<number[]>;
|
|
pageSize?: XStandardType<number>;
|
|
first?: XTableActionButton;
|
|
last?: XTableActionButton;
|
|
next?: XTableActionButton;
|
|
prev?: XTableActionButton;
|
|
pageInfoProvider?: (
|
|
locale: XLocale,
|
|
currentPage: number,
|
|
pageSize: number,
|
|
totalPages: number,
|
|
totalItems: number
|
|
) => string;
|
|
}
|
|
|
|
export interface XTableActionOptions {
|
|
end?: XTableActionButton[];
|
|
start?: XTableActionButton[];
|
|
}
|
|
|
|
export enum XTableAction {
|
|
//
|
|
Refresh = 'refresh',
|
|
|
|
//
|
|
TOGGLE_SELECT_ALL = 'toggle-select-all',
|
|
SELECT_ALL = 'select-all',
|
|
DE_SELECT_ALL = 'deselect-all',
|
|
INVERSE_SELECTION = 'inverse-selection',
|
|
FIRST_PAGE = 'first-page',
|
|
LAST_PAGE = 'last-page',
|
|
NEXT_PAGE = 'next-page',
|
|
PREVIOUS_PAGE = 'previous-page',
|
|
TO_PAGE = 'to-page',
|
|
}
|
|
|
|
export type XTableActionIdentifier = XTableAction | string;
|
|
|
|
export interface XTableActionModel
|
|
extends XBaseActionModel<XTableActionIdentifier> {}
|
|
|
|
//
|
|
//#region Inside Card/Empty Container ...
|
|
export interface IXTableContainer extends IXCardEmptyContainer {
|
|
//
|
|
//#region Other Props ...
|
|
//
|
|
actionProvider: Subject<XTableActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
foregroundColor: XStandardType<boolean>;
|
|
|
|
canClearSort: XStandardType<boolean>;
|
|
cellCssClass: XStandardType<XOneOrManyType<string>>;
|
|
properties: XTableConfig<any>;
|
|
cellTemplate: TemplateRef<any>;
|
|
customCellTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Header Props ...
|
|
//
|
|
showHeader: XStandardType<boolean>;
|
|
stickyHeader: XStandardType<boolean>;
|
|
headerCellCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
headerColor: XStandardType<XColorIdentifier>;
|
|
headerForegroundColor: XStandardType<boolean>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Click Props ...
|
|
clickableRows: XStandardType<boolean>;
|
|
rowClicked: EventEmitter<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selection props ...
|
|
selectableRows: XStandardType<boolean>;
|
|
rowSelected: EventEmitter<any>;
|
|
rowSelectionChanged: EventEmitter<any[]>;
|
|
allowMultiSelect: XStandardType<boolean>;
|
|
initialSelectedValues: XStandardType<any[]>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Filter/Search Props ...
|
|
showSearchBar: XStandardType<boolean>;
|
|
searchBarPosition: XStandardType<XTableItemPositionIdentifier>;
|
|
searchBarColor: XStandardType<XColorIdentifier>;
|
|
searchTitle: XStandardType<XResourceIdentifier>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Paginator Props ...
|
|
showPaginator: XStandardType<boolean>;
|
|
paginatorPosition: XStandardType<XTableItemPositionIdentifier>;
|
|
paginatorColor: XStandardType<XColorIdentifier>;
|
|
paginatorOptions: XStandardType<XTablePaginatorOptions>;
|
|
pageChanged: EventEmitter<number>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Props ...
|
|
showActionBar: XStandardType<boolean>;
|
|
actionBarPosition: XStandardType<XTableItemPositionIdentifier>;
|
|
actionBarColor: XStandardType<XColorIdentifier>;
|
|
actionOptions: XStandardType<XTableActionOptions>;
|
|
removeItems: EventEmitter<any[]>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XTableContainer
|
|
extends XCardEmptyContainer
|
|
implements Readonly<IXTableContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Other Props ...
|
|
//
|
|
readonly actionProvider: Subject<XTableActionModel> =
|
|
new Subject<XTableActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
readonly foregroundColor: XStandardType<boolean> = false;
|
|
|
|
readonly canClearSort: XStandardType<boolean> = true;
|
|
readonly cellCssClass: XStandardType<XOneOrManyType<string>>;
|
|
readonly properties: XTableConfig<any>;
|
|
readonly cellTemplate: TemplateRef<any>;
|
|
readonly customCellTemplate: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Header Props ...
|
|
//
|
|
readonly showHeader: XStandardType<boolean> = true;
|
|
readonly stickyHeader: XStandardType<boolean> = true;
|
|
readonly headerCellCssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly headerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly headerForegroundColor: XStandardType<boolean> = false;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Click Props ...
|
|
readonly clickableRows: XStandardType<boolean> = false;
|
|
readonly rowClicked: EventEmitter<any> = new EventEmitter<any>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selection props ...
|
|
readonly selectableRows: XStandardType<boolean> = false;
|
|
readonly rowSelected: EventEmitter<any> = new EventEmitter<any>();
|
|
readonly rowSelectionChanged: EventEmitter<any[]> = new EventEmitter<any[]>();
|
|
readonly allowMultiSelect: XStandardType<boolean> = true;
|
|
readonly initialSelectedValues: XStandardType<any[]> = [];
|
|
//#endregion
|
|
|
|
//
|
|
//#region Filter/Search Props ...
|
|
readonly showSearchBar: XStandardType<boolean> = false;
|
|
readonly searchBarPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
XTableItemPosition.TOP;
|
|
readonly searchBarColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly searchTitle: XStandardType<XResourceIdentifier> =
|
|
XResourceIDs.search;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Paginator Props ...
|
|
readonly showPaginator: XStandardType<boolean>;
|
|
readonly paginatorPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
XTableItemPosition.BOTTOM;
|
|
readonly paginatorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly paginatorOptions: XStandardType<XTablePaginatorOptions>;
|
|
readonly pageChanged: EventEmitter<number> = new EventEmitter<number>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Props ...
|
|
readonly showActionBar: XStandardType<boolean>;
|
|
readonly actionBarPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
XTableItemPosition.TOP;
|
|
readonly actionBarColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly actionOptions: XStandardType<XTableActionOptions>;
|
|
readonly removeItems: EventEmitter<any[]> = new EventEmitter<any[]>();
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XTableContainerComponent
|
|
extends XCardEmptyContainerComponent
|
|
implements IXTableContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Other Props ...
|
|
@Input()
|
|
actionProvider: Subject<XTableActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
canClearSort: XStandardType<boolean> = this.propertyProvider.canClearSort;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
foregroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.foregroundColor;
|
|
|
|
@Input()
|
|
cellCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cellCssClass;
|
|
|
|
@Input()
|
|
properties: XTableConfig<any> = this.propertyProvider.properties;
|
|
|
|
@Input()
|
|
cellTemplate: TemplateRef<any> = this.propertyProvider.cellTemplate;
|
|
|
|
@Input()
|
|
customCellTemplate: TemplateRef<any> =
|
|
this.propertyProvider.customCellTemplate;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Header Props ...
|
|
@Input()
|
|
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
|
|
|
|
@Input()
|
|
stickyHeader: XStandardType<boolean> = this.propertyProvider.stickyHeader;
|
|
|
|
@Input()
|
|
headerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerColor;
|
|
|
|
@Input()
|
|
headerForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.headerForegroundColor;
|
|
|
|
@Input()
|
|
headerCellCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.headerCellCssClass;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Click Props ...
|
|
@Input()
|
|
clickableRows: XStandardType<boolean> = this.propertyProvider.clickableRows;
|
|
|
|
@Output()
|
|
rowClicked: EventEmitter<any> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Selection props ...
|
|
@Input()
|
|
selectableRows: XStandardType<boolean> = this.propertyProvider.selectableRows;
|
|
|
|
@Output()
|
|
rowSelected: EventEmitter<any> = new EventEmitter();
|
|
|
|
@Output()
|
|
rowSelectionChanged: EventEmitter<any[]> = new EventEmitter();
|
|
|
|
@Input()
|
|
allowMultiSelect: XStandardType<boolean> =
|
|
this.propertyProvider.allowMultiSelect;
|
|
|
|
@Input()
|
|
initialSelectedValues: XStandardType<any[]> =
|
|
this.propertyProvider.initialSelectedValues;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Filter/Search Props ...
|
|
@Input()
|
|
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
|
|
|
|
@Input()
|
|
searchBarPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
this.propertyProvider.searchBarPosition;
|
|
|
|
@Input()
|
|
searchBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.searchBarColor;
|
|
|
|
@Input()
|
|
searchTitle: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.searchTitle;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Paginator Props ...
|
|
@Input()
|
|
showPaginator: XStandardType<boolean> = this.propertyProvider.showPaginator;
|
|
|
|
@Input()
|
|
paginatorPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
this.propertyProvider.paginatorPosition;
|
|
|
|
@Input()
|
|
paginatorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.paginatorColor;
|
|
|
|
@Input()
|
|
paginatorOptions: XStandardType<XTablePaginatorOptions> =
|
|
this.propertyProvider.paginatorOptions;
|
|
|
|
@Output()
|
|
pageChanged: EventEmitter<number> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Action Props ...
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
@Input()
|
|
actionBarPosition: XStandardType<XTableItemPositionIdentifier> =
|
|
this.propertyProvider.actionBarPosition;
|
|
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionOptions: XStandardType<XTableActionOptions> =
|
|
this.propertyProvider.actionOptions;
|
|
|
|
@Output()
|
|
removeItems: EventEmitter<any[]> = new EventEmitter();
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XTableContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXTableContainer
|
|
): Observable<IXTableContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
canClearSort: this.getValue(
|
|
container ? container.canClearSort : this.canClearSort
|
|
),
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
foregroundColor: this.getValue(
|
|
container ? container.foregroundColor : this.foregroundColor
|
|
),
|
|
cellCssClass: this.getValue(
|
|
container ? container.cellCssClass : this.cellCssClass
|
|
),
|
|
properties: this.getValue(
|
|
container ? container.properties : this.properties
|
|
),
|
|
cellTemplate: this.getValue(
|
|
container ? container.cellTemplate : this.cellTemplate
|
|
),
|
|
customCellTemplate: this.getValue(
|
|
container ? container.customCellTemplate : this.customCellTemplate
|
|
),
|
|
showHeader: this.getValue(
|
|
container ? container.showHeader : this.showHeader
|
|
),
|
|
stickyHeader: this.getValue(
|
|
container ? container.stickyHeader : this.stickyHeader
|
|
),
|
|
headerColor: this.getValue(
|
|
container ? container.headerColor : this.headerColor
|
|
),
|
|
headerForegroundColor: this.getValue(
|
|
container
|
|
? container.headerForegroundColor
|
|
: this.headerForegroundColor
|
|
),
|
|
headerCellCssClass: this.getValue(
|
|
container ? container.headerCellCssClass : this.headerCellCssClass
|
|
),
|
|
clickableRows: this.getValue(
|
|
container ? container.clickableRows : this.clickableRows
|
|
),
|
|
selectableRows: this.getValue(
|
|
container ? container.selectableRows : this.selectableRows
|
|
),
|
|
allowMultiSelect: this.getValue(
|
|
container ? container.allowMultiSelect : this.allowMultiSelect
|
|
),
|
|
initialSelectedValues: this.getValue(
|
|
container
|
|
? container.initialSelectedValues
|
|
: this.initialSelectedValues
|
|
),
|
|
showSearchBar: this.getValue(
|
|
container ? container.showSearchBar : this.showSearchBar
|
|
),
|
|
searchBarPosition: this.getValue(
|
|
container ? container.searchBarPosition : this.searchBarPosition
|
|
),
|
|
searchBarColor: this.getValue(
|
|
container ? container.searchBarColor : this.searchBarColor
|
|
),
|
|
searchTitle: this.getValue(
|
|
container ? container.searchTitle : this.searchTitle
|
|
),
|
|
showPaginator: this.getValue(
|
|
container ? container.showPaginator : this.showPaginator
|
|
),
|
|
paginatorPosition: this.getValue(
|
|
container ? container.paginatorPosition : this.paginatorPosition
|
|
),
|
|
paginatorColor: this.getValue(
|
|
container ? container.paginatorColor : this.paginatorColor
|
|
),
|
|
paginatorOptions: this.getValue(
|
|
container ? container.paginatorOptions : this.paginatorOptions
|
|
),
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarPosition: this.getValue(
|
|
container ? container.actionBarPosition : this.actionBarPosition
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionOptions: this.getValue(
|
|
container ? container.actionOptions : this.actionOptions
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
rowSelectionChanged: this.rowSelectionChanged,
|
|
pageChanged: this.pageChanged,
|
|
rowClicked: this.rowClicked,
|
|
rowSelected: this.rowSelected,
|
|
removeItems: this.removeItems,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else tabsRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="tabsRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Ref -->
|
|
<ng-template #tabsRef>
|
|
<div
|
|
xSwipable
|
|
class="x-tabs x-wrapper"
|
|
[supportedDirections]="2"
|
|
(swipeEnd)="handleSwipeEnd()"
|
|
(swipeStart)="handleSwipeStart()"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[swipeDisabled]="swipeDisabled() | async"
|
|
[class.swipable]="!(swipeDisabled() | async)"
|
|
[class.hide-header]="!(getValue(showHeader) | async)"
|
|
>
|
|
<mat-tab-group
|
|
#group
|
|
[(selectedIndex)]="selectedIndex"
|
|
[color]="getValue(color) | async"
|
|
(animationDone)="animationDone.emit()"
|
|
[dynamicHeight]="isDynamicHeight() | async"
|
|
[headerPosition]="getHeaderPosition() | async"
|
|
[attr.mat-stretch-tabs]="isStretched() | async"
|
|
[disableRipple]="getValue(disableRipple) | async"
|
|
[attr.mat-align-tabs]="getTabAlignValue() | async"
|
|
(selectedTabChange)="handleSelectedTabChanged($event)"
|
|
[disablePagination]="getValue(disablePagination) | async"
|
|
[animationDuration]="getValue(animationDuration) | async"
|
|
>
|
|
<mat-tab
|
|
*ngFor="let tab of tabs"
|
|
[disabled]="uiDisabled || (getValueStream(disablePagination) | async)"
|
|
>
|
|
<ng-template mat-tab-label>
|
|
<div [xColor]="getValue(headerColor) | async" [isForeground]="false">
|
|
<ng-container *ngTemplateOutlet="tab.label"></ng-container>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template matTabContent>
|
|
<ng-container *ngTemplateOutlet="tab.content"></ng-container>
|
|
</ng-template>
|
|
</mat-tab>
|
|
</mat-tab-group>
|
|
</div>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.scss
|
|
|
|
:host {
|
|
//
|
|
--tab-header-color: var(--x-color-primary);
|
|
|
|
//
|
|
--tab-indicator-color: var(--x-color-secondary);
|
|
|
|
//
|
|
--tab-paginator-foreground-color: var(--x-color-secondary-contrast);
|
|
--tab-paginator-background-color: var(--x-color-secondary);
|
|
|
|
//
|
|
--active-tab-foreground-color: var(--x-color-secondary-contrast);
|
|
--active-tab-background-color: var(--x-color-secondary);
|
|
}
|
|
|
|
:host ::ng-deep.mat-ink-bar {
|
|
background-color: var(--tab-indicator-color) !important;
|
|
}
|
|
|
|
.x-wrapper {
|
|
//
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
x-card {
|
|
//
|
|
width: inherit;
|
|
height: inherit;
|
|
}
|
|
|
|
:host ::ng-deep .x-wrapper {
|
|
.mat-tab-header {
|
|
display: flex;
|
|
}
|
|
|
|
&.hide-header {
|
|
.mat-tab-header {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep.swipable {
|
|
//
|
|
cursor: grab;
|
|
|
|
//
|
|
-webkit-user-select: none; /* Chrome all / Safari all */
|
|
-moz-user-select: none; /* Firefox all */
|
|
-ms-user-select: none; /* IE 10+ */
|
|
user-select: none; /* Likely future */
|
|
}
|
|
|
|
:host ::ng-deep.mat-tab-label-active {
|
|
opacity: 1 !important;
|
|
|
|
//
|
|
color: var(--active-tab-foreground-color) !important;
|
|
background-color: var(--active-tab-background-color) !important;
|
|
|
|
.mat-tab-label-content {
|
|
//
|
|
color: var(--active-tab-foreground-color) !important;
|
|
background-color: var(--active-tab-background-color) !important;
|
|
|
|
* {
|
|
//
|
|
color: var(--active-tab-foreground-color) !important;
|
|
background-color: var(--active-tab-background-color) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
:host ::ng-deep .mat-tab-header-pagination {
|
|
//
|
|
background-color: var(--tab-paginator-background-color) !important;
|
|
}
|
|
|
|
:host ::ng-deep.mat-tab-header-pagination-chevron {
|
|
border-color: var(--tab-paginator-foreground-color) !important;
|
|
}
|
|
|
|
:host ::ng-deep .mat-tab-labels {
|
|
//
|
|
background-color: var(--tab-header-color) !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.ts
|
|
|
|
import {
|
|
QueryList,
|
|
Component,
|
|
ContentChildren,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
nameof,
|
|
parseXColor,
|
|
isNullOrEmptyString,
|
|
getXColorCssVariableName,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XTabAlign,
|
|
XTabsAction,
|
|
XTabsCssVars,
|
|
XTabChangeEvent,
|
|
XTabsActionModel,
|
|
XTabsHeaderPosition,
|
|
XTabsContainerComponent,
|
|
} from './x-tabs.typings';
|
|
import { map, concatMap } from 'rxjs/operators';
|
|
import { XTabComponent } from './x-tab/x-tab.component';
|
|
import { MatTabChangeEvent } from '@angular/material/tabs';
|
|
import { of, Subject, Subscription, Observable } from 'rxjs';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-tabs',
|
|
templateUrl: './x-tabs.component.html',
|
|
styleUrls: ['./x-tabs.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XTabsComponent extends XTabsContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private TABS: QueryList<XTabComponent>;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
canPrev$ = new Subject<boolean>();
|
|
canNext$ = new Subject<boolean>();
|
|
|
|
//
|
|
get tabs() {
|
|
return this.TABS;
|
|
}
|
|
|
|
//
|
|
@ContentChildren(XTabComponent)
|
|
set tabs(s: QueryList<XTabComponent>) {
|
|
this.TABS = s;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onInit() {
|
|
super.onInit();
|
|
|
|
//
|
|
await this.handleSelectedIndex();
|
|
await this.applyDefaultColors();
|
|
}
|
|
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
const hasSelectedIndex = changeKeys.includes(
|
|
nameof<XTabsComponent>('selectedIndex')
|
|
);
|
|
if (hasSelectedIndex) {
|
|
await this.handleSelectedIndex();
|
|
}
|
|
|
|
//
|
|
//#region Color Changed ...
|
|
//
|
|
// Tab Header Color ...
|
|
const isTabHeaderColorChanged = changeKeys.includes(
|
|
nameof<XTabsComponent>('headerColor')
|
|
);
|
|
if (isTabHeaderColorChanged) {
|
|
await this.applyTabHeaderColor();
|
|
}
|
|
|
|
//
|
|
// Active Tab Color ...
|
|
const isActiveTabColorChanged = changeKeys.includes(
|
|
nameof<XTabsComponent>('activeTabColor')
|
|
);
|
|
if (isActiveTabColorChanged) {
|
|
await this.applyActiveTabColor();
|
|
}
|
|
|
|
//
|
|
// Tab Indicator Color ...
|
|
const isTabIndicatorColorChanged = changeKeys.includes(
|
|
nameof<XTabsComponent>('tabIndicatorColor')
|
|
);
|
|
if (isTabIndicatorColorChanged) {
|
|
await this.applyTabIndicatorColor();
|
|
}
|
|
|
|
//
|
|
// Tab Paginator Color ...
|
|
const isTabPaginatorColorChanged = changeKeys.includes(
|
|
nameof<XTabsComponent>('tabPaginatorColor')
|
|
);
|
|
if (isTabPaginatorColorChanged) {
|
|
await this.applyTabPaginatorColor();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XTabsComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Task Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
isDynamicHeight() {
|
|
return this.getValue(this.dynamicHeight).pipe(
|
|
map((isDynamic) => (isDynamic ? '' : undefined))
|
|
);
|
|
}
|
|
|
|
isStretched() {
|
|
return this.getValue(this.alignTabs).pipe(
|
|
map((align) => (align === XTabAlign.STRETCH ? '' : undefined))
|
|
);
|
|
}
|
|
|
|
getTabAlignValue() {
|
|
return this.isStretched().pipe(
|
|
concatMap((isStretched) => {
|
|
if (isStretched) {
|
|
return of(undefined);
|
|
} else {
|
|
return this.getValue(this.alignTabs);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
swipeDisabled() {
|
|
return this.getValue(this.swipable).pipe(
|
|
map((swipable) => !swipable || this.uiDisabled)
|
|
);
|
|
}
|
|
|
|
getHeaderPosition(): Observable<'above' | 'below'> {
|
|
return this.getValue(this.headerPosition).pipe(
|
|
map((position) =>
|
|
position === XTabsHeaderPosition.ABOVE ? 'above' : 'below'
|
|
)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleSelectedTabChanged(event: MatTabChangeEvent) {
|
|
//
|
|
const mEvent: XTabChangeEvent = {
|
|
index: event.index,
|
|
tab: this.tabs.toArray()[event.index],
|
|
};
|
|
|
|
//
|
|
const canLoop = await this.canLoop();
|
|
|
|
//
|
|
if (event.index === 0) {
|
|
//
|
|
this.canPrev$.next(false || canLoop);
|
|
this.canNext$.next(true);
|
|
} else if (event.index === this.tabs.length - 1) {
|
|
//
|
|
this.canPrev$.next(true);
|
|
this.canNext$.next(false || canLoop);
|
|
} else if (event.index > 0 && event.index < this.tabs.length) {
|
|
//
|
|
this.canPrev$.next(true);
|
|
this.canNext$.next(true);
|
|
}
|
|
|
|
//
|
|
this.selectedTabChange.emit(mEvent);
|
|
this.selectedIndexChange.emit(mEvent.index);
|
|
}
|
|
|
|
async handleSwipeEnd() {
|
|
await this.prev();
|
|
}
|
|
|
|
async handleSwipeStart() {
|
|
await this.next();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
length() {
|
|
return this.tabs ? this.tabs.length : 0;
|
|
}
|
|
|
|
getTab(index: number) {
|
|
return this.checkIndex(index) ? this.tabs.toArray()[index] : null;
|
|
}
|
|
|
|
async next() {
|
|
//
|
|
const isLocked = await this.isLocked();
|
|
if (isLocked) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const current = this.selectedIndex;
|
|
const canLoop = await this.canLoop();
|
|
const next = this.checkIndex(current + 1)
|
|
? current + 1
|
|
: canLoop
|
|
? 0
|
|
: current;
|
|
|
|
//
|
|
this.selectedIndex = next;
|
|
this.detectChanges();
|
|
}
|
|
|
|
async prev() {
|
|
//
|
|
const isLocked = await this.isLocked();
|
|
if (isLocked) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const current = this.selectedIndex;
|
|
const canLoop = await this.canLoop();
|
|
const prev = this.checkIndex(current - 1)
|
|
? current - 1
|
|
: canLoop
|
|
? this.tabs.length - 1
|
|
: current;
|
|
|
|
//
|
|
this.selectedIndex = prev;
|
|
this.detectChanges();
|
|
}
|
|
|
|
async first() {
|
|
//
|
|
const isLocked = await this.isLocked();
|
|
if (isLocked) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selectedIndex = 0;
|
|
this.detectChanges();
|
|
}
|
|
|
|
async last() {
|
|
//
|
|
const isLocked = await this.isLocked();
|
|
if (isLocked) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selectedIndex = this.tabs.length - 1;
|
|
this.detectChanges();
|
|
}
|
|
|
|
async to(index: number) {
|
|
//
|
|
const isLocked = await this.isLocked();
|
|
if (isLocked) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!this.checkIndex(index)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selectedIndex = index;
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XTabsActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XTabsAction.FIRST:
|
|
await this.first();
|
|
break;
|
|
|
|
//
|
|
case XTabsAction.LAST:
|
|
await this.last();
|
|
break;
|
|
|
|
//
|
|
case XTabsAction.NEXT:
|
|
await this.next();
|
|
break;
|
|
|
|
//
|
|
case XTabsAction.PREV:
|
|
await this.prev();
|
|
break;
|
|
|
|
//
|
|
case XTabsAction.TO:
|
|
if (model.payload) {
|
|
await this.to(model.payload);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XTabsAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private checkIndex(index: number) {
|
|
return this.tabs && index < this.tabs.length && index >= 0;
|
|
}
|
|
|
|
private async canLoop() {
|
|
//
|
|
const result = await this.getValueAsync(this.loopTabs);
|
|
return result || false;
|
|
}
|
|
|
|
private async isLocked() {
|
|
//
|
|
const result = await this.getValueAsync(this.lock);
|
|
return result || false;
|
|
}
|
|
|
|
private async handleSelectedIndex() {
|
|
//
|
|
const startIndex = await this.getValueAsync(this.selectedIndex);
|
|
|
|
//
|
|
if (!this.checkIndex(startIndex)) {
|
|
//
|
|
this.selectedIndex = 0;
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.selectedIndex = startIndex;
|
|
}
|
|
|
|
//
|
|
//#region Color Appliers ...
|
|
private async applyDefaultColors() {
|
|
//
|
|
await this.applyActiveTabColor();
|
|
await this.applyTabHeaderColor();
|
|
await this.applyTabPaginatorColor();
|
|
await this.applyTabIndicatorColor();
|
|
}
|
|
|
|
private async applyTabHeaderColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.headerColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabsCssVars.TabHeaderColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyActiveTabColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.activeTabColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabsCssVars.ActiveTabForegroundColor, `var(${fgColor})`);
|
|
this.setCssVar(XTabsCssVars.ActiveTabBackgroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyTabIndicatorColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.tabIndicatorColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabsCssVars.TabIndicatorColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async applyTabPaginatorColor() {
|
|
//
|
|
const color = await this.getValueAsync(this.tabPaginatorColor);
|
|
if (!color) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const colorDescriptor = parseXColor(color);
|
|
if (!colorDescriptor) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const fgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
true,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
const bgColor = getXColorCssVariableName(
|
|
colorDescriptor.name,
|
|
false,
|
|
colorDescriptor.brightnessLevel
|
|
);
|
|
if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.setCssVar(XTabsCssVars.TabPaginatorForegroundColor, `var(${fgColor})`);
|
|
this.setCssVar(XTabsCssVars.TabPaginatorBackgroundColor, `var(${bgColor})`);
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XTabsComponent } from './x-tabs.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XTabComponent } from './x-tab/x-tab.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XTabsContainerComponent } from './x-tabs.typings';
|
|
|
|
@NgModule({
|
|
declarations: [XTabsComponent, XTabComponent, XTabsContainerComponent],
|
|
imports: [CommonModule, XBaseComponentModule, XIconModule, XCardModule],
|
|
exports: [
|
|
XIconModule,
|
|
XCardModule,
|
|
XTabComponent,
|
|
XTabsComponent,
|
|
XBaseComponentModule
|
|
]
|
|
})
|
|
export class XTabsModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XTabComponent } from './x-tab/x-tab.component';
|
|
import { MatTabChangeEvent } from '@angular/material/tabs';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XTabsHeaderPosition {
|
|
ABOVE = 'above',
|
|
BELOW = 'below',
|
|
}
|
|
|
|
export type XTabsHeaderPositionIdentifier = XTabsHeaderPosition | string;
|
|
|
|
export interface XTabChangeEvent extends Pick<MatTabChangeEvent, 'index'> {
|
|
tab: XTabComponent;
|
|
}
|
|
|
|
export enum XTabAlign {
|
|
START = 'start',
|
|
CENTER = 'center',
|
|
END = 'end',
|
|
STRETCH = 'stretch',
|
|
}
|
|
|
|
export type XTabAlignIdentifier = XTabAlign | string;
|
|
|
|
export enum XTabsAction {
|
|
FIRST = 'first',
|
|
LAST = 'last',
|
|
PREV = 'prev',
|
|
NEXT = 'next',
|
|
TO = 'to',
|
|
|
|
//
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XTabsActionIdentifier = XTabsAction | string;
|
|
|
|
export interface XTabsActionModel
|
|
extends XBaseActionModel<XTabsActionIdentifier> {}
|
|
|
|
export enum XTabsCssVars {
|
|
//
|
|
TabHeaderColor = 'tab-header-color',
|
|
|
|
//
|
|
TabIndicatorColor = 'tab-indicator-color',
|
|
|
|
//
|
|
ActiveTabForegroundColor = 'active-tab-foreground-color',
|
|
ActiveTabBackgroundColor = 'active-tab-background-color',
|
|
|
|
//
|
|
TabPaginatorForegroundColor = 'tab-paginator-foreground-color',
|
|
TabPaginatorBackgroundColor = 'tab-paginator-background-color',
|
|
}
|
|
|
|
export type XTabsCssVarsIdentifier = XTabsCssVars | string;
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
export interface IXTabsContainer extends IXComponentCardContainer {
|
|
//
|
|
actionProvider: Subject<XTabsActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
selectedIndex: number;
|
|
selectedIndexChange: EventEmitter<number>;
|
|
|
|
//
|
|
showHeader: XStandardType<boolean>;
|
|
disablePagination: XStandardType<boolean>;
|
|
alignTabs: XStandardType<XTabAlignIdentifier>;
|
|
dynamicHeight: XStandardType<boolean>;
|
|
animationDuration: XStandardType<string>;
|
|
disableRipple: XStandardType<boolean>;
|
|
headerPosition: XStandardType<XTabsHeaderPositionIdentifier>;
|
|
|
|
//
|
|
loopTabs: XStandardType<boolean>;
|
|
swipable: XStandardType<boolean>;
|
|
animationDone: EventEmitter<void>;
|
|
|
|
//
|
|
lock: XStandardType<boolean>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
headerColor: XStandardType<XColorIdentifier>;
|
|
activeTabColor: XStandardType<XColorIdentifier>;
|
|
tabIndicatorColor: XStandardType<XColorIdentifier>;
|
|
tabPaginatorColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
selectedTabChange: EventEmitter<XTabChangeEvent>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XTabsContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXTabsContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XTabsActionModel> =
|
|
new Subject<XTabsActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly selectedIndex: number = 0;
|
|
readonly selectedIndexChange: EventEmitter<number> =
|
|
new EventEmitter<number>();
|
|
|
|
//
|
|
readonly showHeader: XStandardType<boolean> = true;
|
|
readonly disablePagination: XStandardType<boolean> = false;
|
|
readonly alignTabs: XStandardType<XTabAlignIdentifier> = XTabAlign.START;
|
|
readonly dynamicHeight: XStandardType<boolean> = false;
|
|
readonly disableRipple: XStandardType<boolean> = false;
|
|
readonly headerPosition: XStandardType<XTabsHeaderPositionIdentifier> =
|
|
XTabsHeaderPosition.ABOVE;
|
|
|
|
//
|
|
readonly loopTabs: XStandardType<boolean> = true;
|
|
readonly swipable: XStandardType<boolean> = false;
|
|
readonly animationDuration: XStandardType<string> = '500ms';
|
|
|
|
//
|
|
readonly lock: XStandardType<boolean> = false;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Transparent;
|
|
readonly headerColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Primary;
|
|
readonly activeTabColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Secondary;
|
|
readonly tabIndicatorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.SecondaryTint;
|
|
readonly tabPaginatorColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.SecondaryShade;
|
|
|
|
//
|
|
readonly animationDone: EventEmitter<void> = new EventEmitter();
|
|
readonly selectedTabChange: EventEmitter<XTabChangeEvent> =
|
|
new EventEmitter<XTabChangeEvent>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export class XTabsContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXTabsContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XTabsActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
selectedIndex: number = this.propertyProvider.selectedIndex;
|
|
|
|
@Output()
|
|
selectedIndexChange: EventEmitter<number> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
|
|
|
|
@Input()
|
|
disablePagination: XStandardType<boolean> =
|
|
this.propertyProvider.disablePagination;
|
|
|
|
@Input()
|
|
alignTabs: XStandardType<XTabAlignIdentifier> =
|
|
this.propertyProvider.alignTabs;
|
|
|
|
@Input()
|
|
dynamicHeight: XStandardType<boolean> = this.propertyProvider.dynamicHeight;
|
|
|
|
@Input()
|
|
disableRipple: XStandardType<boolean> = this.propertyProvider.disableRipple;
|
|
|
|
@Input()
|
|
headerPosition: XStandardType<XTabsHeaderPositionIdentifier> =
|
|
this.propertyProvider.headerPosition;
|
|
|
|
//
|
|
@Input()
|
|
loopTabs: XStandardType<boolean> = this.propertyProvider.loopTabs;
|
|
|
|
@Input()
|
|
swipable: XStandardType<boolean> = this.propertyProvider.swipable;
|
|
|
|
@Input()
|
|
animationDuration: XStandardType<string> =
|
|
this.propertyProvider.animationDuration;
|
|
|
|
//
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
@Input()
|
|
headerColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.headerColor;
|
|
|
|
@Input()
|
|
activeTabColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.activeTabColor;
|
|
|
|
@Input()
|
|
tabIndicatorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.tabIndicatorColor;
|
|
|
|
@Input()
|
|
tabPaginatorColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.tabPaginatorColor;
|
|
|
|
//
|
|
@Output()
|
|
animationDone: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Output()
|
|
selectedTabChange: EventEmitter<XTabChangeEvent> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XTabsContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXTabsContainer
|
|
): Observable<IXTabsContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
selectedIndex: this.getValue(
|
|
container ? container.selectedIndex : this.selectedIndex
|
|
),
|
|
showHeader: this.getValue(
|
|
container ? container.showHeader : this.showHeader
|
|
),
|
|
disablePagination: this.getValue(
|
|
container ? container.disablePagination : this.disablePagination
|
|
),
|
|
alignTabs: this.getValue(
|
|
container ? container.alignTabs : this.alignTabs
|
|
),
|
|
dynamicHeight: this.getValue(
|
|
container ? container.dynamicHeight : this.dynamicHeight
|
|
),
|
|
animationDuration: this.getValue(
|
|
container ? container.animationDuration : this.animationDuration
|
|
),
|
|
disableRipple: this.getValue(
|
|
container ? container.disableRipple : this.disableRipple
|
|
),
|
|
headerPosition: this.getValue(
|
|
container ? container.headerPosition : this.headerPosition
|
|
),
|
|
loopTabs: this.getValue(
|
|
container ? container.loopTabs : this.loopTabs
|
|
),
|
|
swipable: this.getValue(
|
|
container ? container.swipable : this.swipable
|
|
),
|
|
lock: this.getValue(container ? container.lock : this.lock),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
headerColor: this.getValue(
|
|
container ? container.headerColor : this.headerColor
|
|
),
|
|
activeTabColor: this.getValue(
|
|
container ? container.activeTabColor : this.activeTabColor
|
|
),
|
|
tabIndicatorColor: this.getValue(
|
|
container ? container.tabIndicatorColor : this.tabIndicatorColor
|
|
),
|
|
tabPaginatorColor: this.getValue(
|
|
container ? container.tabPaginatorColor : this.tabPaginatorColor
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
animationDone: this.animationDone,
|
|
selectedTabChange: this.selectedTabChange,
|
|
selectedIndexChange: this.selectedIndexChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.html
|
|
|
|
<ng-template #label>
|
|
<ng-content select="[x-tab-label]"></ng-content>
|
|
</ng-template>
|
|
|
|
<ng-template #content>
|
|
<ng-content></ng-content>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.scss
|
|
|
|
.full-width {
|
|
width: 100%;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.ts
|
|
|
|
import {
|
|
Component,
|
|
ViewChild,
|
|
TemplateRef,
|
|
ChangeDetectionStrategy,
|
|
} from '@angular/core';
|
|
import {
|
|
XTabAction,
|
|
XTabActionModel,
|
|
XTabContainerComponent,
|
|
} from './x-tab.typings';
|
|
import { nameof } from 'x-framework-core';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-tab',
|
|
templateUrl: './x-tab.component.html',
|
|
styleUrls: ['./x-tab.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XTabComponent extends XTabContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
@ViewChild('label', { static: false })
|
|
label!: TemplateRef<any>;
|
|
|
|
//
|
|
@ViewChild('content', { static: false })
|
|
content!: TemplateRef<any>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XTabComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XTabActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XTabAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Renderer2,
|
|
ElementRef,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../../classes/i-x-base.container';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { Component, Injectable } from '@angular/core';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
|
|
export enum XTabAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XTabActionIdentifier = XTabAction | string;
|
|
|
|
export interface XTabActionModel
|
|
extends XBaseActionModel<XTabActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXTabContainer extends IXBaseContainer {
|
|
actionProvider: Subject<XTabActionModel>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XTabContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXTabContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
readonly actionProvider: Subject<XTabActionModel> =
|
|
new Subject<XTabActionModel>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XTabContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXTabContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XTabActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XTabContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(container?: IXTabContainer): Observable<IXTabContainer> {
|
|
return forkJoin({
|
|
//
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
// ...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-typings.ts
|
|
|
|
//
|
|
//#region Form Interfaces ...
|
|
export interface XThemeBaseFormModel {
|
|
name: string;
|
|
}
|
|
|
|
export interface XThemeDarkFormModel {
|
|
//
|
|
//#region Dark ...
|
|
darkXColorPrimary: string;
|
|
darkXColorPrimaryContrast: string;
|
|
darkXColorPrimaryShade: string;
|
|
darkXColorPrimaryShadeContrast: string;
|
|
darkXColorPrimaryTint: string;
|
|
darkXColorPrimaryTintContrast: string;
|
|
darkXColorSecondary: string;
|
|
darkXColorSecondaryContrast: string;
|
|
darkXColorSecondaryShade: string;
|
|
darkXColorSecondaryShadeContrast: string;
|
|
darkXColorSecondaryTint: string;
|
|
darkXColorSecondaryTintContrast: string;
|
|
darkXColorTertiary: string;
|
|
darkXColorTertiaryContrast: string;
|
|
darkXColorTertiaryShade: string;
|
|
darkXColorTertiaryShadeContrast: string;
|
|
darkXColorTertiaryTint: string;
|
|
darkXColorTertiaryTintContrast: string;
|
|
darkXColorSuccess: string;
|
|
darkXColorSuccessContrast: string;
|
|
darkXColorSuccessShade: string;
|
|
darkXColorSuccessShadeContrast: string;
|
|
darkXColorSuccessTint: string;
|
|
darkXColorSuccessTintContrast: string;
|
|
darkXColorWarning: string;
|
|
darkXColorWarningContrast: string;
|
|
darkXColorWarningShade: string;
|
|
darkXColorWarningShadeContrast: string;
|
|
darkXColorWarningTint: string;
|
|
darkXColorWarningTintContrast: string;
|
|
darkXColorDanger: string;
|
|
darkXColorDangerContrast: string;
|
|
darkXColorDangerShade: string;
|
|
darkXColorDangerShadeContrast: string;
|
|
darkXColorDangerTint: string;
|
|
darkXColorDangerTintContrast: string;
|
|
darkXColorDark: string;
|
|
darkXColorDarkContrast: string;
|
|
darkXColorDarkShade: string;
|
|
darkXColorDarkShadeContrast: string;
|
|
darkXColorDarkTint: string;
|
|
darkXColorDarkTintContrast: string;
|
|
darkXColorMedium: string;
|
|
darkXColorMediumContrast: string;
|
|
darkXColorMediumShade: string;
|
|
darkXColorMediumShadeContrast: string;
|
|
darkXColorMediumTint: string;
|
|
darkXColorMediumTintContrast: string;
|
|
darkXColorLight: string;
|
|
darkXColorLightContrast: string;
|
|
darkXColorLightShade: string;
|
|
darkXColorLightShadeContrast: string;
|
|
darkXColorLightTint: string;
|
|
darkXColorLightTintContrast: string;
|
|
//#endregion
|
|
}
|
|
|
|
export interface XThemeLightFormModel {
|
|
//
|
|
//#region Light ...
|
|
lightXColorPrimary: string;
|
|
lightXColorPrimaryContrast: string;
|
|
lightXColorPrimaryShade: string;
|
|
lightXColorPrimaryShadeContrast: string;
|
|
lightXColorPrimaryTint: string;
|
|
lightXColorPrimaryTintContrast: string;
|
|
lightXColorSecondary: string;
|
|
lightXColorSecondaryContrast: string;
|
|
lightXColorSecondaryShade: string;
|
|
lightXColorSecondaryShadeContrast: string;
|
|
lightXColorSecondaryTint: string;
|
|
lightXColorSecondaryTintContrast: string;
|
|
lightXColorTertiary: string;
|
|
lightXColorTertiaryContrast: string;
|
|
lightXColorTertiaryShade: string;
|
|
lightXColorTertiaryShadeContrast: string;
|
|
lightXColorTertiaryTint: string;
|
|
lightXColorTertiaryTintContrast: string;
|
|
lightXColorSuccess: string;
|
|
lightXColorSuccessContrast: string;
|
|
lightXColorSuccessShade: string;
|
|
lightXColorSuccessShadeContrast: string;
|
|
lightXColorSuccessTint: string;
|
|
lightXColorSuccessTintContrast: string;
|
|
lightXColorWarning: string;
|
|
lightXColorWarningContrast: string;
|
|
lightXColorWarningShade: string;
|
|
lightXColorWarningShadeContrast: string;
|
|
lightXColorWarningTint: string;
|
|
lightXColorWarningTintContrast: string;
|
|
lightXColorDanger: string;
|
|
lightXColorDangerContrast: string;
|
|
lightXColorDangerShade: string;
|
|
lightXColorDangerShadeContrast: string;
|
|
lightXColorDangerTint: string;
|
|
lightXColorDangerTintContrast: string;
|
|
lightXColorDark: string;
|
|
lightXColorDarkContrast: string;
|
|
lightXColorDarkShade: string;
|
|
lightXColorDarkShadeContrast: string;
|
|
lightXColorDarkTint: string;
|
|
lightXColorDarkTintContrast: string;
|
|
lightXColorMedium: string;
|
|
lightXColorMediumContrast: string;
|
|
lightXColorMediumShade: string;
|
|
lightXColorMediumShadeContrast: string;
|
|
lightXColorMediumTint: string;
|
|
lightXColorMediumTintContrast: string;
|
|
lightXColorLight: string;
|
|
lightXColorLightContrast: string;
|
|
lightXColorLightShade: string;
|
|
lightXColorLightShadeContrast: string;
|
|
lightXColorLightTint: string;
|
|
lightXColorLightTintContrast: string;
|
|
//#endregion
|
|
}
|
|
|
|
export interface XThemeFormModel
|
|
extends XThemeBaseFormModel,
|
|
XThemeDarkFormModel,
|
|
XThemeLightFormModel {}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XTabsModule } from '../x-tabs/x-tabs.module';
|
|
import { XListModule } from '../x-list/x-list.module';
|
|
import { XFormModule } from '../x-form/x-form.module';
|
|
import { XColorModule } from '../x-color/x-color.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
import { XColorPickerModule } from '../x-color-picker/x-color-picker.module';
|
|
import { XThemeManagerComponent } from './x-theme-manager/x-theme-manager.component';
|
|
import { XModelPresenterModule } from '../x-model-presenter/x-model-presenter.module';
|
|
|
|
@NgModule({
|
|
declarations: [XThemeManagerComponent],
|
|
imports: [
|
|
XFormModule,
|
|
XIconModule,
|
|
XCardModule,
|
|
XTabsModule,
|
|
XListModule,
|
|
XColorModule,
|
|
CommonModule,
|
|
XColorPickerModule,
|
|
XBaseComponentModule,
|
|
XModelPresenterModule,
|
|
],
|
|
exports: [
|
|
XFormModule,
|
|
XIconModule,
|
|
XCardModule,
|
|
XTabsModule,
|
|
XListModule,
|
|
XColorModule,
|
|
CommonModule,
|
|
XColorPickerModule,
|
|
XBaseComponentModule,
|
|
XModelPresenterModule,
|
|
XThemeManagerComponent,
|
|
],
|
|
providers: [],
|
|
})
|
|
export class XThemeModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme.tools.ts
|
|
|
|
import { XThemePack, XThemeType } from 'x-framework-core';
|
|
import { XThemeBaseFormModel, XThemeDarkFormModel, XThemeFormModel, XThemeLightFormModel } from './x-theme-typings';
|
|
|
|
/**
|
|
* convert to XThemeFormModel
|
|
*
|
|
* @param theme an instance of XThemePack ...
|
|
*/
|
|
export function themeToForm(theme: XThemePack) {
|
|
//
|
|
if (!theme) {
|
|
return getEmptyThemeFormModel();
|
|
}
|
|
|
|
//
|
|
return {
|
|
name: theme.name,
|
|
|
|
//
|
|
//#region Dark ...
|
|
darkXColorPrimary: theme.dark.colors.XColorPrimary || '',
|
|
darkXColorPrimaryContrast: theme.dark.colors.XColorPrimaryContrast || '',
|
|
darkXColorPrimaryShade: theme.dark.colors.XColorPrimaryShade || '',
|
|
darkXColorPrimaryShadeContrast:
|
|
theme.dark.colors.XColorPrimaryShadeContrast || '',
|
|
darkXColorPrimaryTint: theme.dark.colors.XColorPrimaryTint || '',
|
|
darkXColorPrimaryTintContrast:
|
|
theme.dark.colors.XColorPrimaryTintContrast || '',
|
|
darkXColorSecondary: theme.dark.colors.XColorSecondary || '',
|
|
darkXColorSecondaryContrast:
|
|
theme.dark.colors.XColorSecondaryContrast || '',
|
|
darkXColorSecondaryShade: theme.dark.colors.XColorSecondaryShade || '',
|
|
darkXColorSecondaryShadeContrast:
|
|
theme.dark.colors.XColorSecondaryShadeContrast || '',
|
|
darkXColorSecondaryTint: theme.dark.colors.XColorSecondaryTint || '',
|
|
darkXColorSecondaryTintContrast:
|
|
theme.dark.colors.XColorSecondaryTintContrast || '',
|
|
darkXColorTertiary: theme.dark.colors.XColorTertiary || '',
|
|
darkXColorTertiaryContrast: theme.dark.colors.XColorTertiaryContrast || '',
|
|
darkXColorTertiaryShade: theme.dark.colors.XColorTertiaryShade || '',
|
|
darkXColorTertiaryShadeContrast:
|
|
theme.dark.colors.XColorTertiaryShadeContrast || '',
|
|
darkXColorTertiaryTint: theme.dark.colors.XColorTertiaryTint || '',
|
|
darkXColorTertiaryTintContrast:
|
|
theme.dark.colors.XColorTertiaryTintContrast || '',
|
|
darkXColorSuccess: theme.dark.colors.XColorSuccess || '',
|
|
darkXColorSuccessContrast: theme.dark.colors.XColorSuccessContrast || '',
|
|
darkXColorSuccessShade: theme.dark.colors.XColorSuccessShade || '',
|
|
darkXColorSuccessShadeContrast:
|
|
theme.dark.colors.XColorSuccessShadeContrast || '',
|
|
darkXColorSuccessTint: theme.dark.colors.XColorSuccessTint || '',
|
|
darkXColorSuccessTintContrast:
|
|
theme.dark.colors.XColorSuccessTintContrast || '',
|
|
darkXColorWarning: theme.dark.colors.XColorWarning || '',
|
|
darkXColorWarningContrast: theme.dark.colors.XColorWarningContrast || '',
|
|
darkXColorWarningShade: theme.dark.colors.XColorWarningShade || '',
|
|
darkXColorWarningShadeContrast:
|
|
theme.dark.colors.XColorWarningShadeContrast || '',
|
|
darkXColorWarningTint: theme.dark.colors.XColorWarningTint || '',
|
|
darkXColorWarningTintContrast:
|
|
theme.dark.colors.XColorWarningTintContrast || '',
|
|
darkXColorDanger: theme.dark.colors.XColorDanger || '',
|
|
darkXColorDangerContrast: theme.dark.colors.XColorDangerContrast || '',
|
|
darkXColorDangerShade: theme.dark.colors.XColorDangerShade || '',
|
|
darkXColorDangerShadeContrast:
|
|
theme.dark.colors.XColorDangerShadeContrast || '',
|
|
darkXColorDangerTint: theme.dark.colors.XColorDangerTint || '',
|
|
darkXColorDangerTintContrast:
|
|
theme.dark.colors.XColorDangerTintContrast || '',
|
|
darkXColorDark: theme.dark.colors.XColorDark || '',
|
|
darkXColorDarkContrast: theme.dark.colors.XColorDarkContrast || '',
|
|
darkXColorDarkShade: theme.dark.colors.XColorDarkShade || '',
|
|
darkXColorDarkShadeContrast:
|
|
theme.dark.colors.XColorDarkShadeContrast || '',
|
|
darkXColorDarkTint: theme.dark.colors.XColorDarkTint || '',
|
|
darkXColorDarkTintContrast: theme.dark.colors.XColorDarkTintContrast || '',
|
|
darkXColorMedium: theme.dark.colors.XColorMedium || '',
|
|
darkXColorMediumContrast: theme.dark.colors.XColorMediumContrast || '',
|
|
darkXColorMediumShade: theme.dark.colors.XColorMediumShade || '',
|
|
darkXColorMediumShadeContrast:
|
|
theme.dark.colors.XColorMediumShadeContrast || '',
|
|
darkXColorMediumTint: theme.dark.colors.XColorMediumTint || '',
|
|
darkXColorMediumTintContrast:
|
|
theme.dark.colors.XColorMediumTintContrast || '',
|
|
darkXColorLight: theme.dark.colors.XColorLight || '',
|
|
darkXColorLightContrast: theme.dark.colors.XColorLightContrast || '',
|
|
darkXColorLightShade: theme.dark.colors.XColorLightShade || '',
|
|
darkXColorLightShadeContrast:
|
|
theme.dark.colors.XColorLightShadeContrast || '',
|
|
darkXColorLightTint: theme.dark.colors.XColorLightTint || '',
|
|
darkXColorLightTintContrast:
|
|
theme.dark.colors.XColorLightTintContrast || '',
|
|
//#endregion
|
|
|
|
//
|
|
//#region Light ...
|
|
lightXColorPrimary: theme.light.colors.XColorPrimary || '',
|
|
lightXColorPrimaryContrast: theme.light.colors.XColorPrimaryContrast || '',
|
|
lightXColorPrimaryShade: theme.light.colors.XColorPrimaryShade || '',
|
|
lightXColorPrimaryShadeContrast:
|
|
theme.light.colors.XColorPrimaryShadeContrast || '',
|
|
lightXColorPrimaryTint: theme.light.colors.XColorPrimaryTint || '',
|
|
lightXColorPrimaryTintContrast:
|
|
theme.light.colors.XColorPrimaryTintContrast || '',
|
|
lightXColorSecondary: theme.light.colors.XColorSecondary || '',
|
|
lightXColorSecondaryContrast:
|
|
theme.light.colors.XColorSecondaryContrast || '',
|
|
lightXColorSecondaryShade: theme.light.colors.XColorSecondaryShade || '',
|
|
lightXColorSecondaryShadeContrast:
|
|
theme.light.colors.XColorSecondaryShadeContrast || '',
|
|
lightXColorSecondaryTint: theme.light.colors.XColorSecondaryTint || '',
|
|
lightXColorSecondaryTintContrast:
|
|
theme.light.colors.XColorSecondaryTintContrast || '',
|
|
lightXColorTertiary: theme.light.colors.XColorTertiary || '',
|
|
lightXColorTertiaryContrast:
|
|
theme.light.colors.XColorTertiaryContrast || '',
|
|
lightXColorTertiaryShade: theme.light.colors.XColorTertiaryShade || '',
|
|
lightXColorTertiaryShadeContrast:
|
|
theme.light.colors.XColorTertiaryShadeContrast || '',
|
|
lightXColorTertiaryTint: theme.light.colors.XColorTertiaryTint || '',
|
|
lightXColorTertiaryTintContrast:
|
|
theme.light.colors.XColorTertiaryTintContrast || '',
|
|
lightXColorSuccess: theme.light.colors.XColorSuccess || '',
|
|
lightXColorSuccessContrast: theme.light.colors.XColorSuccessContrast || '',
|
|
lightXColorSuccessShade: theme.light.colors.XColorSuccessShade || '',
|
|
lightXColorSuccessShadeContrast:
|
|
theme.light.colors.XColorSuccessShadeContrast || '',
|
|
lightXColorSuccessTint: theme.light.colors.XColorSuccessTint || '',
|
|
lightXColorSuccessTintContrast:
|
|
theme.light.colors.XColorSuccessTintContrast || '',
|
|
lightXColorWarning: theme.light.colors.XColorWarning || '',
|
|
lightXColorWarningContrast: theme.light.colors.XColorWarningContrast || '',
|
|
lightXColorWarningShade: theme.light.colors.XColorWarningShade || '',
|
|
lightXColorWarningShadeContrast:
|
|
theme.light.colors.XColorWarningShadeContrast || '',
|
|
lightXColorWarningTint: theme.light.colors.XColorWarningTint || '',
|
|
lightXColorWarningTintContrast:
|
|
theme.light.colors.XColorWarningTintContrast || '',
|
|
lightXColorDanger: theme.light.colors.XColorDanger || '',
|
|
lightXColorDangerContrast: theme.light.colors.XColorDangerContrast || '',
|
|
lightXColorDangerShade: theme.light.colors.XColorDangerShade || '',
|
|
lightXColorDangerShadeContrast:
|
|
theme.light.colors.XColorDangerShadeContrast || '',
|
|
lightXColorDangerTint: theme.light.colors.XColorDangerTint || '',
|
|
lightXColorDangerTintContrast:
|
|
theme.light.colors.XColorDangerTintContrast || '',
|
|
lightXColorDark: theme.light.colors.XColorDark || '',
|
|
lightXColorDarkContrast: theme.light.colors.XColorDarkContrast || '',
|
|
lightXColorDarkShade: theme.light.colors.XColorDarkShade || '',
|
|
lightXColorDarkShadeContrast:
|
|
theme.light.colors.XColorDarkShadeContrast || '',
|
|
lightXColorDarkTint: theme.light.colors.XColorDarkTint || '',
|
|
lightXColorDarkTintContrast:
|
|
theme.light.colors.XColorDarkTintContrast || '',
|
|
lightXColorMedium: theme.light.colors.XColorMedium || '',
|
|
lightXColorMediumContrast: theme.light.colors.XColorMediumContrast || '',
|
|
lightXColorMediumShade: theme.light.colors.XColorMediumShade || '',
|
|
lightXColorMediumShadeContrast:
|
|
theme.light.colors.XColorMediumShadeContrast || '',
|
|
lightXColorMediumTint: theme.light.colors.XColorMediumTint || '',
|
|
lightXColorMediumTintContrast:
|
|
theme.light.colors.XColorMediumTintContrast || '',
|
|
lightXColorLight: theme.light.colors.XColorLight || '',
|
|
lightXColorLightContrast: theme.light.colors.XColorLightContrast || '',
|
|
lightXColorLightShade: theme.light.colors.XColorLightShade || '',
|
|
lightXColorLightShadeContrast:
|
|
theme.light.colors.XColorLightShadeContrast || '',
|
|
lightXColorLightTint: theme.light.colors.XColorLightTint || '',
|
|
lightXColorLightTintContrast:
|
|
theme.light.colors.XColorLightTintContrast || '',
|
|
//#endregion
|
|
} as XThemeFormModel;
|
|
}
|
|
|
|
/**
|
|
* convert to XThemePack
|
|
*
|
|
* @param form an instance of XThemeFormModel ...
|
|
*/
|
|
export function formToTheme(form: XThemeFormModel) {
|
|
//
|
|
if (!form) {
|
|
return getEmptyThemePack();
|
|
}
|
|
|
|
//
|
|
return {
|
|
//
|
|
name: form.name || '',
|
|
|
|
//
|
|
// Dark ...
|
|
dark: {
|
|
type: XThemeType.Dark,
|
|
colors: {
|
|
XColorPrimary: form.darkXColorPrimary || '',
|
|
XColorPrimaryContrast: form.darkXColorPrimaryContrast || '',
|
|
XColorPrimaryShade: form.darkXColorPrimaryShade || '',
|
|
XColorPrimaryShadeContrast: form.darkXColorPrimaryShadeContrast || '',
|
|
XColorPrimaryTint: form.darkXColorPrimaryTint || '',
|
|
XColorPrimaryTintContrast: form.darkXColorPrimaryTintContrast || '',
|
|
XColorSecondary: form.darkXColorSecondary || '',
|
|
XColorSecondaryContrast: form.darkXColorSecondaryContrast || '',
|
|
XColorSecondaryShade: form.darkXColorSecondaryShade || '',
|
|
XColorSecondaryShadeContrast:
|
|
form.darkXColorSecondaryShadeContrast || '',
|
|
XColorSecondaryTint: form.darkXColorSecondaryTint || '',
|
|
XColorSecondaryTintContrast: form.darkXColorSecondaryTintContrast || '',
|
|
XColorTertiary: form.darkXColorTertiary || '',
|
|
XColorTertiaryContrast: form.darkXColorTertiaryContrast || '',
|
|
XColorTertiaryShade: form.darkXColorTertiaryShade || '',
|
|
XColorTertiaryShadeContrast: form.darkXColorTertiaryShadeContrast || '',
|
|
XColorTertiaryTint: form.darkXColorTertiaryTint || '',
|
|
XColorTertiaryTintContrast: form.darkXColorTertiaryTintContrast || '',
|
|
XColorSuccess: form.darkXColorSuccess || '',
|
|
XColorSuccessContrast: form.darkXColorSuccessContrast || '',
|
|
XColorSuccessShade: form.darkXColorSuccessShade || '',
|
|
XColorSuccessShadeContrast: form.darkXColorSuccessShadeContrast || '',
|
|
XColorSuccessTint: form.darkXColorSuccessTint || '',
|
|
XColorSuccessTintContrast: form.darkXColorSuccessTintContrast || '',
|
|
XColorWarning: form.darkXColorWarning || '',
|
|
XColorWarningContrast: form.darkXColorWarningContrast || '',
|
|
XColorWarningShade: form.darkXColorWarningShade || '',
|
|
XColorWarningShadeContrast: form.darkXColorWarningShadeContrast || '',
|
|
XColorWarningTint: form.darkXColorWarningTint || '',
|
|
XColorWarningTintContrast: form.darkXColorWarningTintContrast || '',
|
|
XColorDanger: form.darkXColorDanger || '',
|
|
XColorDangerContrast: form.darkXColorDangerContrast || '',
|
|
XColorDangerShade: form.darkXColorDangerShade || '',
|
|
XColorDangerShadeContrast: form.darkXColorDangerShadeContrast || '',
|
|
XColorDangerTint: form.darkXColorDangerTint || '',
|
|
XColorDangerTintContrast: form.darkXColorDangerTintContrast || '',
|
|
XColorDark: form.darkXColorDark || '',
|
|
XColorDarkContrast: form.darkXColorDarkContrast || '',
|
|
XColorDarkShade: form.darkXColorDarkShade || '',
|
|
XColorDarkShadeContrast: form.darkXColorDarkShadeContrast || '',
|
|
XColorDarkTint: form.darkXColorDarkTint || '',
|
|
XColorDarkTintContrast: form.darkXColorDarkTintContrast || '',
|
|
XColorMedium: form.darkXColorMedium || '',
|
|
XColorMediumContrast: form.darkXColorMediumContrast || '',
|
|
XColorMediumShade: form.darkXColorMediumShade || '',
|
|
XColorMediumShadeContrast: form.darkXColorMediumShadeContrast || '',
|
|
XColorMediumTint: form.darkXColorMediumTint || '',
|
|
XColorMediumTintContrast: form.darkXColorMediumTintContrast || '',
|
|
XColorLight: form.darkXColorLight || '',
|
|
XColorLightContrast: form.darkXColorLightContrast || '',
|
|
XColorLightShade: form.darkXColorLightShade || '',
|
|
XColorLightShadeContrast: form.darkXColorLightShadeContrast || '',
|
|
XColorLightTint: form.darkXColorLightTint || '',
|
|
XColorLightTintContrast: form.darkXColorLightTintContrast || '',
|
|
},
|
|
},
|
|
|
|
//
|
|
// Light ...
|
|
light: {
|
|
type: XThemeType.Light,
|
|
colors: {
|
|
XColorPrimary: form.lightXColorPrimary || '',
|
|
XColorPrimaryContrast: form.lightXColorPrimaryContrast || '',
|
|
XColorPrimaryShade: form.lightXColorPrimaryShade || '',
|
|
XColorPrimaryShadeContrast: form.lightXColorPrimaryShadeContrast || '',
|
|
XColorPrimaryTint: form.lightXColorPrimaryTint || '',
|
|
XColorPrimaryTintContrast: form.lightXColorPrimaryTintContrast || '',
|
|
XColorSecondary: form.lightXColorSecondary || '',
|
|
XColorSecondaryContrast: form.lightXColorSecondaryContrast || '',
|
|
XColorSecondaryShade: form.lightXColorSecondaryShade || '',
|
|
XColorSecondaryShadeContrast:
|
|
form.lightXColorSecondaryShadeContrast || '',
|
|
XColorSecondaryTint: form.lightXColorSecondaryTint || '',
|
|
XColorSecondaryTintContrast:
|
|
form.lightXColorSecondaryTintContrast || '',
|
|
XColorTertiary: form.lightXColorTertiary || '',
|
|
XColorTertiaryContrast: form.lightXColorTertiaryContrast || '',
|
|
XColorTertiaryShade: form.lightXColorTertiaryShade || '',
|
|
XColorTertiaryShadeContrast:
|
|
form.lightXColorTertiaryShadeContrast || '',
|
|
XColorTertiaryTint: form.lightXColorTertiaryTint || '',
|
|
XColorTertiaryTintContrast: form.lightXColorTertiaryTintContrast || '',
|
|
XColorSuccess: form.lightXColorSuccess || '',
|
|
XColorSuccessContrast: form.lightXColorSuccessContrast || '',
|
|
XColorSuccessShade: form.lightXColorSuccessShade || '',
|
|
XColorSuccessShadeContrast: form.lightXColorSuccessShadeContrast || '',
|
|
XColorSuccessTint: form.lightXColorSuccessTint || '',
|
|
XColorSuccessTintContrast: form.lightXColorSuccessTintContrast || '',
|
|
XColorWarning: form.lightXColorWarning || '',
|
|
XColorWarningContrast: form.lightXColorWarningContrast || '',
|
|
XColorWarningShade: form.lightXColorWarningShade || '',
|
|
XColorWarningShadeContrast: form.lightXColorWarningShadeContrast || '',
|
|
XColorWarningTint: form.lightXColorWarningTint || '',
|
|
XColorWarningTintContrast: form.lightXColorWarningTintContrast || '',
|
|
XColorDanger: form.lightXColorDanger || '',
|
|
XColorDangerContrast: form.lightXColorDangerContrast || '',
|
|
XColorDangerShade: form.lightXColorDangerShade || '',
|
|
XColorDangerShadeContrast: form.lightXColorDangerShadeContrast || '',
|
|
XColorDangerTint: form.lightXColorDangerTint || '',
|
|
XColorDangerTintContrast: form.lightXColorDangerTintContrast || '',
|
|
XColorDark: form.lightXColorDark || '',
|
|
XColorDarkContrast: form.lightXColorDarkContrast || '',
|
|
XColorDarkShade: form.lightXColorDarkShade || '',
|
|
XColorDarkShadeContrast: form.lightXColorDarkShadeContrast || '',
|
|
XColorDarkTint: form.lightXColorDarkTint || '',
|
|
XColorDarkTintContrast: form.lightXColorDarkTintContrast || '',
|
|
XColorMedium: form.lightXColorMedium || '',
|
|
XColorMediumContrast: form.lightXColorMediumContrast || '',
|
|
XColorMediumShade: form.lightXColorMediumShade || '',
|
|
XColorMediumShadeContrast: form.lightXColorMediumShadeContrast || '',
|
|
XColorMediumTint: form.lightXColorMediumTint || '',
|
|
XColorMediumTintContrast: form.lightXColorMediumTintContrast || '',
|
|
XColorLight: form.lightXColorLight || '',
|
|
XColorLightContrast: form.lightXColorLightContrast || '',
|
|
XColorLightShade: form.lightXColorLightShade || '',
|
|
XColorLightShadeContrast: form.lightXColorLightShadeContrast || '',
|
|
XColorLightTint: form.lightXColorLightTint || '',
|
|
XColorLightTintContrast: form.lightXColorLightTintContrast || '',
|
|
},
|
|
},
|
|
} as XThemePack;
|
|
}
|
|
|
|
/**
|
|
* prepare an empty XThemePack instance ...
|
|
*/
|
|
export function getEmptyThemePack() {
|
|
return {
|
|
name: '',
|
|
dark: {
|
|
type: XThemeType.Dark,
|
|
colors: {
|
|
XColorPrimary: '',
|
|
XColorPrimaryContrast: '',
|
|
XColorPrimaryShade: '',
|
|
XColorPrimaryShadeContrast: '',
|
|
XColorPrimaryTint: '',
|
|
XColorPrimaryTintContrast: '',
|
|
XColorSecondary: '',
|
|
XColorSecondaryContrast: '',
|
|
XColorSecondaryShade: '',
|
|
XColorSecondaryShadeContrast: '',
|
|
XColorSecondaryTint: '',
|
|
XColorSecondaryTintContrast: '',
|
|
XColorTertiary: '',
|
|
XColorTertiaryContrast: '',
|
|
XColorTertiaryShade: '',
|
|
XColorTertiaryShadeContrast: '',
|
|
XColorTertiaryTint: '',
|
|
XColorTertiaryTintContrast: '',
|
|
XColorSuccess: '',
|
|
XColorSuccessContrast: '',
|
|
XColorSuccessShade: '',
|
|
XColorSuccessShadeContrast: '',
|
|
XColorSuccessTint: '',
|
|
XColorSuccessTintContrast: '',
|
|
XColorWarning: '',
|
|
XColorWarningContrast: '',
|
|
XColorWarningShade: '',
|
|
XColorWarningShadeContrast: '',
|
|
XColorWarningTint: '',
|
|
XColorWarningTintContrast: '',
|
|
XColorDanger: '',
|
|
XColorDangerContrast: '',
|
|
XColorDangerShade: '',
|
|
XColorDangerShadeContrast: '',
|
|
XColorDangerTint: '',
|
|
XColorDangerTintContrast: '',
|
|
XColorDark: '',
|
|
XColorDarkContrast: '',
|
|
XColorDarkShade: '',
|
|
XColorDarkShadeContrast: '',
|
|
XColorDarkTint: '',
|
|
XColorDarkTintContrast: '',
|
|
XColorMedium: '',
|
|
XColorMediumContrast: '',
|
|
XColorMediumShade: '',
|
|
XColorMediumShadeContrast: '',
|
|
XColorMediumTint: '',
|
|
XColorMediumTintContrast: '',
|
|
XColorLight: '',
|
|
XColorLightContrast: '',
|
|
XColorLightShade: '',
|
|
XColorLightShadeContrast: '',
|
|
XColorLightTint: '',
|
|
XColorLightTintContrast: '',
|
|
},
|
|
},
|
|
light: {
|
|
type: XThemeType.Light,
|
|
colors: {
|
|
XColorPrimary: '',
|
|
XColorPrimaryContrast: '',
|
|
XColorPrimaryShade: '',
|
|
XColorPrimaryShadeContrast: '',
|
|
XColorPrimaryTint: '',
|
|
XColorPrimaryTintContrast: '',
|
|
XColorSecondary: '',
|
|
XColorSecondaryContrast: '',
|
|
XColorSecondaryShade: '',
|
|
XColorSecondaryShadeContrast: '',
|
|
XColorSecondaryTint: '',
|
|
XColorSecondaryTintContrast: '',
|
|
XColorTertiary: '',
|
|
XColorTertiaryContrast: '',
|
|
XColorTertiaryShade: '',
|
|
XColorTertiaryShadeContrast: '',
|
|
XColorTertiaryTint: '',
|
|
XColorTertiaryTintContrast: '',
|
|
XColorSuccess: '',
|
|
XColorSuccessContrast: '',
|
|
XColorSuccessShade: '',
|
|
XColorSuccessShadeContrast: '',
|
|
XColorSuccessTint: '',
|
|
XColorSuccessTintContrast: '',
|
|
XColorWarning: '',
|
|
XColorWarningContrast: '',
|
|
XColorWarningShade: '',
|
|
XColorWarningShadeContrast: '',
|
|
XColorWarningTint: '',
|
|
XColorWarningTintContrast: '',
|
|
XColorDanger: '',
|
|
XColorDangerContrast: '',
|
|
XColorDangerShade: '',
|
|
XColorDangerShadeContrast: '',
|
|
XColorDangerTint: '',
|
|
XColorDangerTintContrast: '',
|
|
XColorDark: '',
|
|
XColorDarkContrast: '',
|
|
XColorDarkShade: '',
|
|
XColorDarkShadeContrast: '',
|
|
XColorDarkTint: '',
|
|
XColorDarkTintContrast: '',
|
|
XColorMedium: '',
|
|
XColorMediumContrast: '',
|
|
XColorMediumShade: '',
|
|
XColorMediumShadeContrast: '',
|
|
XColorMediumTint: '',
|
|
XColorMediumTintContrast: '',
|
|
XColorLight: '',
|
|
XColorLightContrast: '',
|
|
XColorLightShade: '',
|
|
XColorLightShadeContrast: '',
|
|
XColorLightTint: '',
|
|
XColorLightTintContrast: '',
|
|
},
|
|
},
|
|
} as XThemePack;
|
|
}
|
|
|
|
/**
|
|
* prepare an empty XThemeBaseFormModel instance ...
|
|
*/
|
|
export function getEmptyThemeBaseFormModel() {
|
|
return {
|
|
name: '',
|
|
} as XThemeBaseFormModel;
|
|
}
|
|
|
|
/**
|
|
* prepare an empty XThemeLightFormModel instance ...
|
|
*/
|
|
export function getEmptyThemeLightFormModel() {
|
|
return {
|
|
lightXColorPrimary: '',
|
|
lightXColorPrimaryContrast: '',
|
|
lightXColorPrimaryShade: '',
|
|
lightXColorPrimaryShadeContrast: '',
|
|
lightXColorPrimaryTint: '',
|
|
lightXColorPrimaryTintContrast: '',
|
|
lightXColorSecondary: '',
|
|
lightXColorSecondaryContrast: '',
|
|
lightXColorSecondaryShade: '',
|
|
lightXColorSecondaryShadeContrast: '',
|
|
lightXColorSecondaryTint: '',
|
|
lightXColorSecondaryTintContrast: '',
|
|
lightXColorTertiary: '',
|
|
lightXColorTertiaryContrast: '',
|
|
lightXColorTertiaryShade: '',
|
|
lightXColorTertiaryShadeContrast: '',
|
|
lightXColorTertiaryTint: '',
|
|
lightXColorTertiaryTintContrast: '',
|
|
lightXColorSuccess: '',
|
|
lightXColorSuccessContrast: '',
|
|
lightXColorSuccessShade: '',
|
|
lightXColorSuccessShadeContrast: '',
|
|
lightXColorSuccessTint: '',
|
|
lightXColorSuccessTintContrast: '',
|
|
lightXColorWarning: '',
|
|
lightXColorWarningContrast: '',
|
|
lightXColorWarningShade: '',
|
|
lightXColorWarningShadeContrast: '',
|
|
lightXColorWarningTint: '',
|
|
lightXColorWarningTintContrast: '',
|
|
lightXColorDanger: '',
|
|
lightXColorDangerContrast: '',
|
|
lightXColorDangerShade: '',
|
|
lightXColorDangerShadeContrast: '',
|
|
lightXColorDangerTint: '',
|
|
lightXColorDangerTintContrast: '',
|
|
lightXColorDark: '',
|
|
lightXColorDarkContrast: '',
|
|
lightXColorDarkShade: '',
|
|
lightXColorDarkShadeContrast: '',
|
|
lightXColorDarkTint: '',
|
|
lightXColorDarkTintContrast: '',
|
|
lightXColorMedium: '',
|
|
lightXColorMediumContrast: '',
|
|
lightXColorMediumShade: '',
|
|
lightXColorMediumShadeContrast: '',
|
|
lightXColorMediumTint: '',
|
|
lightXColorMediumTintContrast: '',
|
|
lightXColorLight: '',
|
|
lightXColorLightContrast: '',
|
|
lightXColorLightShade: '',
|
|
lightXColorLightShadeContrast: '',
|
|
lightXColorLightTint: '',
|
|
lightXColorLightTintContrast: '',
|
|
} as XThemeLightFormModel;
|
|
}
|
|
|
|
/**
|
|
* prepare an empty XThemeDarkFormModel instance ...
|
|
*/
|
|
export function getEmptyThemeDarkFormModel() {
|
|
return {
|
|
darkXColorPrimary: '',
|
|
darkXColorPrimaryContrast: '',
|
|
darkXColorPrimaryShade: '',
|
|
darkXColorPrimaryShadeContrast: '',
|
|
darkXColorPrimaryTint: '',
|
|
darkXColorPrimaryTintContrast: '',
|
|
darkXColorSecondary: '',
|
|
darkXColorSecondaryContrast: '',
|
|
darkXColorSecondaryShade: '',
|
|
darkXColorSecondaryShadeContrast: '',
|
|
darkXColorSecondaryTint: '',
|
|
darkXColorSecondaryTintContrast: '',
|
|
darkXColorTertiary: '',
|
|
darkXColorTertiaryContrast: '',
|
|
darkXColorTertiaryShade: '',
|
|
darkXColorTertiaryShadeContrast: '',
|
|
darkXColorTertiaryTint: '',
|
|
darkXColorTertiaryTintContrast: '',
|
|
darkXColorSuccess: '',
|
|
darkXColorSuccessContrast: '',
|
|
darkXColorSuccessShade: '',
|
|
darkXColorSuccessShadeContrast: '',
|
|
darkXColorSuccessTint: '',
|
|
darkXColorSuccessTintContrast: '',
|
|
darkXColorWarning: '',
|
|
darkXColorWarningContrast: '',
|
|
darkXColorWarningShade: '',
|
|
darkXColorWarningShadeContrast: '',
|
|
darkXColorWarningTint: '',
|
|
darkXColorWarningTintContrast: '',
|
|
darkXColorDanger: '',
|
|
darkXColorDangerContrast: '',
|
|
darkXColorDangerShade: '',
|
|
darkXColorDangerShadeContrast: '',
|
|
darkXColorDangerTint: '',
|
|
darkXColorDangerTintContrast: '',
|
|
darkXColorDark: '',
|
|
darkXColorDarkContrast: '',
|
|
darkXColorDarkShade: '',
|
|
darkXColorDarkShadeContrast: '',
|
|
darkXColorDarkTint: '',
|
|
darkXColorDarkTintContrast: '',
|
|
darkXColorMedium: '',
|
|
darkXColorMediumContrast: '',
|
|
darkXColorMediumShade: '',
|
|
darkXColorMediumShadeContrast: '',
|
|
darkXColorMediumTint: '',
|
|
darkXColorMediumTintContrast: '',
|
|
darkXColorLight: '',
|
|
darkXColorLightContrast: '',
|
|
darkXColorLightShade: '',
|
|
darkXColorLightShadeContrast: '',
|
|
darkXColorLightTint: '',
|
|
darkXColorLightTintContrast: '',
|
|
} as XThemeDarkFormModel;
|
|
}
|
|
|
|
/**
|
|
* prepare an empty XThemeFormModel instance ...
|
|
*/
|
|
export function getEmptyThemeFormModel() {
|
|
return {
|
|
...getEmptyThemeBaseFormModel(),
|
|
...getEmptyThemeDarkFormModel(),
|
|
...getEmptyThemeLightFormModel(),
|
|
} as XThemeFormModel;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.html
|
|
|
|
<!-- Card Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Ref -->
|
|
<ng-template #componentRef>
|
|
<div
|
|
class="x-theme-manager x-wrapper"
|
|
[xColor]="getValue(color) | async"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<!-- Tabs -->
|
|
<x-tabs
|
|
#xTabs
|
|
[swipable]="false"
|
|
[loading]="loading"
|
|
[showHeader]="false"
|
|
[dynamicHeight]="true"
|
|
[color]="'transparent'"
|
|
[uiDisabled]="uiDisabled"
|
|
[disablePagination]="true"
|
|
[(selectedIndex)]="currentTab"
|
|
[actionProvider]="tabsActionProvider"
|
|
(selectedTabChange)="handleSelectedTabChanged($event)"
|
|
>
|
|
<!-- List Tab -->
|
|
<x-tab>
|
|
<!-- Theme List -->
|
|
<x-list
|
|
#listPresenter
|
|
[items]="listItems"
|
|
[loading]="loading"
|
|
[showToolbar]="true"
|
|
[stickyToolbar]="true"
|
|
[selectableItems]="false"
|
|
[foregroundColor]="false"
|
|
[uiDisabled]="uiDisabled"
|
|
[enableReordering]="false"
|
|
[itemTemplate]="themeListItemRef"
|
|
[color]="getValue(color) | async"
|
|
(emptyRefresh)="handleListRefresh()"
|
|
[actionProvider]="listActionProvider"
|
|
[filteringHandler]="listFilteringHandler"
|
|
[actionBarColor]="getValue(actionBarColor)"
|
|
*ngIf="
|
|
(getValue(listShowSearchBar) | async) &&
|
|
(hasChildValue(listItems) | async)
|
|
"
|
|
[actionBarForegroundColor]="
|
|
getValue(actionBarForegroundColor) | async
|
|
"
|
|
[showEmpty]="getValue(listShowEmpty) | async"
|
|
[emptyColor]="getValue(listEmptyColor) | async"
|
|
[emptyActionProvider]="listEmptyActionProvider"
|
|
[emptyRefreshButtonColor]="
|
|
getValue(listEmptyRefreshButtonColor) | async
|
|
"
|
|
[searchBarForegroundColor]="
|
|
getValue(listSearchBarForegroundColor) | async
|
|
"
|
|
[cssClass]="getArrayValue(listCssClass) | async"
|
|
[searchBarCancelButtonIcon]="
|
|
getValue(listSearchBarCancelButtonIcon) | async
|
|
"
|
|
[searchBarSearchInputColor]="
|
|
getValue(listSearchBarSearchInputColor) | async
|
|
"
|
|
[showDivider]="getValue(listShowDivider) | async"
|
|
[showActionBar]="getValue(showActionBar) | async"
|
|
[searchBarType]="getValue(searchBarType) | async"
|
|
[searchBarShowCancelButton]="
|
|
getValue(listSearchBarShowCancelButton) | async
|
|
"
|
|
[searchBarCancelButtonTitle]="
|
|
getValue(listSearchBarCancelButtonTitle) | async
|
|
"
|
|
[searchBarSpellcheck]="
|
|
getOptionalValue(listSearchBarSpellcheck) | async
|
|
"
|
|
[emptyForegroundMessageColor]="
|
|
getValue(listEmptyForegroundMessageColor) | async
|
|
"
|
|
[searchBarActionProvider]="searchBarActionProvider"
|
|
[emptyCssClass]="getValue(listEmptyCssClass) | async"
|
|
[searchBarClearButtonIconColor]="
|
|
getValue(listSearchBarClearButtonIconColor) | async
|
|
"
|
|
[searchBarSearchButtonIconColor]="
|
|
getValue(listSearchBarSearchButtonIconColor) | async
|
|
"
|
|
(searchBarOnEvent)="handleListSearchBarOnEvent($event)"
|
|
[searchBarColor]="getValue(listSearchBarColor) | async"
|
|
[searchBarValue]="getValue(listSearchBarValue) | async"
|
|
[emptyForegroundRefreshButtonColor]="
|
|
getValue(listEmptyForegroundRefreshButtonColor) | async
|
|
"
|
|
[emptyHasRefresh]="getValue(listEmptyHasRefresh) | async"
|
|
[emptyMessage]="getResourceValue(listEmptyMessage) | async"
|
|
[emptyRefreshIcon]="getValue(listEmptyRefreshIcon) | async"
|
|
[showSearchBar]="(countChildsValue(listItems) | async) > 2"
|
|
[searchBarForegroundSearchInputColor]="
|
|
getValue(listSearchBarForegroundSearchInputColor) | async
|
|
"
|
|
[actionBarActions]="getArrayValue(actionBarActions) | async"
|
|
[searchBarDebounce]="getValue(listSearchBarDebounce) | async"
|
|
[emptyMessageColor]="getValue(listEmptyMessageColor) | async"
|
|
[actionBarCssClass]="getArrayValue(actionBarCssClass) | async"
|
|
[searchBarTitle]="getResourceValue(listSearchBarTitle) | async"
|
|
(actionBarActionFired)="handleListActionBarActionFired($event)"
|
|
(searchBarQueryChange)="handleListSearchBarQueryChange($event)"
|
|
[searchBarCssClass]="getArrayValue(listSearchBarCssClass) | async"
|
|
[emptyForegroundColor]="getValue(listEmptyForegroundColor) | async"
|
|
[searchBarKeyboardType]="getValue(listSearchBarKeyboardType) | async"
|
|
[searchBarEnterKeyHint]="getValue(listSearchBarEnterKeyHint) | async"
|
|
[searchBarClearButtonIcon]="
|
|
getValue(listSearchBarClearButtonIcon) | async
|
|
"
|
|
[searchBarSearchButtonIcon]="
|
|
getValue(listSearchBarSearchButtonIcon) | async
|
|
"
|
|
>
|
|
</x-list>
|
|
</x-tab>
|
|
|
|
<!-- Preview/Details Tab -->
|
|
<x-tab>
|
|
<!-- Theme Preview -->
|
|
<x-model-presenter
|
|
[color]="getValue(color) | async"
|
|
[modelKeyProvider]="themeKeyProvider"
|
|
[hiddenModelKeys]="hiddenThemModelKeys"
|
|
[model]="getValue(selectedTheme) | async"
|
|
[cardColor]="getValue(cardColor) | async"
|
|
[propertyActionTemplate]="previewActionRef"
|
|
[labelColor]="getValue(propertyLabelColor) | async"
|
|
[valueColor]="getValue(propertyValueColor) | async"
|
|
*ngIf="notNullOrUndefinedValue(selectedTheme) | async"
|
|
[headerHighlightColor]="
|
|
getValue(presenterHeaderHighlightColor) | async
|
|
"
|
|
[headerColor]="getValue(presenterHeaderColor) | async"
|
|
[contentColor]="getValue(presenterContentColor) | async"
|
|
[cardForegroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
</x-model-presenter>
|
|
</x-tab>
|
|
|
|
<!-- Edit -->
|
|
<x-tab>
|
|
<x-action-bar
|
|
*ngIf="getValue(showActionBar) | async"
|
|
[actionProvider]="actionBarActionProvider"
|
|
[color]="getValue(actionBarColor) | async"
|
|
[actions]="themeModelPresenterActionActions"
|
|
[cssClass]="getValue(actionBarCssClass) | async"
|
|
[foregroundColor]="getValue(actionBarForegroundColor) | async"
|
|
>
|
|
</x-action-bar>
|
|
|
|
<!-- Model Presenter -->
|
|
<x-model-presenter
|
|
[color]="getValue(color) | async"
|
|
[modelKeyProvider]="themeKeyProvider"
|
|
[hiddenModelKeys]="hiddenThemModelKeys"
|
|
[model]="getValue(selectedTheme) | async"
|
|
[cardColor]="getValue(cardColor) | async"
|
|
[propertyActionTemplate]="themeEditActionRef"
|
|
[labelColor]="getValue(propertyLabelColor) | async"
|
|
[valueColor]="getValue(propertyValueColor) | async"
|
|
[actionProvider]="themeModelPresenterActionProvider"
|
|
(onModelChanged)="handleThemeContentChanged($event)"
|
|
*ngIf="notNullOrUndefinedValue(selectedTheme) | async"
|
|
[headerHighlightColor]="
|
|
getValue(presenterHeaderHighlightColor) | async
|
|
"
|
|
[headerColor]="getValue(presenterHeaderColor) | async"
|
|
[contentColor]="getValue(presenterContentColor) | async"
|
|
[cardForegroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
</x-model-presenter>
|
|
|
|
<!-- Action -->
|
|
<div class="actions">
|
|
<x-slotter [layout]="SlotLayouts.HORIZONTAL">
|
|
<!-- Center -->
|
|
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
|
|
<x-button
|
|
[loading]="loading"
|
|
[type]="ButtonTypes.Raised"
|
|
class="ion-margin-horizontal"
|
|
(clicked)="handleUpdateTheme()"
|
|
[color]="getValue(saveColor) | async"
|
|
[title]="getResourceValue(saveLabel) | async"
|
|
[uiDisabled]="!(getValue(canSaveTheme) | async)"
|
|
></x-button>
|
|
</x-slot>
|
|
</x-slotter>
|
|
</div>
|
|
</x-tab>
|
|
|
|
<!-- Import -->
|
|
<x-tab>
|
|
<x-file-upload
|
|
[showEmpty]="true"
|
|
[wrapWithCard]="false"
|
|
[showActionBar]="true"
|
|
[listShowToolbar]="true"
|
|
[emptyHasRefresh]="false"
|
|
[listStickyToolbar]="true"
|
|
[listEnableReordering]="false"
|
|
[actionProvider]="themeUploadActionProvider"
|
|
[allowedExtensions]="allowedThemeExtensions"
|
|
[color]="getValue(themeUploadColor) | async"
|
|
[emptyColor]="getValue(listEmptyColor) | async"
|
|
[actionBarColor]="getValue(actionBarColor) | async"
|
|
(fileChange)="handleThemeUploadFileChanged($event)"
|
|
[maxAllowedSize]="getValue(maxAllowedSize) | async"
|
|
[listActionProvider]="themeUploadListActionProvider"
|
|
[actionBarActions]="themeUploadListActionbarActions"
|
|
[listCssClass]="getArrayValue(listCssClass) | async"
|
|
[listShowDivider]="getValue(listShowDivider) | async"
|
|
[maxAllowedFiles]="getValue(maxAllowedFiles) | async"
|
|
[cssClass]="getArrayValue(themeUploadCssClass) | async"
|
|
[searchBarColor]="getValue(listSearchBarColor) | async"
|
|
[fileDropAreaAllowedExtensions]="allowedThemeExtensions"
|
|
[emptyMessage]="getValue(themeUploadEmptyMessage) | async"
|
|
[emptyCssClass]="getArrayValue(listEmptyCssClass) | async"
|
|
[minAllowedFileSize]="getValue(minAllowedFileSize) | async"
|
|
[maxAllowedFileSize]="getValue(maxAllowedFileSize) | async"
|
|
[actionBarHideActions]="themeUploadListActionBarHideActions"
|
|
(actionBarActionFired)="handleThemeUploadActionFired($event)"
|
|
[emptyMessageColor]="getValue(listEmptyMessageColor) | async"
|
|
[showSearchBar]="(countChildsValue(uploadThemes) | async) > 1"
|
|
[actionBarCssClass]="getArrayValue(actionBarCssClass) | async"
|
|
[foregroundColor]="getValue(themeUploadForegroundColor) | async"
|
|
[fileDropAreaSupportsMultipleFiles]="
|
|
getValue(themeUploadFileDropAreaSupportsMultipleFiles) | async
|
|
"
|
|
[searchBarCssClass]="getArrayValue(listSearchBarCssClass) | async"
|
|
[fileDropAreaIcon]="getValue(themeUploadFileDropAreaIcon) | async"
|
|
[emptyForegroundColor]="getValue(listEmptyForegroundColor) | async"
|
|
[fileDropAreaColor]="getValue(themeUploadFileDropAreaColor) | async"
|
|
[fileDropAreaActionProvider]="themeUploadFileDropAreaActionProvider"
|
|
[searchBarSearchInputColor]="
|
|
getValue(listSearchBarSearchInputColor) | async
|
|
"
|
|
[fileDropAreaErrorColor]="
|
|
getValue(themeUploadFileDropAreaErrorColor) | async
|
|
"
|
|
[fileDropAreaAccentColor]="
|
|
getValue(themeUploadFileDropAreaAccentColor) | async
|
|
"
|
|
[fileDropAreaSuccessColor]="
|
|
getValue(themeUploadFileDropAreaSuccessColor) | async
|
|
"
|
|
[fileDropAreaForegroundColor]="
|
|
getValue(themeUploadFileDropAreaForegroundColor) | async
|
|
"
|
|
[emptyForegroundMessageColor]="
|
|
getValue(themeUploadEmptyForegroundMessageColor) | async
|
|
"
|
|
[fileDropAreaMessage]="
|
|
getValue(themeUploadFileDropAreaMessage) | async
|
|
"
|
|
[fileDropAreaCssClass]="
|
|
getArrayValue(themeUploadFileDropAreaCssClass) | async
|
|
"
|
|
[showFileDropArea]="
|
|
(isNotMobileUi$ | async) && getValue(themeUploadShowFileDropArea)
|
|
| async
|
|
"
|
|
></x-file-upload>
|
|
</x-tab>
|
|
</x-tabs>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<!-- pack List Item Template -->
|
|
<ng-template #themeListItemRef let-item="item" let-index="index">
|
|
{{ item.data.name }}
|
|
</ng-template>
|
|
|
|
<!-- previewActionRef -->
|
|
<ng-template
|
|
#previewActionRef
|
|
let-key="key"
|
|
let-prefix="prefix"
|
|
let-value="value"
|
|
>
|
|
<x-color
|
|
[showLabel]="false"
|
|
class="x-color-item"
|
|
*ngIf="key !== 'name'"
|
|
[value]="getColorValue(key, value)"
|
|
[borderColor]="getValue(colorViewBorderColor) | async"
|
|
[borderWidth]="getValue(colorViewBorderWidth) | async"
|
|
[borderStyle]="getValue(colorViewBorderStyle) | async"
|
|
></x-color>
|
|
</ng-template>
|
|
|
|
<!-- ThemeEditActionRef -->
|
|
<ng-template
|
|
#themeEditActionRef
|
|
let-key="key"
|
|
let-prefix="prefix"
|
|
let-value="value"
|
|
>
|
|
<ng-container *ngIf="key !== 'name'">
|
|
<!-- Color Viewer -->
|
|
<x-color
|
|
[showLabel]="false"
|
|
class="x-color-item"
|
|
[value]="getColorValue(key, value)"
|
|
[borderColor]="getValue(colorViewBorderColor) | async"
|
|
[borderWidth]="getValue(colorViewBorderWidth) | async"
|
|
[borderStyle]="getValue(colorViewBorderStyle) | async"
|
|
></x-color>
|
|
|
|
<!-- is Small Screen -->
|
|
<ng-container *ngIf="isMobileUi$ | async">
|
|
<!-- Property Selector -->
|
|
<x-icon
|
|
[clickable]="true"
|
|
[foregroundColor]="true"
|
|
[name]="getValue(propertyActionMenuIcon) | async"
|
|
[color]="getValue(propertyActionMenuIconColor) | async"
|
|
(clicked)="handleThemePropertyActionMenuClicked(key, prefix, value)"
|
|
></x-icon>
|
|
</ng-container>
|
|
|
|
<!-- is Big Screen -->
|
|
<ng-container *ngIf="isNotMobileUi$ | async">
|
|
<!-- Property Selector -->
|
|
<x-icon
|
|
[clickable]="true"
|
|
[foregroundColor]="true"
|
|
[name]="getValue(propertyEditIcon) | async"
|
|
(clicked)="handleThemePropertyEdit(key, prefix, value)"
|
|
[color]="
|
|
(notNullOrUndefinedValue(value) | async)
|
|
? (getValue(propertyEditIconColor) | async)
|
|
: (getValue(emptyPropertyEditIconColor) | async)
|
|
"
|
|
></x-icon>
|
|
</ng-container>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.scss
|
|
|
|
:host ::ng-deep x-color {
|
|
--size: 24px !important;
|
|
display: inline-block;
|
|
}
|
|
|
|
.actions {
|
|
margin: {
|
|
top: 8px;
|
|
bottom: 8px;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
assign,
|
|
XParam,
|
|
toArray,
|
|
hasChild,
|
|
XUiEvent,
|
|
cloneJson,
|
|
parseJson,
|
|
isFunction,
|
|
isSameType,
|
|
XThemeType,
|
|
XThemePack,
|
|
isSameObject,
|
|
XResourceIDs,
|
|
XDialogResult,
|
|
XExceptionIDs,
|
|
XBaseKeyValue,
|
|
XStandardType,
|
|
XPickerOptions,
|
|
toNormalString,
|
|
XOneOrManyType,
|
|
XModelProperty,
|
|
XThemeDescriptor,
|
|
XModalButtonRole,
|
|
XModelKeyProvider,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XThemeTypeIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XThemeManagerTabs,
|
|
XThemeManagerAction,
|
|
XThemeManagerActionModel,
|
|
XThemeManagerContainerComponent,
|
|
} from './x-theme-manager.typings';
|
|
import {
|
|
XTabsAction,
|
|
XTabChangeEvent,
|
|
XTabsActionModel,
|
|
} from '../../x-tabs/x-tabs.typings';
|
|
import {
|
|
XListItem,
|
|
XListAction,
|
|
XListActionModel,
|
|
XListItemSlideOption,
|
|
XListFilteringHandler,
|
|
defaultListFilteringHandler,
|
|
} from '../../x-list/x-list.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import {
|
|
XActionBarItem,
|
|
XActionBarAction,
|
|
XActionBarActionModel,
|
|
DefaultActionBarItemIds,
|
|
defaultActionBarSetItem,
|
|
defaultActionBarUploadItem,
|
|
XActionBarActionFiredModel,
|
|
} from '../../x-action-bar/x-action-bar.typings';
|
|
import {
|
|
XSearchBarType,
|
|
XSearchBarAction,
|
|
XSearchBarActionModel,
|
|
XSearchBarEventIdentifier,
|
|
} from '../../x-search-bar/x-search-bar.typings';
|
|
import {
|
|
XFileUploadAction,
|
|
XFileUploadActionModel,
|
|
} from '../../x-file-upload/x-file-upload.typings';
|
|
import { getEmptyThemePack } from '../x-theme.tools';
|
|
import { XIconNames } from '../../x-icon/x-icon.typings';
|
|
import {
|
|
XModelPresenterAction,
|
|
XModelPresenterActionModel,
|
|
} from '../../x-model-presenter/x-model-presenter.typings';
|
|
import { XButtonType } from '../../x-button/x-button.typings';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
import { XSlotLayout, XSlotName } from '../../x-slotter/x-slotter.typings';
|
|
import { XPopoverComponent } from '../../dialogs/x-popover/x-popover.component';
|
|
import { XColorPickerOutputFormat } from '../../x-color-picker/x-color-picker.typings';
|
|
import { XFileDropAreaActionModel } from '../../x-file-drop-area/x-file-drop-area.typings';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-theme-manager',
|
|
templateUrl: './x-theme-manager.component.html',
|
|
styleUrls: ['./x-theme-manager.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XThemeManagerComponent extends XThemeManagerContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private loadingObject: HTMLIonLoadingElement;
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
readonly SlotNames = Object.assign({}, XSlotName);
|
|
readonly Tabs = Object.assign({}, XThemeManagerTabs);
|
|
readonly SlotLayouts = Object.assign({}, XSlotLayout);
|
|
readonly ButtonTypes = Object.assign({}, XButtonType);
|
|
readonly ColorNames = Object.assign({}, XColorWithBrightness);
|
|
readonly themeUploadListActionProvider = new Subject<XListActionModel>();
|
|
readonly allowedThemeExtensions: XStandardType<XOneOrManyType<string>> = [
|
|
'.json',
|
|
];
|
|
readonly themeUploadActionProvider = new Subject<XFileUploadActionModel>();
|
|
readonly themeUploadListActionBarHideActions: XStandardType<
|
|
XOneOrManyType<string>
|
|
>;
|
|
readonly themeModelPresenterActionProvider =
|
|
new Subject<XModelPresenterActionModel>();
|
|
readonly themeUploadListActionbarActions: XStandardType<
|
|
XOneOrManyType<XActionBarItem>
|
|
>;
|
|
readonly themeUploadFileDropAreaActionProvider =
|
|
new Subject<XFileDropAreaActionModel>();
|
|
|
|
//
|
|
canSaveTheme = false;
|
|
listItems: XListItem<any>[];
|
|
selectedTheme: XThemePack = null;
|
|
uploadThemes: XOneOrManyType<File>;
|
|
currentTab: number = this.Tabs.List;
|
|
baseTheme: Readonly<XThemePack> = null;
|
|
showList: XStandardType<boolean> = true;
|
|
hiddenThemModelKeys: XOneOrManyType<string> = [
|
|
`${nameof<XThemePack>('dark')}.${nameof<XThemeDescriptor>('type')}`,
|
|
`${nameof<XThemePack>('light')}.${nameof<XThemeDescriptor>('type')}`,
|
|
];
|
|
themeKeyProvider: XModelKeyProvider = (key) => {
|
|
//
|
|
let result = key as string;
|
|
|
|
//
|
|
switch (key) {
|
|
//
|
|
case nameof<XThemePack>('name'):
|
|
result = this.resourceProvider(this.ResourceIDs.theme);
|
|
break;
|
|
|
|
//
|
|
case nameof<XThemePack>('dark'):
|
|
result = this.resourceProvider(this.ResourceIDs.theme_dark);
|
|
break;
|
|
|
|
//
|
|
case nameof<XThemePack>('light'):
|
|
result = this.resourceProvider(this.ResourceIDs.theme_light);
|
|
break;
|
|
|
|
//
|
|
case nameof<XThemeDescriptor>('colors'):
|
|
result = this.resourceProvider(this.ResourceIDs.colors);
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = key as string;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
};
|
|
listActionProvider = new Subject<XListActionModel>();
|
|
tabsActionProvider = new Subject<XTabsActionModel>();
|
|
searchBarType: XStandardType<string> = XSearchBarType.Search;
|
|
searchBarActionProvider = new Subject<XSearchBarActionModel>();
|
|
actionBarActionProvider = new Subject<XActionBarActionModel>();
|
|
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>>;
|
|
themeModelPresenterActionActions: XOneOrManyType<XActionBarItem> = [
|
|
{
|
|
//
|
|
...defaultActionBarSetItem,
|
|
|
|
//
|
|
title: this.ResourceIDs.save,
|
|
disabled: true,
|
|
|
|
//
|
|
handler: async (id) => {
|
|
await this.handleUpdateTheme();
|
|
},
|
|
},
|
|
];
|
|
listFilteringHandler: XListFilteringHandler = defaultListFilteringHandler;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async afterViewInit() {
|
|
super.afterViewInit();
|
|
|
|
//
|
|
await this.startUp();
|
|
}
|
|
|
|
onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XThemeManagerComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Provider ...
|
|
getColorValue(key: string, value: string) {
|
|
return {
|
|
key,
|
|
value,
|
|
} as XBaseKeyValue<string>;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handler ...
|
|
//
|
|
async handleSelectedTabChanged(event: XTabChangeEvent) {
|
|
this.currentTab = event.index;
|
|
}
|
|
|
|
async handleListRefresh() {
|
|
//
|
|
await this.startUp();
|
|
|
|
//
|
|
if (!isNullOrUndefined(this.listEmptyRefresh)) {
|
|
this.listEmptyRefresh.emit();
|
|
}
|
|
}
|
|
|
|
async handleListActionBarActionFired(model: XActionBarActionFiredModel) {
|
|
//
|
|
if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case DefaultActionBarItemIds.Upload:
|
|
await this.handleUploadTheme();
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (!isNullOrUndefined(this.listActionBarActionFired)) {
|
|
this.listActionBarActionFired.emit(model);
|
|
}
|
|
}
|
|
|
|
async handleListSearchBarOnEvent(event: XSearchBarEventIdentifier) {
|
|
//
|
|
if (!isNullOrUndefined(this.listSearchBarOnEvent)) {
|
|
this.listSearchBarOnEvent.emit(event);
|
|
}
|
|
}
|
|
|
|
async handleListSearchBarQueryChange(event: string) {
|
|
//
|
|
if (!isNullOrUndefined(this.listSearchBarQueryChange)) {
|
|
this.listSearchBarQueryChange.emit(event);
|
|
}
|
|
}
|
|
|
|
async handleThemeUploadActionFired(model: XActionBarActionFiredModel) {
|
|
//
|
|
// Validate Args ...
|
|
if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case DefaultActionBarItemIds.Upload:
|
|
await this.handleThemesImport();
|
|
break;
|
|
}
|
|
}
|
|
|
|
async handleThemeUploadFileChanged(files: XOneOrManyType<File>) {
|
|
this.uploadThemes = files;
|
|
}
|
|
|
|
//
|
|
//#region ModelPresenter Handlers ...
|
|
async handleThemePropertyActionMenuClicked(
|
|
key: string,
|
|
prefix: string,
|
|
value: any
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const onlyIcon = false;
|
|
const slideOptions: XListItemSlideOption[] = [];
|
|
|
|
//
|
|
// Edit ...
|
|
slideOptions.push({
|
|
id: 'property_edit',
|
|
icon: await this.getValueAsync(this.propertyEditIcon),
|
|
title: this.ResourceIDs.edit,
|
|
color: isNullOrUndefined(value)
|
|
? await this.getValueAsync(this.emptyPropertyEditIconColor)
|
|
: await this.getValueAsync(this.propertyEditIconColor),
|
|
slot: 'start',
|
|
onlyIcon,
|
|
handler: async () => {
|
|
await this.handleThemePropertyEdit(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 handleThemePropertyEdit(key: string, prefix: string, value: any) {
|
|
//
|
|
if (isNullOrEmptyString(key)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.colorPickerDialogService.openDialog({
|
|
//
|
|
title: key,
|
|
|
|
//
|
|
selectedColor: value,
|
|
|
|
//
|
|
showColorInput: true,
|
|
showPresetColors: false,
|
|
showCopyToClipboard: true,
|
|
|
|
//
|
|
cardColor: await this.getValueAsync(this.cardColor),
|
|
cardForegroundColor: await this.getValueAsync(this.cardForegroundColor),
|
|
|
|
//
|
|
representColorFormats: [XColorPickerOutputFormat.XHEX],
|
|
});
|
|
|
|
//
|
|
const subscription = this.colorPickerDialogService.onResult
|
|
.asObservable()
|
|
.subscribe((result) => {
|
|
//
|
|
if (
|
|
result.result !== XDialogResult.Ok ||
|
|
!result.payload ||
|
|
isNullOrEmptyString(result.payload)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const value = result.payload as string;
|
|
this.themeModelPresenterActionProvider.next({
|
|
action: XModelPresenterAction.SetProperty,
|
|
payload: {
|
|
key,
|
|
value,
|
|
prefix,
|
|
} as XModelProperty,
|
|
});
|
|
|
|
//
|
|
subscription.unsubscribe();
|
|
});
|
|
}
|
|
|
|
async handleThemeContentChanged(event: any) {
|
|
//
|
|
const isTheme = isSameType(event, this.selectedTheme);
|
|
if (!isTheme) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isThemeChanged = !isSameObject(this.baseTheme, this.selectedTheme);
|
|
this.canSaveTheme = isThemeChanged;
|
|
|
|
//
|
|
toArray(this.themeModelPresenterActionActions)[0].disabled =
|
|
!this.canSaveTheme;
|
|
|
|
//
|
|
this.themeChange.emit(isThemeChanged);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async handleUpdateTheme() {
|
|
//
|
|
if (!this.selectedTheme || !this.baseTheme || !this.canSaveTheme) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(
|
|
async () => {
|
|
await this.updateTheme(this.selectedTheme);
|
|
}
|
|
);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async back() {
|
|
//
|
|
switch (this.currentTab) {
|
|
//
|
|
case this.Tabs.List:
|
|
this.baseTheme = null;
|
|
this.selectedTheme = null;
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Details:
|
|
await this.changeTab(this.Tabs.List);
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Import:
|
|
//
|
|
this.uploadThemes = [];
|
|
this.themeUploadActionProvider.next({
|
|
action: XFileUploadAction.CLEAR_LIST,
|
|
});
|
|
await this.changeTab(this.Tabs.List);
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Edit:
|
|
this.baseTheme = null;
|
|
this.selectedTheme = null;
|
|
this.canSaveTheme = false;
|
|
this.themeChange.emit(false);
|
|
await this.changeTab(this.Tabs.List);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async clearList() {
|
|
//
|
|
this.listItems = [];
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async setTheme(theme: XThemePack, whichType: XThemeTypeIdentifier) {
|
|
//
|
|
if (!theme && isNullOrEmptyString(theme.name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const restart = await this.getOptionalValueAsync(this.restartAfterSetTheme);
|
|
|
|
//
|
|
const isSetted = await this.managerService.themeManagerService.setTheme(
|
|
theme,
|
|
whichType,
|
|
true,
|
|
restart
|
|
);
|
|
if (isSetted) {
|
|
//
|
|
await this.prepareListItems();
|
|
|
|
//
|
|
this.managerService.settingsService.restart();
|
|
}
|
|
}
|
|
|
|
async editTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme || !isNullOrUndefined(this.loadingObject)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.presentLoading();
|
|
|
|
//
|
|
this.baseTheme = cloneJson(theme);
|
|
this.selectedTheme = {
|
|
...theme,
|
|
};
|
|
await this.changeTab(this.Tabs.Edit);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async cloneTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.dialogService.presentAlert({
|
|
subHeader: XResourceIDs.theme,
|
|
message: XResourceIDs.theme_clone_title,
|
|
inputs: [
|
|
{
|
|
type: 'text',
|
|
name: 'name',
|
|
placeholder: XResourceIDs.theme_name_description,
|
|
},
|
|
],
|
|
buttons: [
|
|
{
|
|
text: XResourceIDs.clone,
|
|
role: XModalButtonRole.Selected,
|
|
cssClass: ['btn-selected'],
|
|
handler: async (value) => {
|
|
//
|
|
if (value && value.name && !isNullOrEmptyString(value.name)) {
|
|
//
|
|
const themeName = toNormalString(theme.name);
|
|
const clonedThemeName = toNormalString(value.name as string);
|
|
const isCloned =
|
|
await this.managerService.themeManagerService.cloneTheme(
|
|
themeName,
|
|
clonedThemeName,
|
|
false
|
|
);
|
|
|
|
//
|
|
if (isCloned) {
|
|
//
|
|
this.showSuccess();
|
|
await this.prepareListItems();
|
|
} else {
|
|
this.showError(XExceptionIDs.ActionFailed);
|
|
}
|
|
} else {
|
|
this.showError(XExceptionIDs.InvalidData);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
text: XResourceIDs.cancel,
|
|
role: XModalButtonRole.Cancel,
|
|
cssClass: ['btn-cancel'],
|
|
handler: () => {},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
async downloadTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.themeManagerService.exportTheme(theme.name);
|
|
}
|
|
|
|
async removeTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => {
|
|
this.managerService.themeManagerService
|
|
.removeTheme(toNormalString(theme.name), false)
|
|
.then((isRemoved) => {
|
|
if (isRemoved) {
|
|
//
|
|
this.showSuccess();
|
|
this.prepareListItems();
|
|
} else {
|
|
this.showError();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
async previewTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme || !isNullOrUndefined(this.loadingObject)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
await this.presentLoading();
|
|
|
|
//
|
|
this.selectedTheme = {
|
|
...theme,
|
|
};
|
|
await this.changeTab(this.Tabs.Details);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
async saveTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
if (
|
|
isNullOrEmptyString(theme.name) ||
|
|
(await this.managerService.themeManagerService.isThemeExists(theme.name))
|
|
) {
|
|
this.showError(XExceptionIDs.Duplicate);
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isSaved = await this.managerService.themeManagerService.saveTheme(
|
|
theme,
|
|
false
|
|
);
|
|
|
|
//
|
|
if (isSaved) {
|
|
//
|
|
this.themeChange.emit(false);
|
|
this.managerService.settingsService.restart();
|
|
}
|
|
|
|
return isSaved;
|
|
}
|
|
|
|
async updateTheme(theme: XThemePack) {
|
|
//
|
|
if (!theme || isNullOrEmptyString(theme.name)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isExists =
|
|
await this.managerService.themeManagerService.isThemeExists(theme.name);
|
|
if (!isExists) {
|
|
this.showError(XExceptionIDs.NotFound);
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isUpdated = await this.managerService.themeManagerService.updateTheme(
|
|
theme.name,
|
|
theme,
|
|
false,
|
|
true
|
|
);
|
|
|
|
//
|
|
if (isUpdated) {
|
|
//
|
|
this.themeChange.emit(false);
|
|
this.managerService.settingsService.restart();
|
|
}
|
|
|
|
//
|
|
return isUpdated;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Handler Registerrers ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XThemeManagerActionModel>();
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XThemeManagerAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XThemeManagerAction.Back:
|
|
await this.back();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private Actions ...
|
|
private async startUp() {
|
|
//
|
|
this.tabChange.emit(this.currentTab);
|
|
await this.prepareActionBarActions();
|
|
await this.prepareListItems();
|
|
}
|
|
|
|
private async prepareListItems() {
|
|
//
|
|
this.listItems = null;
|
|
|
|
//
|
|
const loadingDialog =
|
|
await this.managerService.dialogService.presentLoading({
|
|
showBackdrop: true,
|
|
backdropDismiss: false,
|
|
message: this.resourceProvider(XResourceIDs.loading),
|
|
});
|
|
|
|
//
|
|
const currentTheme =
|
|
await this.managerService.themeManagerService.getCurrentTheme();
|
|
const themes = await this.managerService.themeManagerService.getThemes();
|
|
if (!currentTheme || !hasChild(themes)) {
|
|
//
|
|
await this.clearList();
|
|
await loadingDialog.dismiss();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Prepare List Items ...
|
|
this.listItems = themes.map((theme) => {
|
|
//
|
|
const isCurrent =
|
|
toNormalString(theme.name) === toNormalString(currentTheme.name);
|
|
|
|
//
|
|
return {
|
|
data: theme,
|
|
slideOptions: [
|
|
//
|
|
// Remove ...
|
|
{
|
|
id: 'delete_theme',
|
|
icon: XIconNames.remove,
|
|
title: this.ResourceIDs.delete,
|
|
color: XColorWithBrightness.Danger,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading || isCurrent,
|
|
slot: 'end',
|
|
handler: () => {
|
|
this.removeTheme(theme);
|
|
},
|
|
},
|
|
//
|
|
// Set As Current ...
|
|
{
|
|
id: 'set_theme',
|
|
icon: XIconNames.checked,
|
|
title: this.ResourceIDs.set,
|
|
color: XColorWithBrightness.Success,
|
|
onlyIcon: true,
|
|
disabled:
|
|
this.uiDisabled ||
|
|
this.loading ||
|
|
toNormalString(theme.name) === toNormalString(currentTheme.name),
|
|
slot: 'start',
|
|
handler: () => {
|
|
//
|
|
// Prepare Picker Options for Theme Setting ...
|
|
const options: XPickerOptions = {
|
|
buttons: [
|
|
{
|
|
text: XResourceIDs.set,
|
|
role: XModalButtonRole.Selected,
|
|
cssClass: ['btn-selected'],
|
|
handler: async (value) => {
|
|
//
|
|
if (!value || !value.type || !value.type.value) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const type = value.type.value as XThemeTypeIdentifier;
|
|
await this.setTheme(theme, type);
|
|
},
|
|
},
|
|
{
|
|
text: XResourceIDs.cancel,
|
|
role: XModalButtonRole.Cancel,
|
|
cssClass: ['btn-cancel'],
|
|
},
|
|
],
|
|
columns: [
|
|
{
|
|
name: 'type',
|
|
options: [
|
|
{
|
|
text: XResourceIDs.theme_light,
|
|
value: XThemeType.Light,
|
|
},
|
|
{
|
|
text: XResourceIDs.theme_dark,
|
|
value: XThemeType.Dark,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
//
|
|
// Present Theme Picker ...
|
|
this.managerService.dialogService.presentPicker(options);
|
|
},
|
|
},
|
|
//
|
|
// Check For Change Mode ...
|
|
...(isCurrent
|
|
? [
|
|
//
|
|
// Change Mode ...
|
|
{
|
|
id: 'change_theme_mode',
|
|
icon: XIconNames.contrast,
|
|
title: this.ResourceIDs.theme_mode,
|
|
color: XColorWithBrightness.Success,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading,
|
|
slot: 'start',
|
|
handler: async () => {
|
|
//
|
|
const currentType =
|
|
await this.managerService.themeManagerService.getCurrentThemeType();
|
|
const type =
|
|
currentType === XThemeType.Light
|
|
? XThemeType.Dark
|
|
: XThemeType.Light;
|
|
await this.setTheme(theme, type);
|
|
},
|
|
},
|
|
]
|
|
: []),
|
|
//
|
|
// Preview ...
|
|
{
|
|
id: 'preview_theme',
|
|
icon: XIconNames.preview,
|
|
title: this.ResourceIDs.details,
|
|
color: XColorWithBrightness.Secondary,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading,
|
|
slot: 'start',
|
|
handler: async () => {
|
|
await this.previewTheme(theme);
|
|
},
|
|
},
|
|
//
|
|
// Edit ...
|
|
{
|
|
id: 'edit_theme',
|
|
icon: XIconNames.edit,
|
|
title: this.ResourceIDs.edit,
|
|
color: XColorWithBrightness.Tertiary,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading, // || isCurrent,
|
|
slot: 'start',
|
|
handler: () => {
|
|
this.editTheme(theme);
|
|
},
|
|
},
|
|
//
|
|
// Clone ...
|
|
{
|
|
id: 'clone_theme',
|
|
icon: XIconNames.copy,
|
|
title: this.ResourceIDs.clone,
|
|
color: XColorWithBrightness.Success,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading,
|
|
slot: 'start',
|
|
handler: async () => {
|
|
await this.cloneTheme(theme);
|
|
},
|
|
},
|
|
//
|
|
// Download ...
|
|
{
|
|
id: 'download_theme',
|
|
icon: XIconNames.download,
|
|
title: this.ResourceIDs.download,
|
|
color: XColorWithBrightness.SecondaryShade,
|
|
onlyIcon: true,
|
|
disabled: this.uiDisabled || this.loading,
|
|
slot: 'start',
|
|
handler: async () => {
|
|
await this.downloadTheme(theme);
|
|
},
|
|
},
|
|
],
|
|
} as XListItem<XThemePack>;
|
|
});
|
|
|
|
//
|
|
await loadingDialog.dismiss();
|
|
|
|
//
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
private handleChangeDetection() {
|
|
//
|
|
this.tabsActionProvider.next({
|
|
action: XTabsAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.listActionProvider.next({
|
|
action: XListAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.actionBarActionProvider.next({
|
|
action: XActionBarAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.searchBarActionProvider.next({
|
|
action: XSearchBarAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.themeUploadActionProvider.next({
|
|
action: XFileUploadAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.themeUploadListActionProvider.next({
|
|
action: XListAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.themeModelPresenterActionProvider.next({
|
|
action: XModelPresenterAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.themeUploadFileDropAreaActionProvider.next({
|
|
action: XFileUploadAction.Refresh,
|
|
});
|
|
|
|
//
|
|
this.managerService.dispatchResizeEvent();
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
|
|
private async presentLoading() {
|
|
//
|
|
this.loadingObject = await this.managerService.dialogService.presentLoading(
|
|
{
|
|
message: this.resourceProvider(this.ResourceIDs.loading),
|
|
}
|
|
);
|
|
}
|
|
|
|
private async changeTab(tab?: XThemeManagerTabs) {
|
|
//
|
|
if (!tab) {
|
|
tab = this.Tabs.List;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Prevent go forward if args is not ready ...
|
|
if (this.loading || this.uiDisabled || this.currentTab === tab) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
//#region Pre Change Actions ...
|
|
//
|
|
// Based On Current Tab ...
|
|
switch (this.currentTab) {
|
|
//
|
|
case this.Tabs.List:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Details:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Import:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Edit:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Based On Dest Tab ...
|
|
switch (tab) {
|
|
//
|
|
case this.Tabs.List:
|
|
this.baseTheme = null;
|
|
this.selectedTheme = null;
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Details:
|
|
//
|
|
if (isNullOrUndefined(this.selectedTheme)) {
|
|
return;
|
|
}
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Import:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Edit:
|
|
//
|
|
if (isNullOrUndefined(this.selectedTheme)) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Change Current Tab ...
|
|
this.currentTab = tab;
|
|
this.detectChanges();
|
|
|
|
//
|
|
//#region Post Change Actions ...
|
|
switch (tab) {
|
|
//
|
|
case this.Tabs.List:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Details:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Import:
|
|
break;
|
|
|
|
//
|
|
case this.Tabs.Edit:
|
|
break;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
this.tabChange.emit(tab);
|
|
this.handleChangeDetection();
|
|
}
|
|
|
|
private async handleUploadTheme() {
|
|
await this.changeTab(this.Tabs.Import);
|
|
}
|
|
|
|
private async handleThemesImport() {
|
|
//
|
|
if (!this.hasChild(this.uploadThemes)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const emptyTheme = getEmptyThemePack();
|
|
const importedThemes = await this.getArrayValueAsync(this.uploadThemes);
|
|
|
|
//
|
|
importedThemes.forEach(async (themeFile) => {
|
|
//
|
|
const fileReader = new FileReader();
|
|
fileReader.readAsText(themeFile);
|
|
fileReader.onloadend = async (e) => {
|
|
//
|
|
if (!e || !e.target || !e.target.result) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
try {
|
|
//
|
|
// Check Theme Valid ...
|
|
const themePack = parseJson<XThemePack>(e.target.result.toString());
|
|
if (!themePack) {
|
|
//
|
|
await this.issueThemeError(
|
|
themeFile.name,
|
|
XExceptionIDs.InavlidFile
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Theme Type ...
|
|
const isCorrectThemeType = isSameType(themePack, emptyTheme);
|
|
if (!isCorrectThemeType) {
|
|
//
|
|
await this.issueThemeError(
|
|
themeFile.name,
|
|
XExceptionIDs.UnsupportedFileType
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Theme Name and Existance ...
|
|
if (
|
|
isNullOrEmptyString(themePack.name) ||
|
|
(await this.managerService.themeManagerService.isThemeExists(
|
|
themePack.name
|
|
))
|
|
) {
|
|
//
|
|
this.issueThemeError(themeFile.name, XExceptionIDs.Duplicate);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isSaved = await this.saveTheme(themePack);
|
|
if (isSaved) {
|
|
await this.prepareListItems();
|
|
} else {
|
|
//
|
|
await this.issueThemeError(
|
|
themeFile.name,
|
|
XExceptionIDs.ActionFailed
|
|
);
|
|
|
|
//
|
|
return;
|
|
}
|
|
} catch {
|
|
await this.issueThemeError(themeFile.name, XExceptionIDs.InavlidFile);
|
|
}
|
|
};
|
|
});
|
|
|
|
//
|
|
await this.back();
|
|
}
|
|
|
|
private async issueThemeError(fileName: string, exception: XExceptionIDs) {
|
|
//
|
|
if (isNullOrEmptyString(fileName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const message = `${this.managerService.localizationService.getErrorMessage(
|
|
exception
|
|
)}_${fileName}`;
|
|
|
|
//
|
|
await this.managerService.notificationService.presentDangerNotification({
|
|
dissmissable: true,
|
|
message,
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar Actions ...
|
|
private async prepareActionBarActions() {
|
|
//
|
|
//#region Prepare Default Actions ...
|
|
const hideActions: string | string[] = [];
|
|
|
|
//
|
|
const defaultActions: XOneOrManyType<XActionBarItem> = [];
|
|
|
|
//
|
|
// Import ...
|
|
const importId = DefaultActionBarItemIds.Upload.toString();
|
|
if (!hideActions.includes(importId)) {
|
|
defaultActions.push({
|
|
//
|
|
...defaultActionBarUploadItem,
|
|
|
|
//
|
|
title: XResourceIDs.import,
|
|
color: XColorWithBrightness.Success,
|
|
|
|
//
|
|
index: 1,
|
|
disabled: this.uiDisabled,
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
if (!this.actionBarActions) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
this.handleChangeDetection();
|
|
return;
|
|
}
|
|
|
|
//
|
|
const actions = await this.getArrayValueAsync(this.actionBarActions);
|
|
if (!hasChild(actions)) {
|
|
//
|
|
this.actionBarActions = defaultActions;
|
|
this.handleChangeDetection();
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.actionBarActions = actions;
|
|
this.handleChangeDetection();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
NgZone,
|
|
Output,
|
|
Renderer2,
|
|
Component,
|
|
Injectable,
|
|
ElementRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XResourceIDs,
|
|
XBorderStyle,
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
XBorderStyleIdentifier,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XCardContainer,
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../../x-card/x-card.typings';
|
|
import {
|
|
XComponentListContainer,
|
|
IXComponentListContainer,
|
|
} from '../../x-list/x-list.typings';
|
|
import {
|
|
XFileContainer,
|
|
IXFileContainer,
|
|
} from '../../classes/i-x-file.container';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import {
|
|
XActionBarActionFiredModel,
|
|
XComponentActionBarContainer,
|
|
IXComponentActionBarContainer,
|
|
} from '../../x-action-bar/x-action-bar.typings';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { forkJoin, Observable, Subject } from 'rxjs';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../../classes/x-base-action.model';
|
|
import { XIconIdentifier, XIconNames } from '../../x-icon/x-icon.typings';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens';
|
|
import { IXFileUploadContainer } from '../../x-file-upload/x-file-upload.typings';
|
|
import { XFileUploadContainer } from './../../x-file-upload/x-file-upload.typings';
|
|
import { XSearchBarEventIdentifier } from '../../x-search-bar/x-search-bar.typings';
|
|
import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config';
|
|
import { XColorPickerDialogService } from '../../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service';
|
|
|
|
export enum XThemeManagerAction {
|
|
//
|
|
Back = 'back',
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XThemeManagerActionIdentifier = XThemeManagerAction | string;
|
|
|
|
export interface XThemeManagerActionModel
|
|
extends XBaseActionModel<XThemeManagerActionIdentifier> {}
|
|
|
|
export enum XThemeManagerTabs {
|
|
List,
|
|
Details,
|
|
Edit,
|
|
Import,
|
|
}
|
|
|
|
//
|
|
//#region Inside Card Container ...
|
|
//
|
|
type TXSelectedComponentListContainer = Pick<
|
|
IXComponentListContainer,
|
|
| 'listCssClass'
|
|
| 'listShowDivider'
|
|
//
|
|
// List Empty ...
|
|
| 'listShowEmpty'
|
|
| 'listEmptyActionProvider'
|
|
| 'listEmptyColor'
|
|
| 'listEmptyCssClass'
|
|
| 'listEmptyForegroundColor'
|
|
| 'listEmptyForegroundMessageColor'
|
|
| 'listEmptyForegroundRefreshButtonColor'
|
|
| 'listEmptyHasRefresh'
|
|
| 'listEmptyMessage'
|
|
| 'listEmptyMessageColor'
|
|
| 'listEmptyRefresh'
|
|
| 'listEmptyRefreshButtonColor'
|
|
| 'listEmptyRefreshIcon'
|
|
//
|
|
// List Search ...
|
|
| 'listSearchBarValue'
|
|
| 'listSearchBarColor'
|
|
| 'listSearchBarDebounce'
|
|
| 'listSearchBarSearchInputColor'
|
|
| 'listSearchBarForegroundSearchInputColor'
|
|
| 'listSearchBarCancelButtonIcon'
|
|
| 'listSearchBarCancelButtonTitle'
|
|
| 'listSearchBarClearButtonIcon'
|
|
| 'listSearchBarClearButtonIconColor'
|
|
| 'listSearchBarCssClass'
|
|
| 'listSearchBarEnterKeyHint'
|
|
| 'listSearchBarForegroundColor'
|
|
| 'listSearchBarKeyboardType'
|
|
| 'listActionBarActionFired'
|
|
| 'listSearchBarOnEvent'
|
|
| 'listSearchBarQueryChange'
|
|
| 'listSearchBarSearchButtonIcon'
|
|
| 'listSearchBarSearchButtonIconColor'
|
|
| 'listSearchBarShowCancelButton'
|
|
| 'listSearchBarSpellcheck'
|
|
| 'listSearchBarTitle'
|
|
| 'listShowSearchBar'
|
|
>;
|
|
|
|
//
|
|
type TXSelectedComponentActionBarContainer = Pick<
|
|
IXComponentActionBarContainer,
|
|
| 'showActionBar'
|
|
| 'actionBarColor'
|
|
| 'actionBarCssClass'
|
|
| 'actionBarForegroundColor'
|
|
>;
|
|
|
|
//
|
|
type TXSelectedComponentFileUploadContainer = Pick<
|
|
{
|
|
[TKey in keyof IXFileUploadContainer as `themeUpload${Capitalize<
|
|
string & TKey
|
|
>}`]: IXFileUploadContainer[TKey];
|
|
},
|
|
//
|
|
| 'themeUploadColor'
|
|
| 'themeUploadCssClass'
|
|
| 'themeUploadEmptyMessage'
|
|
| 'themeUploadForegroundColor'
|
|
| 'themeUploadFileDropAreaIcon'
|
|
| 'themeUploadShowFileDropArea'
|
|
| 'themeUploadFileDropAreaColor'
|
|
| 'themeUploadFileDropAreaMessage'
|
|
| 'themeUploadFileDropAreaCssClass'
|
|
| 'themeUploadFileDropAreaErrorColor'
|
|
| 'themeUploadFileDropAreaAccentColor'
|
|
| 'themeUploadFileDropAreaSuccessColor'
|
|
| 'themeUploadFileDropAreaForegroundColor'
|
|
| 'themeUploadEmptyForegroundMessageColor'
|
|
| 'themeUploadFileDropAreaSupportsMultipleFiles'
|
|
>;
|
|
|
|
//
|
|
type TXSelectedFileContainer = Pick<
|
|
IXFileContainer,
|
|
| 'maxAllowedSize'
|
|
| 'minAllowedFileSize'
|
|
| 'maxAllowedFileSize'
|
|
| 'maxAllowedFiles'
|
|
>;
|
|
|
|
//
|
|
type TXThemeManagerContainer = IXComponentCardContainer &
|
|
TXSelectedComponentActionBarContainer &
|
|
TXSelectedComponentListContainer &
|
|
TXSelectedComponentFileUploadContainer &
|
|
TXSelectedFileContainer & {};
|
|
|
|
//
|
|
export interface IXThemeManagerContainer extends TXThemeManagerContainer {
|
|
//
|
|
actionProvider: Subject<XThemeManagerActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
color: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
themeChange: EventEmitter<boolean>;
|
|
tabChange: EventEmitter<XStandardType<number>>;
|
|
|
|
//
|
|
restartAfterSetTheme: XStandardType<boolean>;
|
|
colorViewBorderWidth: XStandardType<number>;
|
|
colorViewBorderStyle: XStandardType<XBorderStyleIdentifier>;
|
|
|
|
//
|
|
propertyLabelColor: XStandardType<XColorIdentifier>;
|
|
propertyValueColor: XStandardType<XColorIdentifier>;
|
|
colorViewBorderColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
propertyActionMenuIconColor: XStandardType<XColorIdentifier>;
|
|
propertyActionMenuIcon: XStandardType<XIconIdentifier>;
|
|
propertyEditIconColor: XStandardType<XColorIdentifier>;
|
|
propertyEditIcon: XStandardType<XIconIdentifier>;
|
|
propertyClearIconColor: XStandardType<XColorIdentifier>;
|
|
propertyClearIcon: XStandardType<XIconIdentifier>;
|
|
emptyPropertyEditIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
presenterHeaderColor: XStandardType<XColorIdentifier>;
|
|
presenterContentColor: XStandardType<XColorIdentifier>;
|
|
presenterHeaderHighlightColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
saveColor: XStandardType<XColorIdentifier>;
|
|
saveLabel: XStandardType<XResourceIdentifier>;
|
|
resetColor: XStandardType<XColorIdentifier>;
|
|
resetLabel: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XThemeManagerContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXThemeManagerContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
readonly actionProvider: Subject<XThemeManagerActionModel> =
|
|
new Subject<XThemeManagerActionModel>();
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
|
|
|
|
//
|
|
readonly themeChange: EventEmitter<boolean> = new EventEmitter<boolean>();
|
|
readonly tabChange: EventEmitter<XStandardType<number>> = new EventEmitter<
|
|
XStandardType<number>
|
|
>();
|
|
|
|
//
|
|
readonly restartAfterSetTheme: XStandardType<boolean> = true;
|
|
readonly colorViewBorderWidth: XStandardType<number> = 1;
|
|
readonly colorViewBorderStyle: XStandardType<XBorderStyleIdentifier> =
|
|
XBorderStyle.Solid;
|
|
|
|
//
|
|
readonly propertyLabelColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly propertyValueColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly colorViewBorderColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
|
|
//
|
|
readonly propertyActionMenuIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly propertyActionMenuIcon: XStandardType<XIconIdentifier> =
|
|
XIconNames.menu_vertical;
|
|
readonly propertyEditIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly propertyEditIcon: XStandardType<XIconIdentifier> = XIconNames.edit;
|
|
readonly propertyClearIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
readonly propertyClearIcon: XStandardType<XIconIdentifier> = XIconNames.clear;
|
|
readonly emptyPropertyEditIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Danger;
|
|
|
|
//
|
|
readonly presenterHeaderColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Light;
|
|
readonly presenterContentColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
readonly presenterHeaderHighlightColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.LightShade;
|
|
|
|
//
|
|
readonly saveColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Tertiary;
|
|
readonly saveLabel: XStandardType<XResourceIdentifier> = XResourceIDs.save;
|
|
|
|
//
|
|
readonly resetColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.WarningShade;
|
|
readonly resetLabel: XStandardType<XResourceIdentifier> = XResourceIDs.reset;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
readonly showActionBar = this.actionBarPropertyProvider.showActionBar;
|
|
readonly actionBarColor = this.actionBarPropertyProvider.actionBarColor;
|
|
readonly actionBarCssClass = this.actionBarPropertyProvider.actionBarCssClass;
|
|
readonly actionBarForegroundColor =
|
|
this.actionBarPropertyProvider.actionBarForegroundColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List ...
|
|
readonly listCssClass = this.listPropertyProvider.listCssClass;
|
|
readonly listShowDivider = this.listPropertyProvider.listShowDivider;
|
|
|
|
//
|
|
//#region List Empty ...
|
|
readonly listShowEmpty = this.listPropertyProvider.listShowEmpty;
|
|
readonly listEmptyActionProvider =
|
|
this.listPropertyProvider.listEmptyActionProvider;
|
|
readonly listEmptyColor = this.listPropertyProvider.listEmptyColor;
|
|
readonly listEmptyCssClass = this.listPropertyProvider.listEmptyCssClass;
|
|
readonly listEmptyForegroundColor =
|
|
this.listPropertyProvider.listEmptyForegroundColor;
|
|
readonly listEmptyForegroundMessageColor =
|
|
this.listPropertyProvider.listEmptyForegroundMessageColor;
|
|
readonly listEmptyForegroundRefreshButtonColor =
|
|
this.listPropertyProvider.listEmptyForegroundRefreshButtonColor;
|
|
readonly listEmptyHasRefresh = this.listPropertyProvider.listEmptyHasRefresh;
|
|
readonly listEmptyMessage = this.listPropertyProvider.listEmptyMessage;
|
|
readonly listEmptyMessageColor =
|
|
this.listPropertyProvider.listEmptyMessageColor;
|
|
readonly listEmptyRefresh = this.listPropertyProvider.listEmptyRefresh;
|
|
readonly listEmptyRefreshButtonColor =
|
|
this.listPropertyProvider.listEmptyRefreshButtonColor;
|
|
readonly listEmptyRefreshIcon =
|
|
this.listPropertyProvider.listEmptyRefreshIcon;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Search ...
|
|
readonly listSearchBarValue = this.listPropertyProvider.listSearchBarValue;
|
|
readonly listSearchBarColor = this.listPropertyProvider.listSearchBarColor;
|
|
readonly listSearchBarDebounce =
|
|
this.listPropertyProvider.listSearchBarDebounce;
|
|
readonly listSearchBarSearchInputColor =
|
|
this.listPropertyProvider.listSearchBarSearchInputColor;
|
|
readonly listSearchBarForegroundSearchInputColor =
|
|
this.listPropertyProvider.listSearchBarForegroundSearchInputColor;
|
|
readonly listSearchBarCancelButtonIcon =
|
|
this.listPropertyProvider.listSearchBarCancelButtonIcon;
|
|
readonly listSearchBarCancelButtonTitle =
|
|
this.listPropertyProvider.listSearchBarCancelButtonTitle;
|
|
readonly listSearchBarClearButtonIcon =
|
|
this.listPropertyProvider.listSearchBarClearButtonIcon;
|
|
readonly listSearchBarClearButtonIconColor =
|
|
this.listPropertyProvider.listSearchBarClearButtonIconColor;
|
|
readonly listSearchBarCssClass =
|
|
this.listPropertyProvider.listSearchBarCssClass;
|
|
readonly listSearchBarEnterKeyHint =
|
|
this.listPropertyProvider.listSearchBarEnterKeyHint;
|
|
readonly listSearchBarForegroundColor =
|
|
this.listPropertyProvider.listSearchBarForegroundColor;
|
|
readonly listSearchBarKeyboardType =
|
|
this.listPropertyProvider.listSearchBarKeyboardType;
|
|
readonly listActionBarActionFired =
|
|
this.listPropertyProvider.listActionBarActionFired;
|
|
readonly listSearchBarOnEvent =
|
|
this.listPropertyProvider.listSearchBarOnEvent;
|
|
readonly listSearchBarQueryChange =
|
|
this.listPropertyProvider.listSearchBarQueryChange;
|
|
readonly listSearchBarSearchButtonIcon =
|
|
this.listPropertyProvider.listSearchBarSearchButtonIcon;
|
|
readonly listSearchBarSearchButtonIconColor =
|
|
this.listPropertyProvider.listSearchBarSearchButtonIconColor;
|
|
readonly listSearchBarShowCancelButton =
|
|
this.listPropertyProvider.listSearchBarShowCancelButton;
|
|
readonly listSearchBarSpellcheck =
|
|
this.listPropertyProvider.listSearchBarSpellcheck;
|
|
readonly listSearchBarTitle = this.listPropertyProvider.listSearchBarTitle;
|
|
readonly listShowSearchBar = this.listPropertyProvider.listShowSearchBar;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Upload ...
|
|
readonly themeUploadColor = this.fileUploadPropertyProvider.color;
|
|
readonly themeUploadCssClass = this.fileUploadPropertyProvider.cssClass;
|
|
readonly themeUploadEmptyMessage =
|
|
this.fileUploadPropertyProvider.emptyMessage;
|
|
readonly themeUploadForegroundColor =
|
|
this.fileUploadPropertyProvider.foregroundColor;
|
|
readonly themeUploadFileDropAreaIcon =
|
|
this.fileUploadPropertyProvider.fileDropAreaIcon;
|
|
readonly themeUploadShowFileDropArea =
|
|
this.fileUploadPropertyProvider.showFileDropArea;
|
|
readonly themeUploadFileDropAreaColor =
|
|
this.fileUploadPropertyProvider.fileDropAreaColor;
|
|
readonly themeUploadFileDropAreaMessage =
|
|
this.fileUploadPropertyProvider.fileDropAreaMessage;
|
|
readonly themeUploadFileDropAreaCssClass =
|
|
this.fileUploadPropertyProvider.fileDropAreaCssClass;
|
|
readonly themeUploadFileDropAreaErrorColor =
|
|
this.fileUploadPropertyProvider.fileDropAreaErrorColor;
|
|
readonly themeUploadFileDropAreaAccentColor =
|
|
this.fileUploadPropertyProvider.fileDropAreaAccentColor;
|
|
readonly themeUploadFileDropAreaSuccessColor =
|
|
this.fileUploadPropertyProvider.fileDropAreaSuccessColor;
|
|
readonly themeUploadFileDropAreaForegroundColor =
|
|
this.fileUploadPropertyProvider.fileDropAreaForegroundColor;
|
|
readonly themeUploadEmptyForegroundMessageColor =
|
|
this.fileUploadPropertyProvider.emptyForegroundMessageColor;
|
|
readonly themeUploadFileDropAreaSupportsMultipleFiles =
|
|
this.fileUploadPropertyProvider.fileDropAreaSupportsMultipleFiles;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
readonly maxAllowedSize = this.filePropertyProvider.maxAllowedSize;
|
|
readonly minAllowedFileSize = this.filePropertyProvider.minAllowedFileSize;
|
|
readonly maxAllowedFileSize = this.filePropertyProvider.maxAllowedFileSize;
|
|
readonly maxAllowedFiles = this.filePropertyProvider.maxAllowedFiles;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
protected filePropertyProvider: XFileContainer,
|
|
protected cardPropertyProvider: XCardContainer,
|
|
protected listPropertyProvider: XComponentListContainer,
|
|
protected fileUploadPropertyProvider: XFileUploadContainer,
|
|
protected actionBarPropertyProvider: XComponentActionBarContainer
|
|
) {
|
|
super(cardPropertyProvider);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XThemeManagerContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXThemeManagerContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
//#region Self ...
|
|
@Input()
|
|
actionProvider: Subject<XThemeManagerActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
|
|
|
|
//
|
|
@Output()
|
|
themeChange: EventEmitter<boolean> = new EventEmitter();
|
|
|
|
@Output()
|
|
tabChange: EventEmitter<XStandardType<number>> = new EventEmitter();
|
|
|
|
//
|
|
@Input()
|
|
restartAfterSetTheme: XStandardType<boolean> =
|
|
this.propertyProvider.restartAfterSetTheme;
|
|
|
|
@Input()
|
|
colorViewBorderWidth: XStandardType<number> =
|
|
this.propertyProvider.colorViewBorderWidth;
|
|
|
|
@Input()
|
|
colorViewBorderStyle: XStandardType<XBorderStyleIdentifier> =
|
|
this.propertyProvider.colorViewBorderStyle;
|
|
|
|
//
|
|
@Input()
|
|
propertyLabelColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.propertyLabelColor;
|
|
|
|
@Input()
|
|
propertyValueColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.propertyValueColor;
|
|
|
|
@Input()
|
|
colorViewBorderColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.colorViewBorderColor;
|
|
|
|
//
|
|
@Input()
|
|
propertyActionMenuIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.propertyActionMenuIconColor;
|
|
|
|
@Input()
|
|
propertyActionMenuIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.propertyActionMenuIcon;
|
|
|
|
@Input()
|
|
propertyEditIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.propertyEditIconColor;
|
|
|
|
@Input()
|
|
propertyEditIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.propertyEditIcon;
|
|
|
|
@Input()
|
|
propertyClearIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.propertyClearIconColor;
|
|
|
|
@Input()
|
|
propertyClearIcon: XStandardType<XIconIdentifier> =
|
|
this.propertyProvider.propertyClearIcon;
|
|
|
|
@Input()
|
|
emptyPropertyEditIconColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.emptyPropertyEditIconColor;
|
|
|
|
//
|
|
@Input()
|
|
presenterHeaderColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.presenterHeaderColor;
|
|
|
|
@Input()
|
|
presenterContentColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.presenterContentColor;
|
|
|
|
@Input()
|
|
presenterHeaderHighlightColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.presenterHeaderHighlightColor;
|
|
|
|
//
|
|
@Input()
|
|
saveColor: XStandardType<XColorIdentifier> = this.propertyProvider.saveColor;
|
|
|
|
@Input()
|
|
saveLabel: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.saveLabel;
|
|
|
|
//
|
|
@Input()
|
|
resetColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.resetColor;
|
|
|
|
@Input()
|
|
resetLabel: XStandardType<XResourceIdentifier> =
|
|
this.propertyProvider.resetLabel;
|
|
//#endregion
|
|
|
|
//
|
|
//#region ActionBar ...
|
|
@Input()
|
|
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
|
|
|
|
@Input()
|
|
actionBarColor: XStandardType<XColorIdentifier> =
|
|
this.propertyProvider.actionBarColor;
|
|
|
|
@Input()
|
|
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.actionBarCssClass;
|
|
|
|
@Input()
|
|
actionBarForegroundColor: XStandardType<boolean> =
|
|
this.propertyProvider.actionBarForegroundColor;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List ...
|
|
@Input()
|
|
listCssClass = this.propertyProvider.listCssClass;
|
|
|
|
@Input()
|
|
listShowDivider = this.propertyProvider.listShowDivider;
|
|
|
|
//
|
|
//#region List Empty ...
|
|
@Input()
|
|
listShowEmpty = this.propertyProvider.listShowEmpty;
|
|
|
|
@Input()
|
|
listEmptyActionProvider = this.propertyProvider.listEmptyActionProvider;
|
|
|
|
@Input()
|
|
listEmptyColor = this.propertyProvider.listEmptyColor;
|
|
|
|
@Input()
|
|
listEmptyCssClass = this.propertyProvider.listEmptyCssClass;
|
|
|
|
@Input()
|
|
listEmptyForegroundColor = this.propertyProvider.listEmptyForegroundColor;
|
|
|
|
@Input()
|
|
listEmptyForegroundMessageColor =
|
|
this.propertyProvider.listEmptyForegroundMessageColor;
|
|
|
|
@Input()
|
|
listEmptyForegroundRefreshButtonColor =
|
|
this.propertyProvider.listEmptyForegroundRefreshButtonColor;
|
|
|
|
@Input()
|
|
listEmptyHasRefresh = this.propertyProvider.listEmptyHasRefresh;
|
|
|
|
@Input()
|
|
listEmptyMessage = this.propertyProvider.listEmptyMessage;
|
|
|
|
@Input()
|
|
listEmptyMessageColor = this.propertyProvider.listEmptyMessageColor;
|
|
|
|
@Output()
|
|
listEmptyRefresh: EventEmitter<void> = new EventEmitter();
|
|
|
|
@Input()
|
|
listEmptyRefreshButtonColor =
|
|
this.propertyProvider.listEmptyRefreshButtonColor;
|
|
|
|
@Input()
|
|
listEmptyRefreshIcon = this.propertyProvider.listEmptyRefreshIcon;
|
|
//#endregion
|
|
|
|
//
|
|
//#region List Search ...
|
|
@Input()
|
|
listSearchBarValue = this.propertyProvider.listSearchBarValue;
|
|
|
|
@Input()
|
|
listSearchBarColor = this.propertyProvider.listSearchBarColor;
|
|
|
|
@Input()
|
|
listSearchBarDebounce = this.propertyProvider.listSearchBarDebounce;
|
|
|
|
@Input()
|
|
listSearchBarSearchInputColor =
|
|
this.propertyProvider.listSearchBarSearchInputColor;
|
|
|
|
@Input()
|
|
listSearchBarForegroundSearchInputColor =
|
|
this.propertyProvider.listSearchBarForegroundSearchInputColor;
|
|
|
|
@Input()
|
|
listSearchBarCancelButtonIcon =
|
|
this.propertyProvider.listSearchBarCancelButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarCancelButtonTitle =
|
|
this.propertyProvider.listSearchBarCancelButtonTitle;
|
|
|
|
@Input()
|
|
listSearchBarClearButtonIcon =
|
|
this.propertyProvider.listSearchBarClearButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarClearButtonIconColor =
|
|
this.propertyProvider.listSearchBarClearButtonIconColor;
|
|
|
|
@Input()
|
|
listSearchBarCssClass = this.propertyProvider.listSearchBarCssClass;
|
|
|
|
@Input()
|
|
listSearchBarEnterKeyHint = this.propertyProvider.listSearchBarEnterKeyHint;
|
|
|
|
@Input()
|
|
listSearchBarForegroundColor =
|
|
this.propertyProvider.listSearchBarForegroundColor;
|
|
|
|
@Input()
|
|
listSearchBarKeyboardType = this.propertyProvider.listSearchBarKeyboardType;
|
|
|
|
@Output()
|
|
listActionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
|
|
|
|
@Output()
|
|
listSearchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> = new EventEmitter();
|
|
|
|
@Output()
|
|
listSearchBarQueryChange: EventEmitter<string> = new EventEmitter();
|
|
|
|
@Input()
|
|
listSearchBarSearchButtonIcon =
|
|
this.propertyProvider.listSearchBarSearchButtonIcon;
|
|
|
|
@Input()
|
|
listSearchBarSearchButtonIconColor =
|
|
this.propertyProvider.listSearchBarSearchButtonIconColor;
|
|
|
|
@Input()
|
|
listSearchBarShowCancelButton =
|
|
this.propertyProvider.listSearchBarShowCancelButton;
|
|
|
|
@Input()
|
|
listSearchBarSpellcheck = this.propertyProvider.listSearchBarSpellcheck;
|
|
|
|
@Input()
|
|
listSearchBarTitle = this.propertyProvider.listSearchBarTitle;
|
|
|
|
@Input()
|
|
listShowSearchBar = this.propertyProvider.listShowSearchBar;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region File Upload ...
|
|
@Input()
|
|
themeUploadColor = this.propertyProvider.themeUploadColor;
|
|
|
|
@Input()
|
|
themeUploadCssClass = this.propertyProvider.themeUploadCssClass;
|
|
|
|
@Input()
|
|
themeUploadEmptyMessage = this.propertyProvider.themeUploadEmptyMessage;
|
|
|
|
@Input()
|
|
themeUploadForegroundColor = this.propertyProvider.themeUploadForegroundColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaIcon =
|
|
this.propertyProvider.themeUploadFileDropAreaIcon;
|
|
|
|
@Input()
|
|
themeUploadShowFileDropArea =
|
|
this.propertyProvider.themeUploadShowFileDropArea;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaColor =
|
|
this.propertyProvider.themeUploadFileDropAreaColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaMessage =
|
|
this.propertyProvider.themeUploadFileDropAreaMessage;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaCssClass =
|
|
this.propertyProvider.themeUploadFileDropAreaCssClass;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaErrorColor =
|
|
this.propertyProvider.themeUploadFileDropAreaErrorColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaAccentColor =
|
|
this.propertyProvider.themeUploadFileDropAreaAccentColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaSuccessColor =
|
|
this.propertyProvider.themeUploadFileDropAreaSuccessColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaForegroundColor =
|
|
this.propertyProvider.themeUploadFileDropAreaForegroundColor;
|
|
|
|
@Input()
|
|
themeUploadEmptyForegroundMessageColor =
|
|
this.propertyProvider.themeUploadEmptyForegroundMessageColor;
|
|
|
|
@Input()
|
|
themeUploadFileDropAreaSupportsMultipleFiles =
|
|
this.propertyProvider.themeUploadFileDropAreaSupportsMultipleFiles;
|
|
//#endregion
|
|
|
|
//
|
|
//#region File ...
|
|
@Input()
|
|
maxAllowedSize = this.propertyProvider.maxAllowedSize;
|
|
|
|
@Input()
|
|
minAllowedFileSize = this.propertyProvider.minAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFileSize = this.propertyProvider.maxAllowedFileSize;
|
|
|
|
@Input()
|
|
maxAllowedFiles = this.propertyProvider.maxAllowedFiles;
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XThemeManagerContainer,
|
|
public colorPickerDialogService: XColorPickerDialogService
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXThemeManagerContainer
|
|
): Observable<IXThemeManagerContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
restartAfterSetTheme: this.getValue(
|
|
container
|
|
? container.restartAfterSetTheme
|
|
: this.restartAfterSetTheme
|
|
),
|
|
colorViewBorderWidth: this.getValue(
|
|
container
|
|
? container.colorViewBorderWidth
|
|
: this.colorViewBorderWidth
|
|
),
|
|
colorViewBorderStyle: this.getValue(
|
|
container
|
|
? container.colorViewBorderStyle
|
|
: this.colorViewBorderStyle
|
|
),
|
|
|
|
//
|
|
propertyLabelColor: this.getValue(
|
|
container ? container.propertyLabelColor : this.propertyLabelColor
|
|
),
|
|
propertyValueColor: this.getValue(
|
|
container ? container.propertyValueColor : this.propertyValueColor
|
|
),
|
|
colorViewBorderColor: this.getValue(
|
|
container
|
|
? container.colorViewBorderColor
|
|
: this.colorViewBorderColor
|
|
),
|
|
color: this.getValue(container ? container.color : this.color),
|
|
|
|
//
|
|
propertyActionMenuIconColor: this.getValue(
|
|
container
|
|
? container.propertyActionMenuIconColor
|
|
: this.propertyActionMenuIconColor
|
|
),
|
|
propertyActionMenuIcon: this.getValue(
|
|
container
|
|
? container.propertyActionMenuIcon
|
|
: this.propertyActionMenuIcon
|
|
),
|
|
propertyEditIconColor: this.getValue(
|
|
container
|
|
? container.propertyEditIconColor
|
|
: this.propertyEditIconColor
|
|
),
|
|
propertyEditIcon: this.getValue(
|
|
container ? container.propertyEditIcon : this.propertyEditIcon
|
|
),
|
|
propertyClearIconColor: this.getValue(
|
|
container
|
|
? container.propertyClearIconColor
|
|
: this.propertyClearIconColor
|
|
),
|
|
propertyClearIcon: this.getValue(
|
|
container ? container.propertyClearIcon : this.propertyClearIcon
|
|
),
|
|
emptyPropertyEditIconColor: this.getValue(
|
|
container
|
|
? container.emptyPropertyEditIconColor
|
|
: this.emptyPropertyEditIconColor
|
|
),
|
|
|
|
//
|
|
presenterHeaderColor: this.getValue(
|
|
container
|
|
? container.presenterHeaderColor
|
|
: this.presenterHeaderColor
|
|
),
|
|
presenterContentColor: this.getValue(
|
|
container
|
|
? container.presenterContentColor
|
|
: this.presenterContentColor
|
|
),
|
|
presenterHeaderHighlightColor: this.getValue(
|
|
container
|
|
? container.presenterHeaderHighlightColor
|
|
: this.presenterHeaderHighlightColor
|
|
),
|
|
|
|
//
|
|
saveColor: this.getValue(
|
|
container ? container.saveColor : this.saveColor
|
|
),
|
|
saveLabel: this.getValue(
|
|
container ? container.saveLabel : this.saveLabel
|
|
),
|
|
|
|
//
|
|
resetColor: this.getValue(
|
|
container ? container.resetColor : this.resetColor
|
|
),
|
|
resetLabel: this.getValue(
|
|
container ? container.resetLabel : this.resetLabel
|
|
),
|
|
|
|
//
|
|
showActionBar: this.getValue(
|
|
container ? container.showActionBar : this.showActionBar
|
|
),
|
|
actionBarColor: this.getValue(
|
|
container ? container.actionBarColor : this.actionBarColor
|
|
),
|
|
actionBarCssClass: this.getValue(
|
|
container ? container.actionBarCssClass : this.actionBarCssClass
|
|
),
|
|
actionBarForegroundColor: this.getValue(
|
|
container
|
|
? container.actionBarForegroundColor
|
|
: this.actionBarForegroundColor
|
|
),
|
|
|
|
//
|
|
listCssClass: this.getValue(
|
|
container ? container.listCssClass : this.listCssClass
|
|
),
|
|
listShowDivider: this.getValue(
|
|
container ? container.listShowDivider : this.listShowDivider
|
|
),
|
|
|
|
//
|
|
listShowEmpty: this.getValue(
|
|
container ? container.listShowEmpty : this.listShowEmpty
|
|
),
|
|
listEmptyColor: this.getValue(
|
|
container ? container.listEmptyColor : this.listEmptyColor
|
|
),
|
|
listEmptyCssClass: this.getValue(
|
|
container ? container.listEmptyCssClass : this.listEmptyCssClass
|
|
),
|
|
listEmptyForegroundColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundColor
|
|
: this.listEmptyForegroundColor
|
|
),
|
|
listEmptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundMessageColor
|
|
: this.listEmptyForegroundMessageColor
|
|
),
|
|
listEmptyForegroundRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.listEmptyForegroundRefreshButtonColor
|
|
: this.listEmptyForegroundRefreshButtonColor
|
|
),
|
|
listEmptyHasRefresh: this.getValue(
|
|
container
|
|
? container.listEmptyHasRefresh
|
|
: this.listEmptyHasRefresh
|
|
),
|
|
listEmptyMessage: this.getValue(
|
|
container ? container.listEmptyMessage : this.listEmptyMessage
|
|
),
|
|
listEmptyMessageColor: this.getValue(
|
|
container
|
|
? container.listEmptyMessageColor
|
|
: this.listEmptyMessageColor
|
|
),
|
|
listEmptyRefreshButtonColor: this.getValue(
|
|
container
|
|
? container.listEmptyRefreshButtonColor
|
|
: this.listEmptyRefreshButtonColor
|
|
),
|
|
listEmptyRefreshIcon: this.getValue(
|
|
container
|
|
? container.listEmptyRefreshIcon
|
|
: this.listEmptyRefreshIcon
|
|
),
|
|
|
|
//
|
|
listSearchBarValue: this.getValue(
|
|
container ? container.listSearchBarValue : this.listSearchBarValue
|
|
),
|
|
listSearchBarColor: this.getValue(
|
|
container ? container.listSearchBarColor : this.listSearchBarColor
|
|
),
|
|
listSearchBarDebounce: this.getValue(
|
|
container
|
|
? container.listSearchBarDebounce
|
|
: this.listSearchBarDebounce
|
|
),
|
|
listSearchBarSearchInputColor: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchInputColor
|
|
: this.listSearchBarSearchInputColor
|
|
),
|
|
listSearchBarForegroundSearchInputColor: this.getValue(
|
|
container
|
|
? container.listSearchBarForegroundSearchInputColor
|
|
: this.listSearchBarForegroundSearchInputColor
|
|
),
|
|
listSearchBarCancelButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarCancelButtonIcon
|
|
: this.listSearchBarCancelButtonIcon
|
|
),
|
|
listSearchBarCancelButtonTitle: this.getValue(
|
|
container
|
|
? container.listSearchBarCancelButtonTitle
|
|
: this.listSearchBarCancelButtonTitle
|
|
),
|
|
listSearchBarClearButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarClearButtonIcon
|
|
: this.listSearchBarClearButtonIcon
|
|
),
|
|
listSearchBarClearButtonIconColor: this.getValue(
|
|
container
|
|
? container.listSearchBarClearButtonIconColor
|
|
: this.listSearchBarClearButtonIconColor
|
|
),
|
|
listSearchBarCssClass: this.getValue(
|
|
container
|
|
? container.listSearchBarCssClass
|
|
: this.listSearchBarCssClass
|
|
),
|
|
listSearchBarEnterKeyHint: this.getValue(
|
|
container
|
|
? container.listSearchBarEnterKeyHint
|
|
: this.listSearchBarEnterKeyHint
|
|
),
|
|
listSearchBarForegroundColor: this.getValue(
|
|
container
|
|
? container.listSearchBarForegroundColor
|
|
: this.listSearchBarForegroundColor
|
|
),
|
|
listSearchBarKeyboardType: this.getValue(
|
|
container
|
|
? container.listSearchBarKeyboardType
|
|
: this.listSearchBarKeyboardType
|
|
),
|
|
listSearchBarSearchButtonIcon: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchButtonIcon
|
|
: this.listSearchBarSearchButtonIcon
|
|
),
|
|
listSearchBarSearchButtonIconColor: this.getValue(
|
|
container
|
|
? container.listSearchBarSearchButtonIconColor
|
|
: this.listSearchBarSearchButtonIconColor
|
|
),
|
|
listSearchBarShowCancelButton: this.getValue(
|
|
container
|
|
? container.listSearchBarShowCancelButton
|
|
: this.listSearchBarShowCancelButton
|
|
),
|
|
listSearchBarSpellcheck: this.getValue(
|
|
container
|
|
? container.listSearchBarSpellcheck
|
|
: this.listSearchBarSpellcheck
|
|
),
|
|
listSearchBarTitle: this.getValue(
|
|
container ? container.listSearchBarTitle : this.listSearchBarTitle
|
|
),
|
|
listShowSearchBar: this.getValue(
|
|
container ? container.listShowSearchBar : this.listShowSearchBar
|
|
),
|
|
|
|
//
|
|
themeUploadColor: this.getValue(
|
|
container ? container.themeUploadColor : this.themeUploadColor
|
|
),
|
|
themeUploadCssClass: this.getValue(
|
|
container
|
|
? container.themeUploadCssClass
|
|
: this.themeUploadCssClass
|
|
),
|
|
themeUploadEmptyMessage: this.getValue(
|
|
container
|
|
? container.themeUploadEmptyMessage
|
|
: this.themeUploadEmptyMessage
|
|
),
|
|
themeUploadForegroundColor: this.getValue(
|
|
container
|
|
? container.themeUploadForegroundColor
|
|
: this.themeUploadForegroundColor
|
|
),
|
|
themeUploadFileDropAreaIcon: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaIcon
|
|
: this.themeUploadFileDropAreaIcon
|
|
),
|
|
themeUploadShowFileDropArea: this.getValue(
|
|
container
|
|
? container.themeUploadShowFileDropArea
|
|
: this.themeUploadShowFileDropArea
|
|
),
|
|
themeUploadFileDropAreaColor: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaColor
|
|
: this.themeUploadFileDropAreaColor
|
|
),
|
|
themeUploadFileDropAreaMessage: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaMessage
|
|
: this.themeUploadFileDropAreaMessage
|
|
),
|
|
themeUploadFileDropAreaCssClass: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaCssClass
|
|
: this.themeUploadFileDropAreaCssClass
|
|
),
|
|
themeUploadFileDropAreaErrorColor: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaErrorColor
|
|
: this.themeUploadFileDropAreaErrorColor
|
|
),
|
|
themeUploadFileDropAreaAccentColor: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaAccentColor
|
|
: this.themeUploadFileDropAreaAccentColor
|
|
),
|
|
themeUploadFileDropAreaSuccessColor: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaSuccessColor
|
|
: this.themeUploadFileDropAreaSuccessColor
|
|
),
|
|
themeUploadFileDropAreaForegroundColor: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaForegroundColor
|
|
: this.themeUploadFileDropAreaForegroundColor
|
|
),
|
|
themeUploadEmptyForegroundMessageColor: this.getValue(
|
|
container
|
|
? container.themeUploadEmptyForegroundMessageColor
|
|
: this.themeUploadEmptyForegroundMessageColor
|
|
),
|
|
themeUploadFileDropAreaSupportsMultipleFiles: this.getValue(
|
|
container
|
|
? container.themeUploadFileDropAreaSupportsMultipleFiles
|
|
: this.themeUploadFileDropAreaSupportsMultipleFiles
|
|
),
|
|
|
|
//
|
|
maxAllowedSize: this.getValue(
|
|
container ? container.maxAllowedSize : this.maxAllowedSize
|
|
),
|
|
minAllowedFileSize: this.getValue(
|
|
container ? container.minAllowedFileSize : this.minAllowedFileSize
|
|
),
|
|
maxAllowedFileSize: this.getValue(
|
|
container ? container.maxAllowedFileSize : this.maxAllowedFileSize
|
|
),
|
|
maxAllowedFiles: this.getValue(
|
|
container ? container.maxAllowedFiles : this.maxAllowedFiles
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
themeChange: this.themeChange,
|
|
tabChange: this.tabChange,
|
|
|
|
//
|
|
listEmptyActionProvider: container
|
|
? container.listEmptyActionProvider
|
|
: this.listEmptyActionProvider,
|
|
|
|
//
|
|
listEmptyRefresh: this.listEmptyRefresh,
|
|
|
|
//
|
|
listActionBarActionFired: this.listActionBarActionFired,
|
|
listSearchBarOnEvent: this.listSearchBarOnEvent,
|
|
listSearchBarQueryChange: this.listSearchBarQueryChange,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
function XStandardType<T>() {
|
|
throw new Error('Function not implemented.');
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.html
|
|
|
|
<div
|
|
(click)="handleClicked()"
|
|
class="x-thumbnail x-wrapper"
|
|
*ngIf="preparedIdentifier"
|
|
[class.mobile]="isMobileUi$ | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
>
|
|
<ion-thumbnail
|
|
*ngIf="preparedIdentifier"
|
|
class="x-thumbnail push-auto"
|
|
[class.circular]="getValue(circular) | async"
|
|
[class.ion-activatable]="
|
|
(getValue(selectable) | async) || (getValue(clickable) | async)
|
|
"
|
|
>
|
|
<!-- Ripple Effect -->
|
|
<ion-ripple-effect
|
|
*ngIf="!(getValue(uiDisabled) | async)"
|
|
></ion-ripple-effect>
|
|
|
|
<!-- General Type -->
|
|
<ng-container *ngIf="isTypeGeneral() | async">
|
|
<ng-container *ngTemplateOutlet="generalRef"></ng-container>
|
|
</ng-container>
|
|
|
|
<!-- Custom Type -->
|
|
<ng-container *ngIf="isTypeCustom() | async">
|
|
<ng-container *ngTemplateOutlet="customRef"></ng-container>
|
|
</ng-container>
|
|
</ion-thumbnail>
|
|
</div>
|
|
|
|
<!-- General Ref -->
|
|
<ng-template #generalRef>
|
|
<x-icon
|
|
class="x-item"
|
|
[name]="getGThumbnail(preparedIdentifier) | async"
|
|
></x-icon>
|
|
</ng-template>
|
|
|
|
<!-- By Url Ref -->
|
|
<ng-template #byUrlRef>
|
|
<img class="x-item" [src]="preparedIdentifier" />
|
|
</ng-template>
|
|
|
|
<!-- Image Type Ref -->
|
|
<ng-template #imageTypeRef>
|
|
<img
|
|
#thumbImage
|
|
class="x-item"
|
|
[xFileReader]="preparedIdentifier"
|
|
(onFileReaderFinish)="thumbImage.src = $event"
|
|
/>
|
|
</ng-template>
|
|
|
|
<!-- Custom Ref -->
|
|
<ng-template #customRef>
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
(isUrlIdentifier() | async)
|
|
? byUrlRef
|
|
: (isImageTypeIdentifier() | async)
|
|
? imageTypeRef
|
|
: generalRef
|
|
"
|
|
>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.scss
|
|
|
|
:host {
|
|
--thumbnail-size: 32px;
|
|
}
|
|
|
|
x-icon {
|
|
--size: var(--thumbnail-size, 32px);
|
|
color: inherit;
|
|
}
|
|
|
|
.x-item,
|
|
.x-wrapper,
|
|
ion-thumbnail {
|
|
//
|
|
width: var(--thumbnail-size, 32px);
|
|
min-width: var(--thumbnail-size, 32px);
|
|
|
|
//
|
|
height: var(--thumbnail-size, 32px);
|
|
min-height: var(--thumbnail-size, 32px);
|
|
|
|
//
|
|
color: inherit;
|
|
}
|
|
|
|
ion-thumbnail.circular {
|
|
--border-radius: 50%;
|
|
}
|
|
|
|
.x-thumbnail {
|
|
//
|
|
display: inline-block;
|
|
position: relative;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.ts
|
|
|
|
import {
|
|
nameof,
|
|
isString,
|
|
XFileType,
|
|
getFileType,
|
|
XGeneralThumbnails,
|
|
getGeneralThumbnail,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XThumbnailType,
|
|
XThumbnailAction,
|
|
XThumbnailInputType,
|
|
XThumbnailActionModel,
|
|
XThumbnailContainerComponent,
|
|
} from './x-thumbnail.typings';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { XIconNames } from '../x-icon/x-icon.typings';
|
|
import { map, filter, concatMap } from 'rxjs/operators';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-thumbnail',
|
|
templateUrl: './x-thumbnail.component.html',
|
|
styleUrls: ['./x-thumbnail.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XThumbnailComponent extends XThumbnailContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
private PREPARED_IDENTIFIER: XThumbnailInputType;
|
|
|
|
get preparedIdentifier() {
|
|
return this.PREPARED_IDENTIFIER;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XThumbnailComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Identifier Changed ...
|
|
const isIdentifierChanged = changeKeys.includes(
|
|
nameof<XThumbnailComponent>('identifier')
|
|
);
|
|
if (isIdentifierChanged) {
|
|
await this.prepareIdentifier();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
//
|
|
//#region Type Providers ...
|
|
isTypeGeneral() {
|
|
return this.getValue(this.type).pipe(
|
|
map(
|
|
(type) =>
|
|
type === XThumbnailType.GENERAL || type !== XThumbnailType.CUSTOM
|
|
)
|
|
);
|
|
}
|
|
|
|
isTypeCustom() {
|
|
return this.getValue(this.type).pipe(
|
|
map((type) => type === XThumbnailType.CUSTOM)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
isUrlIdentifier() {
|
|
//
|
|
// && isValidURL(identifier as string)
|
|
return this.getIdentifier().pipe(map((identifier) => isString(identifier)));
|
|
}
|
|
|
|
isImageTypeIdentifier() {
|
|
return this.isUrlIdentifier().pipe(
|
|
filter((isUrl) => !isUrl),
|
|
concatMap(() => this.getIdentifier()),
|
|
map((identifier) => {
|
|
//
|
|
const type = getFileType(identifier);
|
|
return [
|
|
XFileType.CoverImage,
|
|
XFileType.Image,
|
|
XFileType.ProfileImage,
|
|
].includes(type);
|
|
})
|
|
);
|
|
}
|
|
|
|
getGThumbnail(identifier: XThumbnailInputType) {
|
|
return this.getValue(getGeneralThumbnail(identifier)).pipe(
|
|
map((type) => {
|
|
switch (type) {
|
|
//
|
|
case XGeneralThumbnails.IMAGE:
|
|
return XIconNames.image;
|
|
|
|
//
|
|
case XGeneralThumbnails.AUDIO:
|
|
return XIconNames.audio;
|
|
|
|
//
|
|
case XGeneralThumbnails.VIDEO:
|
|
return XIconNames.video;
|
|
|
|
//
|
|
case XGeneralThumbnails.DOCUMENT:
|
|
default:
|
|
return XIconNames.document;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
async handleClicked() {
|
|
//
|
|
if (this.uiDisabled || this.loading) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const isClickable = await this.getValueAsync(this.clickable);
|
|
if (isClickable) {
|
|
this.clicked.emit();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XThumbnailActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XThumbnailAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
private getIdentifier() {
|
|
return this.getValue(this.identifier);
|
|
}
|
|
|
|
private async prepareIdentifier() {
|
|
//
|
|
const identifier = await this.getValueAsync(this.identifier);
|
|
this.PREPARED_IDENTIFIER = identifier;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XThumbnailComponent } from './x-thumbnail.component';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XThumbnailComponent],
|
|
imports: [CommonModule, XIconModule, XBaseComponentModule],
|
|
exports: [XIconModule, XBaseComponentModule, XThumbnailComponent],
|
|
})
|
|
export class XThumbnailModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Output,
|
|
Inject,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import { map } from 'rxjs/operators';
|
|
import {
|
|
XBaseContainer,
|
|
IXBaseContainer,
|
|
XBaseContainerComponent,
|
|
} from '../classes/i-x-base.container';
|
|
import { Subject, forkJoin, Observable } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { XFileBlob, XOneOrManyType, XStandardType } from 'x-framework-core';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export enum XThumbnailType {
|
|
GENERAL = 'general',
|
|
CUSTOM = 'custom',
|
|
}
|
|
|
|
export type XThumbnailTypeIdentifier = XThumbnailType | string;
|
|
|
|
export type XThumbnailInputType = File | Blob | XFileBlob | string;
|
|
|
|
export enum XThumbnailAction {
|
|
Refresh = 'refresh',
|
|
}
|
|
|
|
export type XThumbnailActionIdentifier = XThumbnailAction | string;
|
|
|
|
export interface XThumbnailActionModel
|
|
extends XBaseActionModel<XThumbnailActionIdentifier> {}
|
|
|
|
//
|
|
//#region Container ...
|
|
export interface IXThumbnailContainer extends IXBaseContainer {
|
|
//
|
|
actionProvider: Subject<XThumbnailActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
circular: XStandardType<boolean>;
|
|
clickable: XStandardType<boolean>;
|
|
selectable: XStandardType<boolean>;
|
|
type: XStandardType<XThumbnailTypeIdentifier>;
|
|
identifier: XStandardType<XThumbnailInputType>;
|
|
|
|
//
|
|
clicked: EventEmitter<void>;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XThumbnailContainer
|
|
extends XBaseContainer
|
|
implements Readonly<IXThumbnailContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XThumbnailActionModel> =
|
|
new Subject<XThumbnailActionModel>();
|
|
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly circular: XStandardType<boolean> = false;
|
|
|
|
readonly clickable: XStandardType<boolean> = false;
|
|
|
|
readonly selectable: XStandardType<boolean> = false;
|
|
|
|
readonly type: XStandardType<XThumbnailTypeIdentifier> = XThumbnailType.GENERAL;
|
|
|
|
readonly identifier: XStandardType<XThumbnailInputType>;
|
|
|
|
//
|
|
readonly clicked: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XThumbnailContainerComponent
|
|
extends XBaseContainerComponent
|
|
implements IXThumbnailContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
actionProvider: Subject<XThumbnailActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
@Input()
|
|
circular: XStandardType<boolean> = this.propertyProvider.circular;
|
|
|
|
@Input()
|
|
clickable: XStandardType<boolean> = this.propertyProvider.clickable;
|
|
|
|
@Input()
|
|
selectable: XStandardType<boolean> = this.propertyProvider.selectable;
|
|
|
|
@Input()
|
|
type: XStandardType<XThumbnailTypeIdentifier> = this.propertyProvider.type;
|
|
|
|
@Input()
|
|
identifier: XStandardType<XThumbnailInputType> =
|
|
this.propertyProvider.identifier;
|
|
|
|
@Output()
|
|
clicked: EventEmitter<void> = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XThumbnailContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXThumbnailContainer
|
|
): Observable<IXThumbnailContainer> {
|
|
return forkJoin({
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
circular: this.getValue(container ? container.circular : this.circular),
|
|
clickable: this.getValue(
|
|
container ? container.clickable : this.clickable
|
|
),
|
|
selectable: this.getValue(
|
|
container ? container.selectable : this.selectable
|
|
),
|
|
type: this.getValue(container ? container.type : this.type),
|
|
identifier: this.getValue(
|
|
container ? container.identifier : this.identifier
|
|
),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
//
|
|
...data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
clicked: this.clicked,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.html
|
|
|
|
<!-- Component Template -->
|
|
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
|
|
<x-card
|
|
class="x-card"
|
|
[showActions]="true"
|
|
[color]="getValue(cardColor) | async"
|
|
[ngClass]="getValue(cssClass) | async"
|
|
[isInPage]="getValue(isInPage) | async"
|
|
[showHeader]="
|
|
(notEmptyValue(cardTitle) | async) ||
|
|
(notEmptyValue(cardSubTitle) | async)
|
|
"
|
|
[subTitle]="getResourceValue(cardSubTitle)"
|
|
[title]="getResourceValue(cardTitle) | async"
|
|
[showFooter]="getValue(cardShowFooter) | async"
|
|
[showActions]="getValue(cardShowActions) | async"
|
|
[foregroundColor]="getValue(cardForegroundColor) | async"
|
|
>
|
|
<!-- Content -->
|
|
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
|
|
|
|
<!-- Footer -->
|
|
<div footer *ngIf="getValue(cardShowFooter) | async">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</x-card>
|
|
</ng-container>
|
|
|
|
<!-- Component Template -->
|
|
<ng-template #componentRef>
|
|
<ng-container
|
|
*ngIf="
|
|
(notNullOrUndefinedValue(treeControl) | async) &&
|
|
(notNullOrUndefinedValue(treeFlattener) | async) &&
|
|
(notNullOrUndefinedValue(dataSource) | async) &&
|
|
(hasChildValue(nodes) | async) &&
|
|
(hasChildValue(dataSource.data) | async)
|
|
"
|
|
>
|
|
<!-- Tree -->
|
|
<mat-tree
|
|
class="x-tree"
|
|
[dataSource]="dataSource"
|
|
[treeControl]="treeControl"
|
|
>
|
|
<!-- This is the tree node template for leaf nodes -->
|
|
<mat-tree-node
|
|
matTreeNodePadding
|
|
*matTreeNodeDef="let node"
|
|
[ngClass]="getNodeClassNames(node) | async"
|
|
>
|
|
<!-- Toggler Button -->
|
|
<button mat-icon-button disabled></button>
|
|
|
|
<!-- Body -->
|
|
<div class="x-tree-node-container">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nodeTemplate;
|
|
context: { $implicit: node.data, nodeId: node.id }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</mat-tree-node>
|
|
|
|
<!-- This is the tree node template for expandable nodes -->
|
|
<mat-tree-node
|
|
matTreeNodePadding
|
|
[ngClass]="getNodeClassNames(node) | async"
|
|
*matTreeNodeDef="let node; when: nodeHasChild"
|
|
>
|
|
<!-- Toggler Button -->
|
|
<button
|
|
mat-icon-button
|
|
matTreeNodeToggle
|
|
[disabled]="loading || uiDisabled"
|
|
[matTooltipDisabled]="loading || uiDisabled"
|
|
[matTooltip]="getResourceValue(node.tooltip) | async"
|
|
(click)="handleTreeNodeToggle(node.id, treeControl.isExpanded(node))"
|
|
>
|
|
<!-- Icon Button -->
|
|
<mat-icon
|
|
class="mat-icon-rtl-mirror"
|
|
[xColor]="getValue(toggleIconColor) | async"
|
|
[isForeground]="getValue(isForegroundToggleColor) | async"
|
|
>
|
|
{{ treeControl.isExpanded(node) ? "expand_more" : "chevron_right" }}
|
|
</mat-icon>
|
|
</button>
|
|
|
|
<!-- Body -->
|
|
<div class="x-tree-node-container">
|
|
<ng-container
|
|
*ngTemplateOutlet="
|
|
nodeTemplate;
|
|
context: { $implicit: node.data, nodeId: node.id }
|
|
"
|
|
></ng-container>
|
|
</div>
|
|
</mat-tree-node>
|
|
</mat-tree>
|
|
</ng-container>
|
|
</ng-template>
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.scss
|
|
|
|
:host(::ng-deep.mat-tree) {
|
|
background-color: unset !important;
|
|
}
|
|
|
|
:host(::ng-deep.mat-tree-node) {
|
|
align-items: baseline !important;
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.ts
|
|
|
|
import {
|
|
XTreeNode,
|
|
XTreeAction,
|
|
XTreeFlatNode,
|
|
XTreeActionModel,
|
|
XTreeContainerComponent,
|
|
} from './x-tree.typings';
|
|
import {
|
|
nameof,
|
|
toArray,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
MatTreeFlattener,
|
|
MatTreeFlatDataSource,
|
|
} from '@angular/material/tree';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { FlatTreeControl } from '@angular/cdk/tree';
|
|
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
|
|
@Component({
|
|
// tslint:disable-next-line:component-selector
|
|
selector: 'x-tree',
|
|
templateUrl: './x-tree.component.html',
|
|
styleUrls: ['./x-tree.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class XTreeComponent extends XTreeContainerComponent {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
|
|
|
|
//
|
|
treeControl: FlatTreeControl<XTreeFlatNode, XTreeFlatNode> = null;
|
|
|
|
//
|
|
treeFlattener: MatTreeFlattener<
|
|
XTreeNode<any>,
|
|
XTreeFlatNode,
|
|
XTreeFlatNode
|
|
> = null;
|
|
|
|
//
|
|
dataSource: MatTreeFlatDataSource<
|
|
XTreeNode<any>,
|
|
XTreeFlatNode,
|
|
XTreeFlatNode
|
|
> = null;
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
async onChange(changeKeys: string[]) {
|
|
super.onChange(changeKeys);
|
|
|
|
//
|
|
//#region ActionProvider Changed ...
|
|
const isActionProviderChanged = changeKeys.includes(
|
|
nameof<XTreeComponent>('actionProvider')
|
|
);
|
|
if (isActionProviderChanged) {
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Nodes Changes ...
|
|
const isNodesChanged = changeKeys.includes(nameof<XTreeComponent>('nodes'));
|
|
if (isNodesChanged) {
|
|
await this.prepareDataSource();
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
onDestroy() {
|
|
super.onDestroy();
|
|
|
|
//
|
|
this.unregisterActionProvider();
|
|
}
|
|
|
|
registerViewHandlers() {
|
|
super.registerViewHandlers();
|
|
|
|
//
|
|
this.registerActionProvider();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Register Handlers ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Providers ...
|
|
getNodeClassNames(node: XTreeFlatNode<any>) {
|
|
//
|
|
const result = ['x-tree-node', `x-tree-node-level-${node.level}`];
|
|
|
|
//
|
|
if (node.expandable) {
|
|
result.push('x-tree-expandable-node');
|
|
}
|
|
|
|
//
|
|
if (!isNullOrEmptyString(node.id)) {
|
|
result.push(`x-tree-node-id-${node.id}`);
|
|
result.push(`x-tree-node-id-${node.id}-level-${node.level}`);
|
|
}
|
|
|
|
//
|
|
return this.getArrayValue(result);
|
|
}
|
|
|
|
nodeHasChild = (_: number, node: XTreeFlatNode) => node.expandable;
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Handlers ...
|
|
handleTreeNodeToggle(id: string, isExpanded: boolean) {
|
|
//
|
|
if (isNullOrEmptyString(id)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.onNodeToggle.emit({
|
|
id,
|
|
isExpanded,
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region ActionProvider ...
|
|
private registerActionProvider() {
|
|
//
|
|
this.unregisterActionProvider();
|
|
|
|
//
|
|
if (!this.actionProvider) {
|
|
this.actionProvider = new Subject<XTreeActionModel>();
|
|
}
|
|
|
|
//
|
|
// Handle Action Provider ...
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider
|
|
.asObservable()
|
|
.subscribe(async (model) => {
|
|
//
|
|
if (!model) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
switch (model.action) {
|
|
//
|
|
case XTreeAction.Refresh:
|
|
this.detectChanges();
|
|
break;
|
|
|
|
//
|
|
case XTreeAction.Expand:
|
|
//
|
|
if (this.treeControl) {
|
|
//
|
|
// Get Tree Node ...
|
|
if (model.payload) {
|
|
//
|
|
const id = model.payload.toString();
|
|
if (!isNullOrEmptyString(id)) {
|
|
//
|
|
const node = this.treeControl.dataNodes.find(
|
|
(d) => d.id === id
|
|
);
|
|
if (!isNullOrUndefined(node)) {
|
|
this.treeControl.expand(node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XTreeAction.Collapse:
|
|
//
|
|
if (this.treeControl) {
|
|
//
|
|
// Get Tree Node ...
|
|
if (model.payload) {
|
|
//
|
|
const id = model.payload.toString();
|
|
if (!isNullOrEmptyString(id)) {
|
|
//
|
|
const node = this.treeControl.dataNodes.find(
|
|
(d) => d.id === id
|
|
);
|
|
if (!isNullOrUndefined(node)) {
|
|
this.treeControl.collapse(node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XTreeAction.ExpandAll:
|
|
//
|
|
if (this.treeControl) {
|
|
this.treeControl.expandAll();
|
|
}
|
|
break;
|
|
|
|
//
|
|
case XTreeAction.CollapseAll:
|
|
//
|
|
if (this.treeControl) {
|
|
this.treeControl.collapseAll();
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
private unregisterActionProvider() {
|
|
//
|
|
if (!this.ACTION_PROVIDER_SUBSCRIPTION) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe();
|
|
this.ACTION_PROVIDER_SUBSCRIPTION = null;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tree ...
|
|
async prepareDataSource() {
|
|
//
|
|
this.treeControl = null;
|
|
this.treeFlattener = null;
|
|
this.dataSource = null;
|
|
|
|
//
|
|
const nodes = await this.getArrayValueAsync(this.nodes);
|
|
if (!this.hasChild(nodes)) {
|
|
this.detectChanges();
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.treeControl = new FlatTreeControl<XTreeFlatNode>(
|
|
(node) => node.level,
|
|
(node) => node.expandable
|
|
);
|
|
|
|
//
|
|
this.treeFlattener = new MatTreeFlattener(
|
|
(node: XTreeNode<any>, level: number) => {
|
|
return {
|
|
id: node.id,
|
|
level: level,
|
|
data: node.data,
|
|
tooltip: node.tooltip,
|
|
expandable: this.hasChild(node.childs),
|
|
} as XTreeFlatNode;
|
|
},
|
|
(node) => node.level,
|
|
(node) => node.expandable,
|
|
(node) => toArray(node.childs)
|
|
);
|
|
|
|
//
|
|
this.dataSource = new MatTreeFlatDataSource(
|
|
this.treeControl,
|
|
this.treeFlattener
|
|
);
|
|
this.dataSource.data = nodes;
|
|
|
|
//
|
|
this.detectChanges();
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XTreeComponent } from './x-tree.component';
|
|
import { XCardModule } from '../x-card/x-card.module';
|
|
import { XIconModule } from '../x-icon/x-icon.module';
|
|
import { XBaseComponentModule } from '../modules/x-base-component.module';
|
|
|
|
@NgModule({
|
|
declarations: [XTreeComponent],
|
|
imports: [CommonModule, XCardModule, XIconModule, XBaseComponentModule],
|
|
exports: [XIconModule, XCardModule, XBaseComponentModule, XTreeComponent],
|
|
})
|
|
export class XTreeModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.typings.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
Output,
|
|
NgZone,
|
|
Component,
|
|
Renderer2,
|
|
ElementRef,
|
|
Injectable,
|
|
TemplateRef,
|
|
EventEmitter,
|
|
ChangeDetectorRef,
|
|
} from '@angular/core';
|
|
import {
|
|
XStandardType,
|
|
XOneOrManyType,
|
|
XColorIdentifier,
|
|
XResourceIdentifier,
|
|
XColorWithBrightness,
|
|
} from 'x-framework-core';
|
|
import {
|
|
XComponentCardContainer,
|
|
IXComponentCardContainer,
|
|
XComponentCardContainerComponent,
|
|
} from '../x-card/x-card.typings';
|
|
import { concatMap, map } from 'rxjs/operators';
|
|
import { Observable, Subject, forkJoin } from 'rxjs';
|
|
import { ViewportRuler } from '@angular/cdk/overlay';
|
|
import { XManagerService } from 'x-framework-services';
|
|
import { XBaseActionModel } from '../classes/x-base-action.model';
|
|
import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkComponentsConfig } from '../config/x-framework-components.config';
|
|
|
|
export interface XTreeNodeToggle {
|
|
id: string;
|
|
isExpanded: boolean;
|
|
}
|
|
|
|
export interface XTreeNode<T = any> {
|
|
id: string;
|
|
data: T;
|
|
childs?: XOneOrManyType<XTreeNode<T>>;
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
export interface XTreeFlatNode<T = any> {
|
|
id: string;
|
|
level: number;
|
|
data: XTreeNode<T>;
|
|
expandable: boolean;
|
|
tooltip?: XStandardType<XResourceIdentifier>;
|
|
}
|
|
|
|
export enum XTreeAction {
|
|
//
|
|
Refresh = 'refresh',
|
|
|
|
//
|
|
Expand = 'expand',
|
|
Collapse = 'collapse',
|
|
|
|
//
|
|
ExpandAll = 'expand-all',
|
|
CollapseAll = 'collapse-all',
|
|
}
|
|
|
|
export type XTreeActionIdentifier = XTreeAction | string;
|
|
|
|
export interface XTreeActionModel
|
|
extends XBaseActionModel<XTreeActionIdentifier> {}
|
|
|
|
//
|
|
//#region Component Container Typings ...
|
|
export interface IXTreeContainer extends IXComponentCardContainer {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
actionProvider: Subject<XTreeActionModel>;
|
|
cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
isForegroundToggleColor: XStandardType<boolean>;
|
|
toggleIconColor: XStandardType<XColorIdentifier>;
|
|
|
|
//
|
|
nodes: XStandardType<XOneOrManyType<XTreeNode<any>>>;
|
|
|
|
//
|
|
nodeTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
onNodeToggle: EventEmitter<XTreeNodeToggle>;
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XTreeContainer
|
|
extends XComponentCardContainer
|
|
implements Readonly<IXTreeContainer>
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
readonly actionProvider: Subject<XTreeActionModel>;
|
|
readonly cssClass: XStandardType<XOneOrManyType<string>>;
|
|
|
|
//
|
|
readonly isForegroundToggleColor: XStandardType<boolean> = true;
|
|
readonly toggleIconColor: XStandardType<XColorIdentifier> =
|
|
XColorWithBrightness.Dark;
|
|
|
|
//
|
|
readonly nodes: XStandardType<XOneOrManyType<XTreeNode<any>>>;
|
|
|
|
//
|
|
readonly nodeTemplate: TemplateRef<any>;
|
|
|
|
//
|
|
readonly onNodeToggle = new EventEmitter<XTreeNodeToggle>();
|
|
//#endregion
|
|
}
|
|
|
|
@Injectable()
|
|
@Component({
|
|
template: ``,
|
|
})
|
|
export abstract class XTreeContainerComponent
|
|
extends XComponentCardContainerComponent
|
|
implements IXTreeContainer
|
|
{
|
|
//
|
|
//#region Props ...
|
|
//
|
|
@Input()
|
|
actionProvider: Subject<XTreeActionModel> =
|
|
this.propertyProvider.actionProvider;
|
|
|
|
//
|
|
@Input()
|
|
cssClass: XStandardType<XOneOrManyType<string>> =
|
|
this.propertyProvider.cssClass;
|
|
|
|
//
|
|
@Input()
|
|
toggleIconColor: XStandardType<string> =
|
|
this.propertyProvider.toggleIconColor;
|
|
|
|
//
|
|
@Input()
|
|
isForegroundToggleColor: XStandardType<boolean> =
|
|
this.propertyProvider.isForegroundToggleColor;
|
|
|
|
//
|
|
@Input()
|
|
nodes: XStandardType<XOneOrManyType<XTreeNode<any>>> =
|
|
this.propertyProvider.nodes;
|
|
|
|
//
|
|
@Input()
|
|
nodeTemplate: TemplateRef<any> = this.propertyProvider.nodeTemplate;
|
|
|
|
//
|
|
@Output()
|
|
onNodeToggle = new EventEmitter<XTreeNodeToggle>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
public constructor(
|
|
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
|
|
public config: XFrameworkComponentsConfig,
|
|
public managerService: XManagerService,
|
|
public element: ElementRef,
|
|
public renderer: Renderer2,
|
|
public ruler: ViewportRuler,
|
|
public zone: NgZone,
|
|
public changeDetector: ChangeDetectorRef,
|
|
protected propertyProvider: XTreeContainer
|
|
) {
|
|
super(
|
|
config,
|
|
managerService,
|
|
element,
|
|
renderer,
|
|
ruler,
|
|
zone,
|
|
changeDetector,
|
|
propertyProvider
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Abstract ...
|
|
public extractProps(
|
|
container?: IXTreeContainer
|
|
): Observable<IXTreeContainer> {
|
|
return super
|
|
.extractProps(container ? container : this)
|
|
.pipe(
|
|
concatMap((superData) => {
|
|
return forkJoin({
|
|
//
|
|
cssClass: this.getArrayValue(
|
|
container ? container.cssClass : this.cssClass
|
|
),
|
|
|
|
//
|
|
toggleIconColor: this.getValue(
|
|
container ? container.toggleIconColor : this.toggleIconColor
|
|
),
|
|
|
|
//
|
|
isForegroundToggleColor: this.getValue(
|
|
container
|
|
? container.isForegroundToggleColor
|
|
: this.isForegroundToggleColor
|
|
),
|
|
|
|
//
|
|
nodes: this.getArrayValue(container ? container.nodes : this.nodes),
|
|
}).pipe(
|
|
map((data) => {
|
|
return {
|
|
superData,
|
|
data,
|
|
};
|
|
})
|
|
);
|
|
})
|
|
)
|
|
.pipe(
|
|
map((info) => {
|
|
return {
|
|
//
|
|
...info.superData,
|
|
|
|
//
|
|
...info.data,
|
|
|
|
//
|
|
actionProvider: container
|
|
? container.actionProvider
|
|
: this.actionProvider,
|
|
|
|
//
|
|
nodeTemplate: container
|
|
? container.nodeTemplate
|
|
: this.nodeTemplate,
|
|
|
|
//
|
|
onNodeToggle: container.onNodeToggle
|
|
? container.onNodeToggle
|
|
: this.onNodeToggle,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
//#endregion
|