bard-attachment_field 0.2.5 → 0.3.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/input-attachment.js +55 -33
- data/input-attachment/src/components/attachment-file/direct-upload-controller.tsx +8 -4
- data/input-attachment/src/components/input-attachment/form-controller.spec.ts +63 -0
- data/input-attachment/src/components/input-attachment/form-controller.tsx +32 -26
- data/input-attachment/src/components/input-attachment/input-attachment.tsx +2 -1
- data/input-attachment/src/components/input-attachment/readme.md +11 -10
- data/input-attachment/src/components.d.ts +8 -0
- data/lib/bard/attachment_field/field.rb +3 -0
- data/lib/bard/attachment_field/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 77372a4e55bd97d9a4c52f8089427717d9181d225d58b18814194a938a1c1631
|
|
4
|
+
data.tar.gz: 2eaa2f26f3a3f6fbf57523527923e21694596a13ab1de7968f4c401a5d368f88
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd9cb5858441b97a1fde1189fad046b5c0d1295f5da2b7d5134bd84113cc9be32e419217a910ce716ce2702ec71d40586a1bf59bbd0cfa2fdeed41d0eafd0b57
|
|
7
|
+
data.tar.gz: 4881721450377ab4e55467c6ea7dae84ca371186a66ef3f77d50ffcbac921204d8dab282a0668a0997c5b5c36c9fae1d5136f33d4c530980bc5b279c2a25c4b5
|
|
@@ -4864,22 +4864,22 @@ var DirectUploadController2 = class {
|
|
|
4864
4864
|
recordXHR;
|
|
4865
4865
|
uploadXHR;
|
|
4866
4866
|
callback = null;
|
|
4867
|
+
cancelled = false;
|
|
4868
|
+
completed = false;
|
|
4867
4869
|
constructor(uploadedFile, file) {
|
|
4868
4870
|
this.uploadedFile = uploadedFile;
|
|
4869
4871
|
this.file = file;
|
|
4870
4872
|
this.directUpload = new DirectUpload(this.file, this.uploadedFile.url, this);
|
|
4871
4873
|
}
|
|
4872
4874
|
cancel() {
|
|
4873
|
-
this.
|
|
4875
|
+
this.cancelled = true;
|
|
4874
4876
|
this.abortXHR(this.recordXHR);
|
|
4875
4877
|
this.abortXHR(this.uploadXHR);
|
|
4878
|
+
this.complete("aborted", {});
|
|
4876
4879
|
}
|
|
4877
4880
|
abortXHR(xhr) {
|
|
4878
4881
|
if (!xhr)
|
|
4879
4882
|
return;
|
|
4880
|
-
xhr.addEventListener("abort", () => {
|
|
4881
|
-
this.complete("aborted", {});
|
|
4882
|
-
});
|
|
4883
4883
|
xhr.abort();
|
|
4884
4884
|
}
|
|
4885
4885
|
start(callback) {
|
|
@@ -4890,6 +4890,9 @@ var DirectUploadController2 = class {
|
|
|
4890
4890
|
});
|
|
4891
4891
|
}
|
|
4892
4892
|
complete(error, _attributes) {
|
|
4893
|
+
if (this.completed)
|
|
4894
|
+
return;
|
|
4895
|
+
this.completed = true;
|
|
4893
4896
|
if (error) {
|
|
4894
4897
|
this.dispatchError(error);
|
|
4895
4898
|
}
|
|
@@ -4920,12 +4923,22 @@ var DirectUploadController2 = class {
|
|
|
4920
4923
|
}
|
|
4921
4924
|
directUploadWillCreateBlobWithXHR(xhr) {
|
|
4922
4925
|
this.recordXHR = xhr;
|
|
4926
|
+
if (this.cancelled) {
|
|
4927
|
+
xhr.send = () => {
|
|
4928
|
+
};
|
|
4929
|
+
return;
|
|
4930
|
+
}
|
|
4923
4931
|
this.dispatch("before-blob-request", {
|
|
4924
4932
|
xhr
|
|
4925
4933
|
});
|
|
4926
4934
|
}
|
|
4927
4935
|
directUploadWillStoreFileWithXHR(xhr) {
|
|
4928
4936
|
this.uploadXHR = xhr;
|
|
4937
|
+
if (this.cancelled) {
|
|
4938
|
+
xhr.send = () => {
|
|
4939
|
+
};
|
|
4940
|
+
return;
|
|
4941
|
+
}
|
|
4929
4942
|
this.uploadedFile.value = this.recordXHR.response.signed_id;
|
|
4930
4943
|
this.dispatch("before-storage-request", {
|
|
4931
4944
|
xhr
|
|
@@ -5425,8 +5438,8 @@ var AttachmentPreview3 = AttachmentPreview;
|
|
|
5425
5438
|
|
|
5426
5439
|
// dist/components/input-attachment.js
|
|
5427
5440
|
var FormController = class _FormController {
|
|
5428
|
-
static instance(form) {
|
|
5429
|
-
return form.inputAttachmentFormController ||= new _FormController(form);
|
|
5441
|
+
static instance(form, options = {}) {
|
|
5442
|
+
return form.inputAttachmentFormController ||= new _FormController(form, options);
|
|
5430
5443
|
}
|
|
5431
5444
|
progressContainerTarget;
|
|
5432
5445
|
dialog;
|
|
@@ -5435,22 +5448,24 @@ var FormController = class _FormController {
|
|
|
5435
5448
|
controllers;
|
|
5436
5449
|
submitted;
|
|
5437
5450
|
processing;
|
|
5438
|
-
constructor(form) {
|
|
5451
|
+
constructor(form, { uploadDialog = true } = {}) {
|
|
5439
5452
|
this.element = form;
|
|
5440
5453
|
this.progressTargetMap = {};
|
|
5441
5454
|
this.controllers = [];
|
|
5442
5455
|
this.submitted = false;
|
|
5443
5456
|
this.processing = false;
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
<div class="direct-upload-
|
|
5447
|
-
<
|
|
5448
|
-
|
|
5457
|
+
if (uploadDialog) {
|
|
5458
|
+
this.element.insertAdjacentHTML("beforeend", `<dialog id="form-controller-dialog">
|
|
5459
|
+
<div class="direct-upload-wrapper">
|
|
5460
|
+
<div class="direct-upload-content">
|
|
5461
|
+
<h3>Uploading your media</h3>
|
|
5462
|
+
<div id="progress-container"></div>
|
|
5463
|
+
</div>
|
|
5449
5464
|
</div>
|
|
5450
|
-
</
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5465
|
+
</dialog>`);
|
|
5466
|
+
this.dialog = this.element.querySelector("#form-controller-dialog");
|
|
5467
|
+
this.progressContainerTarget = this.dialog.querySelector("#progress-container");
|
|
5468
|
+
}
|
|
5454
5469
|
this.element.addEventListener("submit", (event) => this.submit(event));
|
|
5455
5470
|
window.addEventListener("beforeunload", (event) => this.beforeUnload(event));
|
|
5456
5471
|
this.element.addEventListener("direct-upload:initialize", (event) => this.init(event));
|
|
@@ -5474,7 +5489,7 @@ var FormController = class _FormController {
|
|
|
5474
5489
|
this.setInputAttachmentsDisabled(true);
|
|
5475
5490
|
this.startNextController();
|
|
5476
5491
|
if (this.processing) {
|
|
5477
|
-
this.dialog
|
|
5492
|
+
this.dialog?.showModal();
|
|
5478
5493
|
}
|
|
5479
5494
|
}
|
|
5480
5495
|
startNextController() {
|
|
@@ -5510,7 +5525,7 @@ var FormController = class _FormController {
|
|
|
5510
5525
|
if (!this.submitted)
|
|
5511
5526
|
return;
|
|
5512
5527
|
if (this.hasUploadErrors()) {
|
|
5513
|
-
this.dialog
|
|
5528
|
+
this.dialog?.close();
|
|
5514
5529
|
this.setInputAttachmentsDisabled(false);
|
|
5515
5530
|
return;
|
|
5516
5531
|
}
|
|
@@ -5532,36 +5547,41 @@ var FormController = class _FormController {
|
|
|
5532
5547
|
}
|
|
5533
5548
|
init(event) {
|
|
5534
5549
|
const { id: id2, file, controller } = event.detail;
|
|
5535
|
-
this.progressContainerTarget
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5550
|
+
if (this.progressContainerTarget) {
|
|
5551
|
+
this.progressContainerTarget.insertAdjacentHTML("beforebegin", `
|
|
5552
|
+
<progress-bar id="direct-upload-${id2}" class="direct-upload--pending">${file?.name || "Uploading..."}</progress-bar>
|
|
5553
|
+
`);
|
|
5554
|
+
this.progressTargetMap[id2] = document.getElementById(`direct-upload-${id2}`);
|
|
5555
|
+
}
|
|
5540
5556
|
this.controllers.push(controller);
|
|
5541
5557
|
this.startNextController();
|
|
5542
5558
|
}
|
|
5543
5559
|
start(event) {
|
|
5544
|
-
this.progressTargetMap[event.detail.id]
|
|
5560
|
+
this.progressTargetMap[event.detail.id]?.classList.remove("direct-upload--pending");
|
|
5545
5561
|
}
|
|
5546
5562
|
progress(event) {
|
|
5547
5563
|
const { id: id2, progress } = event.detail;
|
|
5548
|
-
this.progressTargetMap[id2]
|
|
5564
|
+
const target = this.progressTargetMap[id2];
|
|
5565
|
+
if (target)
|
|
5566
|
+
target.percent = progress;
|
|
5549
5567
|
}
|
|
5550
5568
|
error(event) {
|
|
5551
5569
|
event.preventDefault();
|
|
5552
5570
|
const { id: id2, error } = event.detail;
|
|
5553
5571
|
const target = this.progressTargetMap[id2];
|
|
5554
|
-
target
|
|
5555
|
-
|
|
5572
|
+
if (target) {
|
|
5573
|
+
target.classList.add("direct-upload--error");
|
|
5574
|
+
target.title = error;
|
|
5575
|
+
}
|
|
5556
5576
|
}
|
|
5557
5577
|
end(event) {
|
|
5558
|
-
this.progressTargetMap[event.detail.id]
|
|
5578
|
+
this.progressTargetMap[event.detail.id]?.classList.add("direct-upload--complete");
|
|
5559
5579
|
}
|
|
5560
5580
|
removeUploadedFile(event) {
|
|
5561
5581
|
const uploadedFile = event.detail;
|
|
5562
5582
|
const id2 = uploadedFile.controller?.directUpload?.id;
|
|
5563
5583
|
if (id2) {
|
|
5564
|
-
document.getElementById(`direct-upload-${id2}`)
|
|
5584
|
+
document.getElementById(`direct-upload-${id2}`)?.remove();
|
|
5565
5585
|
delete this.progressTargetMap[id2];
|
|
5566
5586
|
}
|
|
5567
5587
|
this.setInputAttachmentsDisabled(false);
|
|
@@ -5746,6 +5766,7 @@ var InputAttachment$1 = /* @__PURE__ */ proxyCustomElement(class InputAttachment
|
|
|
5746
5766
|
max;
|
|
5747
5767
|
preview = true;
|
|
5748
5768
|
disabled = false;
|
|
5769
|
+
uploadDialog = true;
|
|
5749
5770
|
form;
|
|
5750
5771
|
internals;
|
|
5751
5772
|
fileInput;
|
|
@@ -5762,7 +5783,7 @@ var InputAttachment$1 = /* @__PURE__ */ proxyCustomElement(class InputAttachment
|
|
|
5762
5783
|
this.form = this.internals.form;
|
|
5763
5784
|
if (this.form) {
|
|
5764
5785
|
this.form.addEventListener("reset", () => this.reset());
|
|
5765
|
-
FormController.instance(this.form);
|
|
5786
|
+
FormController.instance(this.form, { uploadDialog: this.uploadDialog });
|
|
5766
5787
|
}
|
|
5767
5788
|
const existingFiles = Array.from(this.el.children).filter((e) => e.tagName == "ATTACHMENT-FILE");
|
|
5768
5789
|
if (existingFiles.length > 0)
|
|
@@ -5935,12 +5956,12 @@ var InputAttachment$1 = /* @__PURE__ */ proxyCustomElement(class InputAttachment
|
|
|
5935
5956
|
return this.disabled || !!this.el.closest("fieldset[disabled]");
|
|
5936
5957
|
}
|
|
5937
5958
|
render() {
|
|
5938
|
-
return h(Host, { key: "
|
|
5959
|
+
return h(Host, { key: "e63c2624a4d88232adacc7d1610983fac89eb9db" }, h("input", { key: "baea544d4d62e31e1228d92ba8b0356d40e75ce5", ref: (el) => this.fileInput = el, type: "file", multiple: this.multiple, accept: this.accepts, required: this.required && this.files.length === 0, disabled: this.isDisabled, onChange: () => this.handleFileInputChange(), style: {
|
|
5939
5960
|
opacity: "0.01",
|
|
5940
5961
|
width: "1px",
|
|
5941
5962
|
height: "1px",
|
|
5942
5963
|
zIndex: "-999"
|
|
5943
|
-
} }), h("file-drop", { key: "
|
|
5964
|
+
} }), h("file-drop", { key: "0b5621010445988462b8056cb360bf18ac6b0b59", onClick: () => this.fileInput?.click(), onDrop: this.handleDrop }, h("p", { key: "718fe6b91ed9cdc5c5a2b54317fad8f1f25b3cd4", part: "title" }, h("strong", { key: "f28b9ffc58bb086bb1941ee01e943fe5068482a4" }, "Choose ", this.multiple ? "files" : "file", " "), h("span", { key: "eeca7b2f619a7a4d7863f98ba37218d6a66fdcfd" }, "or drag ", this.multiple ? "them" : "it", " here.")), h("div", { key: "2a1d0a824139f5c26833611a5523354965be0d9d", class: `media-preview ${this.multiple ? "-stacked" : ""}` }, h("slot", { key: "59455a857d01dfabd7aa5e697616f4be72cbbb20" }))));
|
|
5944
5965
|
}
|
|
5945
5966
|
componentDidRender() {
|
|
5946
5967
|
if (this.files.length === 0) {
|
|
@@ -6016,7 +6037,8 @@ var InputAttachment$1 = /* @__PURE__ */ proxyCustomElement(class InputAttachment
|
|
|
6016
6037
|
"accepts": [1],
|
|
6017
6038
|
"max": [2],
|
|
6018
6039
|
"preview": [4],
|
|
6019
|
-
"disabled": [4]
|
|
6040
|
+
"disabled": [4],
|
|
6041
|
+
"uploadDialog": [4, "upload-dialog"]
|
|
6020
6042
|
}, [[0, "attachment-file:remove", "removeUploadedFile"], [0, "attachment-file:validation", "handleChildValidation"], [0, "attachment-file:ready", "handleChildReady"], [0, "direct-upload:end", "fireChangeEvent"]]]);
|
|
6021
6043
|
var InputAttachment2 = InputAttachment$1;
|
|
6022
6044
|
|
|
@@ -8,6 +8,8 @@ export default class DirectUploadController {
|
|
|
8
8
|
recordXHR: XMLHttpRequest
|
|
9
9
|
uploadXHR: XMLHttpRequest
|
|
10
10
|
callback = null
|
|
11
|
+
cancelled = false
|
|
12
|
+
completed = false
|
|
11
13
|
|
|
12
14
|
constructor(uploadedFile, file: File) {
|
|
13
15
|
this.uploadedFile = uploadedFile
|
|
@@ -16,16 +18,14 @@ export default class DirectUploadController {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
cancel() {
|
|
19
|
-
this.
|
|
21
|
+
this.cancelled = true
|
|
20
22
|
this.abortXHR(this.recordXHR)
|
|
21
23
|
this.abortXHR(this.uploadXHR)
|
|
24
|
+
this.complete("aborted", {})
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
abortXHR(xhr) {
|
|
25
28
|
if(!xhr) return
|
|
26
|
-
xhr.addEventListener("abort", () => {
|
|
27
|
-
this.complete("aborted", {})
|
|
28
|
-
})
|
|
29
29
|
xhr.abort()
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -38,6 +38,8 @@ export default class DirectUploadController {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
complete(error, _attributes) {
|
|
41
|
+
if (this.completed) return
|
|
42
|
+
this.completed = true
|
|
41
43
|
if (error) {
|
|
42
44
|
this.dispatchError(error)
|
|
43
45
|
}
|
|
@@ -69,12 +71,14 @@ export default class DirectUploadController {
|
|
|
69
71
|
}
|
|
70
72
|
directUploadWillCreateBlobWithXHR(xhr) {
|
|
71
73
|
this.recordXHR = xhr
|
|
74
|
+
if (this.cancelled) { xhr.send = () => {}; return }
|
|
72
75
|
this.dispatch("before-blob-request", {
|
|
73
76
|
xhr: xhr
|
|
74
77
|
});
|
|
75
78
|
}
|
|
76
79
|
directUploadWillStoreFileWithXHR(xhr) {
|
|
77
80
|
this.uploadXHR = xhr
|
|
81
|
+
if (this.cancelled) { xhr.send = () => {}; return }
|
|
78
82
|
this.uploadedFile.value = this.recordXHR.response.signed_id
|
|
79
83
|
this.dispatch("before-storage-request", {
|
|
80
84
|
xhr: xhr
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import FormController from "./form-controller"
|
|
2
|
+
|
|
3
|
+
function createForm() {
|
|
4
|
+
const form = document.createElement("form")
|
|
5
|
+
document.body.appendChild(form)
|
|
6
|
+
return form
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
document.body.innerHTML = ""
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe("FormController", () => {
|
|
14
|
+
describe("default (uploadDialog: true)", () => {
|
|
15
|
+
it("creates the dialog and progress container", () => {
|
|
16
|
+
const form = createForm()
|
|
17
|
+
const controller = FormController.instance(form)
|
|
18
|
+
expect(controller.dialog).toBeTruthy()
|
|
19
|
+
expect(controller.progressContainerTarget).toBeTruthy()
|
|
20
|
+
expect(form.querySelector("#form-controller-dialog")).toBeTruthy()
|
|
21
|
+
expect(form.querySelector("#progress-container")).toBeTruthy()
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe("uploadDialog: false", () => {
|
|
26
|
+
it("does not create the dialog or progress container", () => {
|
|
27
|
+
const form = createForm()
|
|
28
|
+
const controller = FormController.instance(form, { uploadDialog: false })
|
|
29
|
+
expect(controller.dialog).toBeFalsy()
|
|
30
|
+
expect(controller.progressContainerTarget).toBeFalsy()
|
|
31
|
+
expect(form.querySelector("#form-controller-dialog")).toBeNull()
|
|
32
|
+
expect(form.querySelector("#progress-container")).toBeNull()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("still registers event listeners and queues controllers", () => {
|
|
36
|
+
const form = createForm()
|
|
37
|
+
FormController.instance(form, { uploadDialog: false })
|
|
38
|
+
|
|
39
|
+
const uploadedFile = document.createElement("div")
|
|
40
|
+
form.appendChild(uploadedFile)
|
|
41
|
+
const mockController = { start: jest.fn(cb => cb(null)), uploadedFile }
|
|
42
|
+
form.dispatchEvent(new CustomEvent("direct-upload:initialize", {
|
|
43
|
+
detail: { id: 1, file: { name: "test.jpg" }, controller: mockController },
|
|
44
|
+
}))
|
|
45
|
+
|
|
46
|
+
expect(mockController.start).toHaveBeenCalled()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it("does not create progress bars on init", () => {
|
|
50
|
+
const form = createForm()
|
|
51
|
+
FormController.instance(form, { uploadDialog: false })
|
|
52
|
+
|
|
53
|
+
const uploadedFile = document.createElement("div")
|
|
54
|
+
form.appendChild(uploadedFile)
|
|
55
|
+
const mockController = { start: jest.fn(cb => cb(null)), uploadedFile }
|
|
56
|
+
form.dispatchEvent(new CustomEvent("direct-upload:initialize", {
|
|
57
|
+
detail: { id: 1, file: { name: "test.jpg" }, controller: mockController },
|
|
58
|
+
}))
|
|
59
|
+
|
|
60
|
+
expect(form.querySelector("progress-bar")).toBeNull()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import DirectUploadController from "../attachment-file/direct-upload-controller"
|
|
2
2
|
|
|
3
3
|
export default class FormController {
|
|
4
|
-
static instance(form) {
|
|
5
|
-
return form.inputAttachmentFormController ||= new FormController(form)
|
|
4
|
+
static instance(form, options = {}) {
|
|
5
|
+
return form.inputAttachmentFormController ||= new FormController(form, options)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
progressContainerTarget: HTMLElement
|
|
@@ -14,25 +14,27 @@ export default class FormController {
|
|
|
14
14
|
submitted: boolean
|
|
15
15
|
processing: boolean
|
|
16
16
|
|
|
17
|
-
constructor(form) {
|
|
17
|
+
constructor(form, { uploadDialog = true } = {}) {
|
|
18
18
|
this.element = form
|
|
19
19
|
this.progressTargetMap = {}
|
|
20
20
|
this.controllers = []
|
|
21
21
|
this.submitted = false
|
|
22
22
|
this.processing = false
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<div class="direct-upload-
|
|
28
|
-
<
|
|
29
|
-
|
|
24
|
+
if (uploadDialog) {
|
|
25
|
+
this.element.insertAdjacentHTML("beforeend",
|
|
26
|
+
`<dialog id="form-controller-dialog">
|
|
27
|
+
<div class="direct-upload-wrapper">
|
|
28
|
+
<div class="direct-upload-content">
|
|
29
|
+
<h3>Uploading your media</h3>
|
|
30
|
+
<div id="progress-container"></div>
|
|
31
|
+
</div>
|
|
30
32
|
</div>
|
|
31
|
-
</
|
|
32
|
-
</dialog>`)
|
|
33
|
+
</dialog>`)
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
this.dialog = this.element.querySelector("#form-controller-dialog")
|
|
36
|
+
this.progressContainerTarget = this.dialog.querySelector("#progress-container")
|
|
37
|
+
}
|
|
36
38
|
|
|
37
39
|
this.element.addEventListener("submit", event => this.submit(event))
|
|
38
40
|
window.addEventListener("beforeunload", event => this.beforeUnload(event))
|
|
@@ -60,7 +62,7 @@ export default class FormController {
|
|
|
60
62
|
this.setInputAttachmentsDisabled(true)
|
|
61
63
|
this.startNextController()
|
|
62
64
|
if(this.processing) {
|
|
63
|
-
this.dialog
|
|
65
|
+
this.dialog?.showModal()
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -99,7 +101,7 @@ export default class FormController {
|
|
|
99
101
|
submitForm() {
|
|
100
102
|
if(!this.submitted) return
|
|
101
103
|
if(this.hasUploadErrors()) {
|
|
102
|
-
this.dialog
|
|
104
|
+
this.dialog?.close()
|
|
103
105
|
this.setInputAttachmentsDisabled(false)
|
|
104
106
|
return
|
|
105
107
|
}
|
|
@@ -126,42 +128,46 @@ export default class FormController {
|
|
|
126
128
|
init(event) {
|
|
127
129
|
const { id, file, controller } = event.detail
|
|
128
130
|
|
|
129
|
-
this.progressContainerTarget
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
if (this.progressContainerTarget) {
|
|
132
|
+
this.progressContainerTarget.insertAdjacentHTML("beforebegin", `
|
|
133
|
+
<progress-bar id="direct-upload-${id}" class="direct-upload--pending">${file?.name || 'Uploading...'}</progress-bar>
|
|
134
|
+
`)
|
|
135
|
+
this.progressTargetMap[id] = document.getElementById(`direct-upload-${id}`)
|
|
136
|
+
}
|
|
134
137
|
|
|
135
138
|
this.controllers.push(controller)
|
|
136
139
|
this.startNextController()
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
start(event) {
|
|
140
|
-
this.progressTargetMap[event.detail.id]
|
|
143
|
+
this.progressTargetMap[event.detail.id]?.classList.remove("direct-upload--pending")
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
progress(event) {
|
|
144
147
|
const { id, progress } = event.detail
|
|
145
|
-
this.progressTargetMap[id]
|
|
148
|
+
const target = this.progressTargetMap[id]
|
|
149
|
+
if (target) target.percent = progress
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
error(event) {
|
|
149
153
|
event.preventDefault()
|
|
150
154
|
const { id, error } = event.detail
|
|
151
155
|
const target = this.progressTargetMap[id]
|
|
152
|
-
target
|
|
153
|
-
|
|
156
|
+
if (target) {
|
|
157
|
+
target.classList.add("direct-upload--error")
|
|
158
|
+
target.title = error
|
|
159
|
+
}
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
end(event) {
|
|
157
|
-
this.progressTargetMap[event.detail.id]
|
|
163
|
+
this.progressTargetMap[event.detail.id]?.classList.add("direct-upload--complete")
|
|
158
164
|
}
|
|
159
165
|
|
|
160
166
|
removeUploadedFile(event) {
|
|
161
167
|
const uploadedFile = event.detail
|
|
162
168
|
const id = uploadedFile.controller?.directUpload?.id
|
|
163
169
|
if(id) {
|
|
164
|
-
document.getElementById(`direct-upload-${id}`)
|
|
170
|
+
document.getElementById(`direct-upload-${id}`)?.remove()
|
|
165
171
|
delete this.progressTargetMap[id]
|
|
166
172
|
}
|
|
167
173
|
this.setInputAttachmentsDisabled(false)
|
|
@@ -22,6 +22,7 @@ export class InputAttachment {
|
|
|
22
22
|
@Prop() max: number
|
|
23
23
|
@Prop() preview: boolean = true
|
|
24
24
|
@Prop() disabled: boolean = false
|
|
25
|
+
@Prop({ attribute: "upload-dialog" }) uploadDialog: boolean = true
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
form: HTMLFormElement
|
|
@@ -37,7 +38,7 @@ export class InputAttachment {
|
|
|
37
38
|
this.form = this.internals.form
|
|
38
39
|
if (this.form) {
|
|
39
40
|
this.form.addEventListener("reset", () => this.reset())
|
|
40
|
-
FormController.instance(this.form)
|
|
41
|
+
FormController.instance(this.form, { uploadDialog: this.uploadDialog })
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
// Note: Server-rendered children may not be available yet during componentWillLoad
|
|
@@ -7,16 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
## Properties
|
|
9
9
|
|
|
10
|
-
| Property | Attribute
|
|
11
|
-
| -------------- |
|
|
12
|
-
| `accepts` | `accepts`
|
|
13
|
-
| `directupload` | `directupload`
|
|
14
|
-
| `disabled` | `disabled`
|
|
15
|
-
| `max` | `max`
|
|
16
|
-
| `multiple` | `multiple`
|
|
17
|
-
| `name` | `name`
|
|
18
|
-
| `preview` | `preview`
|
|
19
|
-
| `required` | `required`
|
|
10
|
+
| Property | Attribute | Description | Type | Default |
|
|
11
|
+
| -------------- | --------------- | ----------- | --------- | ----------- |
|
|
12
|
+
| `accepts` | `accepts` | | `string` | `undefined` |
|
|
13
|
+
| `directupload` | `directupload` | | `string` | `undefined` |
|
|
14
|
+
| `disabled` | `disabled` | | `boolean` | `false` |
|
|
15
|
+
| `max` | `max` | | `number` | `undefined` |
|
|
16
|
+
| `multiple` | `multiple` | | `boolean` | `false` |
|
|
17
|
+
| `name` | `name` | | `string` | `undefined` |
|
|
18
|
+
| `preview` | `preview` | | `boolean` | `true` |
|
|
19
|
+
| `required` | `required` | | `boolean` | `false` |
|
|
20
|
+
| `uploadDialog` | `upload-dialog` | | `boolean` | `true` |
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
## Shadow Parts
|
|
@@ -58,6 +58,10 @@ export namespace Components {
|
|
|
58
58
|
* @default false
|
|
59
59
|
*/
|
|
60
60
|
"required": boolean;
|
|
61
|
+
/**
|
|
62
|
+
* @default true
|
|
63
|
+
*/
|
|
64
|
+
"uploadDialog": boolean;
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
export interface AttachmentFileCustomEvent<T> extends CustomEvent<T> {
|
|
@@ -158,6 +162,10 @@ declare namespace LocalJSX {
|
|
|
158
162
|
* @default false
|
|
159
163
|
*/
|
|
160
164
|
"required"?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* @default true
|
|
167
|
+
*/
|
|
168
|
+
"uploadDialog"?: boolean;
|
|
161
169
|
}
|
|
162
170
|
interface IntrinsicElements {
|
|
163
171
|
"attachment-file": AttachmentFile;
|
|
@@ -6,6 +6,9 @@ module Bard
|
|
|
6
6
|
"directupload" => "/rails/active_storage/direct_uploads",
|
|
7
7
|
"preview" => true,
|
|
8
8
|
})
|
|
9
|
+
if options.key?("upload-dialog") && options["upload-dialog"] == false
|
|
10
|
+
options["upload-dialog"] = "false"
|
|
11
|
+
end
|
|
9
12
|
add_default_name_and_id(options)
|
|
10
13
|
|
|
11
14
|
content_tag("input-attachment", options) do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bard-attachment_field
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Micah Geisel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activestorage
|
|
@@ -361,6 +361,7 @@ files:
|
|
|
361
361
|
- input-attachment/src/components/attachment-preview/attachment-preview.spec.tsx
|
|
362
362
|
- input-attachment/src/components/attachment-preview/attachment-preview.tsx
|
|
363
363
|
- input-attachment/src/components/attachment-preview/readme.md
|
|
364
|
+
- input-attachment/src/components/input-attachment/form-controller.spec.ts
|
|
364
365
|
- input-attachment/src/components/input-attachment/form-controller.tsx
|
|
365
366
|
- input-attachment/src/components/input-attachment/input-attachment.css
|
|
366
367
|
- input-attachment/src/components/input-attachment/input-attachment.e2e.ts
|