@onehat/data 1.22.26 → 1.22.28
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/cypress/e2e/Property/Mixed.cy.js +105 -0
- package/package.json +6 -6
- package/src/Property/Mixed.js +408 -0
- package/src/Property/index.js +2 -0
- package/src/Repository/OneBuild.js +22 -12
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import PropertyTypes from '../../../src/Property/index.js';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
|
|
4
|
+
describe('MixedProperty', function() {
|
|
5
|
+
|
|
6
|
+
beforeEach(function() {
|
|
7
|
+
const
|
|
8
|
+
definition = {
|
|
9
|
+
type: 'mixed',
|
|
10
|
+
types: [
|
|
11
|
+
'int',
|
|
12
|
+
'string',
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
Property = PropertyTypes[definition.type];
|
|
16
|
+
this.property = new Property(definition);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('className', function() {
|
|
20
|
+
const className = this.property.getClassName();
|
|
21
|
+
expect(className).to.be.eq('Mixed');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('events are handled properly', function() {
|
|
25
|
+
this.property.on('change', (property, oldValue, newValue) => {
|
|
26
|
+
if (property.getCurrentType() === 'int') {
|
|
27
|
+
expect(oldValue).to.be.eq(null);
|
|
28
|
+
expect(newValue).to.be.eq(42);
|
|
29
|
+
} else {
|
|
30
|
+
expect(oldValue).to.be.eq(null);
|
|
31
|
+
expect(newValue).to.be.eq('here');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
this.property.setValue(42);
|
|
36
|
+
this.property.setValue('here');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('direct methods', function() {
|
|
40
|
+
|
|
41
|
+
it('getCurrentType', function() {
|
|
42
|
+
const currentType = this.property.getCurrentType();
|
|
43
|
+
expect(currentType).to.be.eq('int');
|
|
44
|
+
|
|
45
|
+
// switch type
|
|
46
|
+
this.property.setValue('Hello');
|
|
47
|
+
const newCurrentType = this.property.getCurrentType();
|
|
48
|
+
expect(newCurrentType).to.be.eq('string');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('getInternalProperty', function() {
|
|
52
|
+
const intProperty = this.property.getInternalProperty('int');
|
|
53
|
+
expect(intProperty).to.be.not.undefined;
|
|
54
|
+
expect(intProperty.constructor.type).to.be.eq('int');
|
|
55
|
+
|
|
56
|
+
// switch type
|
|
57
|
+
this.property.setValue('Hello');
|
|
58
|
+
const stringProperty = this.property.getInternalProperty('string');
|
|
59
|
+
expect(stringProperty).to.be.not.undefined;
|
|
60
|
+
expect(stringProperty.constructor.type).to.be.eq('string');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('destroy', function() {
|
|
64
|
+
this.property.destroy();
|
|
65
|
+
expect(this.property.internalProperties).to.be.empty;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('passes methods to currentProperty', function() {
|
|
71
|
+
|
|
72
|
+
this.property.setValue(42);
|
|
73
|
+
expect(this.property.getSubmitValue()).to.be.eq(42);
|
|
74
|
+
expect(this.property.getCurrentType()).to.be.eq('int');
|
|
75
|
+
|
|
76
|
+
this.property.setValue('here');
|
|
77
|
+
expect(this.property.getSubmitValue()).to.be.eq('here');
|
|
78
|
+
expect(this.property.getCurrentType()).to.be.eq('string');
|
|
79
|
+
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('passes configs to internal properties', function() {
|
|
83
|
+
const
|
|
84
|
+
definition = {
|
|
85
|
+
type: 'mixed',
|
|
86
|
+
types: [
|
|
87
|
+
{
|
|
88
|
+
type: 'date',
|
|
89
|
+
readFormat: 'YYYY-MM-DD',
|
|
90
|
+
displayFormat: 'YYYY',
|
|
91
|
+
submitFormat: 'YYYY-MM',
|
|
92
|
+
},
|
|
93
|
+
'string',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
Property = PropertyTypes[definition.type],
|
|
97
|
+
property = new Property(definition);
|
|
98
|
+
|
|
99
|
+
property.setValue('2025-10-17');
|
|
100
|
+
expect(property.getSubmitValue()).to.be.eq('2025-10');
|
|
101
|
+
expect(property.getDisplayValue()).to.be.eq('2025');
|
|
102
|
+
expect(property.getCurrentType()).to.be.eq('date');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onehat/data",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.28",
|
|
4
4
|
"description": "JS data modeling package with adapters for many storage mediums.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@onehat/events": "^1.6.6",
|
|
40
40
|
"accounting-js": "^2.0.3",
|
|
41
|
-
"async-wait-until": "^2.0.
|
|
42
|
-
"axios": "^1.
|
|
43
|
-
"chrono-node": "^2.
|
|
41
|
+
"async-wait-until": "^2.0.31",
|
|
42
|
+
"axios": "^1.13.0",
|
|
43
|
+
"chrono-node": "^2.9.0",
|
|
44
44
|
"he": "^1.2.0",
|
|
45
|
-
"js-base64": "^3.7.
|
|
45
|
+
"js-base64": "^3.7.8",
|
|
46
46
|
"lodash": "^4.17.21",
|
|
47
47
|
"moment": "^2.30.1",
|
|
48
48
|
"natsort": "^2.0.3",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"object-hash": "^3.0.0",
|
|
51
51
|
"qs": "^6.14.0",
|
|
52
52
|
"relative-time-parser": "^1.0.15",
|
|
53
|
-
"uuid": "^
|
|
53
|
+
"uuid": "^13.0.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"fast-xml-parser": "^4.4.1",
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/** @module Property */
|
|
2
|
+
|
|
3
|
+
import EventEmitter from '@onehat/events';
|
|
4
|
+
import Base64Property from './Base64.js';
|
|
5
|
+
import BooleanProperty from './Boolean.js';
|
|
6
|
+
import CurrencyProperty from './Currency.js';
|
|
7
|
+
import DateProperty from './Date.js';
|
|
8
|
+
import DateTimeProperty from './DateTime.js';
|
|
9
|
+
import FileProperty from './File.js';
|
|
10
|
+
import FloatProperty from './Float.js';
|
|
11
|
+
import IntegerProperty from './Integer.js';
|
|
12
|
+
import JsonProperty, { TagProperty } from './Json.js';
|
|
13
|
+
import PercentProperty from './Percent.js';
|
|
14
|
+
import PercentIntProperty from './PercentInt.js';
|
|
15
|
+
import StringProperty from './String.js';
|
|
16
|
+
import TimeProperty from './Time.js';
|
|
17
|
+
import UuidProperty from './Uuid.js';
|
|
18
|
+
import _ from 'lodash';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Class represents a Property that can store values of multiple types.
|
|
22
|
+
* The actual type is determined dynamically based on the value being set.
|
|
23
|
+
*
|
|
24
|
+
* Usage: { name: 'date', title: 'Date', types: ['date', 'string'], },
|
|
25
|
+
* This is primarily used to allow a field that's normally one PropertyType
|
|
26
|
+
* to also accept string values (e.g. values like '2025-01-01' or 'N/A').
|
|
27
|
+
*
|
|
28
|
+
* @extends Property
|
|
29
|
+
*/
|
|
30
|
+
export default class MixedProperty extends EventEmitter {
|
|
31
|
+
|
|
32
|
+
constructor(config = {}, entity) {
|
|
33
|
+
config = _.merge({}, MixedProperty.defaults, config);
|
|
34
|
+
|
|
35
|
+
if (!config.types || !Array.isArray(config.types) || config.types.length < 2) {
|
|
36
|
+
throw Error('MixedProperty requires a types array with at least two types in its configuration.');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
super(config, entity);
|
|
40
|
+
|
|
41
|
+
this.registerEvents([
|
|
42
|
+
'change',
|
|
43
|
+
'changeValidity',
|
|
44
|
+
'destroy',
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
this.types = config.types;
|
|
48
|
+
this.currentType = this.types[0].type || this.types[0];
|
|
49
|
+
this.internalProperties = new Map();
|
|
50
|
+
|
|
51
|
+
this._createInternalProperties();
|
|
52
|
+
|
|
53
|
+
this.currentProperty = this.internalProperties.get(this.currentType);
|
|
54
|
+
|
|
55
|
+
this._proxy = new Proxy(this, {
|
|
56
|
+
get(mixedProperty, prop, receiver) {
|
|
57
|
+
if (prop in mixedProperty) {
|
|
58
|
+
const value = mixedProperty[prop];
|
|
59
|
+
if (typeof value === 'function') {
|
|
60
|
+
return value.bind(mixedProperty);
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
if (mixedProperty.currentProperty && prop in mixedProperty.currentProperty) {
|
|
65
|
+
const value = mixedProperty.currentProperty[prop];
|
|
66
|
+
if (typeof value === 'function') {
|
|
67
|
+
return value.bind(mixedProperty.currentProperty);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
},
|
|
73
|
+
has(mixedProperty, prop) {
|
|
74
|
+
if (prop in mixedProperty) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return mixedProperty.currentProperty ? prop in mixedProperty.currentProperty : false;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return this._proxy;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates internal Property instances for each configured type
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
_createInternalProperties() {
|
|
89
|
+
_.each(this.types, (typeConfig) => {
|
|
90
|
+
let typeName,
|
|
91
|
+
propertyConfig;
|
|
92
|
+
if (typeof typeConfig === 'string') {
|
|
93
|
+
typeName = typeConfig;
|
|
94
|
+
propertyConfig = {};
|
|
95
|
+
} else {
|
|
96
|
+
typeName = typeConfig.type;
|
|
97
|
+
propertyConfig = _.omit(typeConfig, 'type');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const
|
|
101
|
+
PropertyClass = this._getPropertyClass(typeName),
|
|
102
|
+
|
|
103
|
+
// Create a clean config for this internal property
|
|
104
|
+
baseConfig = _.omit(this.config, ['types', 'defaultType']), // Start with base config but exclude Mixed-specific settings
|
|
105
|
+
mergedConfig = _.merge({}, baseConfig, propertyConfig, { // Merge with type-specific config, giving precedence to type-specific settings
|
|
106
|
+
name: this.name,
|
|
107
|
+
}),
|
|
108
|
+
property = new PropertyClass(mergedConfig, this.entity);
|
|
109
|
+
|
|
110
|
+
this._setupEventForwarding(property);
|
|
111
|
+
|
|
112
|
+
this.internalProperties.set(typeName, property);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Gets the Property class for a given type name
|
|
118
|
+
* @param {string} typeName - Name of the property type
|
|
119
|
+
* @returns {Class} Property class
|
|
120
|
+
* @private
|
|
121
|
+
*/
|
|
122
|
+
_getPropertyClass(typeName) {
|
|
123
|
+
const
|
|
124
|
+
typeMap = {
|
|
125
|
+
base64: Base64Property,
|
|
126
|
+
bool: BooleanProperty,
|
|
127
|
+
currency: CurrencyProperty,
|
|
128
|
+
date: DateProperty,
|
|
129
|
+
datetime: DateTimeProperty,
|
|
130
|
+
file: FileProperty,
|
|
131
|
+
float: FloatProperty,
|
|
132
|
+
int: IntegerProperty,
|
|
133
|
+
json: JsonProperty,
|
|
134
|
+
percent: PercentProperty,
|
|
135
|
+
percentint: PercentIntProperty,
|
|
136
|
+
string: StringProperty,
|
|
137
|
+
tag: TagProperty,
|
|
138
|
+
time: TimeProperty,
|
|
139
|
+
uuid: UuidProperty,
|
|
140
|
+
},
|
|
141
|
+
PropertyClass = typeMap[typeName.toLowerCase()];
|
|
142
|
+
|
|
143
|
+
if (!PropertyClass) {
|
|
144
|
+
const availableTypes = Object.keys(typeMap).join(', ');
|
|
145
|
+
throw new Error(`Unknown property type: '${typeName}'. Available types are: ${availableTypes}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return typeMap[typeName.toLowerCase()];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Sets up event forwarding from an internal property to this MixedProperty
|
|
153
|
+
* @param {Property} property - Internal property to forward events from
|
|
154
|
+
* @private
|
|
155
|
+
*/
|
|
156
|
+
_setupEventForwarding(property) {
|
|
157
|
+
// Forward all events from internal property to MixedProperty
|
|
158
|
+
const forwardEvent = (eventName, ...args) => {
|
|
159
|
+
if (property === this.currentProperty) {
|
|
160
|
+
// Replace the property reference in args with this MixedProperty
|
|
161
|
+
const modifiedArgs = args.map(arg => arg === property ? this : arg);
|
|
162
|
+
this.emit(eventName, ...modifiedArgs);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Listen to all registered events on the internal property
|
|
167
|
+
property.getRegisteredEvents().forEach((eventName) => {
|
|
168
|
+
property.on(eventName, (...args) => forwardEvent(eventName, ...args));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Detects the appropriate property type for a given value
|
|
174
|
+
* @param {any} value - Value to analyze
|
|
175
|
+
* @returns {string} Detected type name
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
_detectType(value) {
|
|
179
|
+
if (_.isNil(value)) {
|
|
180
|
+
return this.currentType || this.defaultType || (typeof this.types[0] === 'string' ? this.types[0] : this.types[0].type);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Get available type names from config
|
|
184
|
+
const availableTypes = this.types.map(typeConfig =>
|
|
185
|
+
typeof typeConfig === 'string' ? typeConfig : typeConfig.type
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Define precedence order - more specific types first
|
|
189
|
+
const precedenceOrder = [
|
|
190
|
+
'bool', // Most specific - only true/false/1/0
|
|
191
|
+
'int', // Integers
|
|
192
|
+
'float', // Floating point numbers
|
|
193
|
+
'currency', // Currency values
|
|
194
|
+
'percent', // Percentage values
|
|
195
|
+
'percentint',// Integer percentages
|
|
196
|
+
'date', // Date values
|
|
197
|
+
'datetime', // DateTime values
|
|
198
|
+
'time', // Time values
|
|
199
|
+
'uuid', // UUID format
|
|
200
|
+
'base64', // Base64 encoded data
|
|
201
|
+
'json', // JSON objects/arrays
|
|
202
|
+
'tag', // Tag format
|
|
203
|
+
'file', // File data
|
|
204
|
+
'string' // Most general - accepts anything
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
// Try types in precedence order, but only if they're in the available types
|
|
208
|
+
let typeName;
|
|
209
|
+
for(typeName of precedenceOrder) {
|
|
210
|
+
if (availableTypes.includes(typeName)) {
|
|
211
|
+
const property = this.internalProperties.get(typeName);
|
|
212
|
+
if (property && this._canParseValue(property, value)) {
|
|
213
|
+
return typeName;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
throw new Error(`No configured property type could handle value: ${value}. Available types: ${availableTypes.join(', ')}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Tests if a property can successfully parse a value
|
|
223
|
+
* @param {Property} property - Property to test
|
|
224
|
+
* @param {any} value - Value to test
|
|
225
|
+
* @returns {boolean} Whether the property can parse the value
|
|
226
|
+
* @private
|
|
227
|
+
*/
|
|
228
|
+
_canParseValue(property, value) {
|
|
229
|
+
try {
|
|
230
|
+
switch(property.constructor.type) {
|
|
231
|
+
case 'bool':
|
|
232
|
+
return this._isBooleanValue(value);
|
|
233
|
+
case 'int':
|
|
234
|
+
return this._isIntegerValue(value);
|
|
235
|
+
case 'float':
|
|
236
|
+
return this._isFloatValue(value);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
property.parse(value);
|
|
240
|
+
return true;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Checks if a value represents a boolean
|
|
248
|
+
* @param {any} value - Value to check
|
|
249
|
+
* @returns {boolean} Whether the value is boolean-like
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
_isBooleanValue(value) {
|
|
253
|
+
switch(typeof value) {
|
|
254
|
+
case 'boolean':
|
|
255
|
+
return true;
|
|
256
|
+
case 'number':
|
|
257
|
+
return value === 0 || value === 1;
|
|
258
|
+
case 'string':
|
|
259
|
+
const lower = value.toLowerCase().trim();
|
|
260
|
+
return ['true', 'false', '1', '0'].includes(lower);
|
|
261
|
+
default:
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Checks if a value represents an integer
|
|
268
|
+
* @param {any} value - Value to check
|
|
269
|
+
* @returns {boolean} Whether the value is integer-like
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
_isIntegerValue(value) {
|
|
273
|
+
switch(typeof value) {
|
|
274
|
+
case 'bigint':
|
|
275
|
+
return true;
|
|
276
|
+
case 'number':
|
|
277
|
+
return Number.isInteger(value);
|
|
278
|
+
case 'string':
|
|
279
|
+
const trimmed = value.trim();
|
|
280
|
+
if (trimmed === '') {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
const num = Number(trimmed);
|
|
284
|
+
return !isNaN(num) && Number.isInteger(num) && String(num) === trimmed;
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Checks if a value represents a float
|
|
291
|
+
* @param {any} value - Value to check
|
|
292
|
+
* @returns {boolean} Whether the value is float-like
|
|
293
|
+
* @private
|
|
294
|
+
*/
|
|
295
|
+
_isFloatValue(value) {
|
|
296
|
+
switch(typeof value) {
|
|
297
|
+
case 'number':
|
|
298
|
+
return !Number.isInteger(value) && isFinite(value);
|
|
299
|
+
case 'string':
|
|
300
|
+
const trimmed = value.trim();
|
|
301
|
+
if (trimmed === '') return false;
|
|
302
|
+
const num = Number(trimmed);
|
|
303
|
+
return !isNaN(num) && isFinite(num) && !Number.isInteger(num);
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Sets the value and determines the appropriate type
|
|
310
|
+
* @param {any} value - Value to set
|
|
311
|
+
*/
|
|
312
|
+
setValue(value) {
|
|
313
|
+
const detectedType = this._detectType(value);
|
|
314
|
+
if (this.currentType !== detectedType) {
|
|
315
|
+
this.currentType = detectedType;
|
|
316
|
+
this.currentProperty = this.internalProperties.get(this.currentType);
|
|
317
|
+
}
|
|
318
|
+
this.currentProperty.setValue(value);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Gets the current type name
|
|
323
|
+
* @returns {string} Current type name
|
|
324
|
+
*/
|
|
325
|
+
getCurrentType() {
|
|
326
|
+
return this.currentProperty.constructor.type;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Gets the className of this Property type.
|
|
331
|
+
* @return {string} className
|
|
332
|
+
*/
|
|
333
|
+
getClassName() {
|
|
334
|
+
return this.constructor.className;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Gets the internal property for a specific type
|
|
339
|
+
* @param {string} typeName - Type name
|
|
340
|
+
* @returns {Property} Internal property
|
|
341
|
+
*/
|
|
342
|
+
getInternalProperty(typeName) {
|
|
343
|
+
return this.internalProperties.get(typeName);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ______ __
|
|
347
|
+
// / ____/ _____ ____ / /______
|
|
348
|
+
// / __/ | | / / _ \/ __ \/ __/ ___/
|
|
349
|
+
// / /___ | |/ / __/ / / / /_(__ )
|
|
350
|
+
// /_____/ |___/\___/_/ /_/\__/____/
|
|
351
|
+
//
|
|
352
|
+
// (Override the EventEmitter methods to forward listener management to internal properties)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Add event listener to MixedProperty only
|
|
357
|
+
* Events from internal properties are forwarded via _setupEventForwarding
|
|
358
|
+
*/
|
|
359
|
+
on(eventName, listener) {
|
|
360
|
+
return super.on(eventName, listener);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Add one-time event listener to MixedProperty only
|
|
365
|
+
*/
|
|
366
|
+
once(eventName, listener) {
|
|
367
|
+
return super.once(eventName, listener);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Remove event listener from MixedProperty only
|
|
372
|
+
*/
|
|
373
|
+
off(eventName, listener) {
|
|
374
|
+
return super.off(eventName, listener);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Remove all event listeners from MixedProperty and all internal properties
|
|
379
|
+
*/
|
|
380
|
+
removeAllListeners(eventName) {
|
|
381
|
+
// Remove all listeners from this MixedProperty
|
|
382
|
+
super.removeAllListeners(eventName);
|
|
383
|
+
|
|
384
|
+
// Remove all listeners from internal properties
|
|
385
|
+
this.internalProperties.forEach(property => {
|
|
386
|
+
property.removeAllListeners(eventName);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Destroys all internal properties
|
|
394
|
+
*/
|
|
395
|
+
destroy() {
|
|
396
|
+
// Clean up listener mappings
|
|
397
|
+
if (this._listenerMappings) {
|
|
398
|
+
this._listenerMappings.clear();
|
|
399
|
+
this._listenerMappings = null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
this.internalProperties.forEach((property) => property.destroy());
|
|
403
|
+
this.internalProperties.clear();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
MixedProperty.className = 'Mixed';
|
|
408
|
+
MixedProperty.type = 'mixed';
|
package/src/Property/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import FileProperty from './File.js';
|
|
|
9
9
|
import FloatProperty from './Float.js';
|
|
10
10
|
import IntegerProperty from './Integer.js';
|
|
11
11
|
import JsonProperty, { TagProperty } from './Json.js';
|
|
12
|
+
import MixedProperty from './Mixed.js';
|
|
12
13
|
import PercentProperty from './Percent.js';
|
|
13
14
|
import PercentIntProperty from './PercentInt.js';
|
|
14
15
|
import Property from './Property.js';
|
|
@@ -26,6 +27,7 @@ const PropertyTypes = {
|
|
|
26
27
|
[FloatProperty.type]: FloatProperty,
|
|
27
28
|
[IntegerProperty.type]: IntegerProperty,
|
|
28
29
|
[JsonProperty.type]: JsonProperty,
|
|
30
|
+
[MixedProperty.type]: MixedProperty,
|
|
29
31
|
[PercentProperty.type]: PercentProperty,
|
|
30
32
|
[PercentIntProperty.type]: PercentIntProperty,
|
|
31
33
|
[Property.type]: Property,
|
|
@@ -544,20 +544,30 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
544
544
|
}
|
|
545
545
|
|
|
546
546
|
return this.axios(data)
|
|
547
|
-
|
|
548
|
-
if (this.debugMode) {
|
|
549
|
-
console.log('login response', result);
|
|
550
|
-
}
|
|
547
|
+
.catch((error) => {
|
|
551
548
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
549
|
+
if (this.debugMode) {
|
|
550
|
+
console.log(data.url + ' error', error);
|
|
551
|
+
console.log('response:', error.response);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
this.throwError(error);
|
|
555
|
+
return;
|
|
556
|
+
})
|
|
557
|
+
.then((result) => {
|
|
558
|
+
if (this.debugMode) {
|
|
559
|
+
console.log('login response', result);
|
|
560
|
+
}
|
|
557
561
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
562
|
+
const response = result.data;
|
|
563
|
+
if (!response.success) {
|
|
564
|
+
this.throwError(response.data); // TODO: Fix back-end, so OneBuild submits the error message on response.message, not response.data
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const userData = response.data;
|
|
569
|
+
return userData;
|
|
570
|
+
});
|
|
561
571
|
}
|
|
562
572
|
|
|
563
573
|
/**
|