pcapr-local 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/.document +5 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +64 -0
  4. data/Rakefile +57 -0
  5. data/VERSION +1 -0
  6. data/bin/pcap2par +49 -0
  7. data/bin/startpcapr +40 -0
  8. data/bin/stoppcapr +33 -0
  9. data/bin/xtractr +5 -0
  10. data/lib/environment.rb +106 -0
  11. data/lib/exe/xtractr +0 -0
  12. data/lib/mu/pcap.rb +110 -0
  13. data/lib/mu/pcap/ethernet.rb +148 -0
  14. data/lib/mu/pcap/header.rb +75 -0
  15. data/lib/mu/pcap/io_pair.rb +67 -0
  16. data/lib/mu/pcap/io_wrapper.rb +76 -0
  17. data/lib/mu/pcap/ip.rb +61 -0
  18. data/lib/mu/pcap/ipv4.rb +257 -0
  19. data/lib/mu/pcap/ipv6.rb +148 -0
  20. data/lib/mu/pcap/packet.rb +104 -0
  21. data/lib/mu/pcap/pkthdr.rb +155 -0
  22. data/lib/mu/pcap/reader.rb +61 -0
  23. data/lib/mu/pcap/reader/http_family.rb +170 -0
  24. data/lib/mu/pcap/sctp.rb +367 -0
  25. data/lib/mu/pcap/sctp/chunk.rb +123 -0
  26. data/lib/mu/pcap/sctp/chunk/data.rb +134 -0
  27. data/lib/mu/pcap/sctp/chunk/init.rb +100 -0
  28. data/lib/mu/pcap/sctp/chunk/init_ack.rb +68 -0
  29. data/lib/mu/pcap/sctp/parameter.rb +110 -0
  30. data/lib/mu/pcap/sctp/parameter/ip_address.rb +48 -0
  31. data/lib/mu/pcap/stream_packetizer.rb +72 -0
  32. data/lib/mu/pcap/tcp.rb +505 -0
  33. data/lib/mu/pcap/udp.rb +69 -0
  34. data/lib/mu/scenario/pcap.rb +164 -0
  35. data/lib/mu/scenario/pcap/fields.rb +50 -0
  36. data/lib/mu/scenario/pcap/rtp.rb +71 -0
  37. data/lib/pcapr_local.rb +159 -0
  38. data/lib/pcapr_local/config.rb +336 -0
  39. data/lib/pcapr_local/db.rb +197 -0
  40. data/lib/pcapr_local/scanner.rb +250 -0
  41. data/lib/pcapr_local/server.rb +178 -0
  42. data/lib/pcapr_local/www/favicon.ico +0 -0
  43. data/lib/pcapr_local/www/favicon.png +0 -0
  44. data/lib/pcapr_local/www/home/index.html +138 -0
  45. data/lib/pcapr_local/www/static/image/16x16/Cancel.png +0 -0
  46. data/lib/pcapr_local/www/static/image/16x16/Cancel.png.1 +0 -0
  47. data/lib/pcapr_local/www/static/image/16x16/Download.png +0 -0
  48. data/lib/pcapr_local/www/static/image/16x16/Folder3.png +0 -0
  49. data/lib/pcapr_local/www/static/image/16x16/Full Size.png +0 -0
  50. data/lib/pcapr_local/www/static/image/16x16/Minus.png +0 -0
  51. data/lib/pcapr_local/www/static/image/16x16/Plus.png +0 -0
  52. data/lib/pcapr_local/www/static/image/16x16/Search.png +0 -0
  53. data/lib/pcapr_local/www/static/image/16x16/User.png +0 -0
  54. data/lib/pcapr_local/www/static/image/48x48/Phone.png +0 -0
  55. data/lib/pcapr_local/www/static/image/48x48/Video.png +0 -0
  56. data/lib/pcapr_local/www/static/image/bar-orange.gif +0 -0
  57. data/lib/pcapr_local/www/static/image/beta.png +0 -0
  58. data/lib/pcapr_local/www/static/image/bg.png +0 -0
  59. data/lib/pcapr_local/www/static/image/blockquote.png +0 -0
  60. data/lib/pcapr_local/www/static/image/body-bg.png +0 -0
  61. data/lib/pcapr_local/www/static/image/body-h3.png +0 -0
  62. data/lib/pcapr_local/www/static/image/body-hl1-bg.png +0 -0
  63. data/lib/pcapr_local/www/static/image/body-hl1-h3.png +0 -0
  64. data/lib/pcapr_local/www/static/image/body-hl1-readmore.png +0 -0
  65. data/lib/pcapr_local/www/static/image/body-hl2-bg.png +0 -0
  66. data/lib/pcapr_local/www/static/image/body-hl2-h3.png +0 -0
  67. data/lib/pcapr_local/www/static/image/body-hl2-readmore.png +0 -0
  68. data/lib/pcapr_local/www/static/image/body-hl3-bg.png +0 -0
  69. data/lib/pcapr_local/www/static/image/body-hl3-h3.png +0 -0
  70. data/lib/pcapr_local/www/static/image/body-hl3-readmore.png +0 -0
  71. data/lib/pcapr_local/www/static/image/body-hl4-bg.png +0 -0
  72. data/lib/pcapr_local/www/static/image/body-hl4-h3.png +0 -0
  73. data/lib/pcapr_local/www/static/image/body-hl4-readmore.png +0 -0
  74. data/lib/pcapr_local/www/static/image/body-hl5-h3.png +0 -0
  75. data/lib/pcapr_local/www/static/image/body-hl6-h3.png +0 -0
  76. data/lib/pcapr_local/www/static/image/body-hl7-h3.png +0 -0
  77. data/lib/pcapr_local/www/static/image/body-hl8-h3.png +0 -0
  78. data/lib/pcapr_local/www/static/image/body-readmore.png +0 -0
  79. data/lib/pcapr_local/www/static/image/bottom-bg.png +0 -0
  80. data/lib/pcapr_local/www/static/image/bottom-l.png +0 -0
  81. data/lib/pcapr_local/www/static/image/bottom-r.png +0 -0
  82. data/lib/pcapr_local/www/static/image/btn-search.png +0 -0
  83. data/lib/pcapr_local/www/static/image/bullet-1.png +0 -0
  84. data/lib/pcapr_local/www/static/image/bullet-2.png +0 -0
  85. data/lib/pcapr_local/www/static/image/bullet-3.png +0 -0
  86. data/lib/pcapr_local/www/static/image/bullet-4.png +0 -0
  87. data/lib/pcapr_local/www/static/image/bullet-5.png +0 -0
  88. data/lib/pcapr_local/www/static/image/bullet-6.png +0 -0
  89. data/lib/pcapr_local/www/static/image/bullet-7.png +0 -0
  90. data/lib/pcapr_local/www/static/image/bullet-hl1.png +0 -0
  91. data/lib/pcapr_local/www/static/image/bullet-hl2.png +0 -0
  92. data/lib/pcapr_local/www/static/image/bullet-hl3.png +0 -0
  93. data/lib/pcapr_local/www/static/image/bullet-hl4.png +0 -0
  94. data/lib/pcapr_local/www/static/image/bullet-pathway.png +0 -0
  95. data/lib/pcapr_local/www/static/image/bullet-section1.png +0 -0
  96. data/lib/pcapr_local/www/static/image/bullet-section2.png +0 -0
  97. data/lib/pcapr_local/www/static/image/collapsed.gif +0 -0
  98. data/lib/pcapr_local/www/static/image/crosslink.png +0 -0
  99. data/lib/pcapr_local/www/static/image/expanded.gif +0 -0
  100. data/lib/pcapr_local/www/static/image/favicon.ico +0 -0
  101. data/lib/pcapr_local/www/static/image/favicon.png +0 -0
  102. data/lib/pcapr_local/www/static/image/icon-author.png +0 -0
  103. data/lib/pcapr_local/www/static/image/icon-created.png +0 -0
  104. data/lib/pcapr_local/www/static/image/p-expand.gif +0 -0
  105. data/lib/pcapr_local/www/static/image/pcapr-logo.png +0 -0
  106. data/lib/pcapr_local/www/static/image/powered-by.png +0 -0
  107. data/lib/pcapr_local/www/static/image/section1-bg.png +0 -0
  108. data/lib/pcapr_local/www/static/image/section1-h3.png +0 -0
  109. data/lib/pcapr_local/www/static/image/section1-readmore.png +0 -0
  110. data/lib/pcapr_local/www/static/image/section2-bg.png +0 -0
  111. data/lib/pcapr_local/www/static/image/section2-h3.png +0 -0
  112. data/lib/pcapr_local/www/static/image/section2-readmore.png +0 -0
  113. data/lib/pcapr_local/www/static/image/status-alert.png +0 -0
  114. data/lib/pcapr_local/www/static/image/status-download.png +0 -0
  115. data/lib/pcapr_local/www/static/image/status-info.png +0 -0
  116. data/lib/pcapr_local/www/static/image/status-note.png +0 -0
  117. data/lib/pcapr_local/www/static/image/tab-round.png +0 -0
  118. data/lib/pcapr_local/www/static/image/throbber.gif +0 -0
  119. data/lib/pcapr_local/www/static/image/user.jpg +0 -0
  120. data/lib/pcapr_local/www/static/script/closet/async.js +421 -0
  121. data/lib/pcapr_local/www/static/script/closet/closet.api.js +241 -0
  122. data/lib/pcapr_local/www/static/script/closet/closet.folders.js +94 -0
  123. data/lib/pcapr_local/www/static/script/closet/closet.js +187 -0
  124. data/lib/pcapr_local/www/static/script/closet/closet.mr.js +219 -0
  125. data/lib/pcapr_local/www/static/script/closet/closet.options.js +359 -0
  126. data/lib/pcapr_local/www/static/script/closet/closet.quantity.js +73 -0
  127. data/lib/pcapr_local/www/static/script/closet/closet.render.js +205 -0
  128. data/lib/pcapr_local/www/static/script/closet/closet.report.js +86 -0
  129. data/lib/pcapr_local/www/static/script/closet/closet.reports.http.js +135 -0
  130. data/lib/pcapr_local/www/static/script/closet/closet.reports.overview.js +163 -0
  131. data/lib/pcapr_local/www/static/script/closet/closet.reports.sip.js +159 -0
  132. data/lib/pcapr_local/www/static/script/closet/closet.reports.tcp.js +72 -0
  133. data/lib/pcapr_local/www/static/script/closet/closet.reports.visualize.js +263 -0
  134. data/lib/pcapr_local/www/static/script/closet/closet.util.js +40 -0
  135. data/lib/pcapr_local/www/static/script/jquery/jquery-1.4.2.min.js +154 -0
  136. data/lib/pcapr_local/www/static/script/jquery/jquery-ui.js +10921 -0
  137. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.js +2123 -0
  138. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.selection.js +184 -0
  139. data/lib/pcapr_local/www/static/script/jquery/jquery.flot.stack.js +184 -0
  140. data/lib/pcapr_local/www/static/script/jquery/jquery.form.js +643 -0
  141. data/lib/pcapr_local/www/static/script/jquery/jquery.jsonp.min.js +3 -0
  142. data/lib/pcapr_local/www/static/script/jquery/jquery.menu.js +142 -0
  143. data/lib/pcapr_local/www/static/script/jquery/jquery.suggest.js +308 -0
  144. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.core.js +203 -0
  145. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.slider.js +629 -0
  146. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.sortable.js +1055 -0
  147. data/lib/pcapr_local/www/static/script/jquery/jquery.ui.widget.js +236 -0
  148. data/lib/pcapr_local/www/static/script/json2.js +481 -0
  149. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.cache.js +115 -0
  150. data/lib/pcapr_local/www/static/script/sammy/plugins/sammy.template.js +117 -0
  151. data/lib/pcapr_local/www/static/script/sammy/sammy.js +1696 -0
  152. data/lib/pcapr_local/www/static/script/tipsy/jquery.tipsy.js +104 -0
  153. data/lib/pcapr_local/www/static/style/c3p0.css +116 -0
  154. data/lib/pcapr_local/www/static/style/jquery.suggest.css +27 -0
  155. data/lib/pcapr_local/www/static/style/page.css +1113 -0
  156. data/lib/pcapr_local/www/static/style/tipsy.css +7 -0
  157. data/lib/pcapr_local/www/templates/browse.services.template +10 -0
  158. data/lib/pcapr_local/www/templates/browse.template +77 -0
  159. data/lib/pcapr_local/www/templates/flows.template +38 -0
  160. data/lib/pcapr_local/www/templates/pcap.template +63 -0
  161. data/lib/pcapr_local/www/templates/sip.calls.template +35 -0
  162. data/lib/pcapr_local/www/templates/statistics.template +6 -0
  163. data/lib/pcapr_local/xtractr.rb +179 -0
  164. data/lib/pcapr_local/xtractr/instance.rb +172 -0
  165. data/pcapr-local.gemspec +297 -0
  166. data/test/mu/pcap/reader/tc_http_family.rb +251 -0
  167. data/test/mu/pcap/tc_ethernet.rb +71 -0
  168. data/test/mu/pcap/tc_header.rb +56 -0
  169. data/test/mu/pcap/tc_ipv4.rb +103 -0
  170. data/test/mu/pcap/tc_ipv6.rb +83 -0
  171. data/test/mu/pcap/tc_packet.rb +44 -0
  172. data/test/mu/pcap/tc_pair.rb +58 -0
  173. data/test/mu/pcap/tc_pkthdr.rb +33 -0
  174. data/test/mu/pcap/tc_reader.rb +76 -0
  175. data/test/mu/pcap/tc_tcp.rb +426 -0
  176. data/test/mu/pcap/tc_udp.rb +33 -0
  177. data/test/mu/pcap/tc_wrapper.rb +80 -0
  178. data/test/mu/scenario/pcap/tc_fields.rb +67 -0
  179. data/test/mu/scenario/pcap/tc_rtp.rb +135 -0
  180. data/test/mu/scenario/sip_signalled_call_1.pcap +0 -0
  181. data/test/mu/scenario/tc_pcap.rb +190 -0
  182. data/test/mu/scenario/test_data/arp.pcap +0 -0
  183. data/test/mu/scenario/test_data/dns.pcap +0 -0
  184. data/test/mu/scenario/test_data/http-v6.pcap +0 -0
  185. data/test/mu/scenario/test_data/http.pcap +0 -0
  186. data/test/mu/scenario/test_data/http_chunked.pcap +0 -0
  187. data/test/mu/scenario/test_data/http_deflate.pcap +0 -0
  188. data/test/mu/scenario/test_data/httpauth3.pcap +0 -0
  189. data/test/mu/scenario/test_data/icmp.pcap +0 -0
  190. data/test/mu/scenario/test_data/sip_signalled_call_1.pcap +0 -0
  191. data/test/mu/tc_pcap.rb +39 -0
  192. data/test/mu/testcase.rb +86 -0
  193. data/test/pcapr_local/arp.pcap +0 -0
  194. data/test/pcapr_local/data.js +3 -0
  195. data/test/pcapr_local/http_chunked.pcap +0 -0
  196. data/test/pcapr_local/tc_api.rb +181 -0
  197. data/test/pcapr_local/test.tgz +0 -0
  198. data/test/pcapr_local/test_scanner.rb +241 -0
  199. data/test/pcapr_local/test_xtractr.rb +219 -0
  200. data/test/pcapr_local/testcase.rb +107 -0
  201. data/test/test_export_to_scenario.sh +25 -0
  202. data/test/test_pcapr_local.rb +29 -0
  203. metadata +450 -0
@@ -0,0 +1,184 @@
1
+ /*
2
+ Flot plugin for stacking data sets, i.e. putting them on top of each
3
+ other, for accumulative graphs.
4
+
5
+ The plugin assumes the data is sorted on x (or y if stacking
6
+ horizontally). For line charts, it is assumed that if a line has an
7
+ undefined gap (from a null point), then the line above it should have
8
+ the same gap - insert zeros instead of "null" if you want another
9
+ behaviour. This also holds for the start and end of the chart. Note
10
+ that stacking a mix of positive and negative values in most instances
11
+ doesn't make sense (so it looks weird).
12
+
13
+ Two or more series are stacked when their "stack" attribute is set to
14
+ the same key (which can be any number or string or just "true"). To
15
+ specify the default stack, you can set
16
+
17
+ series: {
18
+ stack: null or true or key (number/string)
19
+ }
20
+
21
+ or specify it for a specific series
22
+
23
+ $.plot($("#placeholder"), [{ data: [ ... ], stack: true }])
24
+
25
+ The stacking order is determined by the order of the data series in
26
+ the array (later series end up on top of the previous).
27
+
28
+ Internally, the plugin modifies the datapoints in each series, adding
29
+ an offset to the y value. For line series, extra data points are
30
+ inserted through interpolation. If there's a second y value, it's also
31
+ adjusted (e.g for bar charts or filled areas).
32
+ */
33
+
34
+ (function ($) {
35
+ var options = {
36
+ series: { stack: null } // or number/string
37
+ };
38
+
39
+ function init(plot) {
40
+ function findMatchingSeries(s, allseries) {
41
+ var res = null
42
+ for (var i = 0; i < allseries.length; ++i) {
43
+ if (s == allseries[i])
44
+ break;
45
+
46
+ if (allseries[i].stack == s.stack)
47
+ res = allseries[i];
48
+ }
49
+
50
+ return res;
51
+ }
52
+
53
+ function stackData(plot, s, datapoints) {
54
+ if (s.stack == null)
55
+ return;
56
+
57
+ var other = findMatchingSeries(s, plot.getData());
58
+ if (!other)
59
+ return;
60
+
61
+ var ps = datapoints.pointsize,
62
+ points = datapoints.points,
63
+ otherps = other.datapoints.pointsize,
64
+ otherpoints = other.datapoints.points,
65
+ newpoints = [],
66
+ px, py, intery, qx, qy, bottom,
67
+ withlines = s.lines.show,
68
+ horizontal = s.bars.horizontal,
69
+ withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),
70
+ withsteps = withlines && s.lines.steps,
71
+ fromgap = true,
72
+ keyOffset = horizontal ? 1 : 0,
73
+ accumulateOffset = horizontal ? 0 : 1,
74
+ i = 0, j = 0, l;
75
+
76
+ while (true) {
77
+ if (i >= points.length)
78
+ break;
79
+
80
+ l = newpoints.length;
81
+
82
+ if (points[i] == null) {
83
+ // copy gaps
84
+ for (m = 0; m < ps; ++m)
85
+ newpoints.push(points[i + m]);
86
+ i += ps;
87
+ }
88
+ else if (j >= otherpoints.length) {
89
+ // for lines, we can't use the rest of the points
90
+ if (!withlines) {
91
+ for (m = 0; m < ps; ++m)
92
+ newpoints.push(points[i + m]);
93
+ }
94
+ i += ps;
95
+ }
96
+ else if (otherpoints[j] == null) {
97
+ // oops, got a gap
98
+ for (m = 0; m < ps; ++m)
99
+ newpoints.push(null);
100
+ fromgap = true;
101
+ j += otherps;
102
+ }
103
+ else {
104
+ // cases where we actually got two points
105
+ px = points[i + keyOffset];
106
+ py = points[i + accumulateOffset];
107
+ qx = otherpoints[j + keyOffset];
108
+ qy = otherpoints[j + accumulateOffset];
109
+ bottom = 0;
110
+
111
+ if (px == qx) {
112
+ for (m = 0; m < ps; ++m)
113
+ newpoints.push(points[i + m]);
114
+
115
+ newpoints[l + accumulateOffset] += qy;
116
+ bottom = qy;
117
+
118
+ i += ps;
119
+ j += otherps;
120
+ }
121
+ else if (px > qx) {
122
+ // we got past point below, might need to
123
+ // insert interpolated extra point
124
+ if (withlines && i > 0 && points[i - ps] != null) {
125
+ intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);
126
+ newpoints.push(qx);
127
+ newpoints.push(intery + qy);
128
+ for (m = 2; m < ps; ++m)
129
+ newpoints.push(points[i + m]);
130
+ bottom = qy;
131
+ }
132
+
133
+ j += otherps;
134
+ }
135
+ else { // px < qx
136
+ if (fromgap && withlines) {
137
+ // if we come from a gap, we just skip this point
138
+ i += ps;
139
+ continue;
140
+ }
141
+
142
+ for (m = 0; m < ps; ++m)
143
+ newpoints.push(points[i + m]);
144
+
145
+ // we might be able to interpolate a point below,
146
+ // this can give us a better y
147
+ if (withlines && j > 0 && otherpoints[j - otherps] != null)
148
+ bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
149
+
150
+ newpoints[l + accumulateOffset] += bottom;
151
+
152
+ i += ps;
153
+ }
154
+
155
+ fromgap = false;
156
+
157
+ if (l != newpoints.length && withbottom)
158
+ newpoints[l + 2] += bottom;
159
+ }
160
+
161
+ // maintain the line steps invariant
162
+ if (withsteps && l != newpoints.length && l > 0
163
+ && newpoints[l] != null
164
+ && newpoints[l] != newpoints[l - ps]
165
+ && newpoints[l + 1] != newpoints[l - ps + 1]) {
166
+ for (m = 0; m < ps; ++m)
167
+ newpoints[l + ps + m] = newpoints[l + m];
168
+ newpoints[l + 1] = newpoints[l - ps + 1];
169
+ }
170
+ }
171
+
172
+ datapoints.points = newpoints;
173
+ }
174
+
175
+ plot.hooks.processDatapoints.push(stackData);
176
+ }
177
+
178
+ $.plot.plugins.push({
179
+ init: init,
180
+ options: options,
181
+ name: 'stack',
182
+ version: '1.2'
183
+ });
184
+ })(jQuery);
@@ -0,0 +1,184 @@
1
+ /*
2
+ Flot plugin for stacking data sets, i.e. putting them on top of each
3
+ other, for accumulative graphs.
4
+
5
+ The plugin assumes the data is sorted on x (or y if stacking
6
+ horizontally). For line charts, it is assumed that if a line has an
7
+ undefined gap (from a null point), then the line above it should have
8
+ the same gap - insert zeros instead of "null" if you want another
9
+ behaviour. This also holds for the start and end of the chart. Note
10
+ that stacking a mix of positive and negative values in most instances
11
+ doesn't make sense (so it looks weird).
12
+
13
+ Two or more series are stacked when their "stack" attribute is set to
14
+ the same key (which can be any number or string or just "true"). To
15
+ specify the default stack, you can set
16
+
17
+ series: {
18
+ stack: null or true or key (number/string)
19
+ }
20
+
21
+ or specify it for a specific series
22
+
23
+ $.plot($("#placeholder"), [{ data: [ ... ], stack: true }])
24
+
25
+ The stacking order is determined by the order of the data series in
26
+ the array (later series end up on top of the previous).
27
+
28
+ Internally, the plugin modifies the datapoints in each series, adding
29
+ an offset to the y value. For line series, extra data points are
30
+ inserted through interpolation. If there's a second y value, it's also
31
+ adjusted (e.g for bar charts or filled areas).
32
+ */
33
+
34
+ (function ($) {
35
+ var options = {
36
+ series: { stack: null } // or number/string
37
+ };
38
+
39
+ function init(plot) {
40
+ function findMatchingSeries(s, allseries) {
41
+ var res = null
42
+ for (var i = 0; i < allseries.length; ++i) {
43
+ if (s == allseries[i])
44
+ break;
45
+
46
+ if (allseries[i].stack == s.stack)
47
+ res = allseries[i];
48
+ }
49
+
50
+ return res;
51
+ }
52
+
53
+ function stackData(plot, s, datapoints) {
54
+ if (s.stack == null)
55
+ return;
56
+
57
+ var other = findMatchingSeries(s, plot.getData());
58
+ if (!other)
59
+ return;
60
+
61
+ var ps = datapoints.pointsize,
62
+ points = datapoints.points,
63
+ otherps = other.datapoints.pointsize,
64
+ otherpoints = other.datapoints.points,
65
+ newpoints = [],
66
+ px, py, intery, qx, qy, bottom,
67
+ withlines = s.lines.show,
68
+ horizontal = s.bars.horizontal,
69
+ withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),
70
+ withsteps = withlines && s.lines.steps,
71
+ fromgap = true,
72
+ keyOffset = horizontal ? 1 : 0,
73
+ accumulateOffset = horizontal ? 0 : 1,
74
+ i = 0, j = 0, l;
75
+
76
+ while (true) {
77
+ if (i >= points.length)
78
+ break;
79
+
80
+ l = newpoints.length;
81
+
82
+ if (points[i] == null) {
83
+ // copy gaps
84
+ for (m = 0; m < ps; ++m)
85
+ newpoints.push(points[i + m]);
86
+ i += ps;
87
+ }
88
+ else if (j >= otherpoints.length) {
89
+ // for lines, we can't use the rest of the points
90
+ if (!withlines) {
91
+ for (m = 0; m < ps; ++m)
92
+ newpoints.push(points[i + m]);
93
+ }
94
+ i += ps;
95
+ }
96
+ else if (otherpoints[j] == null) {
97
+ // oops, got a gap
98
+ for (m = 0; m < ps; ++m)
99
+ newpoints.push(null);
100
+ fromgap = true;
101
+ j += otherps;
102
+ }
103
+ else {
104
+ // cases where we actually got two points
105
+ px = points[i + keyOffset];
106
+ py = points[i + accumulateOffset];
107
+ qx = otherpoints[j + keyOffset];
108
+ qy = otherpoints[j + accumulateOffset];
109
+ bottom = 0;
110
+
111
+ if (px == qx) {
112
+ for (m = 0; m < ps; ++m)
113
+ newpoints.push(points[i + m]);
114
+
115
+ newpoints[l + accumulateOffset] += qy;
116
+ bottom = qy;
117
+
118
+ i += ps;
119
+ j += otherps;
120
+ }
121
+ else if (px > qx) {
122
+ // we got past point below, might need to
123
+ // insert interpolated extra point
124
+ if (withlines && i > 0 && points[i - ps] != null) {
125
+ intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);
126
+ newpoints.push(qx);
127
+ newpoints.push(intery + qy);
128
+ for (m = 2; m < ps; ++m)
129
+ newpoints.push(points[i + m]);
130
+ bottom = qy;
131
+ }
132
+
133
+ j += otherps;
134
+ }
135
+ else { // px < qx
136
+ if (fromgap && withlines) {
137
+ // if we come from a gap, we just skip this point
138
+ i += ps;
139
+ continue;
140
+ }
141
+
142
+ for (m = 0; m < ps; ++m)
143
+ newpoints.push(points[i + m]);
144
+
145
+ // we might be able to interpolate a point below,
146
+ // this can give us a better y
147
+ if (withlines && j > 0 && otherpoints[j - otherps] != null)
148
+ bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
149
+
150
+ newpoints[l + accumulateOffset] += bottom;
151
+
152
+ i += ps;
153
+ }
154
+
155
+ fromgap = false;
156
+
157
+ if (l != newpoints.length && withbottom)
158
+ newpoints[l + 2] += bottom;
159
+ }
160
+
161
+ // maintain the line steps invariant
162
+ if (withsteps && l != newpoints.length && l > 0
163
+ && newpoints[l] != null
164
+ && newpoints[l] != newpoints[l - ps]
165
+ && newpoints[l + 1] != newpoints[l - ps + 1]) {
166
+ for (m = 0; m < ps; ++m)
167
+ newpoints[l + ps + m] = newpoints[l + m];
168
+ newpoints[l + 1] = newpoints[l - ps + 1];
169
+ }
170
+ }
171
+
172
+ datapoints.points = newpoints;
173
+ }
174
+
175
+ plot.hooks.processDatapoints.push(stackData);
176
+ }
177
+
178
+ $.plot.plugins.push({
179
+ init: init,
180
+ options: options,
181
+ name: 'stack',
182
+ version: '1.2'
183
+ });
184
+ })(jQuery);
@@ -0,0 +1,643 @@
1
+ /*
2
+ * jQuery Form Plugin
3
+ * version: 2.28 (10-MAY-2009)
4
+ * @requires jQuery v1.2.2 or later
5
+ *
6
+ * Examples and documentation at: http://malsup.com/jquery/form/
7
+ * Dual licensed under the MIT and GPL licenses:
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ * http://www.gnu.org/licenses/gpl.html
10
+ */
11
+ ;(function($) {
12
+
13
+ /*
14
+ Usage Note:
15
+ -----------
16
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
17
+ functions are intended to be exclusive. Use ajaxSubmit if you want
18
+ to bind your own submit handler to the form. For example,
19
+
20
+ $(document).ready(function() {
21
+ $('#myForm').bind('submit', function() {
22
+ $(this).ajaxSubmit({
23
+ target: '#output'
24
+ });
25
+ return false; // <-- important!
26
+ });
27
+ });
28
+
29
+ Use ajaxForm when you want the plugin to manage all the event binding
30
+ for you. For example,
31
+
32
+ $(document).ready(function() {
33
+ $('#myForm').ajaxForm({
34
+ target: '#output'
35
+ });
36
+ });
37
+
38
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
39
+ at the appropriate time.
40
+ */
41
+
42
+ /**
43
+ * ajaxSubmit() provides a mechanism for immediately submitting
44
+ * an HTML form using AJAX.
45
+ */
46
+ $.fn.ajaxSubmit = function(options) {
47
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
48
+ if (!this.length) {
49
+ log('ajaxSubmit: skipping submit process - no element selected');
50
+ return this;
51
+ }
52
+
53
+ if (typeof options == 'function')
54
+ options = { success: options };
55
+
56
+ var url = $.trim(this.attr('action'));
57
+ if (url) {
58
+ // clean url (don't include hash vaue)
59
+ url = (url.match(/^([^#]+)/)||[])[1];
60
+ }
61
+ url = url || window.location.href || ''
62
+
63
+ options = $.extend({
64
+ url: url,
65
+ type: this.attr('method') || 'GET'
66
+ }, options || {});
67
+
68
+ // hook for manipulating the form data before it is extracted;
69
+ // convenient for use with rich editors like tinyMCE or FCKEditor
70
+ var veto = {};
71
+ this.trigger('form-pre-serialize', [this, options, veto]);
72
+ if (veto.veto) {
73
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
74
+ return this;
75
+ }
76
+
77
+ // provide opportunity to alter form data before it is serialized
78
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
79
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
80
+ return this;
81
+ }
82
+
83
+ var a = this.formToArray(options.semantic);
84
+ if (options.data) {
85
+ options.extraData = options.data;
86
+ for (var n in options.data) {
87
+ if(options.data[n] instanceof Array) {
88
+ for (var k in options.data[n])
89
+ a.push( { name: n, value: options.data[n][k] } );
90
+ }
91
+ else
92
+ a.push( { name: n, value: options.data[n] } );
93
+ }
94
+ }
95
+
96
+ // give pre-submit callback an opportunity to abort the submit
97
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
98
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
99
+ return this;
100
+ }
101
+
102
+ // fire vetoable 'validate' event
103
+ this.trigger('form-submit-validate', [a, this, options, veto]);
104
+ if (veto.veto) {
105
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
106
+ return this;
107
+ }
108
+
109
+ var q = $.param(a);
110
+
111
+ if (options.type.toUpperCase() == 'GET') {
112
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
113
+ options.data = null; // data is null for 'get'
114
+ }
115
+ else
116
+ options.data = q; // data is the query string for 'post'
117
+
118
+ var $form = this, callbacks = [];
119
+ if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
120
+ if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
121
+
122
+ // perform a load on the target only if dataType is not provided
123
+ if (!options.dataType && options.target) {
124
+ var oldSuccess = options.success || function(){};
125
+ callbacks.push(function(data) {
126
+ $(options.target).html(data).each(oldSuccess, arguments);
127
+ });
128
+ }
129
+ else if (options.success)
130
+ callbacks.push(options.success);
131
+
132
+ options.success = function(data, status) {
133
+ for (var i=0, max=callbacks.length; i < max; i++)
134
+ callbacks[i].apply(options, [data, status, $form]);
135
+ };
136
+
137
+ // are there files to upload?
138
+ var files = $('input:file', this).fieldValue();
139
+ var found = false;
140
+ for (var j=0; j < files.length; j++)
141
+ if (files[j])
142
+ found = true;
143
+
144
+ var multipart = false;
145
+ // var mp = 'multipart/form-data';
146
+ // multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
147
+
148
+ // options.iframe allows user to force iframe mode
149
+ if (options.iframe || found || multipart) {
150
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
151
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
152
+ if (options.closeKeepAlive)
153
+ $.get(options.closeKeepAlive, fileUpload);
154
+ else
155
+ fileUpload();
156
+ }
157
+ else
158
+ $.ajax(options);
159
+
160
+ // fire 'notify' event
161
+ this.trigger('form-submit-notify', [this, options]);
162
+ return this;
163
+
164
+
165
+ // private function for handling file uploads (hat tip to YAHOO!)
166
+ function fileUpload() {
167
+ var form = $form[0];
168
+
169
+ if ($(':input[name=submit]', form).length) {
170
+ alert('Error: Form elements must not be named "submit".');
171
+ return;
172
+ }
173
+
174
+ var opts = $.extend({}, $.ajaxSettings, options);
175
+ var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
176
+
177
+ var id = 'jqFormIO' + (new Date().getTime());
178
+ var $io = $('<iframe id="' + id + '" name="' + id + '" src="about:blank" />');
179
+ var io = $io[0];
180
+
181
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
182
+
183
+ var xhr = { // mock object
184
+ aborted: 0,
185
+ responseText: null,
186
+ responseXML: null,
187
+ status: 0,
188
+ statusText: 'n/a',
189
+ getAllResponseHeaders: function() {},
190
+ getResponseHeader: function() {},
191
+ setRequestHeader: function() {},
192
+ abort: function() {
193
+ this.aborted = 1;
194
+ $io.attr('src','about:blank'); // abort op in progress
195
+ }
196
+ };
197
+
198
+ var g = opts.global;
199
+ // trigger ajax global events so that activity/block indicators work like normal
200
+ if (g && ! $.active++) $.event.trigger("ajaxStart");
201
+ if (g) $.event.trigger("ajaxSend", [xhr, opts]);
202
+
203
+ if (s.beforeSend && s.beforeSend(xhr, s) === false) {
204
+ s.global && $.active--;
205
+ return;
206
+ }
207
+ if (xhr.aborted)
208
+ return;
209
+
210
+ var cbInvoked = 0;
211
+ var timedOut = 0;
212
+
213
+ // add submitting element to data if we know it
214
+ var sub = form.clk;
215
+ if (sub) {
216
+ var n = sub.name;
217
+ if (n && !sub.disabled) {
218
+ options.extraData = options.extraData || {};
219
+ options.extraData[n] = sub.value;
220
+ if (sub.type == "image") {
221
+ options.extraData[name+'.x'] = form.clk_x;
222
+ options.extraData[name+'.y'] = form.clk_y;
223
+ }
224
+ }
225
+ }
226
+
227
+ // take a breath so that pending repaints get some cpu time before the upload starts
228
+ setTimeout(function() {
229
+ // make sure form attrs are set
230
+ var t = $form.attr('target'), a = $form.attr('action');
231
+
232
+ // update form attrs in IE friendly way
233
+ form.setAttribute('target',id);
234
+ if (form.getAttribute('method') != 'POST')
235
+ form.setAttribute('method', 'POST');
236
+ if (form.getAttribute('action') != opts.url)
237
+ form.setAttribute('action', opts.url);
238
+
239
+ // ie borks in some cases when setting encoding
240
+ if (! options.skipEncodingOverride) {
241
+ $form.attr({
242
+ encoding: 'multipart/form-data',
243
+ enctype: 'multipart/form-data'
244
+ });
245
+ }
246
+
247
+ // support timout
248
+ if (opts.timeout)
249
+ setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
250
+
251
+ // add "extra" data to form if provided in options
252
+ var extraInputs = [];
253
+ try {
254
+ if (options.extraData)
255
+ for (var n in options.extraData)
256
+ extraInputs.push(
257
+ $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
258
+ .appendTo(form)[0]);
259
+
260
+ // add iframe to doc and submit the form
261
+ $io.appendTo('body');
262
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
263
+ form.submit();
264
+ }
265
+ finally {
266
+ // reset attrs and remove "extra" input elements
267
+ form.setAttribute('action',a);
268
+ t ? form.setAttribute('target', t) : $form.removeAttr('target');
269
+ $(extraInputs).remove();
270
+ }
271
+ }, 10);
272
+
273
+ var nullCheckFlag = 0;
274
+
275
+ function cb() {
276
+ if (cbInvoked++) return;
277
+
278
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
279
+
280
+ var ok = true;
281
+ try {
282
+ if (timedOut) throw 'timeout';
283
+ // extract the server response from the iframe
284
+ var data, doc;
285
+
286
+ doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
287
+
288
+ if ((doc.body == null || doc.body.innerHTML == '') && !nullCheckFlag) {
289
+ // in some browsers (cough, Opera 9.2.x) the iframe DOM is not always traversable when
290
+ // the onload callback fires, so we give them a 2nd chance
291
+ nullCheckFlag = 1;
292
+ cbInvoked--;
293
+ setTimeout(cb, 100);
294
+ return;
295
+ }
296
+
297
+ xhr.responseText = doc.body ? doc.body.innerHTML : null;
298
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
299
+ xhr.getResponseHeader = function(header){
300
+ var headers = {'content-type': opts.dataType};
301
+ return headers[header];
302
+ };
303
+
304
+ if (opts.dataType == 'json' || opts.dataType == 'script') {
305
+ var ta = doc.getElementsByTagName('textarea')[0];
306
+ xhr.responseText = ta ? ta.value : xhr.responseText;
307
+ }
308
+ else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
309
+ xhr.responseXML = toXml(xhr.responseText);
310
+ }
311
+ data = $.httpData(xhr, opts.dataType);
312
+ }
313
+ catch(e){
314
+ ok = false;
315
+ $.handleError(opts, xhr, 'error', e);
316
+ }
317
+
318
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
319
+ if (ok) {
320
+ opts.success(data, 'success');
321
+ if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
322
+ }
323
+ if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
324
+ if (g && ! --$.active) $.event.trigger("ajaxStop");
325
+ if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
326
+
327
+ // clean up
328
+ setTimeout(function() {
329
+ $io.remove();
330
+ xhr.responseXML = null;
331
+ }, 100);
332
+ };
333
+
334
+ function toXml(s, doc) {
335
+ if (window.ActiveXObject) {
336
+ doc = new ActiveXObject('Microsoft.XMLDOM');
337
+ doc.async = 'false';
338
+ doc.loadXML(s);
339
+ }
340
+ else
341
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
342
+ return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
343
+ };
344
+ };
345
+ };
346
+
347
+ /**
348
+ * ajaxForm() provides a mechanism for fully automating form submission.
349
+ *
350
+ * The advantages of using this method instead of ajaxSubmit() are:
351
+ *
352
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
353
+ * is used to submit the form).
354
+ * 2. This method will include the submit element's name/value data (for the element that was
355
+ * used to submit the form).
356
+ * 3. This method binds the submit() method to the form for you.
357
+ *
358
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
359
+ * passes the options argument along after properly binding events for submit elements and
360
+ * the form itself.
361
+ */
362
+ $.fn.ajaxForm = function(options) {
363
+ return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
364
+ $(this).ajaxSubmit(options);
365
+ return false;
366
+ }).each(function() {
367
+ // store options in hash
368
+ $(":submit,input:image", this).bind('click.form-plugin',function(e) {
369
+ var form = this.form;
370
+ form.clk = this;
371
+ if (this.type == 'image') {
372
+ if (e.offsetX != undefined) {
373
+ form.clk_x = e.offsetX;
374
+ form.clk_y = e.offsetY;
375
+ } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
376
+ var offset = $(this).offset();
377
+ form.clk_x = e.pageX - offset.left;
378
+ form.clk_y = e.pageY - offset.top;
379
+ } else {
380
+ form.clk_x = e.pageX - this.offsetLeft;
381
+ form.clk_y = e.pageY - this.offsetTop;
382
+ }
383
+ }
384
+ // clear form vars
385
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
386
+ });
387
+ });
388
+ };
389
+
390
+ // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
391
+ $.fn.ajaxFormUnbind = function() {
392
+ this.unbind('submit.form-plugin');
393
+ return this.each(function() {
394
+ $(":submit,input:image", this).unbind('click.form-plugin');
395
+ });
396
+
397
+ };
398
+
399
+ /**
400
+ * formToArray() gathers form element data into an array of objects that can
401
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
402
+ * Each object in the array has both a 'name' and 'value' property. An example of
403
+ * an array for a simple login form might be:
404
+ *
405
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
406
+ *
407
+ * It is this array that is passed to pre-submit callback functions provided to the
408
+ * ajaxSubmit() and ajaxForm() methods.
409
+ */
410
+ $.fn.formToArray = function(semantic) {
411
+ var a = [];
412
+ if (this.length == 0) return a;
413
+
414
+ var form = this[0];
415
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
416
+ if (!els) return a;
417
+ for(var i=0, max=els.length; i < max; i++) {
418
+ var el = els[i];
419
+ var n = el.name;
420
+ if (!n) continue;
421
+
422
+ if (semantic && form.clk && el.type == "image") {
423
+ // handle image inputs on the fly when semantic == true
424
+ if(!el.disabled && form.clk == el) {
425
+ a.push({name: n, value: $(el).val()});
426
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
427
+ }
428
+ continue;
429
+ }
430
+
431
+ var v = $.fieldValue(el, true);
432
+ if (v && v.constructor == Array) {
433
+ for(var j=0, jmax=v.length; j < jmax; j++)
434
+ a.push({name: n, value: v[j]});
435
+ }
436
+ else if (v !== null && typeof v != 'undefined')
437
+ a.push({name: n, value: v});
438
+ }
439
+
440
+ if (!semantic && form.clk) {
441
+ // input type=='image' are not found in elements array! handle it here
442
+ var $input = $(form.clk), input = $input[0], n = input.name;
443
+ if (n && !input.disabled && input.type == 'image') {
444
+ a.push({name: n, value: $input.val()});
445
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
446
+ }
447
+ }
448
+ return a;
449
+ };
450
+
451
+ /**
452
+ * Serializes form data into a 'submittable' string. This method will return a string
453
+ * in the format: name1=value1&amp;name2=value2
454
+ */
455
+ $.fn.formSerialize = function(semantic) {
456
+ //hand off to jQuery.param for proper encoding
457
+ return $.param(this.formToArray(semantic));
458
+ };
459
+
460
+ /**
461
+ * Serializes all field elements in the jQuery object into a query string.
462
+ * This method will return a string in the format: name1=value1&amp;name2=value2
463
+ */
464
+ $.fn.fieldSerialize = function(successful) {
465
+ var a = [];
466
+ this.each(function() {
467
+ var n = this.name;
468
+ if (!n) return;
469
+ var v = $.fieldValue(this, successful);
470
+ if (v && v.constructor == Array) {
471
+ for (var i=0,max=v.length; i < max; i++)
472
+ a.push({name: n, value: v[i]});
473
+ }
474
+ else if (v !== null && typeof v != 'undefined')
475
+ a.push({name: this.name, value: v});
476
+ });
477
+ //hand off to jQuery.param for proper encoding
478
+ return $.param(a);
479
+ };
480
+
481
+ /**
482
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
483
+ *
484
+ * <form><fieldset>
485
+ * <input name="A" type="text" />
486
+ * <input name="A" type="text" />
487
+ * <input name="B" type="checkbox" value="B1" />
488
+ * <input name="B" type="checkbox" value="B2"/>
489
+ * <input name="C" type="radio" value="C1" />
490
+ * <input name="C" type="radio" value="C2" />
491
+ * </fieldset></form>
492
+ *
493
+ * var v = $(':text').fieldValue();
494
+ * // if no values are entered into the text inputs
495
+ * v == ['','']
496
+ * // if values entered into the text inputs are 'foo' and 'bar'
497
+ * v == ['foo','bar']
498
+ *
499
+ * var v = $(':checkbox').fieldValue();
500
+ * // if neither checkbox is checked
501
+ * v === undefined
502
+ * // if both checkboxes are checked
503
+ * v == ['B1', 'B2']
504
+ *
505
+ * var v = $(':radio').fieldValue();
506
+ * // if neither radio is checked
507
+ * v === undefined
508
+ * // if first radio is checked
509
+ * v == ['C1']
510
+ *
511
+ * The successful argument controls whether or not the field element must be 'successful'
512
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
513
+ * The default value of the successful argument is true. If this value is false the value(s)
514
+ * for each element is returned.
515
+ *
516
+ * Note: This method *always* returns an array. If no valid value can be determined the
517
+ * array will be empty, otherwise it will contain one or more values.
518
+ */
519
+ $.fn.fieldValue = function(successful) {
520
+ for (var val=[], i=0, max=this.length; i < max; i++) {
521
+ var el = this[i];
522
+ var v = $.fieldValue(el, successful);
523
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
524
+ continue;
525
+ v.constructor == Array ? $.merge(val, v) : val.push(v);
526
+ }
527
+ return val;
528
+ };
529
+
530
+ /**
531
+ * Returns the value of the field element.
532
+ */
533
+ $.fieldValue = function(el, successful) {
534
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
535
+ if (typeof successful == 'undefined') successful = true;
536
+
537
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
538
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
539
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
540
+ tag == 'select' && el.selectedIndex == -1))
541
+ return null;
542
+
543
+ if (tag == 'select') {
544
+ var index = el.selectedIndex;
545
+ if (index < 0) return null;
546
+ var a = [], ops = el.options;
547
+ var one = (t == 'select-one');
548
+ var max = (one ? index+1 : ops.length);
549
+ for(var i=(one ? index : 0); i < max; i++) {
550
+ var op = ops[i];
551
+ if (op.selected) {
552
+ var v = op.value;
553
+ if (!v) // extra pain for IE...
554
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
555
+ if (one) return v;
556
+ a.push(v);
557
+ }
558
+ }
559
+ return a;
560
+ }
561
+ return el.value;
562
+ };
563
+
564
+ /**
565
+ * Clears the form data. Takes the following actions on the form's input fields:
566
+ * - input text fields will have their 'value' property set to the empty string
567
+ * - select elements will have their 'selectedIndex' property set to -1
568
+ * - checkbox and radio inputs will have their 'checked' property set to false
569
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
570
+ * - button elements will *not* be effected
571
+ */
572
+ $.fn.clearForm = function() {
573
+ return this.each(function() {
574
+ $('input,select,textarea', this).clearFields();
575
+ });
576
+ };
577
+
578
+ /**
579
+ * Clears the selected form elements.
580
+ */
581
+ $.fn.clearFields = $.fn.clearInputs = function() {
582
+ return this.each(function() {
583
+ var t = this.type, tag = this.tagName.toLowerCase();
584
+ if (t == 'text' || t == 'password' || tag == 'textarea')
585
+ this.value = '';
586
+ else if (t == 'checkbox' || t == 'radio')
587
+ this.checked = false;
588
+ else if (tag == 'select')
589
+ this.selectedIndex = -1;
590
+ });
591
+ };
592
+
593
+ /**
594
+ * Resets the form data. Causes all form elements to be reset to their original value.
595
+ */
596
+ $.fn.resetForm = function() {
597
+ return this.each(function() {
598
+ // guard against an input with the name of 'reset'
599
+ // note that IE reports the reset function as an 'object'
600
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
601
+ this.reset();
602
+ });
603
+ };
604
+
605
+ /**
606
+ * Enables or disables any matching elements.
607
+ */
608
+ $.fn.enable = function(b) {
609
+ if (b == undefined) b = true;
610
+ return this.each(function() {
611
+ this.disabled = !b;
612
+ });
613
+ };
614
+
615
+ /**
616
+ * Checks/unchecks any matching checkboxes or radio buttons and
617
+ * selects/deselects and matching option elements.
618
+ */
619
+ $.fn.selected = function(select) {
620
+ if (select == undefined) select = true;
621
+ return this.each(function() {
622
+ var t = this.type;
623
+ if (t == 'checkbox' || t == 'radio')
624
+ this.checked = select;
625
+ else if (this.tagName.toLowerCase() == 'option') {
626
+ var $sel = $(this).parent('select');
627
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
628
+ // deselect all other options
629
+ $sel.find('option').selected(false);
630
+ }
631
+ this.selected = select;
632
+ }
633
+ });
634
+ };
635
+
636
+ // helper fn for console logging
637
+ // set $.fn.ajaxSubmit.debug to true to enable debug logging
638
+ function log() {
639
+ if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
640
+ window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
641
+ };
642
+
643
+ })(jQuery);