@singularsystems/neo-core 1.0.12 → 1.0.14
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.
- package/dist/Components/DatePicker/DatePicker.d.ts +2 -1
- package/dist/Components/DatePicker/DatePicker.js +28 -17
- package/dist/Components/PositionHelper.d.ts +12 -3
- package/dist/Components/PositionHelper.js +41 -15
- package/dist/Data/Deserialiser.js +11 -7
- package/dist/Model/Decorators.d.ts +3 -1
- package/dist/Model/Decorators.js +3 -1
- package/dist/Model/IModelBase.d.ts +5 -0
- package/dist/Model/List.d.ts +10 -4
- package/dist/Model/List.js +26 -4
- package/dist/Model/ModelBase.d.ts +1 -1
- package/dist/Model/ModelCreatorBase.js +3 -2
- package/dist/Model/NeoTypeInfo.d.ts +1 -0
- package/dist/Model/NeoTypeInfo.js +7 -0
- package/dist/Model/ObservableValue.d.ts +8 -0
- package/dist/Model/ObservableValue.js +17 -0
- package/dist/Model/PropertyInfo.d.ts +5 -3
- package/dist/Model/PropertyInfo.js +12 -4
- package/dist/Model/index.d.ts +1 -1
- package/dist/Model/index.js +1 -1
- package/package.json +2 -2
|
@@ -10,7 +10,7 @@ export default class DatePicker {
|
|
|
10
10
|
private headerAnimationHelper;
|
|
11
11
|
private inputHasChanged;
|
|
12
12
|
private input;
|
|
13
|
-
private popup
|
|
13
|
+
private popup?;
|
|
14
14
|
private headerContainer;
|
|
15
15
|
private currentHeaderLabel;
|
|
16
16
|
private prevButton;
|
|
@@ -22,6 +22,7 @@ export default class DatePicker {
|
|
|
22
22
|
private boundDateNoTime;
|
|
23
23
|
private today;
|
|
24
24
|
private currentViewDate;
|
|
25
|
+
private positionHelper?;
|
|
25
26
|
constructor(container: HTMLDivElement, options?: IPartialDateProps);
|
|
26
27
|
static mustShowInput(options?: IPartialDateProps): boolean | undefined;
|
|
27
28
|
inputFocused(e: FocusEvent): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import DateUtils from '../../Dates/DateUtils';
|
|
2
2
|
import AnimationHelper from '../AnimationHelper';
|
|
3
3
|
import { YearsInYearView, ProcessedDatePickerOptions } from './DatePickerOptions';
|
|
4
|
-
import
|
|
4
|
+
import { FixedPositionHelper } from '../PositionHelper';
|
|
5
5
|
// TODO: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
|
6
6
|
// TODO: Allow input to be shown with inline picker, and specify position.
|
|
7
7
|
var ViewType;
|
|
@@ -114,6 +114,7 @@ var DatePicker = /** @class */ (function () {
|
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
116
|
DatePicker.prototype.removePopup = function (animate) {
|
|
117
|
+
var _a;
|
|
117
118
|
if (this.popup && !this.options.alwaysShow) {
|
|
118
119
|
if (animate) {
|
|
119
120
|
AnimationHelper.scale(this.popup, DatePicker.AnimationClassName, 1, 0);
|
|
@@ -124,7 +125,9 @@ var DatePicker = /** @class */ (function () {
|
|
|
124
125
|
}
|
|
125
126
|
this.currentHeaderLabel = null;
|
|
126
127
|
this.currentContentTable = null;
|
|
127
|
-
this.popup =
|
|
128
|
+
this.popup = undefined;
|
|
129
|
+
(_a = this.positionHelper) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
130
|
+
this.positionHelper = undefined;
|
|
128
131
|
}
|
|
129
132
|
};
|
|
130
133
|
DatePicker.prototype.setBindValue = function (dateValue, options) {
|
|
@@ -140,7 +143,7 @@ var DatePicker = /** @class */ (function () {
|
|
|
140
143
|
if (options.close) {
|
|
141
144
|
this.removePopup(true);
|
|
142
145
|
}
|
|
143
|
-
if (!options.close ||
|
|
146
|
+
if (!options.close || options.forceDraw) {
|
|
144
147
|
this.resetCurrentViewDate();
|
|
145
148
|
this.populateContentContainer(true);
|
|
146
149
|
}
|
|
@@ -173,9 +176,12 @@ var DatePicker = /** @class */ (function () {
|
|
|
173
176
|
}
|
|
174
177
|
};
|
|
175
178
|
DatePicker.prototype.positionPopup = function (fromBottom) {
|
|
176
|
-
if (this.popup) {
|
|
179
|
+
if (this.popup && !this.options.alwaysShow) {
|
|
177
180
|
var textAlign = this.options.popupAlignRight ? undefined : window.getComputedStyle(this.input).textAlign;
|
|
178
|
-
|
|
181
|
+
if (!this.positionHelper) {
|
|
182
|
+
this.positionHelper = new FixedPositionHelper(this.container, this.popup);
|
|
183
|
+
}
|
|
184
|
+
this.positionHelper.positionPopup(this.options.popupAlignRight, textAlign, fromBottom);
|
|
179
185
|
}
|
|
180
186
|
};
|
|
181
187
|
/**
|
|
@@ -234,15 +240,15 @@ var DatePicker = /** @class */ (function () {
|
|
|
234
240
|
this.popup.addEventListener("mouseenter", function () { return _this.positionPopup(false); });
|
|
235
241
|
this.popup.addEventListener("mouseleave", function () { return _this.positionPopup(true); });
|
|
236
242
|
}
|
|
237
|
-
this.createHeader();
|
|
238
|
-
this.createContentContainer();
|
|
243
|
+
this.createHeader(this.popup);
|
|
244
|
+
this.createContentContainer(this.popup);
|
|
239
245
|
}
|
|
240
246
|
else {
|
|
241
247
|
this.populateContentContainer(true);
|
|
242
248
|
}
|
|
243
249
|
};
|
|
244
|
-
DatePicker.prototype.createHeader = function () {
|
|
245
|
-
var header = this.createAndAppend(
|
|
250
|
+
DatePicker.prototype.createHeader = function (parent) {
|
|
251
|
+
var header = this.createAndAppend(parent, "div", "neo-datepicker-header");
|
|
246
252
|
header.addEventListener("mousedown", function (e) { return e.preventDefault(); });
|
|
247
253
|
this.prevButton = this.createAndAppend(header, "button", "left-button");
|
|
248
254
|
this.prevButton.type = "button";
|
|
@@ -258,7 +264,7 @@ var DatePicker = /** @class */ (function () {
|
|
|
258
264
|
this.nextButton.tabIndex = -1;
|
|
259
265
|
this.nextButton.addEventListener("mousedown", this.nextClick.bind(this));
|
|
260
266
|
};
|
|
261
|
-
DatePicker.prototype.createHeaderLabel = function () {
|
|
267
|
+
DatePicker.prototype.createHeaderLabel = function (displayImmediately) {
|
|
262
268
|
this.currentHeaderLabel = this.createAndAppend(this.headerContainer, "div", "header-text");
|
|
263
269
|
if (this.currentViewType == ViewType.Days) {
|
|
264
270
|
this.currentHeaderLabel.innerText = DateUtils.format(this.currentViewDate, "MMMM yyyy");
|
|
@@ -273,10 +279,15 @@ var DatePicker = /** @class */ (function () {
|
|
|
273
279
|
this.currentHeaderLabel.className += " selectable";
|
|
274
280
|
}
|
|
275
281
|
this.headerAnimationHelper.addChild(this.currentHeaderLabel, false);
|
|
276
|
-
|
|
282
|
+
if (displayImmediately) {
|
|
283
|
+
this.headerAnimationHelper.replace();
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
this.headerAnimationHelper.fade();
|
|
287
|
+
}
|
|
277
288
|
};
|
|
278
|
-
DatePicker.prototype.createContentContainer = function () {
|
|
279
|
-
this.contentContainer = this.createAndAppend(
|
|
289
|
+
DatePicker.prototype.createContentContainer = function (parent) {
|
|
290
|
+
this.contentContainer = this.createAndAppend(parent, "div", "neo-datepicker-content");
|
|
280
291
|
this.contentContainer.addEventListener("mousedown", this.contentClick.bind(this));
|
|
281
292
|
this.contentAnimationHelper = new AnimationHelper(this.contentContainer, DatePicker.AnimationClassName);
|
|
282
293
|
this.populateContentContainer(!!this.options.alwaysShow);
|
|
@@ -298,7 +309,7 @@ var DatePicker = /** @class */ (function () {
|
|
|
298
309
|
this.currentViewDate.setFullYear(this.currentViewDate.getFullYear() - this.options.yearsBeforeInYearView);
|
|
299
310
|
this.createYearsView();
|
|
300
311
|
}
|
|
301
|
-
this.createHeaderLabel();
|
|
312
|
+
this.createHeaderLabel(displayImmediately);
|
|
302
313
|
this.contentAnimationHelper.addChild(this.currentContentTable, true);
|
|
303
314
|
if (displayImmediately) {
|
|
304
315
|
this.contentAnimationHelper.replace();
|
|
@@ -412,12 +423,12 @@ var DatePicker = /** @class */ (function () {
|
|
|
412
423
|
};
|
|
413
424
|
DatePicker.prototype.dayClicked = function (datePartsString) {
|
|
414
425
|
var dateParts = datePartsString.split(",");
|
|
415
|
-
this.setBindValue(new Date(parseInt(dateParts[0]), parseInt(dateParts[1]), parseInt(dateParts[2])), { preserveTime: true, close: true });
|
|
426
|
+
this.setBindValue(new Date(parseInt(dateParts[0]), parseInt(dateParts[1]), parseInt(dateParts[2])), { preserveTime: true, close: true, forceDraw: this.options.alwaysShow });
|
|
416
427
|
};
|
|
417
428
|
DatePicker.prototype.monthClicked = function (monthString) {
|
|
418
429
|
this.currentViewDate.setMonth(parseInt(monthString));
|
|
419
430
|
if (this.options.monthView) {
|
|
420
|
-
this.setBindValue(this.currentViewDate, { preserveTime: true, close: true });
|
|
431
|
+
this.setBindValue(this.currentViewDate, { preserveTime: true, close: true, forceDraw: this.options.alwaysShow });
|
|
421
432
|
}
|
|
422
433
|
else {
|
|
423
434
|
this.currentViewType = ViewType.Days;
|
|
@@ -428,7 +439,7 @@ var DatePicker = /** @class */ (function () {
|
|
|
428
439
|
DatePicker.prototype.yearClicked = function (yearString) {
|
|
429
440
|
this.currentViewDate.setFullYear(parseInt(yearString));
|
|
430
441
|
if (this.options.yearView) {
|
|
431
|
-
this.setBindValue(this.currentViewDate, { preserveTime: true, close: true });
|
|
442
|
+
this.setBindValue(this.currentViewDate, { preserveTime: true, close: true, forceDraw: this.options.alwaysShow });
|
|
432
443
|
}
|
|
433
444
|
else {
|
|
434
445
|
this.currentViewType = ViewType.Months;
|
|
@@ -17,6 +17,10 @@ export default class PositionHelper {
|
|
|
17
17
|
* @param hAlign Horizontal alignment of the popup edge relative to the anchor edge. Overrides alignRight
|
|
18
18
|
*/
|
|
19
19
|
static checkScreenBounds(anchor: HTMLElement, popup: HTMLElement, fromBottom?: boolean, alignRight?: boolean, hAlign?: "left" | "center" | "right"): void;
|
|
20
|
+
/**
|
|
21
|
+
* Used internally by neo. Use `checkScreenBounds` instead of this method.
|
|
22
|
+
*/
|
|
23
|
+
static positionElement(popup: HTMLElement, position: IRelativePosition, fromBottom?: boolean): void;
|
|
20
24
|
/**
|
|
21
25
|
* 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
26
|
* @param anchor The element to which the popup is anchored
|
|
@@ -26,14 +30,19 @@ export default class PositionHelper {
|
|
|
26
30
|
*/
|
|
27
31
|
static getRelativePosition(anchor: HTMLElement, popup: HTMLElement, alignRight?: boolean, hAlign?: "left" | "center" | "right"): IRelativePosition;
|
|
28
32
|
}
|
|
29
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Helper used to position elements with position: fixed relative to another element, while maintaining position on scroll.
|
|
35
|
+
* If popupElement has a display of 'absolute', then normal positioning is performed.
|
|
36
|
+
*/
|
|
30
37
|
export declare class FixedPositionHelper implements IDisposable {
|
|
31
38
|
private anchorElement;
|
|
32
39
|
private popupElement;
|
|
40
|
+
private isFixed;
|
|
33
41
|
private topOffset;
|
|
34
42
|
private positionInfo;
|
|
35
|
-
constructor(anchorElement: HTMLElement, popupElement: HTMLElement
|
|
36
|
-
|
|
43
|
+
constructor(anchorElement: HTMLElement, popupElement: HTMLElement);
|
|
44
|
+
positionPopup(alignRight?: boolean, hAlign?: "left" | "center" | "right", fromBottom?: boolean): void;
|
|
45
|
+
private positionFixedPopup;
|
|
37
46
|
dispose(): void;
|
|
38
47
|
}
|
|
39
48
|
export {};
|
|
@@ -13,6 +13,13 @@ var PositionHelper = /** @class */ (function () {
|
|
|
13
13
|
if (fromBottom === void 0) { fromBottom = true; }
|
|
14
14
|
if (alignRight === void 0) { alignRight = false; }
|
|
15
15
|
var position = this.getRelativePosition(anchor, popup, alignRight, hAlign);
|
|
16
|
+
this.positionElement(popup, position, fromBottom);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Used internally by neo. Use `checkScreenBounds` instead of this method.
|
|
20
|
+
*/
|
|
21
|
+
PositionHelper.positionElement = function (popup, position, fromBottom) {
|
|
22
|
+
if (fromBottom === void 0) { fromBottom = true; }
|
|
16
23
|
if (position.onTop) {
|
|
17
24
|
if (fromBottom) {
|
|
18
25
|
popup.style.top = "auto";
|
|
@@ -84,28 +91,45 @@ var PositionHelper = /** @class */ (function () {
|
|
|
84
91
|
return PositionHelper;
|
|
85
92
|
}());
|
|
86
93
|
export default PositionHelper;
|
|
87
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Helper used to position elements with position: fixed relative to another element, while maintaining position on scroll.
|
|
96
|
+
* If popupElement has a display of 'absolute', then normal positioning is performed.
|
|
97
|
+
*/
|
|
88
98
|
var FixedPositionHelper = /** @class */ (function () {
|
|
89
|
-
function FixedPositionHelper(anchorElement, popupElement
|
|
90
|
-
if (alignRight === void 0) { alignRight = false; }
|
|
99
|
+
function FixedPositionHelper(anchorElement, popupElement) {
|
|
91
100
|
this.anchorElement = anchorElement;
|
|
92
101
|
this.popupElement = popupElement;
|
|
102
|
+
this.isFixed = false;
|
|
93
103
|
this.topOffset = 0;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
if (window.getComputedStyle(popupElement).position === "fixed") {
|
|
105
|
+
this.isFixed = true;
|
|
106
|
+
window.addEventListener("scroll", this.positionFixedPopup.bind(this), { capture: true });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
FixedPositionHelper.prototype.positionPopup = function (alignRight, hAlign, fromBottom) {
|
|
110
|
+
if (alignRight === void 0) { alignRight = false; }
|
|
111
|
+
if (fromBottom === void 0) { fromBottom = true; }
|
|
112
|
+
this.positionInfo = PositionHelper.getRelativePosition(this.anchorElement, this.popupElement, alignRight, hAlign);
|
|
113
|
+
if (this.isFixed) {
|
|
114
|
+
// Fixed, need to add scroll listener.
|
|
115
|
+
if (this.positionInfo.onTop) {
|
|
116
|
+
var style = window.getComputedStyle(this.popupElement);
|
|
117
|
+
var marginHeight = parseFloat(style.marginBottom) + parseFloat(style.marginTop);
|
|
118
|
+
this.topOffset = -(this.positionInfo.popupHeight + marginHeight);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
this.topOffset = this.positionInfo.anchorHeight;
|
|
122
|
+
}
|
|
123
|
+
this.positionFixedPopup();
|
|
99
124
|
}
|
|
100
125
|
else {
|
|
101
|
-
|
|
126
|
+
// Simple positioning relative to container.
|
|
127
|
+
PositionHelper.positionElement(this.popupElement, this.positionInfo, fromBottom);
|
|
102
128
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
FixedPositionHelper.prototype.positionPopup = function () {
|
|
129
|
+
};
|
|
130
|
+
FixedPositionHelper.prototype.positionFixedPopup = function () {
|
|
107
131
|
var rect = this.anchorElement.getBoundingClientRect();
|
|
108
|
-
this.popupElement.style.top = (rect.top + this.topOffset) + "px";
|
|
132
|
+
this.popupElement.style.top = (Math.floor(rect.top) + this.topOffset) + "px";
|
|
109
133
|
this.popupElement.style.right = "auto";
|
|
110
134
|
if (this.positionInfo.left !== undefined) {
|
|
111
135
|
this.popupElement.style.left = (rect.left + this.positionInfo.left) + "px";
|
|
@@ -115,7 +139,9 @@ var FixedPositionHelper = /** @class */ (function () {
|
|
|
115
139
|
}
|
|
116
140
|
};
|
|
117
141
|
FixedPositionHelper.prototype.dispose = function () {
|
|
118
|
-
|
|
142
|
+
if (this.isFixed) {
|
|
143
|
+
window.removeEventListener("scroll", this.positionFixedPopup);
|
|
144
|
+
}
|
|
119
145
|
};
|
|
120
146
|
return FixedPositionHelper;
|
|
121
147
|
}());
|
|
@@ -63,7 +63,7 @@ var Deserialiser = /** @class */ (function () {
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
};
|
|
66
|
-
Deserialiser.prototype.deserialiseArray = function (from, to, type) {
|
|
66
|
+
Deserialiser.prototype.deserialiseArray = function (from, to, type, itemFactory) {
|
|
67
67
|
if (!to) {
|
|
68
68
|
throw "Cannot deserialise array into a non initialised property.";
|
|
69
69
|
}
|
|
@@ -99,7 +99,10 @@ var Deserialiser = /** @class */ (function () {
|
|
|
99
99
|
deserialise = false;
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
102
|
-
if (
|
|
102
|
+
if (itemFactory) {
|
|
103
|
+
toItem = itemFactory(fromItem);
|
|
104
|
+
}
|
|
105
|
+
else if (type) {
|
|
103
106
|
toItem = new type();
|
|
104
107
|
}
|
|
105
108
|
else {
|
|
@@ -130,13 +133,14 @@ var Deserialiser = /** @class */ (function () {
|
|
|
130
133
|
else {
|
|
131
134
|
var mustCreate = !to[key];
|
|
132
135
|
if (mustCreate) {
|
|
133
|
-
to[key] = parentProperty.createValueInstance();
|
|
136
|
+
to[key] = parentProperty.createValueInstance(fromItem);
|
|
134
137
|
}
|
|
135
138
|
this.deserialiseObject(fromItem, to[key], mustCreate);
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
};
|
|
139
142
|
Deserialiser.prototype.deserialiseObject = function (from, to, justCreated) {
|
|
143
|
+
var _a;
|
|
140
144
|
if (!from || !to) {
|
|
141
145
|
throw "From and to objects are required.";
|
|
142
146
|
}
|
|
@@ -173,9 +177,9 @@ var Deserialiser = /** @class */ (function () {
|
|
|
173
177
|
}
|
|
174
178
|
else {
|
|
175
179
|
if (fromValue instanceof Array && !propertyInfo.assignOnDeserialise) {
|
|
176
|
-
if (!to[key] || !(to[key] instanceof Array) || to[key].
|
|
180
|
+
if (!to[key] || !(to[key] instanceof Array) || to[key].canDeserialise) {
|
|
177
181
|
// Deserialise into full list.
|
|
178
|
-
this.deserialiseArray(fromValue, to[key], undefined);
|
|
182
|
+
this.deserialiseArray(fromValue, to[key], undefined, (_a = to[key]) === null || _a === void 0 ? void 0 : _a.itemFactory);
|
|
179
183
|
}
|
|
180
184
|
else {
|
|
181
185
|
// Plain array
|
|
@@ -197,7 +201,7 @@ var Deserialiser = /** @class */ (function () {
|
|
|
197
201
|
else {
|
|
198
202
|
var mustCreate = !to[key];
|
|
199
203
|
if (mustCreate) {
|
|
200
|
-
to[key] = propertyInfo.createValueInstance();
|
|
204
|
+
to[key] = propertyInfo.createValueInstance(fromValue);
|
|
201
205
|
}
|
|
202
206
|
this.deserialiseObject(fromValue, to[key], mustCreate);
|
|
203
207
|
}
|
|
@@ -227,7 +231,7 @@ var Deserialiser = /** @class */ (function () {
|
|
|
227
231
|
from.entityIdentifier && from.entityIdentifier.indexOf('000000000000') === -1) {
|
|
228
232
|
toModel.entityIdentifier = from.entityIdentifier;
|
|
229
233
|
}
|
|
230
|
-
if (!this.options.isMap) {
|
|
234
|
+
if (!this.options.isMap && to.isSelfDirty !== undefined) {
|
|
231
235
|
if (!from.trackingState) {
|
|
232
236
|
toModel.isSelfDirty = false;
|
|
233
237
|
toModel.isNew = false;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SerialiseType, DataType, TimeZoneFormat } from './Misc';
|
|
2
|
+
import { IObjectFactoryOptions } from './IModelBase';
|
|
2
3
|
export declare function Display(name: string): (type: any, propertyKey: string) => void;
|
|
3
4
|
/** Indicates that this is a date property. Json strings will be converted to date objects on deserialisation. */
|
|
4
5
|
export declare function Date(timeZoneSerialisation?: TimeZoneFormat): (type: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
@@ -20,10 +21,11 @@ export declare function Observable(isObservable?: boolean): (type: any, property
|
|
|
20
21
|
export declare function NoTracking(serialisation?: SerialiseType): (type: any, propertyKey: string) => void;
|
|
21
22
|
export declare function Serialisation(serialisation: SerialiseType): (type: any, propertyKey: string) => void;
|
|
22
23
|
/** Indicates that this is a list property, and specifies the item type. This is not required if the list is initialised with a value. */
|
|
23
|
-
export declare function ChildList(childType
|
|
24
|
+
export declare function ChildList(childType?: (new () => any) | (() => any) | IObjectFactoryOptions): (type: any, propertyKey: string) => any;
|
|
24
25
|
/** Indicates that this is a child object property, and specifies the child type. This is not required if the property is initialised with a value. */
|
|
25
26
|
export declare function ChildObject(childType: new () => any, isValueObject?: boolean): Function;
|
|
26
27
|
export declare function ChildObject(childType: () => any, isValueObject?: boolean): Function;
|
|
28
|
+
export declare function ChildObject(options: IObjectFactoryOptions, isValueObject?: boolean): Function;
|
|
27
29
|
export declare function Dictionary(valueType: any): (type: any, propertyKey: string) => any;
|
|
28
30
|
export declare function Parent(parentType: () => any): (type: any, propertyKey: string) => void;
|
|
29
31
|
/**
|
package/dist/Model/Decorators.js
CHANGED
|
@@ -85,7 +85,9 @@ export function Serialisation(serialisation) {
|
|
|
85
85
|
export function ChildList(childType) {
|
|
86
86
|
return function (type, propertyKey) {
|
|
87
87
|
var pi = getOrAddPropertyInfo(type, propertyKey);
|
|
88
|
-
|
|
88
|
+
if (childType) {
|
|
89
|
+
pi.setPropertyType(childType);
|
|
90
|
+
}
|
|
89
91
|
if (pi.relationType === RelationType.None) {
|
|
90
92
|
pi.relationType = RelationType.ChildList;
|
|
91
93
|
pi.propertyType = DataType.Array;
|
|
@@ -101,4 +101,9 @@ export interface IModelBase extends INonObservableModelBase {
|
|
|
101
101
|
readonly isDirty: boolean;
|
|
102
102
|
readonly readyToSave: boolean;
|
|
103
103
|
}
|
|
104
|
+
export type ObjectFactory = (rawData: object) => object;
|
|
105
|
+
export interface IObjectFactoryOptions {
|
|
106
|
+
/** Function that creates an instance of an object based on some input data. */
|
|
107
|
+
itemFactory: ObjectFactory;
|
|
108
|
+
}
|
|
104
109
|
export {};
|
package/dist/Model/List.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { ISerialiseOptions } from '../Data/Serialiser';
|
|
2
|
-
import { PlainObject, PartialPlainObject, PlainTrackedObject, IMetaItem } from './IModelBase';
|
|
2
|
+
import { PlainObject, PartialPlainObject, PlainTrackedObject, IMetaItem, ObjectFactory, IObjectFactoryOptions } from './IModelBase';
|
|
3
3
|
import { IDeserialiseOptions } from '../Data/Deserialiser';
|
|
4
4
|
export default class List<T> extends Array<T> {
|
|
5
|
-
childObjectType: (new () => T);
|
|
6
5
|
attachedTo: object | null;
|
|
6
|
+
childObjectType?: new () => T;
|
|
7
|
+
itemFactory?: ObjectFactory;
|
|
7
8
|
private _deletedList;
|
|
8
9
|
get deletedList(): T[];
|
|
10
|
+
get canDeserialise(): ObjectFactory | (new () => T) | undefined;
|
|
9
11
|
private baseMethods;
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Creates an instance of a list. A List is an array with the ability to auto create child instances, and track removed items.
|
|
14
|
+
* @param childObjectType Usually the type that the list contains. Can also pass in options for advanced usage.
|
|
15
|
+
*/
|
|
16
|
+
constructor(childObjectType?: (new () => T) | IObjectFactoryOptions);
|
|
11
17
|
/**
|
|
12
18
|
* Copies the methods and properties from the prototype to the new instance.
|
|
13
19
|
* This is needed because vue / mobx changes the prototype to its own.
|
|
@@ -69,7 +75,7 @@ export default class List<T> extends Array<T> {
|
|
|
69
75
|
removeWithoutTracking(item: T): void;
|
|
70
76
|
private removeItem;
|
|
71
77
|
/** Returns a static meta object containing all the properties of the lists item type. */
|
|
72
|
-
getMetaItem(): IMetaItem;
|
|
78
|
+
getMetaItem(): IMetaItem | null;
|
|
73
79
|
/** True if all items in the list are valid. */
|
|
74
80
|
get isValid(): boolean;
|
|
75
81
|
/** True if any item in the list is dirty, or the list contains any deleted items. */
|
package/dist/Model/List.js
CHANGED
|
@@ -5,10 +5,19 @@ import { ObservableValue } from './ObservableValue';
|
|
|
5
5
|
import { NeoTypeInfo } from './NeoTypeInfo';
|
|
6
6
|
var List = /** @class */ (function (_super) {
|
|
7
7
|
__extends(List, _super);
|
|
8
|
+
/**
|
|
9
|
+
* Creates an instance of a list. A List is an array with the ability to auto create child instances, and track removed items.
|
|
10
|
+
* @param childObjectType Usually the type that the list contains. Can also pass in options for advanced usage.
|
|
11
|
+
*/
|
|
8
12
|
function List(childObjectType) {
|
|
9
13
|
var _this = _super.call(this) || this;
|
|
10
|
-
_this.childObjectType = childObjectType;
|
|
11
14
|
_this._deletedList = new ObservableValue([]);
|
|
15
|
+
if (typeof childObjectType === "function") {
|
|
16
|
+
_this.childObjectType = childObjectType;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
_this.itemFactory = childObjectType === null || childObjectType === void 0 ? void 0 : childObjectType.itemFactory;
|
|
20
|
+
}
|
|
12
21
|
List.copyMethods(_this);
|
|
13
22
|
return _this;
|
|
14
23
|
}
|
|
@@ -19,6 +28,13 @@ var List = /** @class */ (function (_super) {
|
|
|
19
28
|
enumerable: false,
|
|
20
29
|
configurable: true
|
|
21
30
|
});
|
|
31
|
+
Object.defineProperty(List.prototype, "canDeserialise", {
|
|
32
|
+
get: function () {
|
|
33
|
+
return this.itemFactory || this.childObjectType;
|
|
34
|
+
},
|
|
35
|
+
enumerable: false,
|
|
36
|
+
configurable: true
|
|
37
|
+
});
|
|
22
38
|
/**
|
|
23
39
|
* Copies the methods and properties from the prototype to the new instance.
|
|
24
40
|
* This is needed because vue / mobx changes the prototype to its own.
|
|
@@ -80,6 +96,9 @@ var List = /** @class */ (function (_super) {
|
|
|
80
96
|
};
|
|
81
97
|
/** Creates a new item of type T */
|
|
82
98
|
List.prototype.createChild = function () {
|
|
99
|
+
if (!this.childObjectType) {
|
|
100
|
+
throw "Cannot create child, type was not passed to constructor.";
|
|
101
|
+
}
|
|
83
102
|
return new this.childObjectType();
|
|
84
103
|
};
|
|
85
104
|
List.prototype.push = function () {
|
|
@@ -89,7 +108,7 @@ var List = /** @class */ (function (_super) {
|
|
|
89
108
|
items[_i] = arguments[_i];
|
|
90
109
|
}
|
|
91
110
|
items.forEach(function (item) {
|
|
92
|
-
if (!(item instanceof _this.childObjectType)) {
|
|
111
|
+
if (_this.childObjectType && !(item instanceof _this.childObjectType)) {
|
|
93
112
|
throw "Type error, cannot add item of type " + Utils.getTypeName(item.constructor) + " to list of type " + Utils.getTypeName(_this.childObjectType) + ".";
|
|
94
113
|
}
|
|
95
114
|
_this.setParent(item);
|
|
@@ -101,7 +120,7 @@ var List = /** @class */ (function (_super) {
|
|
|
101
120
|
};
|
|
102
121
|
List.prototype.setParent = function (item) {
|
|
103
122
|
if (this.attachedTo) {
|
|
104
|
-
var itemConstructor =
|
|
123
|
+
var itemConstructor = item.constructor.prototype.constructor;
|
|
105
124
|
// set the parent property
|
|
106
125
|
if (itemConstructor.neo) {
|
|
107
126
|
var parentConstructor = this.attachedTo.constructor.prototype.constructor;
|
|
@@ -162,10 +181,13 @@ var List = /** @class */ (function (_super) {
|
|
|
162
181
|
if (this.length) {
|
|
163
182
|
return this[0];
|
|
164
183
|
}
|
|
165
|
-
else {
|
|
184
|
+
else if (this.childObjectType) {
|
|
166
185
|
var ctor = this.childObjectType.prototype.constructor;
|
|
167
186
|
return NeoTypeInfo.ensureInitialised(ctor).metaItem;
|
|
168
187
|
}
|
|
188
|
+
else {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
169
191
|
};
|
|
170
192
|
Object.defineProperty(List.prototype, "isValid", {
|
|
171
193
|
/** True if all items in the list are valid. */
|
|
@@ -83,7 +83,7 @@ export default abstract class ModelBase extends BindableBase implements IModelBa
|
|
|
83
83
|
* ```
|
|
84
84
|
* protected static addBusinessRules(rules: ValidationRules<MyType>) {
|
|
85
85
|
* ``` */
|
|
86
|
-
protected addBusinessRules(validationRules: ValidationRules<
|
|
86
|
+
protected addBusinessRules(validationRules: ValidationRules<ModelBase>): void;
|
|
87
87
|
/**
|
|
88
88
|
* Add custom business rules for this type.
|
|
89
89
|
*/
|
|
@@ -61,11 +61,12 @@ var ModelCreatorBase = /** @class */ (function () {
|
|
|
61
61
|
// @ts-ignore
|
|
62
62
|
var propertyValue = instance[propertyInfo.propertyName];
|
|
63
63
|
if (propertyValue) {
|
|
64
|
-
|
|
64
|
+
var list = propertyValue;
|
|
65
|
+
if (list.itemFactory || list.childObjectType) {
|
|
65
66
|
// This is a list.
|
|
66
67
|
if (propertyInfo.relationType != RelationType.ChildList) {
|
|
67
68
|
// add missing annotation
|
|
68
|
-
propertyInfo = ChildList(
|
|
69
|
+
propertyInfo = ChildList(list.itemFactory ? { itemFactory: list.itemFactory } : list.childObjectType)(instance, propertyInfo.propertyName);
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
else if (propertyValue instanceof ModelBase) {
|
|
@@ -22,6 +22,7 @@ export declare class NeoTypeInfo {
|
|
|
22
22
|
get inheritsBindableBase(): boolean;
|
|
23
23
|
get inheritsModelBase(): boolean;
|
|
24
24
|
get metaItem(): IMetaItem;
|
|
25
|
+
get typeName(): string;
|
|
25
26
|
initialise(objectConstructor: NeoModelConstructor): void;
|
|
26
27
|
private addPropertyInfo;
|
|
27
28
|
getOrAddProperty(propertyName: string): PropertyInfo;
|
|
@@ -55,6 +55,13 @@ var NeoTypeInfo = /** @class */ (function () {
|
|
|
55
55
|
enumerable: false,
|
|
56
56
|
configurable: true
|
|
57
57
|
});
|
|
58
|
+
Object.defineProperty(NeoTypeInfo.prototype, "typeName", {
|
|
59
|
+
get: function () {
|
|
60
|
+
return this.objectConstructor.name;
|
|
61
|
+
},
|
|
62
|
+
enumerable: false,
|
|
63
|
+
configurable: true
|
|
64
|
+
});
|
|
58
65
|
NeoTypeInfo.prototype.initialise = function (objectConstructor) {
|
|
59
66
|
this.objectConstructor = objectConstructor;
|
|
60
67
|
};
|
|
@@ -7,3 +7,11 @@ export declare class ObservableValue<T> implements IObservableValue<T> {
|
|
|
7
7
|
constructor(initialValue: T);
|
|
8
8
|
get peek(): T;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Creates a wrapper around a value with a getter and setter for reading and writing the value.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ValueWrapper<T> implements IObservableValue<T> {
|
|
14
|
+
constructor(getter: () => T, setter: (value: T) => void);
|
|
15
|
+
value: T;
|
|
16
|
+
get peek(): T;
|
|
17
|
+
}
|
|
@@ -24,3 +24,20 @@ var ObservableValue = /** @class */ (function () {
|
|
|
24
24
|
return ObservableValue;
|
|
25
25
|
}());
|
|
26
26
|
export { ObservableValue };
|
|
27
|
+
/**
|
|
28
|
+
* Creates a wrapper around a value with a getter and setter for reading and writing the value.
|
|
29
|
+
*/
|
|
30
|
+
var ValueWrapper = /** @class */ (function () {
|
|
31
|
+
function ValueWrapper(getter, setter) {
|
|
32
|
+
Object.defineProperty(this, "value", { get: getter, set: setter });
|
|
33
|
+
}
|
|
34
|
+
Object.defineProperty(ValueWrapper.prototype, "peek", {
|
|
35
|
+
get: function () {
|
|
36
|
+
return this.value;
|
|
37
|
+
},
|
|
38
|
+
enumerable: false,
|
|
39
|
+
configurable: true
|
|
40
|
+
});
|
|
41
|
+
return ValueWrapper;
|
|
42
|
+
}());
|
|
43
|
+
export { ValueWrapper };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SerialiseType, RelationType, OnChangedOptions, DataType, TimeZoneFormat } from './Misc';
|
|
2
2
|
import { Nullable } from '../Utils';
|
|
3
|
-
import { INonObservableModelBase } from './IModelBase';
|
|
3
|
+
import { INonObservableModelBase, IObjectFactoryOptions, ObjectFactory } from './IModelBase';
|
|
4
4
|
import { Rule } from '../Validation/Rules';
|
|
5
5
|
export type PropertyInfoMap = {
|
|
6
6
|
[index: string]: PropertyInfo;
|
|
@@ -58,6 +58,8 @@ export default class PropertyInfo {
|
|
|
58
58
|
rules: Rule[];
|
|
59
59
|
/** Indicates that this property must be assigned to on de/serialisation. The de/serialiser will not try create a model instance of the object / array. */
|
|
60
60
|
assignOnDeserialise: boolean;
|
|
61
|
+
/** Object factory used for deserialisation. Set by ChildList / ChildObject decorators. */
|
|
62
|
+
itemFactory?: ObjectFactory;
|
|
61
63
|
constructor(propertyName: string);
|
|
62
64
|
/** Gets the readable name of the property. Uses string.readable if Display decorator was not specified. */
|
|
63
65
|
get readableName(): string;
|
|
@@ -67,7 +69,7 @@ export default class PropertyInfo {
|
|
|
67
69
|
get parent(): PropertyInfo | undefined;
|
|
68
70
|
addAttributeRule(rule: Rule): void;
|
|
69
71
|
clone(): PropertyInfo;
|
|
70
|
-
setPropertyType(propertyType: (() => any) | (new () => any)): void;
|
|
72
|
+
setPropertyType(propertyType: (() => any) | (new () => any) | IObjectFactoryOptions): void;
|
|
71
73
|
/**
|
|
72
74
|
* Gets the constructor function of the return type.
|
|
73
75
|
* Returns null if the property has not been decorated with a ChildObject / Parent attribute.
|
|
@@ -78,6 +80,6 @@ export default class PropertyInfo {
|
|
|
78
80
|
* Raises an error if the property has not been decorated with a ChildObject / Parent attribute.
|
|
79
81
|
*/
|
|
80
82
|
get typeWithAssert(): new () => any;
|
|
81
|
-
createValueInstance(): any;
|
|
83
|
+
createValueInstance(data: any): any;
|
|
82
84
|
setupFromInstance(instance: any): void;
|
|
83
85
|
}
|
|
@@ -75,11 +75,16 @@ var PropertyInfo = /** @class */ (function () {
|
|
|
75
75
|
return clone;
|
|
76
76
|
};
|
|
77
77
|
PropertyInfo.prototype.setPropertyType = function (propertyType) {
|
|
78
|
-
if (
|
|
79
|
-
|
|
78
|
+
if (typeof propertyType === "function") {
|
|
79
|
+
if (!propertyType.prototype || !propertyType.prototype.constructor.name) {
|
|
80
|
+
this.typeCallback = propertyType;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this._type = propertyType;
|
|
84
|
+
}
|
|
80
85
|
}
|
|
81
86
|
else {
|
|
82
|
-
this.
|
|
87
|
+
this.itemFactory = propertyType.itemFactory;
|
|
83
88
|
}
|
|
84
89
|
};
|
|
85
90
|
Object.defineProperty(PropertyInfo.prototype, "type", {
|
|
@@ -116,7 +121,10 @@ var PropertyInfo = /** @class */ (function () {
|
|
|
116
121
|
enumerable: false,
|
|
117
122
|
configurable: true
|
|
118
123
|
});
|
|
119
|
-
PropertyInfo.prototype.createValueInstance = function () {
|
|
124
|
+
PropertyInfo.prototype.createValueInstance = function (data) {
|
|
125
|
+
if (this.itemFactory) {
|
|
126
|
+
return this.itemFactory(data);
|
|
127
|
+
}
|
|
120
128
|
try {
|
|
121
129
|
return new this.typeWithAssert();
|
|
122
130
|
}
|
package/dist/Model/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { IBindableBase, IModelBase, NeoModelConstructor, PlainObject, PlainTrack
|
|
|
2
2
|
export { ILookupBase } from './LookupBase';
|
|
3
3
|
export { IPropertyInstance, PropertyAccessor } from './PropertyInstance';
|
|
4
4
|
import PropertyInfo from './PropertyInfo';
|
|
5
|
-
export { IObservableValue, ObservableValue } from './ObservableValue';
|
|
5
|
+
export { IObservableValue, ObservableValue, ValueWrapper } from './ObservableValue';
|
|
6
6
|
export { ObservableProperty } from './ObservableProperty';
|
|
7
7
|
export { ISelectedItem } from './Misc';
|
|
8
8
|
export { ModelFieldInfo, IModelFieldInfoContainer } from './ModelFieldInfo';
|
package/dist/Model/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { PropertyAccessor } from './PropertyInstance';
|
|
2
2
|
import PropertyInfo from './PropertyInfo';
|
|
3
|
-
export { ObservableValue } from './ObservableValue';
|
|
3
|
+
export { ObservableValue, ValueWrapper } from './ObservableValue';
|
|
4
4
|
export { ObservableProperty } from './ObservableProperty';
|
|
5
5
|
export { ModelFieldInfo } from './ModelFieldInfo';
|
|
6
6
|
import * as GraphTraverser from './ModelGraphTraverser';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@singularsystems/neo-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "Core functionality for the Neo client library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@microsoft/signalr": "^6.0.1",
|
|
28
|
-
"axios": "1.
|
|
28
|
+
"axios": "1.7.4",
|
|
29
29
|
"inversify": "^6.0.2",
|
|
30
30
|
"reflect-metadata": "0.1.13",
|
|
31
31
|
"tslib": "2.5.0"
|