File

projects/wms-framework/src/lib/regionsframework/RegionManager.ts

Description

Implementation of region manager

Implements

IRegionManager

Index

Properties
Methods
Accessors

Constructor

constructor(mappings: RegionAdapterMappings, viewsRegistry: IRegionViewRegistry, container: DependencyContainer)
Parameters :
Name Type Optional
mappings RegionAdapterMappings No
viewsRegistry IRegionViewRegistry No
container DependencyContainer No

Properties

regionsCollection
Type : IRegionCollection
Private regionsTargets
Default value : new SimpleDictionary< string, UIElement | WeakRef<UIElement> >()
Static UpdatingRegions
Default value : new SubscriptionEvent()
Private verifyingForRegionsToRemove
Default value : false

Methods

Public AddToRegion
AddToRegion(regionName: string, object: unknown)

Adds a view to a region

Parameters :
Name Type Optional
regionName string No
object unknown No
Returns : void
Private checkForDeadRegion
checkForDeadRegion(regionName: string)
Parameters :
Name Type Optional
regionName string No
Returns : void
Private checkIfStillAttached
checkIfStillAttached(model)
Parameters :
Name Optional
model No
Returns : boolean
Public CreateRegionManager
CreateRegionManager(container?: DependencyContainer)

Creates a child region manager

Parameters :
Name Type Optional
container DependencyContainer Yes
Returns : IRegionManager

{IRegionManager}

Static GetRegionName
GetRegionName(view: unknown)

Gets the value of the RegionName property for the given view

Parameters :
Name Type Optional
view unknown No
Returns : string

{string}

Static NotifyOfUpdatingRegions
NotifyOfUpdatingRegions()

Raises the notification for updating regions

Returns : void
Static ProcessRegionHostBeingRemoved
ProcessRegionHostBeingRemoved(regionName: string, host: unknown)

Removes the region with the given name when the host is being removed from the screen

Parameters :
Name Type Optional
regionName string No
host unknown No
Returns : void
Private registerRegionTarget
registerRegionTarget(regionName: string, view: UIElement)
Parameters :
Name Type Optional
regionName string No
view UIElement No
Returns : void
RegisterRegionTarget
RegisterRegionTarget(regionName: string, view: UIElement)

Registers a host control to a region

Parameters :
Name Type Optional
regionName string No
view UIElement No
Returns : void
Public RegisterViewWithRegion
RegisterViewWithRegion(regionName: string, viewCreationFunc: | RuntimeTypeInfo)

Registers a view inside a region

Parameters :
Name Type Optional
regionName string No
viewCreationFunc | RuntimeTypeInfo No
Returns : void
Static SetRegionName
SetRegionName(view: unknown, regionName: string)

Sets the region name for the given view

Parameters :
Name Type Optional
view unknown No
regionName string No
Returns : void
Static SetRegionNameInScopedRegion
SetRegionNameInScopedRegion(view: unknown, regionName: string, scopedRegionManager: IRegionManager)

Sets the region name for the given view in an scoped RegionManager

Parameters :
Name Type Optional
view unknown No
regionName string No
scopedRegionManager IRegionManager No
Returns : void

Accessors

Regions
getRegions()
setRegions(value: IRegionCollection)
Parameters :
Name Type Optional
value IRegionCollection No
Returns : void
import { DependencyContainer, inject, injectable } from 'tsyringe';
import { UIElement } from '../basecomponentmodel/UIElement';
import { InvalidOperationException } from '../baseframework/Exceptions';
import {
  ReflectionHelper,
  RuntimeTypeInfo,
} from '../baseframework/ReflectionSupport';
import { SimpleDictionary } from '../baseframework/SimpleDictionary';
import { SubscriptionEvent } from '../utils/SubscriptionEvent';
import {
  regionManagerProperty,
  regionNameProperty,
} from './directives/RegionManager.directive';
import {
  containerInjectionToken,
  regionManagerInjectionToken,
  regionViewRegistryInjectionToken,
} from './injectionTokens';
import { IRegion } from './IRegion';
import { IRegionCollection } from './IRegionCollection';
import { IRegionManager } from './IRegionManager';
import { IRegionViewRegistry } from './IRegionViewRegistry';
import { RegionAdapterMappings } from './RegionAdapterMappings';
import { ServiceLocator } from './servicelocation/ServiceLocator';

/**
 * Auxiliary Type for WeakRefs
 */
type WeakRef<T> = {
  deref: () => T;
};

/**
 *  Internal constant to access weak references
 */
// eslint-disable-next-line @typescript-eslint/naming-convention

let WeakRefActualType = (window as any).WeakRef as new (
  obj: any
) => WeakRef<any>;
let weakReferencesSupported = typeof WeakRefActualType !== 'undefined';

/**
 *  Exported function to customize the weak reference configuration (exported for testing)
 * @param weakRefType
 */
export const changeWeakReferenceConfiguration = (weakRefType: any) => {
  weakReferencesSupported = typeof weakRefType !== 'undefined';
  WeakRefActualType = weakRefType;
};

/**
 *  Implementation of region manager
 *
 * @export
 * @class RegionManager
 * @implements {IRegionManager}
 * @wType Microsoft.Practices.Prism.Regions.RegionManager
 */
@injectable()
export class RegionManager implements IRegionManager {
  public static UpdatingRegions = new SubscriptionEvent();

  regionsCollection: IRegionCollection;
  private regionsTargets = new SimpleDictionary<
    string,
    UIElement | WeakRef<UIElement>
  >();
  private verifyingForRegionsToRemove = false;

  get Regions(): IRegionCollection {
    return this.regionsCollection;
  }
  set Regions(value: IRegionCollection) {}

  constructor(
    private mappings: RegionAdapterMappings,
    @inject(regionViewRegistryInjectionToken)
    private viewsRegistry: IRegionViewRegistry,
    @inject(containerInjectionToken) private container: DependencyContainer
  ) {
    this.regionsCollection = new RegionCollection(this);
    if (weakReferencesSupported) {
      RegionManager.UpdatingRegions.addHandler(() => {
        if (!this.verifyingForRegionsToRemove) {
          this.verifyingForRegionsToRemove = true;
          try {
            for (const viewPairToCheck of this.regionsTargets) {
              if (
                WeakRefActualType &&
                viewPairToCheck[1] instanceof WeakRefActualType &&
                typeof viewPairToCheck[1].deref() === 'undefined'
              ) {
                console.log('collecting weak viewref');
                this.Regions.Remove(viewPairToCheck[0]);
              }
            }
          } finally {
            this.verifyingForRegionsToRemove = false;
          }
        }
      });
    }
  }

  /**
   * Sets the region name for the given view
   *
   * @static
   * @param {unknown} view
   * @param {string} regionName
   * @memberof RegionManager
   */
  public static SetRegionName(view: unknown, regionName: string) {
    /* istanbul ignore else */
    if (view instanceof UIElement) {
      view.setValue(regionNameProperty, regionName);
    } else {
      throw new Error('Unexpected view when setting region');
    }
  }

  /**
   * Sets the region name for the given view in an scoped RegionManager
   *
   * @static
   * @param {unknown} view
   * @param {string} regionName
   * @memberof RegionManager
   */
  public static SetRegionNameInScopedRegion(
    view: unknown,
    regionName: string,
    scopedRegionManager: IRegionManager
  ) {
    /* istanbul ignore else */
    if (view instanceof UIElement) {
      view.setValueForScopedRegion(
        regionNameProperty,
        regionName,
        scopedRegionManager
      );
    } else {
      throw new Error('Unexpected view when setting region');
    }
  }

  /**
   *  Gets the value of the `RegionName` property for the given view
   *
   * @static
   * @param {unknown} view
   * @return {*}  {string}
   * @memberof RegionManager
   */
  public static GetRegionName(view: unknown): string {
    if (view instanceof UIElement) {
      return (view.getValue(regionNameProperty) ?? null) as string;
    } else {
      throw new Error('Unexpected view when getting region');
    }
  }

  /**
   *  Removes the region with the given name when the host is being removed from the screen
   *
   * @static
   * @param {string} regionName
   * @param {unknown} host
   * @memberof RegionManager
   * @wIgnore
   */
  public static ProcessRegionHostBeingRemoved(
    regionName: string,
    host: unknown
  ) {
    let regionManager: IRegionManager;
    regionManager = ServiceLocator.current.getInstance(
      regionManagerInjectionToken
    ) as IRegionManager;
    if (regionManager) {
      regionManager.Regions.Remove(regionName);
    }
  }

  /**
   * Creates a child region manager
   *
   * @return {*}  {IRegionManager}
   * @memberof RegionManager
   */
  public CreateRegionManager(container?: DependencyContainer): IRegionManager {
    return container
      ? new RegionManager(this.mappings, this.viewsRegistry, container)
      : this;
  }

  /**
   *  Registers a host control to a region
   *
   * @param {string} regionName
   * @param {UIElement} view
   * @memberof RegionManager
   * @wIgnore
   */
  RegisterRegionTarget(regionName: string, view: UIElement) {
    this.checkForDeadRegion(regionName);
    this.registerRegionTarget(regionName, view);
    var typeInfo = ReflectionHelper.getTypeInfo(view);
    let adapter = this.mappings.getAdapter(typeInfo);
    if (adapter) {
      let region = adapter.Initialize(view, regionName);
      let viewList: Array<unknown> = null;
      for (let aView of this.viewsRegistry.GetContents(regionName)) {
        region.Add(aView);
      }
      region.Name = regionName;
      this.regionsCollection.Add(region);
    } else {
      throw new Error('Cannot find adapter for ' + typeInfo.FullName);
    }
  }

  /**
   *  Registers a view inside a region
   *
   * @param {string} regionName
   * @param {(((() => unknown) | RuntimeTypeInfo))} viewCreationFunc
   * @memberof RegionManager
   */
  public RegisterViewWithRegion(
    regionName: string,
    viewCreationFunc: (() => unknown) | RuntimeTypeInfo
  ): void {
    this.viewsRegistry.RegisterViewWithRegion(regionName, viewCreationFunc);
  }

  /**
   *  Adds a view to a region
   *
   * @param {string} regionName
   * @param {unknown} object
   * @memberof RegionManager
   */
  public AddToRegion(regionName: string, object: unknown): void {
    if (this.regionsCollection.ContainsRegionWithName(regionName)) {
      let theRegion = this.regionsCollection.getItem(regionName);
      theRegion.Add(object);
    } else {
      throw new Error('Region not found: ' + regionName);
    }
  }

  /**
   *  Raises the notification for updating regions
   *
   * @static
   * @memberof RegionManager
   * @wIgnore
   */
  public static NotifyOfUpdatingRegions(): void {
    RegionManager.UpdatingRegions.fire([]);
  }

  private checkForDeadRegion(regionName: string) {
    if (this.regionsTargets.containsKey(regionName)) {
      let actualTarget: any = this.regionsTargets.getItem(regionName);
      if (actualTarget instanceof WeakRefActualType) {
        actualTarget = actualTarget.deref();
      }
      if (!this.checkIfStillAttached(actualTarget)) {
        this.Regions.Remove(regionName);
      }
    }
  }
  private registerRegionTarget(regionName: string, view: UIElement) {
    this.regionsTargets.setItem(
      regionName,
      weakReferencesSupported ? new WeakRefActualType(view) : view
    );
  }

  private checkIfStillAttached(model) {
    let result = false;
    let tmpModel = model;
    while (tmpModel) {
      result = tmpModel.getValue(regionManagerProperty) !== null;
      if (result) {
        break;
      } else {
        tmpModel = tmpModel.Parent;
      }
    }
    return result;
  }
}

export class RegionCollection implements Iterable<IRegion>, IRegionCollection {
  private regionManager: IRegionManager;
  private regions: SimpleDictionary<string, IRegion> = new SimpleDictionary<
    string,
    IRegion
  >();

  constructor(regionManager: IRegionManager) {
    this.regionManager = regionManager;
  }

  Add(region: IRegion): void {
    if (region == null) {
      throw new Error('Region is null.');
    }
    if (region.Name == null) {
      throw new InvalidOperationException('Region cannot be empty');
    }
    RegionManager.NotifyOfUpdatingRegions();
    if (this.getItem(region.Name) != null) {
      throw new InvalidOperationException('Region already exist');
    }
    this.regions.add([region.Name, region]);
    region.RegionManager = this.regionManager;
  }

  Remove(regionName: string): boolean {
    let exists = this.regions.containsKey(regionName);
    if (exists) {
      this.regions.removeEntry(regionName);
      RegionManager.NotifyOfUpdatingRegions();
    } else {
      RegionManager.NotifyOfUpdatingRegions();
      exists = this.regions.containsKey(regionName);
      if (exists) {
        this.regions.removeEntry(regionName);
      }
    }
    return exists;
  }

  ContainsRegionWithName(regionName: string): boolean {
    RegionManager.NotifyOfUpdatingRegions();
    return this.regions.containsKey(regionName);
  }

  tryGetValue(key: string, valueFunc: (v: IRegion) => void): boolean {
    return this.regions.tryGetValue(key, valueFunc);
  }

  getItem(regionName: string): IRegion {
    RegionManager.NotifyOfUpdatingRegions();
    return this.regions.getItem(regionName);
  }

  [Symbol.iterator](): Iterator<IRegion, any, undefined> {
    RegionManager.NotifyOfUpdatingRegions();
    return this.regions.values[Symbol.iterator]();
  }
}

result-matching ""

    No results matching ""