@coolon/angular-ui-powerups 12.3.1 → 12.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/bundles/coolon-angular-ui-powerups-cypress.umd.js +297 -93
  2. package/bundles/coolon-angular-ui-powerups-cypress.umd.js.map +1 -1
  3. package/bundles/coolon-angular-ui-powerups.umd.js +408 -288
  4. package/bundles/coolon-angular-ui-powerups.umd.js.map +1 -1
  5. package/coolon-angular-ui-powerups.metadata.json +1 -1
  6. package/cypress/components/aup-command-face.d.ts +2 -5
  7. package/cypress/components/aup-command.d.ts +18 -4
  8. package/cypress/components/aup-navigation.d.ts +0 -1
  9. package/cypress/components/aup-popup-menu.d.ts +2 -0
  10. package/cypress/components/aup-table.d.ts +19 -0
  11. package/cypress/components/button-mixin.d.ts +17 -0
  12. package/cypress/components/button.d.ts +17 -3
  13. package/cypress/coolon-angular-ui-powerups-cypress.d.ts +1 -0
  14. package/cypress/coolon-angular-ui-powerups-cypress.metadata.json +1 -1
  15. package/cypress/exports.d.ts +3 -0
  16. package/cypress/page-element.d.ts +11 -2
  17. package/cypress/page.d.ts +16 -13
  18. package/cypress/path.d.ts +26 -0
  19. package/cypress/section.d.ts +8 -1
  20. package/esm2015/cypress/components/aup-command-face.js +20 -11
  21. package/esm2015/cypress/components/aup-command-face.js.map +1 -1
  22. package/esm2015/cypress/components/aup-command-face.metadata.json +1 -1
  23. package/esm2015/cypress/components/aup-command.js +10 -7
  24. package/esm2015/cypress/components/aup-command.js.map +1 -1
  25. package/esm2015/cypress/components/aup-command.metadata.json +1 -1
  26. package/esm2015/cypress/components/aup-more-menu.js +1 -2
  27. package/esm2015/cypress/components/aup-more-menu.js.map +1 -1
  28. package/esm2015/cypress/components/aup-more-menu.metadata.json +1 -1
  29. package/esm2015/cypress/components/aup-navigation.js +1 -5
  30. package/esm2015/cypress/components/aup-navigation.js.map +1 -1
  31. package/esm2015/cypress/components/aup-popup-menu.js +12 -3
  32. package/esm2015/cypress/components/aup-popup-menu.js.map +1 -1
  33. package/esm2015/cypress/components/aup-popup-menu.metadata.json +1 -1
  34. package/esm2015/cypress/components/aup-table.js +36 -0
  35. package/esm2015/cypress/components/aup-table.js.map +1 -0
  36. package/esm2015/cypress/components/aup-table.metadata.json +1 -0
  37. package/esm2015/cypress/components/button-mixin.js +15 -0
  38. package/esm2015/cypress/components/button-mixin.js.map +1 -0
  39. package/esm2015/cypress/components/button-mixin.metadata.json +1 -0
  40. package/esm2015/cypress/components/button.js +11 -7
  41. package/esm2015/cypress/components/button.js.map +1 -1
  42. package/esm2015/cypress/components/button.metadata.json +1 -1
  43. package/esm2015/cypress/coolon-angular-ui-powerups-cypress.js.map +1 -1
  44. package/esm2015/cypress/coolon-angular-ui-powerups-cypress.metadata.json +1 -1
  45. package/esm2015/cypress/exports.js +3 -0
  46. package/esm2015/cypress/exports.js.map +1 -1
  47. package/esm2015/cypress/exports.metadata.json +1 -1
  48. package/esm2015/cypress/page-element.js +21 -5
  49. package/esm2015/cypress/page-element.js.map +1 -1
  50. package/esm2015/cypress/page-element.metadata.json +1 -1
  51. package/esm2015/cypress/page.js +32 -22
  52. package/esm2015/cypress/page.js.map +1 -1
  53. package/esm2015/cypress/page.metadata.json +1 -1
  54. package/esm2015/cypress/path.js +61 -0
  55. package/esm2015/cypress/path.js.map +1 -0
  56. package/esm2015/cypress/path.metadata.json +1 -0
  57. package/esm2015/cypress/section.js +20 -10
  58. package/esm2015/cypress/section.js.map +1 -1
  59. package/esm2015/lib/components/switch-case/switch-case.component.js +7 -0
  60. package/esm2015/lib/components/switch-case/switch-case.component.js.map +1 -1
  61. package/esm2015/lib/components/switch-case/switch-case.component.metadata.json +1 -1
  62. package/esm2015/lib/components/tables/table/table.component.js +1 -1
  63. package/esm2015/lib/components/tables/table/table.component.js.map +1 -1
  64. package/esm2015/lib/components/tables/table/table.component.metadata.json +1 -1
  65. package/esm2015/lib/components/tables/tree-table/tree-table-component.js +1 -1
  66. package/esm2015/lib/components/tables/tree-table/tree-table-component.js.map +1 -1
  67. package/esm2015/lib/components/tables/tree-table/tree-table-component.metadata.json +1 -1
  68. package/esm2015/lib/place/components/place-outlet/place-outlet.component.js.map +1 -1
  69. package/esm2015/lib/place/components/place-outlet/place-outlet.component.metadata.json +1 -1
  70. package/esm2015/lib/place/guards/consolidated-param-map.js +7 -2
  71. package/esm2015/lib/place/guards/consolidated-param-map.js.map +1 -1
  72. package/esm2015/lib/place/guards/consolidated-param-map.metadata.json +1 -1
  73. package/esm2015/lib/place/guards/place.guard.js +1 -22
  74. package/esm2015/lib/place/guards/place.guard.js.map +1 -1
  75. package/esm2015/lib/place/navigation/place-component-deactivation-handler.js +24 -14
  76. package/esm2015/lib/place/navigation/place-component-deactivation-handler.js.map +1 -1
  77. package/esm2015/lib/place/navigation/place-component-deactivation-handler.metadata.json +1 -1
  78. package/esm2015/lib/place/navigation/session/interactions/synchronise-interaction-context-ids-with-route.js.map +1 -1
  79. package/esm2015/lib/place/navigation/session/interactions/synchronise-interaction-context-ids-with-route.metadata.json +1 -1
  80. package/esm2015/lib/place/place-component.js +67 -5
  81. package/esm2015/lib/place/place-component.js.map +1 -1
  82. package/esm2015/lib/place/place-component.metadata.json +1 -1
  83. package/esm2015/lib/place/place-definition.js +3 -3
  84. package/esm2015/lib/place/place-definition.js.map +1 -1
  85. package/esm2015/lib/place/place-router.js +9 -4
  86. package/esm2015/lib/place/place-router.js.map +1 -1
  87. package/esm2015/lib/place/place-router.metadata.json +1 -1
  88. package/esm2015/lib/place/route/parameter-decorators.js +13 -14
  89. package/esm2015/lib/place/route/parameter-decorators.js.map +1 -1
  90. package/esm2015/lib/place/route/parameter-decorators.metadata.json +1 -1
  91. package/esm2015/lib/place/route/parameter-definition.js +21 -3
  92. package/esm2015/lib/place/route/parameter-definition.js.map +1 -1
  93. package/esm2015/lib/place/route/parameter-definition.metadata.json +1 -1
  94. package/esm2015/lib/place/route/visit-sanitiser.js +1 -1
  95. package/esm2015/lib/place/route/visit-sanitiser.js.map +1 -1
  96. package/esm2015/lib/place/url-snapshot.js +30 -7
  97. package/esm2015/lib/place/url-snapshot.js.map +1 -1
  98. package/esm2015/lib/place/url-snapshot.metadata.json +1 -1
  99. package/esm2015/lib/place/visit.js +7 -7
  100. package/esm2015/lib/place/visit.js.map +1 -1
  101. package/esm2015/lib/place/visit.metadata.json +1 -1
  102. package/fesm2015/coolon-angular-ui-powerups-cypress.js +235 -74
  103. package/fesm2015/coolon-angular-ui-powerups-cypress.js.map +1 -1
  104. package/fesm2015/coolon-angular-ui-powerups.js +367 -267
  105. package/fesm2015/coolon-angular-ui-powerups.js.map +1 -1
  106. package/lib/components/switch-case/switch-case.component.d.ts +7 -0
  107. package/lib/place/guards/consolidated-param-map.d.ts +2 -2
  108. package/lib/place/navigation/place-component-deactivation-handler.d.ts +3 -1
  109. package/lib/place/place-component.d.ts +26 -3
  110. package/lib/place/route/parameter-definition.d.ts +8 -0
  111. package/lib/place/url-snapshot.d.ts +1 -0
  112. package/lib/place/visit.d.ts +4 -4
  113. package/package.json +1 -1
@@ -21,7 +21,7 @@ import { MatTableModule } from '@angular/material/table';
21
21
  import { MatTooltipModule } from '@angular/material/tooltip';
22
22
  import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
23
23
  import { fas } from '@fortawesome/free-solid-svg-icons';
24
- import { GarbageCollector, DelegatingValueModel, assert, UnaryCommand, lang, Dsl, Logger, TrackExternal, ValueModel, StoreInValueModel, Command, MutableListModel, StoreInListModel, Disposable, MutableValueModel, DelegatingListModel, FocusManager, EventListenerList, Form, Guard, Binding, DebugContext, ListModel, MultipleSelectionModel, DelegatingSelectionModel, AbstractComputedListModel, DirtyTrackingForm, ComputedListModel, PageController, Deferred, Functions } from '@coolon/pectin';
24
+ import { GarbageCollector, DelegatingValueModel, assert, UnaryCommand, lang, Dsl, Logger, TrackExternal, ValueModel, StoreInValueModel, Command, MutableListModel, StoreInListModel, Disposable, MutableValueModel, DelegatingListModel, FocusManager, EventListenerList, Form, Guard, Binding, DebugContext, ListModel, MultipleSelectionModel, DelegatingSelectionModel, AbstractComputedListModel, DirtyTrackingForm, ComputedListModel, PageController, Deferred, Trace, Functions } from '@coolon/pectin';
25
25
  import { __decorate, __metadata, __awaiter } from 'tslib';
26
26
  import { DomSanitizer } from '@angular/platform-browser';
27
27
  import * as _ from 'lodash';
@@ -1846,6 +1846,13 @@ SwitchCaseDefaultDirective.decorators = [
1846
1846
  SwitchCaseDefaultDirective.ctorParameters = () => [
1847
1847
  { type: TemplateRef }
1848
1848
  ];
1849
+ /**
1850
+ * @example
1851
+ * <aup-switch-case [switchModel]="booleanModel">
1852
+ * <div *aupSwitchCaseWhen="true"></div>
1853
+ * <div *aupSwitchCaseDefault>The default content</div>
1854
+ * </aup-switch-case>
1855
+ */
1849
1856
  class SwitchCaseComponent extends DisposableComponent {
1850
1857
  constructor(cdr) {
1851
1858
  super();
@@ -3205,7 +3212,7 @@ class TableComponent extends AbstractTableComponent {
3205
3212
  TableComponent.decorators = [
3206
3213
  { type: Component, args: [{
3207
3214
  selector: 'aup-table',
3208
- template: "<div class=\"scroll-container\">\n <table mat-table [dataSource]=\"getModel().dataSource.value\" [trackBy]=\"getModel().trackBy\">\n\n <ng-container *ngFor=\"let column of columns.value; index as index; first as first; last as last\"\n matColumnDef=\"{{column.columnId}}\">\n <th mat-header-cell *matHeaderCellDef [class.flex]=\"column.isFlex()\" [class.hide]=\"!column.isVisible()\">\n <aup-table-header-cell-renderer [column]=\"column\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-header-cell-renderer>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"notifyCellClicked(column, row)\"\n [class.enable-cursor]=\"getModel().isCursorEnabled(column)\"\n [class.flex]=\"column.isFlex()\"\n [class.hide]=\"!column.isVisible()\"\n >\n <aup-table-cell-renderer [column]=\"column\"\n [row]=\"row\"\n [tableModel]=\"getModel()\"\n [editSession]=\"getModel().getEditSessionFor(row)\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-cell-renderer>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnIds.value\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: columnIds.value; let i = index\"\n [ngClass]=\"getModel().getRowClasses(row)\" [class.enable-hover]=\"getModel().isHoverEnabled()\"\n [attr.trackBy]=\"getModel().trackBy(i, row)\"\n ></tr>\n\n </table>\n</div>\n",
3215
+ template: "<div class=\"scroll-container\">\n <table mat-table [dataSource]=\"getModel().dataSource.value\" [trackBy]=\"getModel().trackBy\">\n\n <ng-container *ngFor=\"let column of columns.value; index as index; first as first; last as last\"\n matColumnDef=\"{{column.columnId}}\">\n <th mat-header-cell *matHeaderCellDef [class.flex]=\"column.isFlex()\" [class.hide]=\"!column.isVisible()\">\n <aup-table-header-cell-renderer [column]=\"column\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-header-cell-renderer>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"notifyCellClicked(column, row)\"\n [class.enable-cursor]=\"getModel().isCursorEnabled(column)\"\n [class.flex]=\"column.isFlex()\"\n [class.hide]=\"!column.isVisible()\"\n >\n <aup-table-cell-renderer [column]=\"column\"\n [row]=\"row\"\n [tableModel]=\"getModel()\"\n [editSession]=\"getModel().getEditSessionFor(row)\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-cell-renderer>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnIds.value\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: columnIds.value; let i = index\"\n [ngClass]=\"getModel().getRowClasses(row)\" [class.enable-hover]=\"getModel().isHoverEnabled()\"\n [attr.aup-row-id]=\"getModel().trackBy(i, row)\"\n ></tr>\n\n </table>\n</div>\n",
3209
3216
  providers: [
3210
3217
  { provide: AbstractTableComponent, useExisting: TableComponent }
3211
3218
  ],
@@ -3795,7 +3802,7 @@ class TreeTableComponent extends AbstractTableComponent {
3795
3802
  TreeTableComponent.decorators = [
3796
3803
  { type: Component, args: [{
3797
3804
  selector: 'aup-tree-table',
3798
- template: "<div class=\"scroll-container\">\n <table mat-table [dataSource]=\"getModel().dataSource.value\" [trackBy]=\"getModel().trackBy\">\n\n <ng-container *ngFor=\"let column of columns.value; index as index; first as first; last as last\"\n matColumnDef=\"{{column.columnId}}\">\n <th mat-header-cell *matHeaderCellDef [class.flex]=\"column.isFlex()\" [class.hide]=\"!column.isVisible()\">\n <aup-table-header-cell-renderer [column]=\"column\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-header-cell-renderer>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"notifyCellClicked(column, row)\"\n [class.enable-cursor]=\"getModel().isCursorEnabled(column)\"\n [class.flex]=\"column.isFlex()\"\n [class.hide]=\"!column.isVisible()\"\n >\n <aup-table-cell-renderer [column]=\"column\"\n [row]=\"row\"\n [tableModel]=\"getModel()\"\n [editSession]=\"getModel().getEditSessionFor(row)\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-cell-renderer>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnIds.value\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: columnIds.value; let i = index\"\n [ngClass]=\"getModel().getRowClasses(row)\" [class.enable-hover]=\"getModel().isHoverEnabled()\"\n [attr.trackBy]=\"getModel().trackBy(i, row)\"\n ></tr>\n\n </table>\n</div>\n",
3805
+ template: "<div class=\"scroll-container\">\n <table mat-table [dataSource]=\"getModel().dataSource.value\" [trackBy]=\"getModel().trackBy\">\n\n <ng-container *ngFor=\"let column of columns.value; index as index; first as first; last as last\"\n matColumnDef=\"{{column.columnId}}\">\n <th mat-header-cell *matHeaderCellDef [class.flex]=\"column.isFlex()\" [class.hide]=\"!column.isVisible()\">\n <aup-table-header-cell-renderer [column]=\"column\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-header-cell-renderer>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"notifyCellClicked(column, row)\"\n [class.enable-cursor]=\"getModel().isCursorEnabled(column)\"\n [class.flex]=\"column.isFlex()\"\n [class.hide]=\"!column.isVisible()\"\n >\n <aup-table-cell-renderer [column]=\"column\"\n [row]=\"row\"\n [tableModel]=\"getModel()\"\n [editSession]=\"getModel().getEditSessionFor(row)\"\n [attr.column-index]=\"index\"\n [attr.column-id]=\"column.columnId\"\n [class]=\"getColumnClasses(column.columnId)\"\n ></aup-table-cell-renderer>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnIds.value\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: columnIds.value; let i = index\"\n [ngClass]=\"getModel().getRowClasses(row)\" [class.enable-hover]=\"getModel().isHoverEnabled()\"\n [attr.aup-row-id]=\"getModel().trackBy(i, row)\"\n ></tr>\n\n </table>\n</div>\n",
3799
3806
  providers: [
3800
3807
  { provide: AbstractTableComponent, useExisting: TreeTableComponent }
3801
3808
  ],
@@ -5568,6 +5575,7 @@ InteractionModule.decorators = [
5568
5575
  },] }
5569
5576
  ];
5570
5577
 
5578
+ const PARAMETER_DEFINITION_KEY = Symbol("parameterDefinition");
5571
5579
  class ParameterDefinition {
5572
5580
  constructor(propertyName, options, urlFormat) {
5573
5581
  this.propertyName = propertyName;
@@ -5583,6 +5591,11 @@ class ParameterDefinition {
5583
5591
  get isRouteParameter() {
5584
5592
  return !!this.urlFormat;
5585
5593
  }
5594
+ createBackingModel() {
5595
+ const model = this.backingModelFactory();
5596
+ model[PARAMETER_DEFINITION_KEY] = this;
5597
+ return model;
5598
+ }
5586
5599
  getOptionValue(key) {
5587
5600
  return this.options.getOptional(key, null);
5588
5601
  }
@@ -5594,7 +5607,7 @@ class ParameterDefinition {
5594
5607
  if (returningFromSomewhereElse) {
5595
5608
  const lastKnownVisit = placeHistory.getMostRecentVisitFor(visit.placeDefinition);
5596
5609
  if (this.remember && lastKnownVisit) {
5597
- value = lastKnownVisit.getParameter(this.name);
5610
+ value = lastKnownVisit.getParameterValue(this);
5598
5611
  }
5599
5612
  return this.isEmptyValue(value) ? this.defaultValue : value;
5600
5613
  }
@@ -5604,7 +5617,7 @@ class ParameterDefinition {
5604
5617
  });
5605
5618
  }
5606
5619
  isMissingFrom(visit) {
5607
- return !visit.hasParameter(this.name);
5620
+ return !visit.hasParameter(this);
5608
5621
  }
5609
5622
  }
5610
5623
  (function (ParameterDefinition) {
@@ -5613,6 +5626,7 @@ class ParameterDefinition {
5613
5626
  super(...arguments);
5614
5627
  this.isRouteId = true;
5615
5628
  this.isArray = false;
5629
+ this.backingModelFactory = () => new MutableValueModel();
5616
5630
  }
5617
5631
  isEmptyValue(value) {
5618
5632
  return ___default.isNil(value);
@@ -5627,6 +5641,7 @@ class ParameterDefinition {
5627
5641
  super(...arguments);
5628
5642
  this.isRouteId = false;
5629
5643
  this.isArray = false;
5644
+ this.backingModelFactory = () => new MutableValueModel();
5630
5645
  }
5631
5646
  isEmptyValue(value) {
5632
5647
  return ___default.isNil(value);
@@ -5641,6 +5656,7 @@ class ParameterDefinition {
5641
5656
  super(parameterName, options, urlFormat);
5642
5657
  this.isRouteId = false;
5643
5658
  this.isArray = true;
5659
+ this.backingModelFactory = () => new MutableListModel();
5644
5660
  }
5645
5661
  isEmptyValue(value) {
5646
5662
  return ___default.isNil(value) || value.length < 1;
@@ -5650,6 +5666,14 @@ class ParameterDefinition {
5650
5666
  }
5651
5667
  }
5652
5668
  ParameterDefinition.ArrayParameter = ArrayParameter;
5669
+ function get(model) {
5670
+ const parameterDefinition = model[PARAMETER_DEFINITION_KEY];
5671
+ if (!parameterDefinition) {
5672
+ lang$1.illegalArgument("model hasn't been annotated with @VisitParameter, @VisitParameterList or @RouteId");
5673
+ }
5674
+ return parameterDefinition;
5675
+ }
5676
+ ParameterDefinition.get = get;
5653
5677
  })(ParameterDefinition || (ParameterDefinition = {}));
5654
5678
 
5655
5679
  class PlaceDefinition {
@@ -5699,7 +5723,7 @@ class PlaceDefinition {
5699
5723
  }
5700
5724
  getRouteIdFrom(visit) {
5701
5725
  const routeIdParameterDef = this.getRouteIdParameterDef();
5702
- return routeIdParameterDef ? visit.getParameter(routeIdParameterDef.name) : null;
5726
+ return routeIdParameterDef ? visit.getParameterValue(routeIdParameterDef) : null;
5703
5727
  }
5704
5728
  getFormattedRouteId(visit) {
5705
5729
  // Note: RouteIds are always present in the url and are just empty strings when not defined. This is
@@ -5713,7 +5737,7 @@ class PlaceDefinition {
5713
5737
  this.getVisitParameterDefs({
5714
5738
  includeRouteId, includeRouteParameters: true
5715
5739
  }).forEach(def => {
5716
- const value = visit.getParameter(def.name);
5740
+ const value = visit.getParameterValue(def);
5717
5741
  if (!def.isEmptyValue(value)) {
5718
5742
  if (def.isArray) {
5719
5743
  assert.isArray(value);
@@ -5730,7 +5754,7 @@ class PlaceDefinition {
5730
5754
  getNonRouteParameters(visit) {
5731
5755
  const result = {};
5732
5756
  this.getVisitParameterDefs({ includeNonRouteParameters: true }).forEach(def => {
5733
- const value = visit.getParameter(def.name);
5757
+ const value = visit.getParameterValue(def);
5734
5758
  if (!def.isEmptyValue(value)) {
5735
5759
  result[def.name] = value;
5736
5760
  }
@@ -5794,14 +5818,25 @@ __decorate([
5794
5818
  const DEFINITION_META_DATA_KEY = 'PLACE_DEFINITION_OPTIONS';
5795
5819
  // this one seems ok.
5796
5820
  const ROUTE_PARAMETER_LIST_KEY = Symbol('place:route:parameters');
5821
+ class ParameterChangeInterceptor {
5822
+ constructor(parameterDef, model, callback, options) {
5823
+ }
5824
+ canProceed(nextState, interactionContext) {
5825
+ return __awaiter(this, void 0, void 0, function* () {
5826
+ return true;
5827
+ });
5828
+ }
5829
+ }
5797
5830
  class PlaceComponent extends DisposableComponent {
5798
5831
  constructor() {
5799
5832
  super();
5833
+ this._placeReadyCallbacks = [];
5800
5834
  this.visitModel = new MutableValueModel();
5801
5835
  this._inVisitUpdate = new Guard();
5802
5836
  this._active = new MutableValueModel(false);
5837
+ this._parameterChangeInterceptors = [];
5803
5838
  const { chain, valueOf, before, when, after, observe, switchOn } = Dsl.disposeWith(this);
5804
- when(this._active).becomesTruthy(() => this.onPlaceReady());
5839
+ when(this._active).becomesTruthy(() => this._notifyPlaceReady());
5805
5840
  this.childPlaces = this.placeDefinition.children.map(d => d.component);
5806
5841
  }
5807
5842
  // @Trace()
@@ -5831,7 +5866,7 @@ class PlaceComponent extends DisposableComponent {
5831
5866
  DebugContext.tag(model, `${this.placeDefinition.component.name}.${parameterDef.propertyName}`);
5832
5867
  const binding = this.registerDisposable(new Binding(this.visitModel, model, {
5833
5868
  toRight(visit) {
5834
- const value = visit.getParameter(parameterDef.name);
5869
+ const value = visit.getParameterValue(parameterDef);
5835
5870
  // console.log('push to component', { name: parameterDef.name, value, visit });
5836
5871
  return value;
5837
5872
  },
@@ -5843,18 +5878,68 @@ class PlaceComponent extends DisposableComponent {
5843
5878
  binding.writeRight();
5844
5879
  }
5845
5880
  get placeDefinition() {
5846
- return PlaceComponent.getDefinition(this.constructor);
5881
+ const definition = PlaceComponent.getDefinition(this.constructor);
5882
+ if (!definition) {
5883
+ lang.illegalState(`${this.constructor.name} extends PlaceComponent but doesn't have @Place({..}) decorator.`);
5884
+ }
5885
+ return definition;
5847
5886
  }
5848
5887
  get active() {
5849
5888
  return this._active.readonly;
5850
5889
  }
5890
+ /**
5891
+ * Called by the router to see if this component can deactivate. This isn't called for route parameter changes.
5892
+ * @param interactionContext
5893
+ */
5894
+ _canLeavePlace(interactionContext) {
5895
+ return __awaiter(this, void 0, void 0, function* () {
5896
+ return this.canDeactivate ? this.canDeactivate(interactionContext) : true;
5897
+ });
5898
+ }
5899
+ /**
5900
+ * Called by the router to see if this component can deactivate. This isn't called for route parameter changes.
5901
+ * @param interactionContext
5902
+ * @param nextState
5903
+ */
5904
+ _canChangeRouteParameters(interactionContext, nextState) {
5905
+ return __awaiter(this, void 0, void 0, function* () {
5906
+ if (this._parameterChangeInterceptors.length > 0) {
5907
+ const visit = nextState.createVisitFor(this.placeDefinition);
5908
+ for (let i = 0; i < this._parameterChangeInterceptors.length; i++) {
5909
+ const interceptor = this._parameterChangeInterceptors[i];
5910
+ const keepGoing = yield interceptor.canProceed(visit, interactionContext);
5911
+ if (!keepGoing) {
5912
+ return false;
5913
+ }
5914
+ }
5915
+ }
5916
+ return true;
5917
+ });
5918
+ }
5851
5919
  /**
5852
5920
  * Called by the router when the place is ready to interact after any animations have run.
5853
5921
  */
5854
5922
  _notifyActive(active) {
5855
5923
  this._active.value = active;
5856
5924
  }
5857
- onPlaceReady() {
5925
+ /**
5926
+ * Called by the router when the place is ready to interact after any animations have run.
5927
+ */
5928
+ _notifyPlaceReady() {
5929
+ if (this.onPlaceReady.length === 1) {
5930
+ this._placeReadyCallbacks.forEach(callback => callback());
5931
+ }
5932
+ else {
5933
+ console.warn('Overriding PlaceComponent.onPlaceReady has been deprecated. Use PlaceComponent.onPlaceReady(() => {... do stuff...}) instead.');
5934
+ this.onPlaceReady(undefined);
5935
+ }
5936
+ }
5937
+ onPlaceReady(callback) {
5938
+ this._placeReadyCallbacks.push(callback);
5939
+ }
5940
+ interceptVisitParameterChange(model, callback, options) {
5941
+ const parameterDef = ParameterDefinition.get(model);
5942
+ this._parameterChangeInterceptors.push(new ParameterChangeInterceptor(parameterDef, model, callback, options));
5858
5943
  }
5859
5944
  }
5860
5945
  PlaceComponent.decorators = [
@@ -5894,6 +5979,234 @@ __decorate([
5894
5979
  PlaceComponent.injectDefinition = injectDefinition;
5895
5980
  })(PlaceComponent || (PlaceComponent = {}));
5896
5981
 
5982
+ /**
5983
+ * This a work around for the fact that an activated route with multiple segments doesn't
5984
+ * include the segment params in the paramMap as well as each segment returns an empty
5985
+ * param map even when `parameter`s has content.
5986
+ */
5987
+ class ConsolidatedParameterMap {
5988
+ constructor(urlSegments, paramMap) {
5989
+ this.paramMaps = [];
5990
+ // TODO: can we get all our params from teh url segments? If so we can drop the paramMap altogether.
5991
+ const segmentParams = (urlSegments || []).map(s => new ParamMapAdapter(s.parameters));
5992
+ this.paramMaps = segmentParams
5993
+ .concat(paramMap)
5994
+ .filter(m => !!m); // the activated route param map can be null
5995
+ }
5996
+ get(name) {
5997
+ const paramMap = this.paramMaps.find(m => m.has(name));
5998
+ return paramMap.get(name);
5999
+ }
6000
+ getAll(name) {
6001
+ const paramMap = this.paramMaps.find(m => m.has(name));
6002
+ return paramMap.getAll(name);
6003
+ }
6004
+ has(name) {
6005
+ return !!this.paramMaps.find(m => m.has(name));
6006
+ }
6007
+ get keys() {
6008
+ return this.paramMaps.reduce((result, params) => result.concat(params.keys), []);
6009
+ }
6010
+ }
6011
+ __decorate([
6012
+ Memoize(),
6013
+ __metadata("design:type", Array),
6014
+ __metadata("design:paramtypes", [])
6015
+ ], ConsolidatedParameterMap.prototype, "keys", null);
6016
+ class ParamMapAdapter {
6017
+ constructor(params) {
6018
+ this.params = params;
6019
+ }
6020
+ get(name) {
6021
+ return this.params[name];
6022
+ }
6023
+ getAll(name) {
6024
+ const value = this.get(name);
6025
+ return Array.isArray(value) ? value : [value];
6026
+ }
6027
+ has(name) {
6028
+ return this.keys.includes(name);
6029
+ }
6030
+ get keys() {
6031
+ return Object.keys(this.params);
6032
+ }
6033
+ }
6034
+
6035
+ class Visit {
6036
+ constructor(placeDefinition, visitParameters = {}) {
6037
+ this.placeDefinition = placeDefinition;
6038
+ this.visitParameters = visitParameters;
6039
+ }
6040
+ // @Trace()
6041
+ getRouteId() {
6042
+ return this.placeDefinition.getRouteIdFrom(this);
6043
+ }
6044
+ // @Trace()
6045
+ hasRouteId() {
6046
+ return !_.isNil(this.getRouteId());
6047
+ }
6048
+ /**
6049
+ * Returns the value of the place parameter with the specified name. The parameter
6050
+ * name is taken from the `as` option, e.g. {as: 'aCustomName'} otherwise it is the
6051
+ * same as the the ValueModel property name.
6052
+ * @param parameterDef the visit parameter definition
6053
+ */
6054
+ getParameterValue(parameterDef) {
6055
+ return this.visitParameters[parameterDef.name];
6056
+ }
6057
+ // @Trace()
6058
+ hasParameter(parameterDef) {
6059
+ return Object.keys(this.visitParameters).includes(parameterDef.name);
6060
+ }
6061
+ replace(parameter, value) {
6062
+ return new Visit(this.placeDefinition, Object.assign(Object.assign({}, this.visitParameters), { [parameter.name]: value }));
6063
+ }
6064
+ mergeRouteParameters(routeParams) {
6065
+ // todo: whitelist parameters.
6066
+ const routeParameterKeys = Object.keys(routeParams);
6067
+ const params = {};
6068
+ this.placeDefinition.getVisitParameterDefs().forEach(def => {
6069
+ if (def.isRouteId || def.isRouteParameter) {
6070
+ if (routeParameterKeys.includes(def.name)) {
6071
+ params[def.name] = routeParams[def.name];
6072
+ }
6073
+ }
6074
+ else {
6075
+ // copy non route params as is, but only if they already exist otherwise we'll inject nil values and break the
6076
+ // defaults and remember sanitisation process.
6077
+ const value = this.getParameterValue(def);
6078
+ if (this.hasParameter(def)) {
6079
+ params[def.name] = value;
6080
+ }
6081
+ }
6082
+ });
6083
+ return new Visit(this.placeDefinition, params);
6084
+ }
6085
+ hasRoutingChangedFrom(other) {
6086
+ const samePlace = other.placeDefinition === this.placeDefinition;
6087
+ const sameRouteParameters = _.isEqual(this.placeDefinition.getFormattedRouteParameters(this, true), this.placeDefinition.getFormattedRouteParameters(other, true));
6088
+ return !samePlace || !sameRouteParameters;
6089
+ }
6090
+ hasChangedFrom(other) {
6091
+ const sameNonRouteParameters = _.isEqual(this.placeDefinition.getNonRouteParameters(this), this.placeDefinition.getNonRouteParameters(other));
6092
+ return !sameNonRouteParameters || this.hasRoutingChangedFrom(other);
6093
+ }
6094
+ toDebugString() {
6095
+ return Object.keys(this.visitParameters).map(k => `${k}=${this.visitParameters[k]}`).join(',');
6096
+ }
6097
+ }
6098
+
6099
+ function extractPrimarySegments(urlTree) {
6100
+ return urlTree.root.children.primary.segments;
6101
+ }
6102
+ class UrlSnapshot {
6103
+ // TODO: Update this accept a url Parser so it can be immutable and generate new trees on mutation using toString() are parseUrl.
6104
+ constructor(urlSerializer, url) {
6105
+ this.urlSerializer = urlSerializer;
6106
+ this.url = url;
6107
+ this.urlTree = urlSerializer.parse(url);
6108
+ }
6109
+ updateVisitSegments(visit) {
6110
+ const newUrlTree = this.urlSerializer.parse(this.url);
6111
+ // Ugly, but it works for now.
6112
+ const segments = [...extractPrimarySegments(newUrlTree)];
6113
+ const visitSegments = this.getSegmentsFor(visit);
6114
+ const replaceAt = segments.findIndex(segment => segment.path === visitSegments[0].path);
6115
+ // do not use the return value, it's the items that were removed!
6116
+ segments.splice(replaceAt, visitSegments.length, ...visitSegments);
6117
+ newUrlTree.root.children.primary.segments = segments;
6118
+ return new UrlSnapshot(this.urlSerializer, newUrlTree.toString());
6119
+ }
6120
+ getPrimarySegments() {
6121
+ return extractPrimarySegments(this.urlTree);
6122
+ }
6123
+ /**
6124
+ * Converts the visit into segments. Please not that these segments are not e
6125
+ * @param visit
6126
+ */
6127
+ getSegmentsFor(visit) {
6128
+ return visit.placeDefinition.hasRouteId() ?
6129
+ [
6130
+ // NOTE:
6131
+ // It's important to attach the params to the root path and not the id. If we attach them
6132
+ // to an empty id then the angular router won't match the pattern.
6133
+ new UrlSegment(visit.placeDefinition.path, visit.placeDefinition.getFormattedRouteParameters(visit)),
6134
+ new UrlSegment(visit.placeDefinition.getFormattedRouteId(visit), {})
6135
+ ]
6136
+ :
6137
+ [
6138
+ new UrlSegment(visit.placeDefinition.path, visit.placeDefinition.getFormattedRouteParameters(visit))
6139
+ ];
6140
+ }
6141
+ includesPathOf(placeDef) {
6142
+ return this.getPrimarySegments().find(s => s.path === placeDef.path);
6143
+ }
6144
+ createVisitFor(placeDef) {
6145
+ return new Visit(placeDef, new ConsolidatedParameterMap(this.getPrimarySegments()));
6146
+ }
6147
+ getInteractionIds() {
6148
+ const queryParam = this.urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM];
6149
+ if (queryParam) {
6150
+ return UrlSnapshot.parseInteractionIds(queryParam);
6151
+ }
6152
+ else {
6153
+ return [];
6154
+ }
6155
+ }
6156
+ hasInteractions() {
6157
+ return this.getInteractionIds().length > 0;
6158
+ }
6159
+ hasInteractionIds(ids) {
6160
+ return ___default.isEqual(this.getInteractionIds(), ids);
6161
+ }
6162
+ // @Trace()
6163
+ updateInteractionIds(ids) {
6164
+ if (ids.length === 0) {
6165
+ return this.removeInteractionIds();
6166
+ }
6167
+ else {
6168
+ const urlTree = this.urlSerializer.parse(this.url);
6169
+ urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM] = UrlSnapshot.createPathIdFor(ids);
6170
+ return new UrlSnapshot(this.urlSerializer, urlTree.toString());
6171
+ }
6172
+ }
6173
+ // @Trace()
6174
+ removeInteractionIds() {
6175
+ const urlTree = this.urlSerializer.parse(this.url);
6176
+ if (urlTree.queryParams && urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM]) {
6177
+ urlTree.queryParams = {}; //[UrlSnapshot.INTERACTION_ROUTER_OUTLET]
6178
+ }
6179
+ return new UrlSnapshot(this.urlSerializer, urlTree.toString());
6180
+ }
6181
+ toString() {
6182
+ return `UrlSnapshot(${this.url})`;
6183
+ }
6184
+ }
6185
+ __decorate([
6186
+ Trace(),
6187
+ __metadata("design:type", Function),
6188
+ __metadata("design:paramtypes", [Visit]),
6189
+ __metadata("design:returntype", UrlSnapshot)
6190
+ ], UrlSnapshot.prototype, "updateVisitSegments", null);
6191
+ __decorate([
6192
+ Memoize(),
6193
+ __metadata("design:type", Function),
6194
+ __metadata("design:paramtypes", []),
6195
+ __metadata("design:returntype", Array)
6196
+ ], UrlSnapshot.prototype, "getPrimarySegments", null);
6197
+ (function (UrlSnapshot) {
6198
+ UrlSnapshot.INTERACTION_QUERY_PARAM = 'aup-interactions';
6199
+ UrlSnapshot.INTERACTION_ID_SEPARATOR = '--';
6200
+ function parseInteractionIds(path) {
6201
+ return path.split(UrlSnapshot.INTERACTION_ID_SEPARATOR);
6202
+ }
6203
+ UrlSnapshot.parseInteractionIds = parseInteractionIds;
6204
+ function createPathIdFor(interactionIds) {
6205
+ return interactionIds.join(UrlSnapshot.INTERACTION_ID_SEPARATOR);
6206
+ }
6207
+ UrlSnapshot.createPathIdFor = createPathIdFor;
6208
+ })(UrlSnapshot || (UrlSnapshot = {}));
6209
+
5897
6210
  /**
5898
6211
  * This class handles the logic around canDeactivate for a given router state transition. It's core responsibilities are:
5899
6212
  * 1. Ensure we only ask the component to deactivate once on a given navigation cycle (since visit sanitisation can result in multiple round trips to through the router.)
@@ -5914,6 +6227,9 @@ class PlaceComponentDeactivationHandler {
5914
6227
  get urlService() {
5915
6228
  return this.navigationSession.urlService;
5916
6229
  }
6230
+ get placeDefinition() {
6231
+ return this.component.placeDefinition;
6232
+ }
5917
6233
  // @Trace()
5918
6234
  canDeactivate(currentUrl, nextState) {
5919
6235
  return __awaiter(this, void 0, void 0, function* () {
@@ -5927,7 +6243,6 @@ class PlaceComponentDeactivationHandler {
5927
6243
  return this.canDeactivatePromise;
5928
6244
  });
5929
6245
  }
5930
- // @Trace()
5931
6246
  canDeactivateComponent(currentUrl, nextState) {
5932
6247
  return __awaiter(this, void 0, void 0, function* () {
5933
6248
  // Automatically cancel any active activities if the navigation session was triggered by the back button.
@@ -5949,31 +6264,38 @@ class PlaceComponentDeactivationHandler {
5949
6264
  }
5950
6265
  }
5951
6266
  }
5952
- // Ok, so now we're really leaving, so we ask the component if we should.;
5953
- if (this.isNotJustAChangeInRouteId(nextState)) {
5954
- if (this.component.canDeactivate) {
5955
- // No interaction in progress, so ask the component .
5956
- // This may start an interaction, hence checking the interaction context before now. I.e. if the place pops up the dialog, and
5957
- // the user clicks back again, we'll re-enter here and go bang when the component tries to open another dialog.
5958
- return this.component.canDeactivate(this.navigationSession.canDeactivateInteractionContext);
5959
- }
6267
+ // No interaction in progress, so ask the component .
6268
+ // This may start an interaction, hence checking the interaction context before now. I.e. if the place pops up the dialog, and
6269
+ // the user clicks back again, we'll re-enter here and go bang when the component tries to open another dialog.
6270
+ if (this.isGoingToADifferentPlace(nextState)) {
6271
+ const canLeave = yield this.component._canLeavePlace(this.navigationSession.canDeactivateInteractionContext);
5960
6272
  // The component has an active interaction but no deactivation hook. Rather than guessing what to do
5961
6273
  // we'll just cancel the navigation and print a warning.
5962
- if (this.routerInteractionAdapter.isComponentInteracting(this.component)) {
6274
+ if (canLeave && this.routerInteractionAdapter.isComponentInteracting(this.component)) {
5963
6275
  console.warn('Route changed while component has active interaction, cancelling navigation');
5964
6276
  return false;
5965
6277
  }
6278
+ return canLeave;
6279
+ }
6280
+ else {
6281
+ // either an interaction or visit parameter change.
6282
+ return yield this.component._canChangeRouteParameters(this.navigationSession.canDeactivateInteractionContext, nextState);
5966
6283
  }
5967
- return true;
5968
6284
  });
5969
6285
  }
5970
- isNotJustAChangeInRouteId(nextState) {
6286
+ isGoingToADifferentPlace(nextState) {
5971
6287
  // Because places with a route-id cover two route segments we get asked to deactivate
5972
6288
  // if the route id is added or removed. So if our path is still present the url
5973
6289
  // then we shouldn't deactivate the place.
5974
6290
  return !nextState.includesPathOf(this.component.placeDefinition);
5975
6291
  }
5976
6292
  }
6293
+ __decorate([
6294
+ Trace(),
6295
+ __metadata("design:type", Function),
6296
+ __metadata("design:paramtypes", [UrlSnapshot, UrlSnapshot]),
6297
+ __metadata("design:returntype", Promise)
6298
+ ], PlaceComponentDeactivationHandler.prototype, "canDeactivateComponent", null);
5977
6299
 
5978
6300
  /**
5979
6301
  * Transient states
@@ -6803,99 +7125,6 @@ PlaceHistory.ctorParameters = () => [];
6803
7125
  // }
6804
7126
  })(PlaceHistory || (PlaceHistory = {}));
6805
7127
 
6806
- class UrlSnapshot {
6807
- // TODO: Update this accept a url Parser so it can be immutable and generate new trees on mutation using toString() are parseUrl.
6808
- constructor(urlSerializer, url) {
6809
- this.urlSerializer = urlSerializer;
6810
- this.url = url;
6811
- this.urlTree = urlSerializer.parse(url);
6812
- }
6813
- updateVisitSegments(visit) {
6814
- const urlTree = this.urlSerializer.parse(this.url);
6815
- // Ugly, but it works for now.
6816
- const segments = [...this.getPrimarySegments(urlTree)];
6817
- const visitSegments = this.getSegmentsFor(visit);
6818
- const replaceAt = segments.findIndex(segment => segment.path === visitSegments[0].path);
6819
- // do not use the return value, it's the items that were removed!
6820
- segments.splice(replaceAt, visitSegments.length, ...visitSegments);
6821
- urlTree.root.children.primary.segments = segments;
6822
- return new UrlSnapshot(this.urlSerializer, urlTree.toString());
6823
- }
6824
- getPrimarySegments(urlTree) {
6825
- return this.urlTree.root.children.primary.segments;
6826
- }
6827
- /**
6828
- * Converts the visit into segments. Please not that these segments are not e
6829
- * @param visit
6830
- */
6831
- getSegmentsFor(visit) {
6832
- return visit.placeDefinition.hasRouteId() ?
6833
- [
6834
- // NOTE:
6835
- // It's important to attach the params to the root path and not the id. If we attach them
6836
- // to an empty id then the angular router won't match the pattern.
6837
- new UrlSegment(visit.placeDefinition.path, visit.placeDefinition.getFormattedRouteParameters(visit)),
6838
- new UrlSegment(visit.placeDefinition.getFormattedRouteId(visit), {})
6839
- ]
6840
- :
6841
- [
6842
- new UrlSegment(visit.placeDefinition.path, visit.placeDefinition.getFormattedRouteParameters(visit))
6843
- ];
6844
- }
6845
- includesPathOf(placeDef) {
6846
- return this.getPrimarySegments(this.urlTree).find(s => s.path === placeDef.path);
6847
- }
6848
- getInteractionIds() {
6849
- const queryParam = this.urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM];
6850
- if (queryParam) {
6851
- return UrlSnapshot.parseInteractionIds(queryParam);
6852
- }
6853
- else {
6854
- return [];
6855
- }
6856
- }
6857
- hasInteractions() {
6858
- return this.getInteractionIds().length > 0;
6859
- }
6860
- hasInteractionIds(ids) {
6861
- return ___default.isEqual(this.getInteractionIds(), ids);
6862
- }
6863
- // @Trace()
6864
- updateInteractionIds(ids) {
6865
- if (ids.length === 0) {
6866
- return this.removeInteractionIds();
6867
- }
6868
- else {
6869
- const urlTree = this.urlSerializer.parse(this.url);
6870
- urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM] = UrlSnapshot.createPathIdFor(ids);
6871
- return new UrlSnapshot(this.urlSerializer, urlTree.toString());
6872
- }
6873
- }
6874
- // @Trace()
6875
- removeInteractionIds() {
6876
- const urlTree = this.urlSerializer.parse(this.url);
6877
- if (urlTree.queryParams && urlTree.queryParams[UrlSnapshot.INTERACTION_QUERY_PARAM]) {
6878
- urlTree.queryParams = {}; //[UrlSnapshot.INTERACTION_ROUTER_OUTLET]
6879
- }
6880
- return new UrlSnapshot(this.urlSerializer, urlTree.toString());
6881
- }
6882
- toString() {
6883
- return `UrlSnapshot(${this.url})`;
6884
- }
6885
- }
6886
- (function (UrlSnapshot) {
6887
- UrlSnapshot.INTERACTION_QUERY_PARAM = 'aup-interactions';
6888
- UrlSnapshot.INTERACTION_ID_SEPARATOR = '--';
6889
- function parseInteractionIds(path) {
6890
- return path.split(UrlSnapshot.INTERACTION_ID_SEPARATOR);
6891
- }
6892
- UrlSnapshot.parseInteractionIds = parseInteractionIds;
6893
- function createPathIdFor(interactionIds) {
6894
- return interactionIds.join(UrlSnapshot.INTERACTION_ID_SEPARATOR);
6895
- }
6896
- UrlSnapshot.createPathIdFor = createPathIdFor;
6897
- })(UrlSnapshot || (UrlSnapshot = {}));
6898
-
6899
7128
  class UrlService {
6900
7129
  constructor(angularRouter, angularLocation, urlSerializer) {
6901
7130
  this.angularRouter = angularRouter;
@@ -7152,7 +7381,7 @@ class PlaceRouter extends GarbageCollector {
7152
7381
  });
7153
7382
  }
7154
7383
  navigateByUrl(urlSnapshot, navigationExtras) {
7155
- // console.log(`### navigationByUrl -> ${urlSnapshot.urlTree.toString()}`);
7384
+ console.log(`### navigationByUrl -> ${urlSnapshot.urlTree.toString()}`);
7156
7385
  return this.angularRouter.navigateByUrl(urlSnapshot.urlTree, navigationExtras);
7157
7386
  }
7158
7387
  get activeVisits() {
@@ -7218,7 +7447,6 @@ class PlaceRouter extends GarbageCollector {
7218
7447
  * to be able to capture the back button on the first page. If we don't then the back click will exit
7219
7448
  * the app directly and we don't get to ask.
7220
7449
  */
7221
- // @Trace()
7222
7450
  syncInteractionContextIdsWithRouter() {
7223
7451
  if (this.navigationSession) {
7224
7452
  // console.log(`Navigation active -> ${this.navigationSession.toString()}, sync delayed until finished.`);
@@ -7260,6 +7488,12 @@ PlaceRouter.ctorParameters = () => [
7260
7488
  { type: UrlService },
7261
7489
  { type: PlaceHistory }
7262
7490
  ];
7491
+ __decorate([
7492
+ Trace(),
7493
+ __metadata("design:type", Function),
7494
+ __metadata("design:paramtypes", []),
7495
+ __metadata("design:returntype", Promise)
7496
+ ], PlaceRouter.prototype, "syncInteractionContextIdsWithRouter", null);
7263
7497
  (function (PlaceRouter) {
7264
7498
  class State {
7265
7499
  constructor(activeVisits) {
@@ -7275,70 +7509,6 @@ PlaceRouter.ctorParameters = () => [
7275
7509
  PlaceRouter.State = State;
7276
7510
  })(PlaceRouter || (PlaceRouter = {}));
7277
7511
 
7278
- class Visit {
7279
- constructor(placeDefinition, visitParameters = {}) {
7280
- this.placeDefinition = placeDefinition;
7281
- this.visitParameters = visitParameters;
7282
- }
7283
- // @Trace()
7284
- getRouteId() {
7285
- return this.placeDefinition.getRouteIdFrom(this);
7286
- }
7287
- // @Trace()
7288
- hasRouteId() {
7289
- return !_.isNil(this.getRouteId());
7290
- }
7291
- /**
7292
- * Returns the value of the place parameter with the specified name. The parameter
7293
- * name is taken from the `as` option, e.g. {as: 'aCustomName'} otherwise it is the
7294
- * same as the the ValueModel property name.
7295
- * @param parameterName the field name of the property model or the `as` option if specified.
7296
- */
7297
- getParameter(parameterName) {
7298
- return this.visitParameters[parameterName];
7299
- }
7300
- // @Trace()
7301
- hasParameter(parameterName) {
7302
- return Object.keys(this.visitParameters).includes(parameterName);
7303
- }
7304
- replace(parameter, value) {
7305
- return new Visit(this.placeDefinition, Object.assign(Object.assign({}, this.visitParameters), { [parameter.name]: value }));
7306
- }
7307
- mergeRouteParameters(routeParams) {
7308
- // todo: whitelist parameters.
7309
- const routeParameterKeys = Object.keys(routeParams);
7310
- const params = {};
7311
- this.placeDefinition.getVisitParameterDefs().forEach(def => {
7312
- if (def.isRouteId || def.isRouteParameter) {
7313
- if (routeParameterKeys.includes(def.name)) {
7314
- params[def.name] = routeParams[def.name];
7315
- }
7316
- }
7317
- else {
7318
- // copy non route params as is, but only if they already exist otherwise we'll inject nil values and break the
7319
- // defaults and remember sanitisation process.
7320
- const value = this.getParameter(def.name);
7321
- if (this.hasParameter(def.name)) {
7322
- params[def.name] = value;
7323
- }
7324
- }
7325
- });
7326
- return new Visit(this.placeDefinition, params);
7327
- }
7328
- hasRoutingChangedFrom(other) {
7329
- const samePlace = other.placeDefinition === this.placeDefinition;
7330
- const sameRouteParameters = _.isEqual(this.placeDefinition.getFormattedRouteParameters(this, true), this.placeDefinition.getFormattedRouteParameters(other, true));
7331
- return !samePlace || !sameRouteParameters;
7332
- }
7333
- hasChangedFrom(other) {
7334
- const sameNonRouteParameters = _.isEqual(this.placeDefinition.getNonRouteParameters(this), this.placeDefinition.getNonRouteParameters(other));
7335
- return !sameNonRouteParameters || this.hasRoutingChangedFrom(other);
7336
- }
7337
- toDebugString() {
7338
- return Object.keys(this.visitParameters).map(k => `${k}=${this.visitParameters[k]}`).join(',');
7339
- }
7340
- }
7341
-
7342
7512
  const AUP_PLACE_CONFIG = new InjectionToken('AUP_PLACE_CONFIG');
7343
7513
 
7344
7514
  class NotAuthorisedNoticeComponent {
@@ -8000,54 +8170,6 @@ function Place(options) {
8000
8170
  };
8001
8171
  }
8002
8172
 
8003
- /**
8004
- * This a work around for the fact that an activated route with multiple segments doesn't
8005
- * include the segment params in the paramMap as well as each segment returns an empty
8006
- * param map even when `parameter`s has content.
8007
- */
8008
- class ConsolidatedParameterMap {
8009
- constructor(paramMap, urlSegments) {
8010
- this.paramMaps = [paramMap].concat((urlSegments || []).map(s => new ParamMapAdapter(s.parameters))).filter(m => !!m); // the activated route param map can be null
8011
- }
8012
- get(name) {
8013
- const paramMap = this.paramMaps.find(m => m.has(name));
8014
- return paramMap.get(name);
8015
- }
8016
- getAll(name) {
8017
- const paramMap = this.paramMaps.find(m => m.has(name));
8018
- return paramMap.getAll(name);
8019
- }
8020
- has(name) {
8021
- return !!this.paramMaps.find(m => m.has(name));
8022
- }
8023
- get keys() {
8024
- return this.paramMaps.reduce((result, params) => result.concat(params.keys), []);
8025
- }
8026
- }
8027
- __decorate([
8028
- Memoize(),
8029
- __metadata("design:type", Array),
8030
- __metadata("design:paramtypes", [])
8031
- ], ConsolidatedParameterMap.prototype, "keys", null);
8032
- class ParamMapAdapter {
8033
- constructor(params) {
8034
- this.params = params;
8035
- }
8036
- get(name) {
8037
- return this.params[name];
8038
- }
8039
- getAll(name) {
8040
- const value = this.get(name);
8041
- return Array.isArray(value) ? value : [value];
8042
- }
8043
- has(name) {
8044
- return this.keys.includes(name);
8045
- }
8046
- get keys() {
8047
- return Object.keys(this.params);
8048
- }
8049
- }
8050
-
8051
8173
  class NoopAuthGuard {
8052
8174
  constructor() {
8053
8175
  }
@@ -8097,7 +8219,7 @@ class VisitSanitiser {
8097
8219
  let sanitisedVisit = visit;
8098
8220
  for (let i = 0; i < parameterDefs.length; i++) {
8099
8221
  const def = parameterDefs[i];
8100
- const value = visit.getParameter(def.name);
8222
+ const value = visit.getParameterValue(def);
8101
8223
  const sanitisedValue = yield def.sanitise(value, sanitisedVisit, this.placeHistory, this.injector, this.navigationSession.isPopState);
8102
8224
  if (def.hasChanged(value, sanitisedValue)) {
8103
8225
  sanitisedVisit = sanitisedVisit.replace(def, sanitisedValue);
@@ -8134,7 +8256,7 @@ class PlaceGuard {
8134
8256
  }
8135
8257
  const result = yield this.cleanInteractionState(activatedRoute, state, () => __awaiter(this, void 0, void 0, function* () {
8136
8258
  // Parse our route params.
8137
- const params = new ConsolidatedParameterMap(activatedRoute.paramMap, activatedRoute.url);
8259
+ const params = new ConsolidatedParameterMap(activatedRoute.url, activatedRoute.paramMap);
8138
8260
  const parsedParams = placeDefinition.parseRouteParams(params);
8139
8261
  const navigationSession = this.placeRouter.navigationSession;
8140
8262
  const initialVisit = navigationSession.getVisitFor(placeDefinition) || new Visit(placeDefinition, parsedParams);
@@ -8182,27 +8304,6 @@ class PlaceGuard {
8182
8304
  const visit = result instanceof Visit ? result : new Visit(PlaceComponent.getDefinition(result), {});
8183
8305
  return this.urlService.createUrlSnapshot(visit).urlTree;
8184
8306
  }
8185
- // protected async ensureAuthenticatedThen(activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot, next: (placeDefinition: PlaceDefinition) => Promise<boolean | UrlTree>): Promise<boolean | UrlTree> {
8186
- // const authoriseResult = placeDefinition.authenticate ? await this.isAuthorised(activatedRoute, state) : true;
8187
- // if (authoriseResult === true) {
8188
- // // we're authorised, now run the place guards.
8189
- // return next(placeDefinition);
8190
- // } else {
8191
- // console.log('not authorised result', authoriseResult);
8192
- // return authoriseResult;
8193
- // }
8194
- // }
8195
- //
8196
- // // @Trace()
8197
- // protected async ensureAuthorisedThen(activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot, next: (placeDefinition: PlaceDefinition) => Promise<boolean | UrlTree>): Promise<boolean | UrlTree> {
8198
- //
8199
- // }
8200
- // @Trace()
8201
- // async isAuthorised(activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean | UrlTree> {
8202
- // const authorised = this.getAuthGuard(this.injector).canActivate(activatedRoute, state);
8203
- // return (authorised instanceof Observable) ? authorised.toPromise() : authorised;
8204
- // }
8205
- // abstract getAuthGuard(injector: Injector): CanActivate;
8206
8307
  // @Trace()
8207
8308
  cleanInteractionState(route, state, next) {
8208
8309
  return __awaiter(this, void 0, void 0, function* () {
@@ -8263,12 +8364,14 @@ var Formatter;
8263
8364
  Formatter.BOOLEAN = new BooleanType();
8264
8365
  })(Formatter || (Formatter = {}));
8265
8366
 
8266
- function installMechanics(prototype, propertyKey, backingModelFactory, tagPrefix, isEmpty) {
8367
+ function installMechanics(parameterDef, prototype, propertyKey, tagPrefix) {
8368
+ Klass.get(prototype).addToOwnMetadataList(ROUTE_PARAMETER_LIST_KEY, parameterDef);
8267
8369
  function getMechanics(instance, propertyName) {
8268
8370
  const key = `__mechanics_${propertyName.toString()}`;
8269
8371
  if (!instance[key]) {
8372
+ const backingModel = parameterDef.createBackingModel();
8270
8373
  instance[key] = {
8271
- backingModel: backingModelFactory(),
8374
+ backingModel: backingModel,
8272
8375
  binding: null
8273
8376
  };
8274
8377
  const tag = `${tagPrefix}(${prototype.constructor.name}.${propertyKey.toString()})`;
@@ -8292,12 +8395,12 @@ function installMechanics(prototype, propertyKey, backingModelFactory, tagPrefix
8292
8395
  toLeft: Functions.identity,
8293
8396
  toRight: Functions.identity
8294
8397
  });
8295
- if (isEmpty(userModel)) {
8398
+ if (parameterDef.isEmptyValue(userModel.value)) {
8296
8399
  // console.log(`Push visit to model for ${tag}`, {value: mechanics.backingModel.value});
8297
8400
  mechanics.binding.writeRight(); // push the visit into the user model;
8298
8401
  }
8299
8402
  else {
8300
- if (!isEmpty(mechanics.backingModel)) {
8403
+ if (!parameterDef.isEmptyValue(mechanics.backingModel.value)) {
8301
8404
  console.warn('Assigning a visit model with an existing value to a visit parameter with an existing value. Visit parameter will be overridden');
8302
8405
  }
8303
8406
  mechanics.binding.writeLeft(); // push the user model into the visit
@@ -8308,25 +8411,22 @@ function installMechanics(prototype, propertyKey, backingModelFactory, tagPrefix
8308
8411
  }
8309
8412
  function RouteId(type, options) {
8310
8413
  return (prototype, propertyKey) => {
8311
- const param = new ParameterDefinition.RouteId(propertyKey.toString(), options, type);
8312
- Klass.get(prototype).addToOwnMetadataList(ROUTE_PARAMETER_LIST_KEY, param);
8313
- installMechanics(prototype, propertyKey, () => new MutableValueModel(), '@RouteId', m => m.query().isNil());
8414
+ const parameterDef = new ParameterDefinition.RouteId(propertyKey.toString(), options, type);
8415
+ installMechanics(parameterDef, prototype, propertyKey, '@RouteId');
8314
8416
  };
8315
8417
  }
8316
8418
  function VisitParameter(options) {
8317
8419
  const opts = Opts.get(options);
8318
8420
  return (prototype, propertyKey) => {
8319
- const param = new ParameterDefinition.ValueParameter(propertyKey.toString(), options, opts.getOptional('storeInUrl', null));
8320
- Klass.get(prototype).addToOwnMetadataList(ROUTE_PARAMETER_LIST_KEY, param);
8321
- installMechanics(prototype, propertyKey, () => new MutableValueModel(), '@VisitParameter', m => m.query().isNil());
8421
+ const parameterDef = new ParameterDefinition.ValueParameter(propertyKey.toString(), options, opts.getOptional('storeInUrl', null));
8422
+ installMechanics(parameterDef, prototype, propertyKey, '@VisitParameter');
8322
8423
  };
8323
8424
  }
8324
8425
  function VisitParameterList(options) {
8325
8426
  const opts = Opts.get(options);
8326
8427
  return (prototype, propertyKey) => {
8327
- const param = new ParameterDefinition.ArrayParameter(propertyKey.toString(), options, opts.getOptional('storeInUrl', null));
8328
- Klass.get(prototype).addToOwnMetadataList(ROUTE_PARAMETER_LIST_KEY, param);
8329
- installMechanics(prototype, propertyKey, () => new MutableListModel(), '@VisitParameterList', m => m.query().isEmpty());
8428
+ const parameterDef = new ParameterDefinition.ArrayParameter(propertyKey.toString(), options, opts.getOptional('storeInUrl', null));
8429
+ installMechanics(parameterDef, prototype, propertyKey, '@VisitParameterList');
8330
8430
  };
8331
8431
  }
8332
8432