@singularsystems/neo-core 1.0.10 → 1.0.12

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.
@@ -1,11 +1,39 @@
1
+ import { IDisposable } from "../Misc";
2
+ interface IRelativePosition {
3
+ left?: number;
4
+ right?: number;
5
+ /** Indicates that there is not enough space at the bottom of the anchor. Popup should be displayed on top. */
6
+ onTop: boolean;
7
+ anchorHeight: number;
8
+ popupHeight: number;
9
+ }
1
10
  export default class PositionHelper {
2
11
  /**
3
12
  * Ensures that a popup element is positioned so that it remains in the bounds of the screen by left/right/top/bottom aligning it relative to the anchor element.
4
- * @param trigger The element to which the popup is anchored
13
+ * @param anchor The element to which the popup is anchored
5
14
  * @param popup The element which pops up from the anchor.
6
15
  * @param fromBottom True if the popups bottom style property must be set. Set to false if there are buttons at the top of the popup and the popups height may change.
7
16
  * @param alignRight True if the popup must be aligned to the anchors right position.
8
17
  * @param hAlign Horizontal alignment of the popup edge relative to the anchor edge. Overrides alignRight
9
18
  */
10
19
  static checkScreenBounds(anchor: HTMLElement, popup: HTMLElement, fromBottom?: boolean, alignRight?: boolean, hAlign?: "left" | "center" | "right"): void;
20
+ /**
21
+ * Ensures that a popup element is positioned so that it remains in the bounds of the screen by left/right/top/bottom aligning it relative to the anchor element.
22
+ * @param anchor The element to which the popup is anchored
23
+ * @param popup The element which pops up from the anchor.
24
+ * @param alignRight True if the popup must be aligned to the anchors right position.
25
+ * @param hAlign Horizontal alignment of the popup edge relative to the anchor edge. Overrides alignRight
26
+ */
27
+ static getRelativePosition(anchor: HTMLElement, popup: HTMLElement, alignRight?: boolean, hAlign?: "left" | "center" | "right"): IRelativePosition;
28
+ }
29
+ /** Helper used to position elements with position: fixed relative to another element, while maintaining position on scroll. */
30
+ export declare class FixedPositionHelper implements IDisposable {
31
+ private anchorElement;
32
+ private popupElement;
33
+ private topOffset;
34
+ private positionInfo;
35
+ constructor(anchorElement: HTMLElement, popupElement: HTMLElement, alignRight?: boolean, hAlign?: "left" | "center" | "right");
36
+ private positionPopup;
37
+ dispose(): void;
11
38
  }
39
+ export {};
@@ -3,7 +3,7 @@ var PositionHelper = /** @class */ (function () {
3
3
  }
4
4
  /**
5
5
  * Ensures that a popup element is positioned so that it remains in the bounds of the screen by left/right/top/bottom aligning it relative to the anchor element.
6
- * @param trigger The element to which the popup is anchored
6
+ * @param anchor The element to which the popup is anchored
7
7
  * @param popup The element which pops up from the anchor.
8
8
  * @param fromBottom True if the popups bottom style property must be set. Set to false if there are buttons at the top of the popup and the popups height may change.
9
9
  * @param alignRight True if the popup must be aligned to the anchors right position.
@@ -12,23 +12,50 @@ var PositionHelper = /** @class */ (function () {
12
12
  PositionHelper.checkScreenBounds = function (anchor, popup, fromBottom, alignRight, hAlign) {
13
13
  if (fromBottom === void 0) { fromBottom = true; }
14
14
  if (alignRight === void 0) { alignRight = false; }
15
- var popupHeight = popup.offsetHeight;
16
- var containerScreenRect = anchor.getBoundingClientRect();
17
- // Vertical
18
- if (containerScreenRect.bottom + anchor.offsetHeight + popupHeight > window.innerHeight - 20 && containerScreenRect.top > popupHeight) {
15
+ var position = this.getRelativePosition(anchor, popup, alignRight, hAlign);
16
+ if (position.onTop) {
19
17
  if (fromBottom) {
20
18
  popup.style.top = "auto";
21
19
  popup.style.bottom = "100%";
22
20
  }
23
21
  else {
24
22
  popup.style.bottom = "";
25
- popup.style.top = -(popupHeight) + "px";
23
+ popup.style.top = -(position.popupHeight) + "px";
26
24
  }
27
25
  }
28
26
  else {
29
27
  popup.style.top = "100%";
30
28
  popup.style.bottom = "auto";
31
29
  }
30
+ if (position.right) {
31
+ popup.style.left = "auto";
32
+ popup.style.right = position.right + "px";
33
+ }
34
+ else if (position.left) {
35
+ popup.style.left = position.left + "px";
36
+ popup.style.right = "";
37
+ }
38
+ };
39
+ /**
40
+ * Ensures that a popup element is positioned so that it remains in the bounds of the screen by left/right/top/bottom aligning it relative to the anchor element.
41
+ * @param anchor The element to which the popup is anchored
42
+ * @param popup The element which pops up from the anchor.
43
+ * @param alignRight True if the popup must be aligned to the anchors right position.
44
+ * @param hAlign Horizontal alignment of the popup edge relative to the anchor edge. Overrides alignRight
45
+ */
46
+ PositionHelper.getRelativePosition = function (anchor, popup, alignRight, hAlign) {
47
+ if (alignRight === void 0) { alignRight = false; }
48
+ var popupHeight = popup.offsetHeight;
49
+ var containerScreenRect = anchor.getBoundingClientRect();
50
+ var position = {
51
+ popupHeight: popupHeight,
52
+ anchorHeight: anchor.offsetHeight,
53
+ };
54
+ // Vertical
55
+ if (containerScreenRect.bottom + anchor.offsetHeight + popupHeight > window.innerHeight - 20 && containerScreenRect.top > popupHeight) {
56
+ position.onTop = true;
57
+ position.popupHeight = popupHeight;
58
+ }
32
59
  // Horizontal
33
60
  var popupWidth = popup.offsetWidth;
34
61
  if (!hAlign) {
@@ -36,8 +63,7 @@ var PositionHelper = /** @class */ (function () {
36
63
  }
37
64
  var isRightAligned = hAlign === "right" && (containerScreenRect.right - popupWidth >= 0);
38
65
  if (isRightAligned) {
39
- popup.style.left = "auto";
40
- popup.style.right = "0";
66
+ position.right = 0;
41
67
  }
42
68
  else {
43
69
  var left = 0;
@@ -51,10 +77,46 @@ var PositionHelper = /** @class */ (function () {
51
77
  else if (leftCheck + popup.offsetWidth > window.innerWidth - 20) {
52
78
  left -= (leftCheck + popup.offsetWidth) - (window.innerWidth - 20);
53
79
  }
54
- popup.style.left = left + "px";
55
- popup.style.right = "";
80
+ position.left = left;
56
81
  }
82
+ return position;
57
83
  };
58
84
  return PositionHelper;
59
85
  }());
60
86
  export default PositionHelper;
87
+ /** Helper used to position elements with position: fixed relative to another element, while maintaining position on scroll. */
88
+ var FixedPositionHelper = /** @class */ (function () {
89
+ function FixedPositionHelper(anchorElement, popupElement, alignRight, hAlign) {
90
+ if (alignRight === void 0) { alignRight = false; }
91
+ this.anchorElement = anchorElement;
92
+ this.popupElement = popupElement;
93
+ this.topOffset = 0;
94
+ this.positionInfo = PositionHelper.getRelativePosition(anchorElement, popupElement, alignRight, hAlign);
95
+ if (this.positionInfo.onTop) {
96
+ var style = window.getComputedStyle(popupElement);
97
+ var marginHeight = parseFloat(style.marginBottom) + parseFloat(style.marginTop);
98
+ this.topOffset = -(this.positionInfo.popupHeight + marginHeight);
99
+ }
100
+ else {
101
+ this.topOffset = this.positionInfo.anchorHeight;
102
+ }
103
+ window.addEventListener("scroll", this.positionPopup.bind(this), { capture: true });
104
+ this.positionPopup();
105
+ }
106
+ FixedPositionHelper.prototype.positionPopup = function () {
107
+ var rect = this.anchorElement.getBoundingClientRect();
108
+ this.popupElement.style.top = (rect.top + this.topOffset) + "px";
109
+ this.popupElement.style.right = "auto";
110
+ if (this.positionInfo.left !== undefined) {
111
+ this.popupElement.style.left = (rect.left + this.positionInfo.left) + "px";
112
+ }
113
+ else {
114
+ this.popupElement.style.left = (rect.right - this.popupElement.offsetWidth) + "px";
115
+ }
116
+ };
117
+ FixedPositionHelper.prototype.dispose = function () {
118
+ window.removeEventListener("scroll", this.positionPopup);
119
+ };
120
+ return FixedPositionHelper;
121
+ }());
122
+ export { FixedPositionHelper };
@@ -17,6 +17,6 @@ export { INotification, INotificationOptions } from './Notifications/Notificatio
17
17
  export { INotificationStore } from './Notifications/NotificationStore';
18
18
  export { INotificationHelper } from './Notifications/INotificationHelper';
19
19
  export { ProgressState } from './TaskRunner/ProgressState';
20
- export { default as PositionHelper } from './PositionHelper';
20
+ export { default as PositionHelper, FixedPositionHelper } from './PositionHelper';
21
21
  import * as Tooltip from './TooltipOptions';
22
22
  export { Tooltip };
@@ -8,6 +8,6 @@ export { default as FileManager } from './FileManager/FileManager';
8
8
  export { default as BoundFileManager } from './FileManager/BoundFileManager';
9
9
  export { FileUploadBatch } from './FileManager/FileUploadBatch';
10
10
  export { ProgressState } from './TaskRunner/ProgressState';
11
- export { default as PositionHelper } from './PositionHelper';
11
+ export { default as PositionHelper, FixedPositionHelper } from './PositionHelper';
12
12
  import * as Tooltip from './TooltipOptions';
13
13
  export { Tooltip };
@@ -98,7 +98,7 @@ export declare class PageManager<TCriteria extends ValueObject, TModel extends I
98
98
  taskRunner: ITaskRunner;
99
99
  private hasInitialised;
100
100
  private pageRequest;
101
- private _totalRecords;
101
+ private _totalExternalRecords;
102
102
  private currentData;
103
103
  private initialFetchState;
104
104
  private isInvalidated;
@@ -13,7 +13,7 @@ var PageManager = /** @class */ (function (_super) {
13
13
  _this.modelType = modelType;
14
14
  _this.dataSource = dataSource;
15
15
  _this.hasInitialised = false;
16
- _this._totalRecords = -1;
16
+ _this._totalExternalRecords = -1;
17
17
  _this.currentData = new List(_this.modelType);
18
18
  _this.initialFetchState = "none";
19
19
  _this.isInvalidated = false;
@@ -104,7 +104,7 @@ var PageManager = /** @class */ (function (_super) {
104
104
  });
105
105
  Object.defineProperty(PageManager.prototype, "totalRecords", {
106
106
  get: function () {
107
- return this._totalRecords;
107
+ return this._totalExternalRecords + this.data.length;
108
108
  },
109
109
  enumerable: false,
110
110
  configurable: true
@@ -239,7 +239,7 @@ var PageManager = /** @class */ (function (_super) {
239
239
  switch (_a.label) {
240
240
  case 0:
241
241
  if (totalRecords >= 0) {
242
- this._totalRecords = totalRecords;
242
+ this._totalExternalRecords = totalRecords - pageRecords.length;
243
243
  }
244
244
  newData = List.fromJSArray(this.modelType, pageRecords, this.options.deserialiseOptions);
245
245
  if (!this.options.afterFetch) return [3 /*break*/, 2];
@@ -261,7 +261,6 @@ var PageManager = /** @class */ (function (_super) {
261
261
  * Adds an item to the current page, and increments the total record count.
262
262
  */
263
263
  PageManager.prototype.addRecord = function (item) {
264
- this._totalRecords += 1;
265
264
  if (item.meta) {
266
265
  this.data.push(item);
267
266
  }
@@ -275,7 +274,7 @@ var PageManager = /** @class */ (function (_super) {
275
274
  PageManager.prototype.reset = function () {
276
275
  this.initialFetchState = "none";
277
276
  this.data.set([]);
278
- this._totalRecords = 0;
277
+ this._totalExternalRecords = 0;
279
278
  };
280
279
  /**
281
280
  * Resets the sort properties. A new sort property can be provided.
@@ -351,7 +350,7 @@ var PageManager = /** @class */ (function (_super) {
351
350
  __decorate([
352
351
  Observable(),
353
352
  __metadata("design:type", Number)
354
- ], PageManager.prototype, "_totalRecords", void 0);
353
+ ], PageManager.prototype, "_totalExternalRecords", void 0);
355
354
  __decorate([
356
355
  Observable(),
357
356
  __metadata("design:type", Object)
@@ -32,6 +32,9 @@ export declare class ContainerValidationState extends ValidationState {
32
32
  private displayInfoSome;
33
33
  brokenRules: Array<RuleContextBase>;
34
34
  get hasDetail(): boolean;
35
+ private _isBusy;
36
+ /** Indicates that an async rule is in progress. */
37
+ get isBusy(): boolean;
35
38
  /**
36
39
  * Gets the error display information.
37
40
  * @param canDisplayAll True if the bound controls have de-focused, or the form attempted to submit.
@@ -37,6 +37,7 @@ var ContainerValidationState = /** @class */ (function (_super) {
37
37
  function ContainerValidationState() {
38
38
  var _this = _super !== null && _super.apply(this, arguments) || this;
39
39
  _this.brokenRules = [];
40
+ _this._isBusy = false;
40
41
  return _this;
41
42
  }
42
43
  Object.defineProperty(ContainerValidationState.prototype, "hasDetail", {
@@ -46,6 +47,14 @@ var ContainerValidationState = /** @class */ (function (_super) {
46
47
  enumerable: false,
47
48
  configurable: true
48
49
  });
50
+ Object.defineProperty(ContainerValidationState.prototype, "isBusy", {
51
+ /** Indicates that an async rule is in progress. */
52
+ get: function () {
53
+ return this._isBusy;
54
+ },
55
+ enumerable: false,
56
+ configurable: true
57
+ });
49
58
  /**
50
59
  * Gets the error display information.
51
60
  * @param canDisplayAll True if the bound controls have de-focused, or the form attempted to submit.
@@ -68,6 +77,9 @@ var ContainerValidationState = /** @class */ (function (_super) {
68
77
  ContainerValidationState.prototype.update = function (ruleState) {
69
78
  this.severity = Math.max(this.severity, ruleState.severity);
70
79
  this.forceDisplaySeverity = Math.max(this.forceDisplaySeverity, ruleState.forceDisplaySeverity);
80
+ if (ruleState.severity === RuleSeverity.AsyncBusy || ruleState.forceDisplaySeverity === RuleSeverity.AsyncBusy) {
81
+ this._isBusy = true;
82
+ }
71
83
  };
72
84
  return ContainerValidationState;
73
85
  }(ValidationState));
@@ -8,6 +8,8 @@ export default interface IModelValidator {
8
8
  /** Causes all errors to be displayed regardless of ValidationDisplayMode. */
9
9
  forceShowErrors: boolean;
10
10
  readonly isValid: boolean;
11
+ /** Indicates that an async rule is in progress. */
12
+ readonly isBusy: boolean;
11
13
  /** The max current severity of all rules in this object. */
12
14
  readonly severity: RuleSeverity;
13
15
  /**
@@ -23,6 +23,7 @@ export default class ModelValidator implements IModelValidator {
23
23
  forceShowErrors: boolean;
24
24
  get ruleState(): ContainerValidationState;
25
25
  get isValid(): boolean;
26
+ get isBusy(): boolean;
26
27
  get severity(): import("../ValidationState").RuleSeverity;
27
28
  private checkRules;
28
29
  /**
@@ -63,6 +63,13 @@ var ModelValidator = /** @class */ (function () {
63
63
  enumerable: false,
64
64
  configurable: true
65
65
  });
66
+ Object.defineProperty(ModelValidator.prototype, "isBusy", {
67
+ get: function () {
68
+ return this.ruleState.isBusy;
69
+ },
70
+ enumerable: false,
71
+ configurable: true
72
+ });
66
73
  Object.defineProperty(ModelValidator.prototype, "severity", {
67
74
  get: function () {
68
75
  return this.ruleState.severity;
@@ -14,7 +14,7 @@ export default class PropertyValidator implements IPropertyValidator {
14
14
  get ruleState(): ContainerValidationState;
15
15
  get isValid(): boolean;
16
16
  private checkRules;
17
- /** Infomation about the errors that must be shown on the UI. Independent from whether or not the property is valid. */
17
+ /** Information about the errors that must be shown on the UI. Independent from whether or not the property is valid. */
18
18
  getDisplayState(validationMode: ValidationDisplayMode): ValidationDisplayInfo;
19
19
  /** True if the validation state is final, e.g. the property has blurred, or validation display mode is always. */
20
20
  canDisplayAll(validationMode: ValidationDisplayMode): boolean;
@@ -35,7 +35,7 @@ var PropertyValidator = /** @class */ (function () {
35
35
  }
36
36
  }
37
37
  };
38
- /** Infomation about the errors that must be shown on the UI. Independent from whether or not the property is valid. */
38
+ /** Information about the errors that must be shown on the UI. Independent from whether or not the property is valid. */
39
39
  PropertyValidator.prototype.getDisplayState = function (validationMode) {
40
40
  if (validationMode === ValidationDisplayMode.Never) {
41
41
  return new ValidationDisplayInfo();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularsystems/neo-core",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Core functionality for the Neo client library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",