Skip to content

Commit be7ed36

Browse files
committed
handle file metadata in input fields
1 parent e0ef341 commit be7ed36

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

src/js/packages/event-to-object/src/index.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ function classToObject(x: any, maxDepth: number): object {
168168
const val = x[prop];
169169
if (!shouldIgnoreValue(val, prop, x)) {
170170
if (typeof val === "object") {
171-
const converted = deepCloneClass(val, maxDepth);
171+
// Ensure files have enough depth to be serialized
172+
const propDepth = prop === "files" ? Math.max(maxDepth, 3) : maxDepth;
173+
const converted = deepCloneClass(val, propDepth);
172174
if (converted !== maxDepthSignal) {
173175
result[prop] = converted;
174176
}
@@ -179,6 +181,35 @@ function classToObject(x: any, maxDepth: number): object {
179181
}
180182
}
181183

184+
// Explicitly include form elements if they exist and are not enumerable
185+
const win = typeof window !== "undefined" ? window : undefined;
186+
// @ts-ignore
187+
const FormClass = win
188+
? win.HTMLFormElement
189+
: typeof HTMLFormElement !== "undefined"
190+
? HTMLFormElement
191+
: undefined;
192+
193+
if (FormClass && x instanceof FormClass && x.elements) {
194+
for (let i = 0; i < x.elements.length; i++) {
195+
const element = x.elements[i] as any;
196+
if (
197+
element.name &&
198+
!Object.prototype.hasOwnProperty.call(result, element.name) &&
199+
!shouldIgnoreValue(element, element.name, x)
200+
) {
201+
if (typeof element === "object") {
202+
const converted = deepCloneClass(element, maxDepth);
203+
if (converted !== maxDepthSignal) {
204+
result[element.name] = converted;
205+
}
206+
} else {
207+
result[element.name] = element;
208+
}
209+
}
210+
}
211+
}
212+
182213
return result;
183214
}
184215

src/js/packages/event-to-object/tests/event-to-object.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,86 @@ test("includes checked property for checkboxes", () => {
521521
},
522522
});
523523
});
524+
525+
test("converts file input with files", () => {
526+
const input = window.document.createElement("input");
527+
input.type = "file";
528+
529+
// Create a mock file
530+
const file = new window.File(["content"], "test.txt", {
531+
type: "text/plain",
532+
lastModified: 1234567890,
533+
});
534+
535+
// Mock the files property
536+
const mockFileList = {
537+
0: file,
538+
length: 1,
539+
item: (index: number) => (index === 0 ? file : null),
540+
[Symbol.iterator]: function* () {
541+
yield file;
542+
},
543+
};
544+
545+
Object.defineProperty(input, "files", {
546+
value: mockFileList,
547+
writable: true,
548+
});
549+
550+
const event = new window.Event("change");
551+
Object.defineProperty(event, "target", {
552+
value: input,
553+
enumerable: true,
554+
writable: true,
555+
});
556+
557+
const converted: any = convert(event);
558+
559+
expect(converted.target.files).toBeDefined();
560+
expect(converted.target.files.length).toBe(1);
561+
expect(converted.target.files[0].name).toBe("test.txt");
562+
});
563+
564+
test("converts form submission with file input", () => {
565+
const form = window.document.createElement("form");
566+
const input = window.document.createElement("input");
567+
input.type = "file";
568+
input.name = "myFile";
569+
570+
// Create a mock file
571+
const file = new window.File(["content"], "test.txt", {
572+
type: "text/plain",
573+
lastModified: 1234567890,
574+
});
575+
576+
// Mock the files property
577+
const mockFileList = {
578+
0: file,
579+
length: 1,
580+
item: (index: number) => (index === 0 ? file : null),
581+
[Symbol.iterator]: function* () {
582+
yield file;
583+
},
584+
};
585+
586+
Object.defineProperty(input, "files", {
587+
value: mockFileList,
588+
writable: true,
589+
});
590+
591+
form.appendChild(input);
592+
593+
const event = new window.Event("submit");
594+
Object.defineProperty(event, "target", {
595+
value: form,
596+
enumerable: true,
597+
writable: true,
598+
});
599+
600+
const converted: any = convert(event);
601+
602+
expect(converted.target.myFile).toBeDefined();
603+
expect(converted.target.myFile.files).toBeDefined();
604+
expect(converted.target.myFile.files.length).toBe(1);
605+
expect(converted.target.myFile.files[0].name).toBe("test.txt");
606+
});

0 commit comments

Comments
 (0)