File

projects/i-components/src/lib/components/xam-grid-column/xam-grid-column.component.ts

Description

Pipe for applying format strings over text columns

Metadata

Name xamFormatString

Methods

transform
transform(format?: string, converter?: IValueConverter, columnModel?: any, dataType?: string)

Generates a formatter function for the underlying columns based on the passed format string or ValueConverter.

Parameters :
Name Type Optional
format string Yes
converter IValueConverter Yes
columnModel any Yes
dataType string Yes
Returns : (value: any, rowData: any) => any
import {
  AfterContentInit,
  Component,
  ContentChild,
  ContentChildren,
  ElementRef,
  EventEmitter,
  Inject,
  Input,
  LOCALE_ID,
  OnInit,
  Output,
  Pipe,
  PipeTransform,
  QueryList,
  TemplateRef,
} from '@angular/core';
import {
  HorizontalAlignment,
  ModelProxy,
  VerticalAlignment,
  XamGridCheckboxColumnModel,
  XamGridColumnModel,
  XamGridTemplateColumnModel,
  XamGridTextColumnModel,
  XamGridUnboundColumnModel,
  DataTemplate,
  TextWrapping,
  RuntimeStyleInfo,
  BindingInfo,
  ColumnWidth,
  IValueConverter,
  XamGridGroupColumnModel,
  smColorToCssColor,
  FrameworkElement,
  simpleStringFormat,
  XamGridModel,
  DependencyObject,
  calculateBindingValue,
  createBindingFromBindingInfo,
  isResourceKeyValue,
  getResourceKeyValue,
  resolveBindingContext,
  DependencyProperty,
} from '@mobilize/wms-framework';
import { BaseWrapperComponent } from '../basewrapper/basewrapper.component';
import { TextBoxComponent } from '../text-box/text-box.component';
import { TextBlockComponent } from '../text-block/text-block.component';
import { Utils } from '../../utils/utilities';

/**
 * Angular component imitating the footer template functionality in the Xam grid.
 *
 * @export
 * @class XamGridColumnFooterComponent
 */
@Component({
  selector: 'wm-column-footer',
  template: `<ng-content></ng-content>`,
})
export class XamGridColumnFooterComponent {
  /**
   * Returns the templated control. Either a text block or a text box.
   *
   * @readonly
   * @memberof XamGridColumnFooterComponent
   */
  public get control() {
    return this.textBox || this.textBlock;
  }

  /**
   * TextBoxComponent
   *
   * @protected
   * @type {TextBoxComponent}
   * @memberof XamGridColumnFooterComponent
   */
  @ContentChild(TextBoxComponent)
  protected textBox: TextBoxComponent;

  /**
   * TextBlockComponent
   *
   * @protected
   * @type {TextBlockComponent}
   * @memberof XamGridColumnFooterComponent
   */
  @ContentChild(TextBlockComponent)
  protected textBlock: TextBlockComponent;
}

/**
 * Angular Component for the Xam Grid Column Control
 *
 * @export
 * @class XamGridColumnComponent
 * @implements {OnInit}
 * @implements {AfterContentInit}
 */
@Component({
  selector: 'wm-xam-grid-column',
  templateUrl: './xam-grid-column.component.html',
  styleUrls: ['./xam-grid-column.component.css'],
})
export class XamGridColumnComponent
  extends BaseWrapperComponent
  implements OnInit, AfterContentInit
{
  /**
   * Object with XamGridComponent properties and events.
   *
   * @type {*}
   * @memberof XamGridColumnComponent
   */
  @Input()
  public model: XamGridColumnModel;

  /**
   * Gets or sets the style to be applied to the column header.
   *
   * @readonly
   * @type {(RuntimeStyleInfo | BindingInfo)}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get headerStyle(): RuntimeStyleInfo | BindingInfo {
    return this.modelProxy.HeaderStyle;
  }

  set headerStyle(value: RuntimeStyleInfo | BindingInfo) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.HeaderStyleProperty,
        value
      )
    ) {
      this.modelProxy.HeaderStyle = value as RuntimeStyleInfo;
    }
  }

  /**
   * Represent the content of the column header.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get headerText(): string | BindingInfo {
    return this.modelProxy.HeaderText;
  }

  set headerText(value: string | BindingInfo) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.HeaderTextProperty,
        value
      )
    ) {
      this.modelProxy.HeaderText = value as string;
    }
  }

  /**
   * headerText two-way binding event emitter
   *
   * @type {EventEmitter<string>}
   * @memberof XamGridColumnComponent
   */
  @Output()
  headerTextChange: EventEmitter<string> = new EventEmitter<string>();

  /**
   * Represent the key value.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get key(): string {
    return this.modelProxy.Key;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set key(value: string) {
    this.modelProxy.Key = value;
  }

  /**
   * Gets/sets the editable property of the column.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get editable(): boolean {
    return this.modelProxy.Editable;
  }

  /**
   * Sets the editable column property
   *
   * @memberof XamGridColumnComponent
   */
  set editable(value: boolean) {
    this.modelProxy.Editable = value;
  }

  /**
   * Alias for the editable property
   *
   * @type {boolean | BindingInfo}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get isReadOnly(): boolean | BindingInfo {
    return this.modelProxy.IsReadOnly;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set isReadOnly(value: boolean | BindingInfo) {
    /* istanbul ignore else */
    if (
      !this.checkAndRegisterCompatibilityBindingColumns(
        XamGridColumnModel.IsReadOnlyProperty,
        value
      )
    ) {
      this.modelProxy.IsReadOnly = value as boolean;
    }
  }

  /**
   * checkAndRegisterCompatibilityBindingColumns
   *
   * @protected
   * @param {DependencyProperty} property
   * @param {*} bindingObjectCandidate
   * @return {*}  {boolean}
   * @memberof XamGridColumnComponent
   */
  protected checkAndRegisterCompatibilityBindingColumns(
    property: DependencyProperty,
    bindingObjectCandidate: any
  ): boolean {
    return Utils.validateCompatibilityBindings(
      property,
      bindingObjectCandidate,
      this.modelProxy,
      this.pendingSetValuesColumns
    );
  }

  /**
   * Event emitter for two-way binding of the `isReadOnly` property.
   *
   * @type {EventEmitter<boolean>}
   * @memberof XamGridColumnComponent
   */
  @Output()
  isReadOnlyChange: EventEmitter<boolean> = new EventEmitter<boolean>();

  /**
   * Gets/sets the header template of the column.
   *
   * @type {TemplateRef<any>}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get headerTemplate(): TemplateRef<any> {
    return this.modelProxy.HeaderTemplate?.templateRef;
  }

  set headerTemplate(template: TemplateRef<any>) {
    this.modelProxy.HeaderTemplate = new DataTemplate(template);
  }

  /**
   * Gets/sets the cell template of the column.
   *
   * @type {TemplateRef<any>}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get itemTemplate(): TemplateRef<any> {
    return (this.modelProxy as any)?.ItemTemplate?.templateRef;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set itemTemplate(template: TemplateRef<any>) {
    (this.modelProxy as any).ItemTemplate = new DataTemplate(template);
  }

  /**
   * Gets/sets the visibility of the column.
   *
   * @type {boolean | BindingInfo}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get visibility(): boolean | BindingInfo {
    return this.modelProxy.Visibility;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set visibility(value: boolean | BindingInfo) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.VisibilityProperty,
        value
      )
    ) {
      this.modelProxy.Visibility = value as boolean;
    }
  }

  /**
   * Event emitter for two-way binding of the `visibility` property.
   *
   * @type {EventEmitter<boolean>}
   * @memberof XamGridColumnComponent
   */
  @Output()
  visibilityChange: EventEmitter<boolean> = new EventEmitter<boolean>();

  /**
   * Gets whether the column can be filtered through the UI.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get isFilterable(): boolean | BindingInfo {
    return this.model.IsFilterable;
  }

  /**
   * Sets whether the column can be filtered through the UI.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  set isFilterable(value: boolean | BindingInfo) {
    /* istanbul ignore else */
    if (
      !this.checkAndRegisterCompatibilityBindingColumns(
        XamGridColumnModel.IsFilterableProperty,
        value
      )
    ) {
      this.modelProxy.IsFilterable = value as boolean;
    }
  }

  /**
   * Gets/sets whether the column can be sorted through the UI.
   *
   * @readonly
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get sortable(): boolean {
    return this.modelProxy.IsSortable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set sortable(value: boolean) {
    this.modelProxy.IsSortable = value;
  }

  /**
   * Gets/sets whether the column can be grouped through the UI.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get groupable(): boolean {
    return this.modelProxy.IsGroupable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set groupable(value: boolean) {
    this.modelProxy.IsGroupable = value;
  }

  /**
   * Gets/sets whether the column can be moved through the UI.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get movable(): boolean {
    return this.modelProxy.IsMovable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set movable(value: boolean) {
    this.modelProxy.IsMovable = value;
  }

  /**
   * Gets/sets whether the column can be resized through the UI.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get resizable(): boolean {
    return this.modelProxy.IsResizable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set resizable(value: boolean) {
    this.modelProxy.IsResizable = value;
  }

  /**
   * Gets/sets whether the column can be hidden.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get hideable(): boolean {
    return this.modelProxy.IsHideable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set hideable(value: boolean) {
    this.modelProxy.IsHideable = value;
  }

  /**
   * Gets/sets whether the column should be pinned/unpinned.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get isFixed(): boolean | string {
    return this.modelProxy.IsFixed !== 0;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set isFixed(value: boolean | string) {
    this.modelProxy.IsFixed = value ? 1 : 0;
  }

  /**
   * Gets/sets whether the column can be pinned/unpinned.
   *
   * @type {boolean}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get fixable(): boolean {
    return this.modelProxy.IsFixable;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set fixable(value: boolean) {
    this.modelProxy.IsFixable = value;
  }

  /**
   * Gets/sets the minimum width the column is allowed to be.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get minimumWidth() {
    return this.modelProxy.MinimumWidth;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set minimumWidth(value) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.MinimumWidthProperty,
        value
      )
    ) {
      this.modelProxy.MinimumWidth = value;
    }
  }

  /**
   * Gets/sets the maximum width the column is allowed to be.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get maximumWidth() {
    return this.modelProxy.MaximumWidth;
  }

  /**
   *
   *
   * @memberof XamGridColumnComponent
   */
  set maximumWidth(value) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.MaximumWidthProperty,
        value
      )
    ) {
      this.modelProxy.MaximumWidth = value;
    }
  }

  /**
   * Gets/sets the width of the column.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get width(): ColumnWidth {
    return this.modelProxy.Width;
  }

  set width(value: ColumnWidth) {
    /* istanbul ignore else */
    if (
      !this.checkForStaticResourceReference(
        XamGridColumnModel.WidthProperty,
        value
      )
    ) {
      this.modelProxy.Width = ColumnWidth.parse(value);
    }
  }

  /**
   * Gets/sets how a child element is horizontally positioned or stretched inside a parent layout slot
   *
   * @type {HorizontalAlignment}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get horizontalContentAlignment(): string | number {
    return this.modelProxy.HorizontalContentAlignment;
  }

  set horizontalContentAlignment(value: string | number) {
    this.modelProxy.HorizontalContentAlignment =
      typeof value === 'number' ? value : HorizontalAlignment.parse(value);
  }

  /**
   * Gets/sets how a child element is vertically positioned or stretched inside a parent layout slot
   *
   * @type {string | number}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get verticalContentAlignment(): string | number {
    return this.modelProxy.VerticalContentAlignment;
  }

  set verticalContentAlignment(value: string | number) {
    this.modelProxy.VerticalContentAlignment =
      typeof value === 'number' ? value : VerticalAlignment.parse(value);
  }

  /**
   * Gets/sets the header text horizontal alignment
   *
   * @type {HorizontalAlignment}
   * @memberof XamGridColumnComponent
   */
  @Input()
  get headerTextHorizontalAlignment(): HorizontalAlignment {
    return this.modelProxy.HeaderTextHorizontalAlignment;
  }

  set headerTextHorizontalAlignment(value: HorizontalAlignment) {
    this.modelProxy.HeaderTextHorizontalAlignment = value;
  }

  /**
   * Gets/sets the style for the column cells.
   *
   * @memberof XamGridColumnComponent
   */
  @Input()
  get cellStyle() {
    return this.model.CellStyle;
  }

  set cellStyle(style) {
    this.modelProxy.CellStyle = style;
  }

  /**
   * Returns the data type of the column
   *
   * @readonly
   * @memberof XamGridColumnComponent
   */
  get dataType() {
    return this.modelProxy.DataType;
  }

  /**
   * This is a reference with the content of each column.
   *
   * @type {TemplateRef<any>}
   * @memberof XamGridColumnComponent
   */
  @ContentChild('columnContentTemplate')
  columnContentTemplate: TemplateRef<any>;

  /**
   * Reference to the header template if any.
   *
   * @type {TemplateRef<any>}
   * @memberof XamGridColumnComponent
   */
  @ContentChild('columnHeaderTemplate')
  columnHeaderTemplate: TemplateRef<any>;

  /**
   * Reference to the editor template if any.
   *
   * @type {TemplateRef<any>}
   * @memberof XamGridColumnComponent
   */
  @ContentChild('columnEditorTemplate')
  columnEditorTemplate: TemplateRef<any>;

  /**
   * Reference to the footer template if any.
   *
   * @type {XamGridColumnFooterComponent}
   * @memberof XamGridColumnComponent
   */
  @ContentChild(XamGridColumnFooterComponent)
  footerTemplate: XamGridColumnFooterComponent;

  /**
   * Model proxy
   *
   * @protected
   * @memberof XamGridColumnComponent
   */
  protected modelProxy = ModelProxy.create<XamGridColumnModel>();

  /**
   * Angular lifecycle hook
   * Initialize the model for each column.
   *
   * @memberof XamGridColumnComponent
   */
  ngOnInit(): void {
    this.model = this.model ?? new XamGridColumnModel();
    ModelProxy.copy(this.modelProxy, this.model);
    this.modelProxy = this.model;
    this.model.change.addHandler(this.applyResourcesOnParentChange, this);
  }

  /**
   * Angular lifecycle hook.
   * Initialize the column templates if present.
   *
   * @memberof XamGridColumnComponent
   */
  ngAfterContentInit() {
    /* istanbul ignore else */
    if (this.columnHeaderTemplate != null)
      this.model.HeaderTemplate = new DataTemplate(this.columnHeaderTemplate);

    /* istanbul ignore else */
    if (this.model instanceof XamGridTemplateColumnModel) {
      /* istanbul ignore else */
      if (this.columnEditorTemplate) {
        this.model.EditorTemplate = new DataTemplate(this.columnEditorTemplate);
      }
      this.model.ItemTemplate = new DataTemplate(this.columnContentTemplate);
      this.model.FooterTemplate = this.footerTemplate;
      this.setupFooters();
    } else if (this.model instanceof XamGridUnboundColumnModel) {
      this.model.ItemTemplate = new DataTemplate(this.columnContentTemplate);
      /* istanbul ignore else */
      if (this.columnEditorTemplate) {
        this.model.EditorTemplate = new DataTemplate(this.columnEditorTemplate);
      }
    }

    this.setupFooters();
  }

  /**
   * Recreates the binding context for the footers section
   *
   * @memberof XamGridColumnComponent
   */
  setupFooters() {
    /* istanbul ignore else */
    if (this.footerTemplate?.control) {
      this.model.CreateFooterOperand(this.footerTemplate);
    }
  }

  /**
   * Overrides the apply pending resource assignments
   *
   * @protected
   * @param {DependencyObject} model
   * @memberof BaseWrapperComponent
   */
  /* istanbul ignore next */
  protected applyPendingResourceAssignment(model: DependencyObject) {
    const contextModel = this.getContextModel();
    if (this.pendingResourceValues && contextModel) {
      for (const [property, value] of this.pendingResourceValues) {
        let processValue: any = null;
        if (typeof value === 'object' && value.bindingPath) {
          const binding = createBindingFromBindingInfo(value, contextModel);
          const theBindingContext = resolveBindingContext(
            binding,
            contextModel
          );
          processValue = calculateBindingValue(
            binding,
            theBindingContext,
            property
          );
          model.SetBinding(property, binding);
        } else if (isResourceKeyValue(value)) {
          processValue = getResourceKeyValue(value, contextModel);
        } else {
          processValue = value;
        }
        model.setValue(property, processValue);
      }
    } else {
      super.applyPendingResourceAssignment(model);
    }
    this.pendingResourceValues = null;
  }

  /**
   * Applies the resources until the parent is set
   *
   * @protected
   * @param {*} propertyName
   * @memberof XamGridColumnComponent
   */
  protected applyResourcesOnParentChange(propertyName: any) {
    /* istanbul ignore else */
    if (propertyName === 'Parent') {
      this.applyPendingResourceAssignment(this.model);
    }
  }

  private getContextModel(): FrameworkElement {
    /* istanbul ignore else */
    if (this.model.Parent instanceof XamGridModel) {
      return this.model.Parent;
    }
    return null;
  }
}

/**
 * Angular component for the Xam grid text column model
 *
 * @export
 * @class XamGridTextColumnComponent
 * @extends {XamGridColumnComponent}
 * @implements {OnInit}
 */
@Component({
  selector: 'wm-xam-grid-text-column',
  providers: [
    {
      provide: XamGridColumnComponent,
      useExisting: XamGridTextColumnComponent,
    },
  ],
  templateUrl: './xam-grid-column.component.html',
  styleUrls: ['./xam-grid-column.component.css'],
})
export class XamGridTextColumnComponent
  extends XamGridColumnComponent
  implements OnInit
{
  /**
   * Gets/Sets the text footer for the current column
   *
   * @memberof XamGridTextColumnComponent
   */
  @Input() set footerText(value: string) {
    this.modelProxy.FooterText = value;
  }

  /**
   * Gets/sets the text wrapping mode for the column.
   *
   * @memberof XamGridTextColumnComponent
   */
  @Input()
  get textWrapping() {
    return this.modelProxy.TextWrapping;
  }

  /**
   *
   *
   * @memberof XamGridTextColumnComponent
   */
  set textWrapping(value) {
    this.modelProxy.TextWrapping = value;
  }

  /**
   * Gets/sets the format string for the cells in the column.
   *
   * @memberof XamGridTextColumnComponent
   */
  @Input()
  get formatString() {
    return this.modelProxy.FormatString;
  }

  set formatString(value: string) {
    this.modelProxy.FormatString = value;
  }

  /**
   * The underlying data column model if provided
   *
   * @type {DataGridTextColumnModel}
   * @memberof XamGridTextColumnComponent
   */
  @Input()
  model: XamGridTextColumnModel;

  /**
   * Model proxy
   *
   * @protected
   * @memberof XamGridTextColumnComponent
   */
  protected modelProxy = ModelProxy.create<XamGridTextColumnModel>();

  /**
   * * Angular lifecycle hook
   * Initialize the model for each column.
   *
   * @memberof XamGridTextColumnComponent
   */
  public ngOnInit() {
    this.model = this.model ?? new XamGridTextColumnModel();
    super.ngOnInit();
  }
}

/**
 * Angular component for the Xam grid checkbox column model
 *
 * @export
 * @class XamGridCheckboxColumnComponent
 * @extends {XamGridColumnComponent}
 * @implements {OnInit}
 */
@Component({
  selector: 'wm-xam-grid-checkbox-column',
  providers: [
    {
      provide: XamGridColumnComponent,
      useExisting: XamGridCheckboxColumnComponent,
    },
  ],
  templateUrl: './xam-grid-column.component.html',
  styleUrls: ['./xam-grid-column.component.css'],
})
export class XamGridCheckboxColumnComponent
  extends XamGridColumnComponent
  implements OnInit
{
  /**
   * The underlying data column model if provided.
   *
   * @type {XamGridCheckboxColumnModel}
   * @memberof XamGridCheckboxColumnComponent
   */
  @Input()
  model: XamGridCheckboxColumnModel;

  protected modelProxy = ModelProxy.create<XamGridCheckboxColumnModel>();

  /**
   * * Angular lifecycle hook
   * Initialize the model for each column.
   *
   * @memberof XamGridCheckboxColumnComponent
   */
  public ngOnInit() {
    this.model = this.model ?? new XamGridCheckboxColumnModel();
    super.ngOnInit();
  }
}

/**
 * An alias for the default Xam grid column for easier transitioning
 *
 * @export
 * @class XamGridTemplateColumnComponent
 * @extends {XamGridColumnComponent}
 * @implements {OnInit}
 */
@Component({
  selector: 'wm-xam-grid-template-column',
  providers: [
    {
      provide: XamGridColumnComponent,
      useExisting: XamGridTemplateColumnComponent,
    },
  ],
  templateUrl: './xam-grid-column.component.html',
  styleUrls: ['./xam-grid-column.component.css'],
})
export class XamGridTemplateColumnComponent
  extends XamGridColumnComponent
  implements OnInit
{
  /**
   * The underlying data column model if provided.
   *
   * @type {XamGridTemplateColumnModel}
   * @memberof XamGridTemplateColumnComponent
   */
  @Input()
  model: XamGridTemplateColumnModel;

  protected modelProxy = ModelProxy.create<XamGridTemplateColumnModel>();

  /**
   * Angular lifecyc\le hook.
   * Initialize the model for each column.
   *
   * @memberof XamGridTemplateColumnComponent
   */
  public ngOnInit() {
    this.model = this.model ?? new XamGridTemplateColumnModel();
    super.ngOnInit();
  }
}

/**
 * Alias for the Xam grid column for easier transitioning
 *
 * @export
 * @class XamGridUnboundColumnComponent
 * @extends {XamGridColumnComponent}
 * @implements {OnInit}
 */
@Component({
  selector: 'wm-xam-grid-unbound-column',
  providers: [
    {
      provide: XamGridColumnComponent,
      useExisting: XamGridUnboundColumnComponent,
    },
  ],
  templateUrl: './xam-grid-column.component.html',
  styleUrls: ['./xam-grid-column.component.css'],
})
export class XamGridUnboundColumnComponent
  extends XamGridColumnComponent
  implements OnInit
{
  /**
   * The underlying data column model if provided.
   *
   * @type {XamGridUnboundColumnModel}
   * @memberof XamGridUnboundColumnComponent
   */
  @Input()
  model: XamGridUnboundColumnModel;

  protected modelProxy = ModelProxy.create<XamGridUnboundColumnModel>();

  /**
   * Initialize the model for each column.
   *
   * @memberof XamGridUnboundColumnComponent
   */
  public ngOnInit() {
    this.model = this.model ?? new XamGridUnboundColumnModel();
    super.ngOnInit();
  }
}

/**
 * Column group container for other Xam grid columns.
 *
 * @export
 * @class XamGridColumnGroupComponent
 * @extends {XamGridColumnComponent}
 * @implements {OnInit}
 * @implements {AfterContentInit}
 */
@Component({
  selector: 'wm-xam-grid-column-group',
  providers: [
    {
      provide: XamGridColumnComponent,
      useExisting: XamGridColumnGroupComponent,
    },
  ],
  template: `<ng-content></ng-content>`,
})
export class XamGridColumnGroupComponent
  extends XamGridColumnComponent
  implements OnInit, AfterContentInit
{
  /**
   * The underlying model.
   *
   * @type {XamGridGroupColumnModel}
   * @memberof XamGridColumnGroupComponent
   */
  @Input()
  public model: XamGridGroupColumnModel;

  /**
   * Returns whether this model represents a a column group.
   *
   * @readonly
   * @memberof XamGridColumnGroupComponent
   */
  get isGroupColumn() {
    return this.model.IsGroupColumn;
  }

  /**
   * The column's children
   *
   * @type {QueryList<XamGridColumnComponent>}
   * @memberof XamGridColumnGroupComponent
   */
  @ContentChildren(XamGridColumnComponent)
  children: QueryList<XamGridColumnComponent>;

  protected modelProxy = ModelProxy.create<XamGridGroupColumnModel>();

  /**
   * Angular life-cycle hook
   *
   * @memberof XamGridColumnGroupComponent
   */
  ngOnInit() {
    this.model = this.model ?? new XamGridGroupColumnModel();
    super.ngOnInit();
  }

  /**
   * Angular life-cycle hook
   *
   * @memberof XamGridColumnGroupComponent
   */
  ngAfterContentInit() {
    this.children.forEach((child) => {
      child.model.Parent = this.model;
      this.model.AddColumn(child.model);
    });
  }
}

/**
 * A No-op wrapper around the columns in the Xam grid.
 * Useful when translating old code and keeping the same tree structure.
 *
 * @export
 * @class XamGridColumnsComponent
 */
@Component({
  selector: 'wm-xam-grid-columns',
  template: `<ng-content></ng-content>`,
})
export class XamGridColumnsComponent {}

/**
 * Mapper pipe transforming XamColumnModels alignments to CSS style properties.
 *
 * @export
 * @class AlignmentMapPipe
 * @implements {PipeTransform}
 */
@Pipe({ name: 'alignmentMap' })
export class AlignmentMapPipe implements PipeTransform {
  /**
   * Vertical mappings to CSS flex properties
   *
   * @memberof AlignmentMapPipe
   */
  verticalMap = new Map([
    [0, { 'align-items': 'flex-start' }],
    [1, { 'align-items': 'flex-center' }],
    [2, { 'align-items': 'flex-end' }],
    [3, { 'align-items': 'stretch' }],
    [4, { 'align-items': 'flex-center' }],
  ]);

  /**
   * Horizontal mappings to CSS flex properties
   *
   * @memberof AlignmentMapPipe
   */
  horizontalMap = new Map([
    [0, { 'justify-content': 'flex-start' }],
    [1, { 'justify-content': 'center' }],
    [2, { 'justify-content': 'flex-end' }],
    [3, { 'justify-content': 'space-between' }],
  ]);

  /**
   * Applies the appropriate horizontal/vertical alignments for the grid cells.
   *
   * @param {HorizontalAlignment} horizontal
   * @param {VerticalAlignment} vertical
   * @return {*}
   * @memberof AlignmentMapPipe
   */
  transform(
    horizontal: HorizontalAlignment,
    vertical: VerticalAlignment,
    styleInfo: RuntimeStyleInfo,
    formatRules: any,
    grid: any,
    isCellChanged: number
  ) {
    const styles = {
      ...this.horizontalMap.get(horizontal),
      ...this.verticalMap.get(vertical),
    };
    this.processColumnStyle(styleInfo, styles);
    this.processFormatRules(formatRules, styles);
    if (grid?.cellStyleEnabled && grid.renderedCalled) {
      this.processRowCellStyleChange(styles, grid, isCellChanged);
    }
    return styles;
  }

  private processFormatRules(
    formatRules: any,
    styles: { 'align-items': string; 'justify-content': string }
  ) {
    if (formatRules) {
      formatRules.forEach((rule) => {
        const [cssProp, cssString] = Object.entries(rule.StyleToApply);
        styles[`${cssProp}`] = (
          data: any,
          key: string,
          value: any,
          index: number
        ) => (rule.callback(value) ? cssString : null);
      });
    }
  }

  /**
   * Process the row cell style change
   *
   * @param {*} styles
   * @param {*} grid
   * @param {number} isCellChanged
   * @memberof AlignmentMapPipe
   */
  processRowCellStyleChange(styles: any, grid: any, isCellChanged: number) {
    const styleBackground = styles['background-color'];
    const styleColor = styles['color'];
    const styleFontFamily = styles['font-family'];
    const styleFontSize = styles['font-size'];
    const styleFontStyle = styles['font-style'];
    const styleFontWeight = styles['font-weight'];
    const stylePadding = styles['padding'];
    const style = {};
    this.addStyleProperty(
      'background-color',
      'Background',
      null,
      colorToCSSColor,
      style,
      grid,
      styleBackground
    );
    this.addStyleProperty(
      'color',
      'Foreground',
      'black',
      colorToCSSColor,
      style,
      grid,
      styleColor
    );
    this.addStyleProperty(
      'font-family',
      'FontFamily',
      null,
      (s) => s,
      style,
      grid,
      styleFontFamily
    );
    this.addStyleProperty(
      'font-size',
      'FontSize',
      'inherit',
      addingPixels,
      style,
      grid,
      styleFontSize
    );
    this.addStyleProperty(
      'font-style',
      'FontStyle',
      null,
      (s) => Utils.getFontStyle(s),
      style,
      grid,
      styleFontStyle
    );
    this.addStyleProperty(
      'font-weight',
      'FontWeight',
      null,
      (s) => Utils.getFontWeight(s),
      style,
      grid,
      styleFontWeight
    );
    this.addStyleProperty(
      'padding',
      'Padding',
      null,
      addingPixels,
      style,
      grid,
      stylePadding
    );
    Object.assign(styles, style);
  }

  /**
   * Generates the property resolve function for the grid mechanism
   *
   * @private
   * @param {string} styleProperty
   * @param {string} modelProperty
   * @param {*} defaultValue
   * @param {*} strategy
   * @param {*} stylesObj
   * @param {*} grid
   * @param {*} styleValue
   * @memberof AlignmentMapPipe
   */
  private addStyleProperty(
    styleProperty: string,
    modelProperty: string,
    defaultValue: any,
    strategy: any,
    stylesObj: any,
    grid: any,
    styleValue: any
  ) {
    stylesObj[styleProperty] = (rowData, colName, cellValue, rowIndex) => {
      return this.processProperty(
        grid,
        rowIndex,
        colName,
        modelProperty,
        defaultValue,
        strategy,
        styleValue
      );
    };
  }

  private processProperty(
    grid: any,
    rowIndex: any,
    colName: any,
    propertyName: string,
    defaultValue: string,
    strategy: any,
    currentStyleValue: any
  ) {
    // Process cell style
    if (grid == null) {
      return null;
    }
    const { row, cell } = grid.getCellByRowColumn(rowIndex, colName);
    let value = defaultValue;
    if (currentStyleValue == null) {
      currentStyleValue = value;
    }
    if (cell?.Style != null) {
      value = this.getStyleValue(cell?.Style, propertyName) ?? defaultValue;
      value = value !== defaultValue ? strategy(value) : currentStyleValue;
    }

    // Process row style
    if (value === defaultValue) {
      value = this.getStyleValue(row.CellStyle, propertyName) ?? defaultValue;
      value = value !== defaultValue ? strategy(value) : currentStyleValue;
    }
    return value;
  }

  private getStyleValue(obj: any, propertyName: string): any {
    return obj?.Setters['internalArray'].find(
      (x) => getPropertyName(x) === propertyName
    )?.Value;
  }

  private processColumnStyle(styleInfo: RuntimeStyleInfo, styles: any) {
    if (styleInfo) {
      styleInfo.Setters.forEach((setter) =>
        Object.assign(styles, runtimeStyleTransform(setter))
      );
    }
  }
}

/**
 * Pipe for applying text wrapping styles over text columns
 *
 * @export
 * @class TextWrappingPipe
 * @implements {PipeTransform}
 */
@Pipe({ name: 'textWrapping' })
export class TextWrappingPipe implements PipeTransform {
  /**
   * Apply the current text wrapping values
   *
   * @param {TextWrapping} value
   * @return {*}
   * @memberof TextWrappingPipe
   */
  transform(value: TextWrapping) {
    /* istanbul ignore else */
    if (!value) {
      return {};
    }
    return {
      whiteSpace: value === 1 ? 'nowrap' : 'normal',
      overflowWrap: 'anywhere',
      fontSize: '0.8125rem',
    };
  }
}

/**
 * Pipe for applying style information over column members
 *
 * @export
 * @class StyleInfoPipe
 * @implements {PipeTransform}
 */
@Pipe({ name: 'styleInfo' })
export class StyleInfoPipe implements PipeTransform {
  /**
   * Apply the current text style
   *
   * @param {RuntimeStyleInfo} value
   * @return {*}
   * @memberof StyleInfoPipe
   */
  transform(value: RuntimeStyleInfo, headerTextAlignment: HorizontalAlignment) {
    const styles = {};
    if (value) {
      value.Setters.forEach((setter) =>
        Object.assign(styles, runtimeStyleTransform(setter))
      );
    }
    if (headerTextAlignment !== null) {
      const map = ['left', 'center', 'right', 'justify'];
      styles['text-align'] = map[headerTextAlignment];
    }

    return styles;
  }
}

/**
 * Pipe for applying format strings over text columns
 *
 * @export
 * @class XamFormatStringPipe
 * @implements {PipeTransform}
 */
@Pipe({ name: 'xamFormatString' })
export class XamFormatStringPipe implements PipeTransform {
  constructor(@Inject(LOCALE_ID) private locale: string, elem: ElementRef) {}

  /**
   * Generates a formatter function for the underlying columns
   * based on the passed format string or ValueConverter.
   *
   * @param {string} [format]
   * @return {*}
   * @memberof XamFormatStringPipe
   */
  transform(
    format?: string,
    converter?: IValueConverter,
    columnModel?: any,
    dataType?: string
  ) {
    if (converter) {
      return (value: any, rowData: any) => {
        if (columnModel instanceof XamGridUnboundColumnModel) {
          //Unbound columns receive the complete row as value
          return converter.Convert(
            rowData?.data ?? rowData,
            undefined,
            columnModel?.ValueConverterParameter,
            undefined
          );
        } else {
          return converter.Convert(value, undefined, undefined, undefined);
        }
      };
    }
    if (!format) {
      if (dataType === 'date') {
        format = '{0:G}';
      } else {
        return undefined;
      }
    }

    return (value) => simpleStringFormat(format.replace(/^{}/, ''), value);
  }
}

/**
 * Map silverlight properties to CSS properties
 *
 * @protected
 * @param {*} setter
 * @return {*}
 * @memberof AlignmentMapPipe
 */
export function runtimeStyleTransform(setter: any): Record<string, unknown> {
  // eslint-disable-next-line
  const Property = getPropertyName(setter);
  const Value = setter.Value;
  // eslint-disable-next-line
  switch (Property) {
    case 'Foreground':
      return { color: smColorToCssColor(Value.Color) };
    case 'Background':
      return { background: smColorToCssColor(Value.Color) };
    case 'BorderThickness':
      return { 'border-width': Value.toString() };
    case 'BorderBrush':
      return { 'border-color': smColorToCssColor(Value.Color) };
    case 'FontSize':
      return { 'font-size': `${Value}px` };
    case 'FontStyle':
      return { 'font-style': Utils.getFontStyle(Value) };
    case 'FontWeight':
      return { 'font-weight': Utils.getFontWeight(Value) };
    case 'FontFamily':
      return { 'font-family': Value?.toString() };
    case 'VerticalContentAlignment':
      return { 'align-self': Utils.getVerticalContentAlignment(Value) };
    case 'HorizontalContentAlignment':
      return { 'justify-self': Utils.getHorizontalContentAlignment(Value) };
    default:
      // eslint-disable-next-line
      return { [Property]: Value };
  }
}

/**
 * Gets the property name from the setter
 *
 * @param {*} setter
 * @returns {string}
 */
function getPropertyName(setter: any): string {
  return typeof setter.Property === 'object'
    ? setter.Property?.name
    : setter.Property;
}

/**
 * Adding pixels to value function
 *
 * @param {string} value
 * @returns {string}
 */
function addingPixels(value: string): string {
  return `${value}px`;
}

/**
 * Color to css color function
 *
 * @param {*} value
 * @returns {string}
 */
export function colorToCSSColor(value: any): string {
  return smColorToCssColor(value.Color);
}

result-matching ""

    No results matching ""