@getdraft/plugin 1.17.5 → 1.19.0-alpha.1
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/README.md +128 -18
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +82 -34
- package/dist/index.es.js.map +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/index.iife.js.map +1 -1
- package/dist/types/index.d.ts +128 -0
- package/package.json +1 -1
- package/src/plugin.ts +80 -4
- package/src/types.ts +134 -0
- package/tsconfig.tsbuildinfo +0 -1
package/src/plugin.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
HandlerParams,
|
|
15
15
|
MessageData,
|
|
16
16
|
ExportAsFileParams,
|
|
17
|
+
RenderSectionPersonalizationGroupInput,
|
|
17
18
|
} from './types';
|
|
18
19
|
import {
|
|
19
20
|
getImageParamsFromFileUrl,
|
|
@@ -22,6 +23,8 @@ import {
|
|
|
22
23
|
} from './utils';
|
|
23
24
|
import pkg from '../package.json';
|
|
24
25
|
|
|
26
|
+
const UNKNOWN_ERROR_MESSAGE = 'Unknown error';
|
|
27
|
+
|
|
25
28
|
const getDeployLink = () => {
|
|
26
29
|
const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);
|
|
27
30
|
const match = document.cookie.match(regex);
|
|
@@ -170,7 +173,7 @@ export class PluginInstance {
|
|
|
170
173
|
reject(
|
|
171
174
|
new DraftError(
|
|
172
175
|
code || 'unknown_error',
|
|
173
|
-
message ||
|
|
176
|
+
message || UNKNOWN_ERROR_MESSAGE,
|
|
174
177
|
),
|
|
175
178
|
);
|
|
176
179
|
} else {
|
|
@@ -221,7 +224,7 @@ export class PluginInstance {
|
|
|
221
224
|
}
|
|
222
225
|
};
|
|
223
226
|
|
|
224
|
-
private onLoadPersonalization = async () => {
|
|
227
|
+
private onLoadPersonalization = async (requestId?: string) => {
|
|
225
228
|
try {
|
|
226
229
|
if (!this.config.on.loadPersonalization) {
|
|
227
230
|
throw new Error('No personalization loader provided');
|
|
@@ -232,9 +235,62 @@ export class PluginInstance {
|
|
|
232
235
|
|
|
233
236
|
this.postEvent('loadPersonalization', {
|
|
234
237
|
items: personalizationDictionary,
|
|
238
|
+
requestId,
|
|
235
239
|
});
|
|
236
240
|
} catch (e) {
|
|
237
|
-
this.postEvent('loadPersonalization', {});
|
|
241
|
+
this.postEvent('loadPersonalization', { requestId });
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
private onLoadSectionPersonalizationCatalog = async (requestId?: string) => {
|
|
246
|
+
try {
|
|
247
|
+
const handler = this.config.on.loadSectionPersonalizationCatalog;
|
|
248
|
+
|
|
249
|
+
if (!handler) {
|
|
250
|
+
throw new Error('No section personalization catalog loader provided');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const catalog = await handler();
|
|
254
|
+
|
|
255
|
+
this.postEvent('loadSectionPersonalizationCatalog', {
|
|
256
|
+
ok: true,
|
|
257
|
+
requestId,
|
|
258
|
+
catalog,
|
|
259
|
+
});
|
|
260
|
+
} catch (error) {
|
|
261
|
+
this.postEvent('loadSectionPersonalizationCatalog', {
|
|
262
|
+
ok: false,
|
|
263
|
+
requestId,
|
|
264
|
+
message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
private onRenderSectionPersonalizationGroup = async (
|
|
270
|
+
data: RenderSectionPersonalizationGroupInput & { requestId?: string },
|
|
271
|
+
) => {
|
|
272
|
+
const { requestId, ...input } = data;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const handler = this.config.on.renderSectionPersonalizationGroup;
|
|
276
|
+
|
|
277
|
+
if (!handler) {
|
|
278
|
+
throw new Error('No section personalization renderer provided');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const renderedHtml = await handler(input);
|
|
282
|
+
|
|
283
|
+
this.postEvent('renderSectionPersonalizationGroup', {
|
|
284
|
+
ok: true,
|
|
285
|
+
requestId,
|
|
286
|
+
html: renderedHtml,
|
|
287
|
+
});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
this.postEvent('renderSectionPersonalizationGroup', {
|
|
290
|
+
ok: false,
|
|
291
|
+
requestId,
|
|
292
|
+
message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,
|
|
293
|
+
});
|
|
238
294
|
}
|
|
239
295
|
};
|
|
240
296
|
|
|
@@ -284,7 +340,17 @@ export class PluginInstance {
|
|
|
284
340
|
} else if (event === 'uploadImage') {
|
|
285
341
|
this.onImageUpload(data as UploadImageParams & { id: string });
|
|
286
342
|
} else if (event === 'loadPersonalization') {
|
|
287
|
-
this.onLoadPersonalization();
|
|
343
|
+
this.onLoadPersonalization((data as { requestId?: string }).requestId);
|
|
344
|
+
} else if (event === 'loadSectionPersonalizationCatalog') {
|
|
345
|
+
this.onLoadSectionPersonalizationCatalog(
|
|
346
|
+
(data as { requestId?: string }).requestId,
|
|
347
|
+
);
|
|
348
|
+
} else if (event === 'renderSectionPersonalizationGroup') {
|
|
349
|
+
this.onRenderSectionPersonalizationGroup(
|
|
350
|
+
data as RenderSectionPersonalizationGroupInput & {
|
|
351
|
+
requestId?: string;
|
|
352
|
+
},
|
|
353
|
+
);
|
|
288
354
|
} else {
|
|
289
355
|
this.triggerEvent(
|
|
290
356
|
this.config.on[event],
|
|
@@ -326,12 +392,21 @@ export class PluginInstance {
|
|
|
326
392
|
apiUrl,
|
|
327
393
|
pluginId,
|
|
328
394
|
authData,
|
|
395
|
+
sectionPersonalization,
|
|
329
396
|
__config,
|
|
330
397
|
} = this.config;
|
|
331
398
|
|
|
332
399
|
verifyConfig(this.config);
|
|
333
400
|
|
|
334
401
|
if (this.iframe && this.iframe.contentWindow) {
|
|
402
|
+
const resolvedSectionPersonalization = {
|
|
403
|
+
...sectionPersonalization,
|
|
404
|
+
enabled:
|
|
405
|
+
sectionPersonalization?.enabled === true &&
|
|
406
|
+
!!on.loadSectionPersonalizationCatalog &&
|
|
407
|
+
!!on.renderSectionPersonalizationGroup,
|
|
408
|
+
};
|
|
409
|
+
|
|
335
410
|
this.postEvent('init', {
|
|
336
411
|
container,
|
|
337
412
|
locale,
|
|
@@ -340,6 +415,7 @@ export class PluginInstance {
|
|
|
340
415
|
token,
|
|
341
416
|
pluginId,
|
|
342
417
|
authData,
|
|
418
|
+
sectionPersonalization: resolvedSectionPersonalization,
|
|
343
419
|
apiUrl,
|
|
344
420
|
__config,
|
|
345
421
|
enabledListeners: Object.keys(on),
|
package/src/types.ts
CHANGED
|
@@ -23,6 +23,130 @@ type PersonalizationDictionaryEntry =
|
|
|
23
23
|
|
|
24
24
|
export type PersonalizationDictionaryItems = PersonalizationDictionaryEntry[];
|
|
25
25
|
|
|
26
|
+
export type SectionPersonalizationScalarValue = string | number | boolean;
|
|
27
|
+
|
|
28
|
+
export interface SectionPersonalizationRangeValue {
|
|
29
|
+
from: string | number | null;
|
|
30
|
+
to: string | number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type SectionPersonalizationValue =
|
|
34
|
+
| SectionPersonalizationScalarValue
|
|
35
|
+
| SectionPersonalizationScalarValue[]
|
|
36
|
+
| SectionPersonalizationRangeValue
|
|
37
|
+
| null;
|
|
38
|
+
|
|
39
|
+
export interface SectionPersonalizationField {
|
|
40
|
+
id: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SectionPersonalizationCondition {
|
|
44
|
+
operatorId: string;
|
|
45
|
+
value: SectionPersonalizationValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type SectionPersonalizationConditions = Record<
|
|
49
|
+
string,
|
|
50
|
+
SectionPersonalizationCondition
|
|
51
|
+
>;
|
|
52
|
+
|
|
53
|
+
export interface SectionPersonalizationCatalogOption {
|
|
54
|
+
label: string;
|
|
55
|
+
value: SectionPersonalizationScalarValue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type SectionPersonalizationRangeEndpointEditor =
|
|
59
|
+
| {
|
|
60
|
+
type: 'number';
|
|
61
|
+
integer?: boolean;
|
|
62
|
+
min?: number;
|
|
63
|
+
max?: number;
|
|
64
|
+
}
|
|
65
|
+
| { type: 'date' };
|
|
66
|
+
|
|
67
|
+
export type SectionPersonalizationValueEditor =
|
|
68
|
+
| { type: 'none' }
|
|
69
|
+
| { type: 'text'; maxLength?: number }
|
|
70
|
+
| {
|
|
71
|
+
type: 'number';
|
|
72
|
+
integer?: boolean;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
}
|
|
76
|
+
| { type: 'boolean' }
|
|
77
|
+
| { type: 'date' }
|
|
78
|
+
| { type: 'select'; options: SectionPersonalizationCatalogOption[] }
|
|
79
|
+
| { type: 'multi-select'; options: SectionPersonalizationCatalogOption[] }
|
|
80
|
+
| {
|
|
81
|
+
type: 'range';
|
|
82
|
+
valueEditor: SectionPersonalizationRangeEndpointEditor;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export interface SectionPersonalizationCatalogOperator {
|
|
86
|
+
id: string;
|
|
87
|
+
label: string;
|
|
88
|
+
/**
|
|
89
|
+
* Optional abbreviation for compact summaries, e.g. a math symbol. The
|
|
90
|
+
* integration owns it, so Draft never derives one from `id` or `label`.
|
|
91
|
+
*/
|
|
92
|
+
shortLabel?: string;
|
|
93
|
+
valueEditor: SectionPersonalizationValueEditor;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface SectionPersonalizationCatalogGroup {
|
|
97
|
+
type: 'group';
|
|
98
|
+
id: string;
|
|
99
|
+
label: string;
|
|
100
|
+
children: SectionPersonalizationCatalogNode[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface SectionPersonalizationCatalogField {
|
|
104
|
+
type: 'field';
|
|
105
|
+
id: string;
|
|
106
|
+
label: string;
|
|
107
|
+
defaultOperatorId: string;
|
|
108
|
+
operators: SectionPersonalizationCatalogOperator[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type SectionPersonalizationCatalogNode =
|
|
112
|
+
| SectionPersonalizationCatalogGroup
|
|
113
|
+
| SectionPersonalizationCatalogField;
|
|
114
|
+
|
|
115
|
+
export interface SectionPersonalizationConfig {
|
|
116
|
+
enabled: boolean;
|
|
117
|
+
aboutUrl?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* One audience the whole group is hidden from. Conditions inside are joined
|
|
122
|
+
* with AND, exclusions between themselves with OR.
|
|
123
|
+
*/
|
|
124
|
+
export interface SectionPersonalizationExclusion {
|
|
125
|
+
id: string;
|
|
126
|
+
conditions: SectionPersonalizationConditions;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface RenderSectionPersonalizationGroupInput {
|
|
130
|
+
groupId: string;
|
|
131
|
+
fields: SectionPersonalizationField[];
|
|
132
|
+
variants: Array<{
|
|
133
|
+
id: string;
|
|
134
|
+
conditions: SectionPersonalizationConditions;
|
|
135
|
+
html: string;
|
|
136
|
+
}>;
|
|
137
|
+
fallback?: {
|
|
138
|
+
id: string;
|
|
139
|
+
html: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Audiences the whole group must be hidden from, already stripped of unfilled
|
|
143
|
+
* conditions. Empty exclusions are dropped by Draft, so every entry carries at
|
|
144
|
+
* least one condition and the renderer never has to guard against a rule that
|
|
145
|
+
* would match everyone.
|
|
146
|
+
*/
|
|
147
|
+
hiddenFor?: SectionPersonalizationExclusion[];
|
|
148
|
+
}
|
|
149
|
+
|
|
26
150
|
export interface SerializedTemplate {
|
|
27
151
|
[key: string]: unknown;
|
|
28
152
|
parentId: string | null;
|
|
@@ -55,6 +179,7 @@ export type MessageData = {
|
|
|
55
179
|
code?: string;
|
|
56
180
|
message?: string;
|
|
57
181
|
action?: string;
|
|
182
|
+
requestId?: string;
|
|
58
183
|
};
|
|
59
184
|
|
|
60
185
|
export interface ExportAsFileParams {
|
|
@@ -266,6 +391,14 @@ export interface Handlers {
|
|
|
266
391
|
openGallery: EventHandler<(url?: string) => Promise<void>>;
|
|
267
392
|
uploadImage: AsyncEventHandler<UploadImageParams, string>;
|
|
268
393
|
loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;
|
|
394
|
+
loadSectionPersonalizationCatalog: AsyncEventHandler<
|
|
395
|
+
void,
|
|
396
|
+
SectionPersonalizationCatalogNode[]
|
|
397
|
+
>;
|
|
398
|
+
renderSectionPersonalizationGroup: AsyncEventHandler<
|
|
399
|
+
RenderSectionPersonalizationGroupInput,
|
|
400
|
+
string
|
|
401
|
+
>;
|
|
269
402
|
}
|
|
270
403
|
|
|
271
404
|
export type HandlerParams<H> = H extends
|
|
@@ -290,6 +423,7 @@ export interface PluginConfig {
|
|
|
290
423
|
pluginId: string;
|
|
291
424
|
apiUrl: string;
|
|
292
425
|
disableHotkeysPassing?: boolean;
|
|
426
|
+
sectionPersonalization?: SectionPersonalizationConfig;
|
|
293
427
|
__config?: object;
|
|
294
428
|
on: Partial<Handlers>;
|
|
295
429
|
}
|