1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
export type FillOptions = {
readonly rejectSelect: boolean;
readonly focusFirst: boolean;
};
const ENGINE = `
const el = this;
if (!el || el.nodeType !== 1) return { ok: false, reason: "ref does not point to an element" };
const tagName = el.tagName || "";
const tag = tagName.toLowerCase();
const type = (el.type || "").toLowerCase();
if (__rejectSelect && tag === "select") {
return { ok: false, reason: "element is a <select>", kind: "select", tag: tagName };
}
if (el.disabled) return { ok: false, reason: "element is disabled", tag: tagName };
const fire = function (t) { el.dispatchEvent(new Event(t, { bubbles: true })); };
if (__focusFirst) { try { el.focus(); } catch (e) {} }
if (tag === "select") {
const want = String(value);
let matched = null;
for (let i = 0; i < el.options.length; i++) {
const o = el.options[i];
if (o.value === want || o.label === want || o.text === want) { matched = o; break; }
}
if (!matched) {
const opts = [];
for (let i = 0; i < el.options.length; i++) opts.push({ value: el.options[i].value, text: el.options[i].text });
return { ok: false, reason: "no matching option", kind: "select", options: opts, tag: tagName };
}
el.value = matched.value;
fire("input"); fire("change");
return { ok: true, kind: "select", value: el.value, text: matched.text, tag: tagName };
}
if (tag === "input" && (type === "checkbox" || type === "radio")) {
const want = value === true || value === "true" || value === "on" || value === 1;
let changed = false;
if (el.checked !== want) {
try { el.click(); } catch (e) {}
if (el.checked !== want) { el.checked = want; fire("input"); fire("change"); }
changed = true;
}
return { ok: true, kind: type, checked: el.checked, changed: changed, tag: tagName };
}
if (el.isContentEditable) {
try { el.focus(); } catch (e) {}
let done = false;
try {
const sel = window.getSelection();
if (sel) { sel.removeAllRanges(); const rng = document.createRange(); rng.selectNodeContents(el); sel.addRange(rng); }
done = document.execCommand("insertText", false, String(value));
} catch (e) { done = false; }
if (!done) {
el.textContent = String(value);
el.dispatchEvent(new InputEvent("input", { bubbles: true }));
}
return { ok: true, kind: "contenteditable", value: el.textContent || "", tag: tagName };
}
if (tag === "input" || tag === "textarea") {
const proto = tag === "textarea" ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype;
const desc = Object.getOwnPropertyDescriptor(proto, "value");
if (desc && desc.set) desc.set.call(el, String(value));
else el.value = String(value);
fire("input"); fire("change");
return { ok: true, kind: el.type || tag, value: el.value, tag: tagName };
}
return { ok: false, reason: "element is not a fillable field (tag=" + tag + ")", tag: tagName };
`;
export const fillBody = (opts: FillOptions): string =>
`const __rejectSelect = ${opts.rejectSelect}; const __focusFirst = ${opts.focusFirst};\n${ENGINE}`;
export const fillDeclaration = (opts: FillOptions): string =>
`function (value) { ${fillBody(opts)} }`;
|