forked from darobin/formic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
formic.js
146 lines (136 loc) · 6.14 KB
/
formic.js
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// this is largely a set of facilities to help with the manipulating of forms
// ideally, some of this would be made part of the platform
(function () {
var filter = Array.prototype.filter
, forEach = Array.prototype.forEach
;
var formic = {
matches: function (el, sels, refs) {
return (
el.matches ||
el.mozMatchesSelector ||
el.webkitMatchesSelector ||
el.msMatchesSelector
).call(el, sels, refs);
}
, ancestors: function (el) {
var ret = [];
while (el.parentNode.nodeType === Node.ELEMENT_NODE) {
ret.push(el.parentNode);
el = el.parentNode;
}
return ret;
}
, submittableElements: function (form) {
return filter.call( document.querySelectorAll("button, input, keygen, object, select, textarea")
, function (el) {
return form === el.form;
}
);
}
, disabled: function (el) {
return formic.matches(el, ":disabled");
}
, formDataSet: function (form, options) {
options = options || {};
var controls = formic.submittableElements(form)
, dataSet = []
;
for (var i = 0, n = controls.length; i < n; i++) {
var field = controls[i];
// Fields To Skip
// We don't check that objects must have loaded a plugin. Bite me.
// Since this is batched, we also don't know the submitter and therefore ignore them all
if (formic.ancestors(field).filter(function (el) { formic.matches(el, "datalist"); }).length) continue;
if (formic.disabled(field)) continue;
if (formic.matches(field, "button")) continue;
if (field.type === "submit" || field.type === "image" || field.type === "button") continue;
if (field.type === "checkbox" && !field.checked) continue;
if (field.type === "radio" && !field.checked) continue;
if (!field.name) continue;
var type = field.type, name = field.name;
if (formic.matches(field, "select")) {
// XXX this should be "> option, > optgroup > option" but it can't be
forEach.call(field.querySelectorAll("option")
, function (el) {
if (!el.disabled && el.selected)
dataSet.push({
name: name
, type: type
, value: el.value
, el: el
});
}
);
}
else if (type === "checkbox" || type === "radio") {
var value;
if (field.hasAttribute("value")) value = field.getAttribute("value");
else if (options.booleanChecked) value = true;
else value = "on";
dataSet.push({
name: name
, type: type
, value: value
, el: field
});
}
else if (type === "file") {
if (field.files.length === 0) {
dataSet.push({ name: name, type: "application/octet-stream", value: "", el: field });
}
else {
forEach.call(field.files
, function (f) {
dataSet.push({
name: name
, type: type
, value: {
type: f.type
, name: f.name
, body: f
}
, el: field
});
}
);
}
}
// here we could process <object>. but we won't
else {
dataSet.push({
name: name
, type: type
, value: field.value
, el: field
});
}
if (type === "textarea" || type === "text" || type === "search") {
if (field.getAttribute("dirname")) {
// here we should fully determine the directionality, but we cheat
dataSet.push({
name: field.getAttribute("dirname")
, type: "direction"
, value: field.dir || "auto"
, el: field
});
}
}
}
// clean up the CRLF
for (var i = 0, n = dataSet.length; i < n; i++) {
var d = dataSet[i];
if (d.type === "textarea" || d.type === "file") continue;
if (typeof d.value !== "string") continue;
d.value = d.value
.replace(/\r(?!\n)/g, "\r\n")
.split("").reverse().join("") // where the fuck are my lookbehinds?
.replace(/\n(?!\r)/, "\n\r")
.split("").reverse().join("")
;
}
return dataSet;
}
};
window.formic = formic;
}());