@nascentdigital/funnel-core 4.4.10 → 4.4.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/schema/ChangeSet.d.ts +6 -0
- package/dist/schema/ChangeSet.js +25 -24
- package/dist/ui/block-layout/BlockLayout.d.ts +33 -5
- package/dist/ui/block-layout/BlockLayout.js +95 -10
- package/dist/ui/fields/Field.d.ts +4 -0
- package/dist/ui/fields/Field.js +18 -0
- package/dist/ui/fields/FieldList.d.ts +6 -1
- package/dist/ui/fields/FieldList.js +25 -1
- package/dist/ui/fields/ObjectField.d.ts +4 -0
- package/dist/ui/fields/ObjectField.js +21 -1
- package/package.json +2 -2
|
@@ -105,4 +105,10 @@ export declare namespace ChangeSet {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
type ConstructorArgs = Omit<Data, 'errors'>;
|
|
108
|
+
type AddChangeArgs<TChange extends Change> = {
|
|
109
|
+
changes: TChange[];
|
|
110
|
+
change: Omit<TChange, 'attribution'>;
|
|
111
|
+
userId: string;
|
|
112
|
+
};
|
|
113
|
+
function addChange<TChange extends Change>({ changes, change, userId }: AddChangeArgs<TChange>): void;
|
|
108
114
|
}
|
package/dist/schema/ChangeSet.js
CHANGED
|
@@ -81,7 +81,7 @@ class ChangeSet {
|
|
|
81
81
|
}
|
|
82
82
|
addPageChange(userId, change) {
|
|
83
83
|
// apply change
|
|
84
|
-
addChange({
|
|
84
|
+
ChangeSet.addChange({
|
|
85
85
|
changes: this._changes,
|
|
86
86
|
change,
|
|
87
87
|
userId
|
|
@@ -98,7 +98,7 @@ class ChangeSet {
|
|
|
98
98
|
}
|
|
99
99
|
addCollectionChange(userId, change) {
|
|
100
100
|
// apply change
|
|
101
|
-
addChange({
|
|
101
|
+
ChangeSet.addChange({
|
|
102
102
|
changes: this._changes,
|
|
103
103
|
change,
|
|
104
104
|
userId
|
|
@@ -115,7 +115,7 @@ class ChangeSet {
|
|
|
115
115
|
}
|
|
116
116
|
addAssetChange(userId, change) {
|
|
117
117
|
// apply change
|
|
118
|
-
addChange({
|
|
118
|
+
ChangeSet.addChange({
|
|
119
119
|
changes: this._changes,
|
|
120
120
|
change,
|
|
121
121
|
userId
|
|
@@ -162,26 +162,27 @@ exports.ChangeSet = ChangeSet;
|
|
|
162
162
|
New.filter = filter;
|
|
163
163
|
})(New = Data.New || (Data.New = {}));
|
|
164
164
|
})(Data = ChangeSet.Data || (ChangeSet.Data = {}));
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
:
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
function addChange({ changes, change, userId }) {
|
|
166
|
+
// update existing page
|
|
167
|
+
const updatedOn = Date.now();
|
|
168
|
+
const changeIndex = changes.findIndex(({ id }) => change.id === id);
|
|
169
|
+
if (changeIndex >= 0) {
|
|
170
|
+
// update attribution (skip if it's the same change by the same user)
|
|
171
|
+
const _a = changes[changeIndex], { type, attribution } = _a, existingChange = __rest(_a, ["type", "attribution"]);
|
|
172
|
+
const lastAttribution = attribution.length > 0
|
|
173
|
+
? attribution[attribution.length - 1]
|
|
174
|
+
: undefined;
|
|
175
|
+
if ((lastAttribution === null || lastAttribution === void 0 ? void 0 : lastAttribution.userId) !== userId || change.type !== type) {
|
|
176
|
+
attribution.push({ userId, updatedOn });
|
|
177
|
+
}
|
|
178
|
+
// update change
|
|
179
|
+
changes[changeIndex] = Object.assign(Object.assign(Object.assign({}, existingChange), change), { type,
|
|
180
|
+
attribution });
|
|
181
|
+
}
|
|
182
|
+
// or add a new one
|
|
183
|
+
else {
|
|
184
|
+
changes.push(Object.assign(Object.assign({}, change), { attribution: [{ userId, updatedOn }] }));
|
|
178
185
|
}
|
|
179
|
-
// update change
|
|
180
|
-
changes[changeIndex] = Object.assign(Object.assign(Object.assign({}, existingChange), change), { type,
|
|
181
|
-
attribution });
|
|
182
|
-
}
|
|
183
|
-
// or add a new one
|
|
184
|
-
else {
|
|
185
|
-
changes.push(Object.assign(Object.assign({}, change), { attribution: [{ userId, updatedOn }] }));
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
ChangeSet.addChange = addChange;
|
|
188
|
+
})(ChangeSet || (exports.ChangeSet = ChangeSet = {}));
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
export type BlockLayout = {
|
|
2
2
|
name: string;
|
|
3
3
|
root: BlockLayout.Root;
|
|
4
|
-
|
|
4
|
+
tight?: BlockLayout.Tight;
|
|
5
|
+
tightMobile?: BlockLayout.Tight;
|
|
6
|
+
tightDesktop?: BlockLayout.Tight;
|
|
5
7
|
};
|
|
6
8
|
export declare namespace BlockLayout {
|
|
9
|
+
type Tight = 'above' | 'below' | 'both' | 'none';
|
|
10
|
+
namespace Tight {
|
|
11
|
+
const values: ReadonlyArray<Tight>;
|
|
12
|
+
function parse(value: string, fallback?: Tight): Tight;
|
|
13
|
+
}
|
|
14
|
+
type Ratio = '1/1' | '1/2' | '1/3' | '2/1' | '3/1' | '2/3' | '3/2';
|
|
15
|
+
namespace Ratio {
|
|
16
|
+
const values: ReadonlyArray<Ratio>;
|
|
17
|
+
function parse(value: string, fallback?: Ratio): Ratio;
|
|
18
|
+
}
|
|
19
|
+
namespace FullBleed {
|
|
20
|
+
function parse(value: string, fallback?: boolean): boolean;
|
|
21
|
+
}
|
|
7
22
|
type Root = Row | Column | Stack;
|
|
8
23
|
type Container = Row | Row.Nested | Column | Column.Nested | Stack | Stack.Nested;
|
|
9
24
|
type Row = {
|
|
@@ -11,10 +26,14 @@ export declare namespace BlockLayout {
|
|
|
11
26
|
items: ReadonlyArray<Column.Nested | Stack.Nested | Panel>;
|
|
12
27
|
alignX?: Alignment;
|
|
13
28
|
alignY?: Alignment;
|
|
29
|
+
ratio?: Ratio;
|
|
30
|
+
ratioMobile?: Ratio;
|
|
31
|
+
ratioDesktop?: Ratio;
|
|
14
32
|
};
|
|
15
33
|
namespace Row {
|
|
16
34
|
type Nested = Omit<Row, 'items'> & {
|
|
17
35
|
items: ReadonlyArray<Panel>;
|
|
36
|
+
mobileOrder?: MobileOrder;
|
|
18
37
|
};
|
|
19
38
|
}
|
|
20
39
|
type Column = {
|
|
@@ -26,6 +45,7 @@ export declare namespace BlockLayout {
|
|
|
26
45
|
namespace Column {
|
|
27
46
|
type Nested = Omit<Column, 'items'> & {
|
|
28
47
|
items: ReadonlyArray<Panel>;
|
|
48
|
+
mobileOrder?: MobileOrder;
|
|
29
49
|
};
|
|
30
50
|
}
|
|
31
51
|
type Stack = {
|
|
@@ -37,6 +57,7 @@ export declare namespace BlockLayout {
|
|
|
37
57
|
namespace Stack {
|
|
38
58
|
type Nested = Omit<Stack, 'items'> & {
|
|
39
59
|
items: ReadonlyArray<Panel>;
|
|
60
|
+
mobileOrder?: MobileOrder;
|
|
40
61
|
};
|
|
41
62
|
}
|
|
42
63
|
type NestedItem = Row.Nested | Column.Nested | Stack.Nested | Panel;
|
|
@@ -46,18 +67,25 @@ export declare namespace BlockLayout {
|
|
|
46
67
|
type Base = {
|
|
47
68
|
key: Key;
|
|
48
69
|
mobileOrder?: MobileOrder;
|
|
49
|
-
alignX
|
|
50
|
-
alignY
|
|
51
|
-
size
|
|
70
|
+
alignX?: Alignment;
|
|
71
|
+
alignY?: Alignment;
|
|
72
|
+
size?: Size;
|
|
73
|
+
fullBleed?: boolean;
|
|
74
|
+
fullBleedMobile?: boolean;
|
|
75
|
+
fullBleedDesktop?: boolean;
|
|
52
76
|
};
|
|
53
77
|
}
|
|
54
78
|
type Message = Panel.Base & {
|
|
55
79
|
type: 'message';
|
|
56
|
-
textAlign
|
|
80
|
+
textAlign?: TextAlignment;
|
|
81
|
+
textAlignMobile?: TextAlignment;
|
|
82
|
+
textAlignDesktop?: TextAlignment;
|
|
57
83
|
};
|
|
58
84
|
type Visual = Panel.Base & {
|
|
59
85
|
type: 'visual';
|
|
60
86
|
aspectRatio: AspectRatio;
|
|
87
|
+
aspectRatioMobile?: AspectRatio;
|
|
88
|
+
aspectRatioDesktop?: AspectRatio;
|
|
61
89
|
};
|
|
62
90
|
type List = Panel.Base & {
|
|
63
91
|
type: 'list';
|
|
@@ -17,6 +17,71 @@ const errors_1 = require("../../errors");
|
|
|
17
17
|
// extension
|
|
18
18
|
var BlockLayout;
|
|
19
19
|
(function (BlockLayout) {
|
|
20
|
+
let Tight;
|
|
21
|
+
(function (Tight) {
|
|
22
|
+
// values
|
|
23
|
+
Tight.values = ['above', 'below', 'both', 'none'];
|
|
24
|
+
// helper
|
|
25
|
+
function parse(value, fallback) {
|
|
26
|
+
// return if it's a match
|
|
27
|
+
if (Tight.values.includes(value)) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
// or fallback if we have one
|
|
31
|
+
else if (fallback) {
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
// or throw
|
|
35
|
+
else {
|
|
36
|
+
throw new errors_1.ArgumentError(`Invalid BlockLayout.Tight "${value}"`, 'value');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
Tight.parse = parse;
|
|
40
|
+
})(Tight = BlockLayout.Tight || (BlockLayout.Tight = {}));
|
|
41
|
+
let Ratio;
|
|
42
|
+
(function (Ratio) {
|
|
43
|
+
// values
|
|
44
|
+
Ratio.values = ['1/1', '1/2', '1/3', '2/1', '3/1', '2/3', '3/2'];
|
|
45
|
+
// helper
|
|
46
|
+
function parse(value, fallback) {
|
|
47
|
+
// return if it's a match
|
|
48
|
+
if (Ratio.values.includes(value)) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
// or fallback if we have one
|
|
52
|
+
else if (fallback) {
|
|
53
|
+
return fallback;
|
|
54
|
+
}
|
|
55
|
+
// or throw
|
|
56
|
+
else {
|
|
57
|
+
throw new errors_1.ArgumentError(`Invalid BlockLayout.Ratio "${value}"`, 'value');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
Ratio.parse = parse;
|
|
61
|
+
})(Ratio = BlockLayout.Ratio || (BlockLayout.Ratio = {}));
|
|
62
|
+
let FullBleed;
|
|
63
|
+
(function (FullBleed) {
|
|
64
|
+
// helper
|
|
65
|
+
function parse(value, fallback) {
|
|
66
|
+
// return true if the string is 'true'
|
|
67
|
+
if (value === 'true') {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// return false if the string is 'false'
|
|
71
|
+
else if (value === 'false') {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// or fallback if we have one
|
|
75
|
+
else if (fallback !== undefined) {
|
|
76
|
+
return fallback;
|
|
77
|
+
}
|
|
78
|
+
// or throw
|
|
79
|
+
else {
|
|
80
|
+
throw new errors_1.ArgumentError(`Invalid BlockLayout.FullBleed "${value}"`, 'value');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
FullBleed.parse = parse;
|
|
84
|
+
})(FullBleed = BlockLayout.FullBleed || (BlockLayout.FullBleed = {}));
|
|
20
85
|
let List;
|
|
21
86
|
(function (List) {
|
|
22
87
|
let ItemType;
|
|
@@ -153,28 +218,32 @@ var BlockLayout;
|
|
|
153
218
|
// parse xml (not sure if this throws on error)
|
|
154
219
|
const blockJson = xmlParser.parse(xml);
|
|
155
220
|
// walk json to create block data
|
|
156
|
-
return
|
|
221
|
+
return parseBlock(blockJson[0]);
|
|
157
222
|
}
|
|
158
223
|
BlockLayout.parse = parse;
|
|
159
224
|
})(BlockLayout || (exports.BlockLayout = BlockLayout = {}));
|
|
160
225
|
// helpers
|
|
161
|
-
function
|
|
226
|
+
function parseBlock(json) {
|
|
162
227
|
// parse block
|
|
163
228
|
const block = ParsedElement.parse({ data: json, expectedTags: ['block'], expectedChildren: 1 });
|
|
229
|
+
const tight = BlockLayout.Tight.parse(block.attributes['tight'], 'none');
|
|
164
230
|
// return block
|
|
165
231
|
return {
|
|
166
232
|
name: block.attributes['name'],
|
|
233
|
+
tight,
|
|
234
|
+
tightMobile: BlockLayout.Tight.parse(block.attributes['tightMobile'], tight),
|
|
235
|
+
tightDesktop: BlockLayout.Tight.parse(block.attributes['tightDesktop'], tight),
|
|
167
236
|
root: parseRoot(ParsedElement.parse({ data: block.children[0], expectedTags: ['row', 'col', 'stack'] })),
|
|
168
|
-
fullbleed: block.attributes['fullbleed'] === 'true'
|
|
169
237
|
};
|
|
170
238
|
}
|
|
171
239
|
function parseRoot({ tag, attributes, children }) {
|
|
240
|
+
const ratio = BlockLayout.Ratio.parse(attributes['ratio'], '1/1');
|
|
172
241
|
// parse attributes
|
|
173
|
-
const
|
|
242
|
+
const _a = parseItemAttributes(attributes), { size } = _a, itemAttributes = __rest(_a, ["size"]);
|
|
174
243
|
// create root
|
|
175
244
|
switch (tag) {
|
|
176
245
|
case 'row':
|
|
177
|
-
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { items: children.map(data => parseNestedItem(ParsedElement.parse({
|
|
246
|
+
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio, ratioMobile: BlockLayout.Ratio.parse(attributes['ratioMobile'], ratio), ratioDesktop: BlockLayout.Ratio.parse(attributes['ratioDesktop'], ratio), items: children.map(data => parseNestedItem(ParsedElement.parse({
|
|
178
247
|
data,
|
|
179
248
|
expectedTags: ParsedElement.tags.filter(t => t !== tag)
|
|
180
249
|
}))) });
|
|
@@ -195,9 +264,14 @@ function parseRoot({ tag, attributes, children }) {
|
|
|
195
264
|
function parseNestedItem({ tag, attributes, children }) {
|
|
196
265
|
// parse attributes
|
|
197
266
|
const _a = parseItemAttributes(attributes), { size } = _a, itemAttributes = __rest(_a, ["size"]);
|
|
267
|
+
const ratio = BlockLayout.Ratio.parse(attributes['ratio'], '1/1');
|
|
198
268
|
// create container
|
|
199
269
|
switch (tag) {
|
|
200
270
|
case 'row':
|
|
271
|
+
return Object.assign(Object.assign({ type: 'row' }, itemAttributes), { ratio, ratioMobile: BlockLayout.Ratio.parse(attributes['ratioMobile'], ratio), ratioDesktop: BlockLayout.Ratio.parse(attributes['ratioDesktop'], ratio), items: children.map(data => parsePanel(Object.assign({}, ParsedElement.parse({
|
|
272
|
+
data,
|
|
273
|
+
expectedTags: ParsedElement.tags.filter(t => t !== 'row' && t !== 'col')
|
|
274
|
+
})))) });
|
|
201
275
|
case 'col':
|
|
202
276
|
case 'stack':
|
|
203
277
|
return Object.assign(Object.assign({ type: tag === 'col' ? 'column' : tag }, itemAttributes), { items: children.map(data => parsePanel(Object.assign({}, ParsedElement.parse({
|
|
@@ -212,13 +286,24 @@ function parsePanel({ tag, attributes }) {
|
|
|
212
286
|
var _a;
|
|
213
287
|
const key = (_a = attributes['key']) !== null && _a !== void 0 ? _a : tag;
|
|
214
288
|
const itemAttributes = parseItemAttributes(attributes);
|
|
289
|
+
const textAlign = BlockLayout.TextAlignment.parse(attributes['textAlign'], 'left');
|
|
290
|
+
const aspectRatio = BlockLayout.AspectRatio.parse(attributes['aspect'], 'auto');
|
|
291
|
+
const fullBleed = BlockLayout.FullBleed.parse(attributes['fullBleed'], false);
|
|
292
|
+
const fullBleedMobile = BlockLayout.FullBleed.parse(attributes['fullBleedMobile'], fullBleed);
|
|
293
|
+
const fullBleedDesktop = BlockLayout.FullBleed.parse(attributes['fullBleedDesktop'], fullBleed);
|
|
215
294
|
switch (tag) {
|
|
216
295
|
case 'message':
|
|
217
|
-
return Object.assign(Object.assign({ type: 'message', key }, itemAttributes), { textAlign: BlockLayout.TextAlignment.parse(attributes['
|
|
296
|
+
return Object.assign(Object.assign({ type: 'message', key }, itemAttributes), { textAlign, textAlignMobile: BlockLayout.TextAlignment.parse(attributes['textAlignMobile'], textAlign), textAlignDesktop: BlockLayout.TextAlignment.parse(attributes['textAlignDesktop'], textAlign), fullBleed,
|
|
297
|
+
fullBleedMobile,
|
|
298
|
+
fullBleedDesktop });
|
|
218
299
|
case 'visual':
|
|
219
|
-
return Object.assign(Object.assign({ type: 'visual', key }, itemAttributes), { aspectRatio: BlockLayout.AspectRatio.parse(attributes['
|
|
300
|
+
return Object.assign(Object.assign({ type: 'visual', key }, itemAttributes), { aspectRatio, aspectRatioMobile: BlockLayout.AspectRatio.parse(attributes['aspectMobile'], aspectRatio), aspectRatioDesktop: BlockLayout.AspectRatio.parse(attributes['aspectDesktop'], aspectRatio), fullBleed,
|
|
301
|
+
fullBleedMobile,
|
|
302
|
+
fullBleedDesktop });
|
|
220
303
|
case 'list':
|
|
221
|
-
return Object.assign(Object.assign({ type: 'list', key }, itemAttributes), {
|
|
304
|
+
return Object.assign(Object.assign({ type: 'list', key }, itemAttributes), { fullBleed,
|
|
305
|
+
fullBleedMobile,
|
|
306
|
+
fullBleedDesktop, itemType: BlockLayout.List.ItemType.parse(attributes['itemType'], 'message+visual') });
|
|
222
307
|
default:
|
|
223
308
|
throw new errors_1.ArgumentError(`Invalid XML BlockLayout - encountered "${tag}" where instead of BlockLayout.Panel`);
|
|
224
309
|
}
|
|
@@ -226,9 +311,9 @@ function parsePanel({ tag, attributes }) {
|
|
|
226
311
|
function parseItemAttributes(attributes) {
|
|
227
312
|
return {
|
|
228
313
|
mobileOrder: BlockLayout.MobileOrder.parse(attributes['mobileOrder']),
|
|
229
|
-
size: BlockLayout.Size.parse(attributes['size'], 'full'),
|
|
230
314
|
alignX: BlockLayout.Alignment.parse(attributes['alignX'], 'start'),
|
|
231
|
-
alignY: BlockLayout.Alignment.parse(attributes['alignY'], 'start')
|
|
315
|
+
alignY: BlockLayout.Alignment.parse(attributes['alignY'], 'start'),
|
|
316
|
+
size: BlockLayout.Size.parse(attributes['size'], 'full'),
|
|
232
317
|
};
|
|
233
318
|
}
|
|
234
319
|
var ParsedElement;
|
|
@@ -11,6 +11,8 @@ export declare class Field<TSchema extends Schema.Field.Type = Schema.Field.Type
|
|
|
11
11
|
private readonly publishedValue;
|
|
12
12
|
private _initialValue;
|
|
13
13
|
private _value;
|
|
14
|
+
private _modifiedOn?;
|
|
15
|
+
private _savingOn?;
|
|
14
16
|
private _editing;
|
|
15
17
|
private _sandboxed;
|
|
16
18
|
private _sandboxedValue;
|
|
@@ -48,6 +50,8 @@ export declare class Field<TSchema extends Schema.Field.Type = Schema.Field.Type
|
|
|
48
50
|
didFocus(): void;
|
|
49
51
|
validate(silent?: boolean): ReadonlyArray<FieldValidator.Error>;
|
|
50
52
|
migrate(previous: Field<TSchema>): void;
|
|
53
|
+
onSaveStart(): void;
|
|
54
|
+
onSaveComplete(): void;
|
|
51
55
|
reset(initialValue?: Schema.Field.Data<TSchema> | null): void;
|
|
52
56
|
clone({ schema, eventBus, name, required }?: Field.CloneArgs<TSchema>): Field<TSchema>;
|
|
53
57
|
private raiseEvent;
|
package/dist/ui/fields/Field.js
CHANGED
|
@@ -122,6 +122,7 @@ class Field {
|
|
|
122
122
|
}
|
|
123
123
|
// update value
|
|
124
124
|
this._value = value;
|
|
125
|
+
this._modifiedOn = Date.now();
|
|
125
126
|
// raise change event
|
|
126
127
|
this.raiseEvent('changed');
|
|
127
128
|
// raise error (if any)
|
|
@@ -134,6 +135,7 @@ class Field {
|
|
|
134
135
|
}
|
|
135
136
|
// update value
|
|
136
137
|
this._value = value;
|
|
138
|
+
this._modifiedOn = Date.now();
|
|
137
139
|
// raise error (if any)
|
|
138
140
|
this.validate(true);
|
|
139
141
|
}
|
|
@@ -189,6 +191,7 @@ class Field {
|
|
|
189
191
|
}
|
|
190
192
|
// rollback sandbox
|
|
191
193
|
this._value = this._sandboxedValue;
|
|
194
|
+
this._modifiedOn = Date.now();
|
|
192
195
|
this._sandboxed = false;
|
|
193
196
|
// raise event
|
|
194
197
|
this.raiseEvent('changed');
|
|
@@ -244,10 +247,25 @@ class Field {
|
|
|
244
247
|
}
|
|
245
248
|
migrate(previous) {
|
|
246
249
|
this._value = previous.value;
|
|
250
|
+
this._modifiedOn = previous._modifiedOn;
|
|
247
251
|
this._editing = true;
|
|
248
252
|
this._sandboxed = previous._sandboxed;
|
|
249
253
|
this._sandboxedValue = previous._sandboxedValue;
|
|
250
254
|
}
|
|
255
|
+
onSaveStart() {
|
|
256
|
+
this._savingOn = Date.now();
|
|
257
|
+
}
|
|
258
|
+
onSaveComplete() {
|
|
259
|
+
// reset to initial value if not modified or if save is newer
|
|
260
|
+
const { _modifiedOn, _savingOn } = this;
|
|
261
|
+
if (_savingOn && (!_modifiedOn || _savingOn >= _modifiedOn)) {
|
|
262
|
+
this._initialValue = this._value;
|
|
263
|
+
delete this._optIn;
|
|
264
|
+
delete this._optOut;
|
|
265
|
+
}
|
|
266
|
+
// clear saving flag
|
|
267
|
+
delete this._savingOn;
|
|
268
|
+
}
|
|
251
269
|
reset(initialValue) {
|
|
252
270
|
// reset initial value if it's set
|
|
253
271
|
if (initialValue !== undefined) {
|
|
@@ -8,11 +8,13 @@ export declare class FieldList {
|
|
|
8
8
|
readonly schema: FieldList.ListSchema;
|
|
9
9
|
readonly composition: FieldList.ListComposition;
|
|
10
10
|
private _items;
|
|
11
|
+
private _modifiedOn?;
|
|
12
|
+
private _savingOn?;
|
|
11
13
|
readonly id: string;
|
|
12
14
|
readonly name: string;
|
|
13
15
|
readonly required: boolean;
|
|
14
16
|
private readonly eventBus;
|
|
15
|
-
|
|
17
|
+
private _initialValue;
|
|
16
18
|
readonly publishedValue: FieldList.ListValue | undefined;
|
|
17
19
|
private readonly _validator;
|
|
18
20
|
private _errors;
|
|
@@ -20,6 +22,7 @@ export declare class FieldList {
|
|
|
20
22
|
private _optOut?;
|
|
21
23
|
constructor(args: FieldList.ConstructorArgs);
|
|
22
24
|
get events$(): Observable<FieldList.Event>;
|
|
25
|
+
get initialValue(): Schema.Field.Data.ForCompositeType<FieldList.ListSchema> | undefined;
|
|
23
26
|
get items(): ReadonlyArray<FieldList.Item>;
|
|
24
27
|
get isNew(): boolean;
|
|
25
28
|
get exists(): boolean;
|
|
@@ -45,6 +48,8 @@ export declare class FieldList {
|
|
|
45
48
|
removeItem(itemId: string): void;
|
|
46
49
|
removeField(field: Field | ObjectField): void;
|
|
47
50
|
moveItem(fromIndex: number, toIndex: number): void;
|
|
51
|
+
onSaveStart(): void;
|
|
52
|
+
onSaveComplete(): void;
|
|
48
53
|
reset(initialValue?: FieldList.ListValue | null): void;
|
|
49
54
|
clone(): FieldList;
|
|
50
55
|
private raiseEvent;
|
|
@@ -70,7 +70,7 @@ class FieldList {
|
|
|
70
70
|
this.id = args.id;
|
|
71
71
|
this.name = args.name;
|
|
72
72
|
this.required = args.required;
|
|
73
|
-
this.
|
|
73
|
+
this._initialValue = args.initialValue;
|
|
74
74
|
this.publishedValue = args.publishedValue;
|
|
75
75
|
this._validator = new FieldListValidator_1.FieldListValidator(this.schema);
|
|
76
76
|
// validate
|
|
@@ -79,6 +79,9 @@ class FieldList {
|
|
|
79
79
|
get events$() {
|
|
80
80
|
return this.eventBus.events$.pipe((0, rxjs_1.filter)(FieldList.Event.filter), (0, rxjs_1.filter)(e => e.field === this));
|
|
81
81
|
}
|
|
82
|
+
get initialValue() {
|
|
83
|
+
return this._initialValue;
|
|
84
|
+
}
|
|
82
85
|
get items() {
|
|
83
86
|
return this._items;
|
|
84
87
|
}
|
|
@@ -127,6 +130,7 @@ class FieldList {
|
|
|
127
130
|
value,
|
|
128
131
|
publishedValue
|
|
129
132
|
});
|
|
133
|
+
this._modifiedOn = Date.now();
|
|
130
134
|
// revalidate
|
|
131
135
|
this.validate();
|
|
132
136
|
// raise event
|
|
@@ -221,6 +225,7 @@ class FieldList {
|
|
|
221
225
|
};
|
|
222
226
|
// add to list
|
|
223
227
|
this._items = [...this._items, item];
|
|
228
|
+
this._modifiedOn = Date.now();
|
|
224
229
|
// revalidate
|
|
225
230
|
this.validate();
|
|
226
231
|
// raise event
|
|
@@ -234,6 +239,8 @@ class FieldList {
|
|
|
234
239
|
this._items = this._items.filter(({ id }) => !itemIds.includes(id));
|
|
235
240
|
// raise event (if there are changes)
|
|
236
241
|
if (this._items.length !== itemCount) {
|
|
242
|
+
// update modified
|
|
243
|
+
this._modifiedOn = Date.now();
|
|
237
244
|
// revalidate
|
|
238
245
|
this.validate();
|
|
239
246
|
// raise change
|
|
@@ -268,11 +275,26 @@ class FieldList {
|
|
|
268
275
|
items.splice(toIndex, 0, item);
|
|
269
276
|
// update items
|
|
270
277
|
this._items = items;
|
|
278
|
+
this._modifiedOn = Date.now();
|
|
271
279
|
// revalidate
|
|
272
280
|
this.validate();
|
|
273
281
|
// raise change
|
|
274
282
|
this.raiseEvent('changed');
|
|
275
283
|
}
|
|
284
|
+
onSaveStart() {
|
|
285
|
+
this._savingOn = Date.now();
|
|
286
|
+
}
|
|
287
|
+
onSaveComplete() {
|
|
288
|
+
// reset to initial value if not modified or if save is newer
|
|
289
|
+
const { _modifiedOn, _savingOn } = this;
|
|
290
|
+
if (_savingOn && (!_modifiedOn || _savingOn >= _modifiedOn)) {
|
|
291
|
+
this._initialValue = this.value;
|
|
292
|
+
delete this._optIn;
|
|
293
|
+
delete this._optOut;
|
|
294
|
+
}
|
|
295
|
+
// clear saving flag
|
|
296
|
+
delete this._savingOn;
|
|
297
|
+
}
|
|
276
298
|
reset(initialValue) {
|
|
277
299
|
// re-bind new initial values
|
|
278
300
|
if (initialValue || initialValue === null) {
|
|
@@ -287,6 +309,8 @@ class FieldList {
|
|
|
287
309
|
else {
|
|
288
310
|
this._items.forEach(({ field }) => field.reset());
|
|
289
311
|
}
|
|
312
|
+
// mark modified
|
|
313
|
+
this._modifiedOn = Date.now();
|
|
290
314
|
// revalidate
|
|
291
315
|
this.validate();
|
|
292
316
|
// raise final change
|
|
@@ -15,6 +15,8 @@ export declare class ObjectField {
|
|
|
15
15
|
private readonly _content;
|
|
16
16
|
private readonly _fields;
|
|
17
17
|
private _initialValue;
|
|
18
|
+
private _modifiedOn?;
|
|
19
|
+
private _savingOn?;
|
|
18
20
|
private _optIn?;
|
|
19
21
|
private _optOut?;
|
|
20
22
|
constructor(args: ObjectField.ConstructorArgs);
|
|
@@ -40,6 +42,8 @@ export declare class ObjectField {
|
|
|
40
42
|
get shouldFocus(): boolean;
|
|
41
43
|
didFocus(): boolean;
|
|
42
44
|
getString(key: string | undefined): string | undefined;
|
|
45
|
+
onSaveStart(): void;
|
|
46
|
+
onSaveComplete(): void;
|
|
43
47
|
reset(initialValue?: ObjectField.Value | null): void;
|
|
44
48
|
clone(): ObjectField;
|
|
45
49
|
private raiseEvent;
|
|
@@ -93,6 +93,8 @@ class ObjectField {
|
|
|
93
93
|
field.value = values[key];
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
|
+
// mark modified
|
|
97
|
+
this._modifiedOn = Date.now();
|
|
96
98
|
}
|
|
97
99
|
get modified() {
|
|
98
100
|
// modified if opted in/our
|
|
@@ -179,9 +181,25 @@ class ObjectField {
|
|
|
179
181
|
return undefined;
|
|
180
182
|
}
|
|
181
183
|
}
|
|
184
|
+
onSaveStart() {
|
|
185
|
+
this._savingOn = Date.now();
|
|
186
|
+
}
|
|
187
|
+
onSaveComplete() {
|
|
188
|
+
// reset to initial value if not modified or if save is newer
|
|
189
|
+
const { _modifiedOn, _savingOn } = this;
|
|
190
|
+
if (_savingOn && (!_modifiedOn || _savingOn >= _modifiedOn)) {
|
|
191
|
+
this._initialValue = this.value;
|
|
192
|
+
delete this._optIn;
|
|
193
|
+
delete this._optOut;
|
|
194
|
+
}
|
|
195
|
+
// clear saving flag
|
|
196
|
+
delete this._savingOn;
|
|
197
|
+
}
|
|
182
198
|
reset(initialValue) {
|
|
183
199
|
var _a;
|
|
200
|
+
// reset fields using specified value
|
|
184
201
|
if (initialValue !== undefined) {
|
|
202
|
+
// update initial value
|
|
185
203
|
this._initialValue = initialValue !== null && initialValue !== void 0 ? initialValue : undefined;
|
|
186
204
|
// re-bind new initial values
|
|
187
205
|
const values = (_a = initialValue === null || initialValue === void 0 ? void 0 : initialValue.value) !== null && _a !== void 0 ? _a : {};
|
|
@@ -198,10 +216,12 @@ class ObjectField {
|
|
|
198
216
|
}
|
|
199
217
|
});
|
|
200
218
|
}
|
|
201
|
-
//
|
|
219
|
+
// or reset each field if there's no initial value
|
|
202
220
|
else {
|
|
203
221
|
this._fields.forEach(field => field.reset());
|
|
204
222
|
}
|
|
223
|
+
// track modified
|
|
224
|
+
this._modifiedOn = Date.now();
|
|
205
225
|
// raise final change
|
|
206
226
|
this.raiseEvent('changed');
|
|
207
227
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nascentdigital/funnel-core",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.14",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "git+https://github.com/nascentdigital/funnel.git",
|
|
6
6
|
"directory": "libs/core"
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"jest-tsd": "^0.2.2",
|
|
64
64
|
"ts-jest": "^29.3.2"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "242a9e0979c03d4037eb2462c5b01b2a095e8e8f"
|
|
67
67
|
}
|