@cloudcannon/editable-regions 0.0.6 → 0.0.7
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/components/ui/editable-array-item-controls.ts +3 -7
- package/components/ui/editable-component-controls.ts +17 -2
- package/nodes/editable-array-item.ts +5 -9
- package/nodes/editable-array.ts +19 -5
- package/nodes/editable-image.ts +3 -1
- package/nodes/editable-text.ts +2 -0
- package/nodes/editable.ts +37 -28
- package/package.json +1 -1
|
@@ -92,15 +92,11 @@ export default class EditableArrayItemControls extends EditableComponentControls
|
|
|
92
92
|
super.render(shadow);
|
|
93
93
|
|
|
94
94
|
this.dragHandle = document.createElement("button");
|
|
95
|
+
this.dragHandle.type = "button";
|
|
95
96
|
this.dragHandle.onclick = (e) => {
|
|
96
97
|
e.stopPropagation();
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.removeAttribute("open");
|
|
100
|
-
} else if (this.contextMenu && this.contextMenu.childElementCount > 0) {
|
|
101
|
-
this.contextMenu?.classList.add("open");
|
|
102
|
-
this.setAttribute("open", "true");
|
|
103
|
-
}
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
this.toggleContextMenu();
|
|
104
100
|
};
|
|
105
101
|
this.dragHandle.ondragstart = () => {
|
|
106
102
|
this.contextMenu?.classList.remove("open");
|
|
@@ -7,6 +7,16 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
7
7
|
|
|
8
8
|
private editButton?: HTMLButtonElement;
|
|
9
9
|
|
|
10
|
+
toggleContextMenu() {
|
|
11
|
+
if (this.contextMenu?.classList.contains("open")) {
|
|
12
|
+
this.contextMenu?.classList.remove("open");
|
|
13
|
+
this.removeAttribute("open");
|
|
14
|
+
} else if (this.contextMenu && this.contextMenu.childElementCount > 0) {
|
|
15
|
+
this.contextMenu?.classList.add("open");
|
|
16
|
+
this.setAttribute("open", "true");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
render(shadow: ShadowRoot): void {
|
|
11
21
|
const style = document.createElement("style");
|
|
12
22
|
style.textContent = styleContent;
|
|
@@ -21,18 +31,23 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
21
31
|
shadow.appendChild(this.contextMenu);
|
|
22
32
|
|
|
23
33
|
this.editButton = document.createElement("button");
|
|
34
|
+
this.editButton.type = "button";
|
|
24
35
|
this.editButton.innerHTML = '<cc-icon name="edit"></cc-icon>';
|
|
25
36
|
this.editButton.onclick = () => {
|
|
26
37
|
this.dispatchEvent(new CustomEvent("edit", { detail: this }));
|
|
27
38
|
};
|
|
28
39
|
this.buttonRow.append(this.editButton);
|
|
29
40
|
|
|
30
|
-
this.onclick = () => {
|
|
41
|
+
this.onclick = (e) => {
|
|
42
|
+
e.preventDefault();
|
|
31
43
|
this.contextMenu?.classList.remove("open");
|
|
32
44
|
this.removeAttribute("open");
|
|
33
45
|
};
|
|
34
46
|
|
|
35
|
-
this.onblur = () => {
|
|
47
|
+
this.onblur = (e) => {
|
|
48
|
+
if ((e.relatedTarget as HTMLElement)?.tagName === "A") {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
36
51
|
this.contextMenu?.classList.remove("open");
|
|
37
52
|
this.removeAttribute("open");
|
|
38
53
|
};
|
|
@@ -44,11 +44,11 @@ export default class EditableArrayItem extends EditableComponent {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
isValidDropzone(e: DragEvent): boolean {
|
|
47
|
-
|
|
48
|
-
if (!source || !e.dataTransfer) {
|
|
47
|
+
if (!e.dataTransfer) {
|
|
49
48
|
return false;
|
|
50
49
|
}
|
|
51
50
|
|
|
51
|
+
const source = this.parent?.contextBase?.fullPath ?? "@currentFile";
|
|
52
52
|
if (e.dataTransfer?.types.includes(source.toLowerCase())) {
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
@@ -96,11 +96,11 @@ export default class EditableArrayItem extends EditableComponent {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
onDragStart(e: DragEvent): void {
|
|
99
|
-
|
|
100
|
-
if (!source || !e.dataTransfer || !this.element.dataset.prop) {
|
|
99
|
+
if (!e.dataTransfer || !this.element.dataset.prop) {
|
|
101
100
|
return;
|
|
102
101
|
}
|
|
103
102
|
|
|
103
|
+
const source = this.parent?.contextBase?.fullPath ?? "@currentFile";
|
|
104
104
|
const clientRect = this.element.getBoundingClientRect();
|
|
105
105
|
|
|
106
106
|
e.stopPropagation();
|
|
@@ -423,11 +423,7 @@ export default class EditableArrayItem extends EditableComponent {
|
|
|
423
423
|
return;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
const source = this.parent?.contextBase?.
|
|
427
|
-
if (!source) {
|
|
428
|
-
throw new Error("Source not found");
|
|
429
|
-
}
|
|
430
|
-
|
|
426
|
+
const source = this.parent?.contextBase?.fullPath ?? "@currentFile";
|
|
431
427
|
const dragType = this.getDragType();
|
|
432
428
|
const sameArrayData = e.dataTransfer.getData(source);
|
|
433
429
|
const otherArrayData = dragType
|
package/nodes/editable-array.ts
CHANGED
|
@@ -29,6 +29,7 @@ export default class EditableArray extends Editable {
|
|
|
29
29
|
value:
|
|
30
30
|
| CloudCannonJavaScriptV1APICollection
|
|
31
31
|
| CloudCannonJavaScriptV1APIDataset
|
|
32
|
+
| CloudCannonJavaScriptV1APIFile
|
|
32
33
|
| unknown[]
|
|
33
34
|
| null
|
|
34
35
|
| undefined = undefined;
|
|
@@ -42,6 +43,7 @@ export default class EditableArray extends Editable {
|
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
const __base_context = { ...this.contextBase };
|
|
45
47
|
let value: unknown[] | CloudCannonJavaScriptV1APIFile[];
|
|
46
48
|
if (CloudCannon.isAPICollection(this.value)) {
|
|
47
49
|
value = await this.value.items();
|
|
@@ -51,8 +53,13 @@ export default class EditableArray extends Editable {
|
|
|
51
53
|
value = items;
|
|
52
54
|
} else {
|
|
53
55
|
const data = await items.data.get();
|
|
56
|
+
__base_context.file = items;
|
|
54
57
|
value = Array.isArray(data) ? data : [];
|
|
55
58
|
}
|
|
59
|
+
} else if (CloudCannon.isAPIFile(this.value)) {
|
|
60
|
+
const data = await this.value.data.get();
|
|
61
|
+
__base_context.file = this.value;
|
|
62
|
+
value = Array.isArray(data) ? data : [];
|
|
56
63
|
} else if (Array.isArray(this.value)) {
|
|
57
64
|
value = this.value;
|
|
58
65
|
} else {
|
|
@@ -84,7 +91,7 @@ export default class EditableArray extends Editable {
|
|
|
84
91
|
|
|
85
92
|
if (listener.path) {
|
|
86
93
|
listener.editable.pushValue(value, listener, {
|
|
87
|
-
__base_context
|
|
94
|
+
__base_context,
|
|
88
95
|
});
|
|
89
96
|
}
|
|
90
97
|
}
|
|
@@ -113,7 +120,8 @@ export default class EditableArray extends Editable {
|
|
|
113
120
|
!Array.isArray(value) &&
|
|
114
121
|
value !== null &&
|
|
115
122
|
!CloudCannon.isAPICollection(value) &&
|
|
116
|
-
!CloudCannon.isAPIDataset(value)
|
|
123
|
+
!CloudCannon.isAPIDataset(value) &&
|
|
124
|
+
!CloudCannon.isAPIFile(value)
|
|
117
125
|
) {
|
|
118
126
|
this.element.classList.add("errored");
|
|
119
127
|
const error = document.createElement("editable-region-error-card");
|
|
@@ -156,6 +164,7 @@ export default class EditableArray extends Editable {
|
|
|
156
164
|
|
|
157
165
|
private async _update(): Promise<void> {
|
|
158
166
|
let value: unknown[] | CloudCannonJavaScriptV1APIFile[];
|
|
167
|
+
const __base_context = { ...this.contextBase };
|
|
159
168
|
if (CloudCannon.isAPICollection(this.value)) {
|
|
160
169
|
value = await this.value.items();
|
|
161
170
|
} else if (CloudCannon.isAPIDataset(this.value)) {
|
|
@@ -164,8 +173,13 @@ export default class EditableArray extends Editable {
|
|
|
164
173
|
value = items;
|
|
165
174
|
} else {
|
|
166
175
|
const data = await items.data.get();
|
|
176
|
+
__base_context.file = items;
|
|
167
177
|
value = Array.isArray(data) ? data : [];
|
|
168
178
|
}
|
|
179
|
+
} else if (CloudCannon.isAPIFile(this.value)) {
|
|
180
|
+
const data = await this.value.data.get();
|
|
181
|
+
__base_context.file = this.value;
|
|
182
|
+
value = Array.isArray(data) ? data : [];
|
|
169
183
|
} else if (Array.isArray(this.value)) {
|
|
170
184
|
value = this.value;
|
|
171
185
|
} else {
|
|
@@ -240,7 +254,7 @@ export default class EditableArray extends Editable {
|
|
|
240
254
|
child.editable?.pushValue(
|
|
241
255
|
value,
|
|
242
256
|
{ path: `${i}`, editable: child.editable },
|
|
243
|
-
{ __base_context
|
|
257
|
+
{ __base_context },
|
|
244
258
|
);
|
|
245
259
|
}
|
|
246
260
|
return;
|
|
@@ -284,7 +298,7 @@ export default class EditableArray extends Editable {
|
|
|
284
298
|
child.editable?.pushValue(
|
|
285
299
|
value,
|
|
286
300
|
{ path: `${index}`, editable: child.editable },
|
|
287
|
-
{ __base_context
|
|
301
|
+
{ __base_context },
|
|
288
302
|
);
|
|
289
303
|
});
|
|
290
304
|
|
|
@@ -374,7 +388,7 @@ export default class EditableArray extends Editable {
|
|
|
374
388
|
matchingChild.editable.pushValue(
|
|
375
389
|
value,
|
|
376
390
|
{ path: `${i}`, editable: matchingChild.editable },
|
|
377
|
-
{ __base_context
|
|
391
|
+
{ __base_context },
|
|
378
392
|
);
|
|
379
393
|
}
|
|
380
394
|
});
|
package/nodes/editable-image.ts
CHANGED
|
@@ -185,7 +185,9 @@ export default class EditableImage extends Editable {
|
|
|
185
185
|
!!this.element.dataset.propTitle || !!this.element.dataset.prop;
|
|
186
186
|
|
|
187
187
|
this.loadInputConfig().then(() => {
|
|
188
|
-
this.imageEl?.addEventListener("click", () => {
|
|
188
|
+
this.imageEl?.addEventListener("click", (e) => {
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
|
|
189
191
|
if (!this.value) {
|
|
190
192
|
throw new Error("Value is not defined");
|
|
191
193
|
}
|
package/nodes/editable-text.ts
CHANGED
package/nodes/editable.ts
CHANGED
|
@@ -88,14 +88,16 @@ export default class Editable {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
async lookupPathAndContext(
|
|
91
|
-
path
|
|
92
|
-
obj
|
|
91
|
+
path?: string,
|
|
92
|
+
obj?: unknown,
|
|
93
93
|
contexts: { [key: string]: EditableContext } = {},
|
|
94
94
|
): Promise<{ value: any; context: EditableContext }> {
|
|
95
95
|
if (!path) {
|
|
96
96
|
return {
|
|
97
97
|
value: obj,
|
|
98
|
-
context: {
|
|
98
|
+
context: {
|
|
99
|
+
...contexts.__base_context,
|
|
100
|
+
},
|
|
99
101
|
};
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -166,9 +168,9 @@ export default class Editable {
|
|
|
166
168
|
): Promise<unknown> {
|
|
167
169
|
const { key, path } = listener ?? {};
|
|
168
170
|
|
|
169
|
-
const { value: resolvedValue, context: newContext } =
|
|
170
|
-
|
|
171
|
-
|
|
171
|
+
const { value: resolvedValue, context: newContext } =
|
|
172
|
+
await this.lookupPathAndContext(path, value, contexts);
|
|
173
|
+
|
|
172
174
|
if (!key) {
|
|
173
175
|
this.propsBase = resolvedValue;
|
|
174
176
|
this.contextBase = newContext;
|
|
@@ -317,9 +319,12 @@ export default class Editable {
|
|
|
317
319
|
let parentEditable: Editable | undefined;
|
|
318
320
|
let parent = this.element.parentElement;
|
|
319
321
|
while (parent) {
|
|
320
|
-
if (hasEditable(parent)) {
|
|
322
|
+
if (hasEditable(parent) && !parentEditable) {
|
|
321
323
|
parentEditable = parent.editable;
|
|
322
|
-
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (parent.tagName === "A") {
|
|
327
|
+
parent.draggable = false;
|
|
323
328
|
}
|
|
324
329
|
parent = parent.parentElement;
|
|
325
330
|
}
|
|
@@ -331,7 +336,7 @@ export default class Editable {
|
|
|
331
336
|
return;
|
|
332
337
|
}
|
|
333
338
|
|
|
334
|
-
const { collection, file, dataset, source, absolute } =
|
|
339
|
+
const { collection, file, dataset, source, absolute, currentFile } =
|
|
335
340
|
this.parseSource(propPath);
|
|
336
341
|
|
|
337
342
|
const listener = {
|
|
@@ -349,8 +354,15 @@ export default class Editable {
|
|
|
349
354
|
// Any single data path should only be able to refer to a single absolute API object
|
|
350
355
|
const obj = collection || dataset || file;
|
|
351
356
|
if (obj) {
|
|
357
|
+
const fullPath = collection
|
|
358
|
+
? `@collections[${collection.collectionKey}]`
|
|
359
|
+
: dataset
|
|
360
|
+
? `@data[${dataset.datasetKey}]`
|
|
361
|
+
: currentFile
|
|
362
|
+
? undefined
|
|
363
|
+
: `@file[${file?.path}]`;
|
|
352
364
|
const handleAPIChange = () => {
|
|
353
|
-
this.pushValue(obj, listener);
|
|
365
|
+
this.pushValue(obj, listener, { __base_context: { fullPath } });
|
|
354
366
|
};
|
|
355
367
|
this.APIListeners.push({
|
|
356
368
|
obj,
|
|
@@ -425,22 +437,6 @@ export default class Editable {
|
|
|
425
437
|
}
|
|
426
438
|
|
|
427
439
|
filePromise.then((file) => {
|
|
428
|
-
if (typeof source !== "string") {
|
|
429
|
-
if (options.action === "get-input-config") {
|
|
430
|
-
options.callback({
|
|
431
|
-
options: {
|
|
432
|
-
disable_reorder: true,
|
|
433
|
-
disable_remove: true,
|
|
434
|
-
disable_add: true,
|
|
435
|
-
},
|
|
436
|
-
});
|
|
437
|
-
return true;
|
|
438
|
-
}
|
|
439
|
-
throw new Error(
|
|
440
|
-
`Failed to resolve source for API call: ${options.source}`,
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
440
|
switch (options.action) {
|
|
445
441
|
case "edit":
|
|
446
442
|
file?.data.edit({ slug: source, position: options.position });
|
|
@@ -474,7 +470,17 @@ export default class Editable {
|
|
|
474
470
|
});
|
|
475
471
|
break;
|
|
476
472
|
case "get-input-config":
|
|
477
|
-
|
|
473
|
+
if (!file) {
|
|
474
|
+
options.callback({
|
|
475
|
+
options: {
|
|
476
|
+
disable_reorder: true,
|
|
477
|
+
disable_remove: true,
|
|
478
|
+
disable_add: true,
|
|
479
|
+
},
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
file?.getInputConfig({ slug: source }).then(options.callback);
|
|
483
|
+
}
|
|
478
484
|
break;
|
|
479
485
|
}
|
|
480
486
|
});
|
|
@@ -521,6 +527,7 @@ export default class Editable {
|
|
|
521
527
|
let file: CloudCannonJavaScriptV1APIFile | undefined;
|
|
522
528
|
let dataset: CloudCannonJavaScriptV1APIDataset | undefined;
|
|
523
529
|
let absolute = false;
|
|
530
|
+
let currentFile = false;
|
|
524
531
|
|
|
525
532
|
const collectionMatch = source?.match(
|
|
526
533
|
/^@collections\[(?<key>[^\]]+)\](\.(?<rest>.+))?$/,
|
|
@@ -550,6 +557,7 @@ export default class Editable {
|
|
|
550
557
|
absolute = true;
|
|
551
558
|
} else {
|
|
552
559
|
file = CloudCannon.currentFile();
|
|
560
|
+
currentFile = true;
|
|
553
561
|
}
|
|
554
562
|
}
|
|
555
563
|
}
|
|
@@ -566,10 +574,11 @@ export default class Editable {
|
|
|
566
574
|
return {
|
|
567
575
|
collection,
|
|
568
576
|
file,
|
|
569
|
-
source,
|
|
577
|
+
source: source ?? "",
|
|
570
578
|
absolute,
|
|
571
579
|
snippets,
|
|
572
580
|
dataset,
|
|
581
|
+
currentFile,
|
|
573
582
|
};
|
|
574
583
|
}
|
|
575
584
|
}
|