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,3 @@
1
+ // jquery.jsonp 2.1.0 (c)2010 Julian Aubourg | MIT License
2
+ // http://code.google.com/p/jquery-jsonp/
3
+ (function(e,b){function d(){}function s(B){c=[B]}function m(B){f.insertBefore(B,f.firstChild)}function l(D,B,C){D&&D.apply(B,C)}function k(B){return/\?/.test(B)?"&":"?"}var n="async",q="",z="error",r="_jqjsp",v="on",o=v+"click",p=v+z,a=v+"load",i=v+"readystatechange",y="removeChild",g="<script/>",u="success",x="timeout",w=e.browser,f=e("head")[0]||document.documentElement,t={},j=0,c,h={callback:r,url:location.href};function A(B){B=e.extend({},h,B);var P=B.complete,D=B.dataFilter,L=B.callbackParameter,Q=B.callback,F=B.cache,H=B.pageCache,C=B.url,K=B.data,O=B.timeout,N,J=B.beforeSend,I=0,G=d;B.abort=function(){!I++&&G()};if(J&&(J(B,B)===false||I)){return B}C=C||q;K=K?((typeof K)=="string"?K:e.param(K,B.traditional)):q;C+=K?(k(C)+K):q;L&&(C+=k(C)+escape(L)+"=?");!F&&!H&&(C+=k(C)+"_"+(new Date()).getTime()+"=");C=C.replace(/=\?(&|$)/,"="+Q+"$1");function M(R){!I++&&b(function(){G();H&&(t[C]={s:[R]});D&&(R=D.apply(B,[R]));l(B.success,B,[R,u]);l(P,B,[B,u])},0)}function E(R){!I++&&b(function(){G();H&&R!=x&&(t[C]=R);l(B.error,B,[B,R]);l(P,B,[B,R])},0)}H&&(N=t[C])?(N.s?M(N.s[0]):E(N)):b(function(S,R,T){if(!I){T=O>0&&b(function(){E(x)},O);G=function(){T&&clearTimeout(T);S[i]=S[o]=S[a]=S[p]=null;f[y](S);R&&f[y](R)};window[Q]=s;S=e(g)[0];S.id=r+j++;function U(V){(S[o]||d)();V=c;c=undefined;V?M(V[0]):E(z)}if(w.msie){S.event=o;S.htmlFor=S.id;S[i]=function(){S.readyState=="loaded"&&U()}}else{S[p]=S[a]=U;w.opera?((R=e(g)[0]).text="jQuery('#"+S.id+"')[0]."+p+"()"):S[n]=n}S.src=C;m(S);R&&m(R)}},0);return B}A.setup=function(B){e.extend(h,B)};e.jsonp=A})(jQuery,setTimeout);
@@ -0,0 +1,142 @@
1
+ /*
2
+ * ContextMenu - jQuery plugin for right-click context menus
3
+ *
4
+ * Author: Chris Domigan
5
+ * Contributors: Dan G. Switzer, II
6
+ * Parts of this plugin are inspired by Joern Zaefferer's Tooltip plugin
7
+ *
8
+ * Dual licensed under the MIT and GPL licenses:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ * http://www.gnu.org/licenses/gpl.html
11
+ *
12
+ * Version: r2
13
+ * Date: 16 July 2007
14
+ *
15
+ * For documentation visit http://www.trendskitchens.co.nz/jquery/contextmenu/
16
+ *
17
+ */
18
+ (function($){
19
+ var menu, shadow, trigger, content, hash, currentTarget;
20
+ var defaults = {
21
+ menuStyle: {
22
+ listStyle: 'none',
23
+ padding: '1px',
24
+ margin: '0px',
25
+ backgroundColor: '#fff',
26
+ border: '1px solid #999',
27
+ width: '100px'
28
+ },
29
+ itemStyle: {
30
+ margin: '0px',
31
+ color: '#000',
32
+ display: 'block',
33
+ cursor: 'default',
34
+ padding: '3px',
35
+ border: '1px solid #fff',
36
+ backgroundColor: 'transparent'
37
+ },
38
+ itemHoverStyle: {
39
+ border: '1px solid #0a246a',
40
+ backgroundColor: '#b6bdd2'
41
+ },
42
+ shadow: true
43
+ };
44
+
45
+ $.fn.contextMenu = function(id, options){
46
+ if (!menu) {
47
+ menu = $('<div id="jqContextMenu"></div>').hide().css({
48
+ position: 'absolute',
49
+ zIndex: '500'
50
+ }).appendTo('body').bind('click', function(e){
51
+ e.stopPropagation();
52
+ });
53
+ }
54
+
55
+ if (!shadow) {
56
+ shadow = $('<div></div>').css({
57
+ backgroundColor: '#000',
58
+ position: 'absolute',
59
+ opacity: 0.2,
60
+ zIndex: 499
61
+ }).appendTo('body').hide();
62
+ }
63
+
64
+ hash = hash || [];
65
+ hash.push({
66
+ id: id,
67
+ menuStyle: $.extend({}, defaults.menuStyle, options.menuStyle || {}),
68
+ itemStyle: $.extend({}, defaults.itemStyle, options.itemStyle || {}),
69
+ itemHoverStyle: $.extend({}, defaults.itemHoverStyle, options.itemHoverStyle || {}),
70
+ bindings: options.bindings || {},
71
+ shadow: options.shadow || options.shadow === false ? options.shadow : defaults.shadow
72
+ });
73
+
74
+ var index = hash.length - 1;
75
+ $(this).bind('click', function(e){
76
+ display(index, this, e, options);
77
+ return false;
78
+ });
79
+ return this;
80
+ };
81
+
82
+ function display(index, trigger, e, options){
83
+ var cur = hash[index];
84
+ content = $('#' + cur.id).find('ul:first').clone(true);
85
+ content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover(function(){
86
+ $(this).css(cur.itemHoverStyle);
87
+ }, function(){
88
+ $(this).css(cur.itemStyle);
89
+ }).find('img').css({
90
+ verticalAlign: 'middle',
91
+ paddingRight: '2px'
92
+ });
93
+
94
+ menu.html(content);
95
+
96
+ $.each(cur.bindings, function(id, func){
97
+ $('#' + id, menu).bind('click', function(e){
98
+ hide();
99
+ func(trigger, currentTarget);
100
+ });
101
+ });
102
+
103
+ var offset = $(trigger).offset();
104
+ menu.css({
105
+ 'left': offset.left,
106
+ 'top': offset.top + offset.height + 2
107
+ }).show();
108
+
109
+ if (cur.shadow) {
110
+ shadow.css({
111
+ width: menu.width(),
112
+ height: menu.height(),
113
+ left: offset.left + 2,
114
+ top: offset.top + offset.height + 4
115
+ }).show();
116
+ }
117
+
118
+ $(document).one('click', hide);
119
+ }
120
+
121
+ function hide(){
122
+ menu.hide();
123
+ shadow.hide();
124
+ }
125
+
126
+ $.contextMenu = {
127
+ defaults: function(userDefaults){
128
+ $.each(userDefaults, function(i, val){
129
+ if (typeof val == 'object' && defaults[i]) {
130
+ $.extend(defaults[i], val);
131
+ }
132
+ else {
133
+ defaults[i] = val;
134
+ }
135
+ });
136
+ }
137
+ };
138
+ })(jQuery);
139
+
140
+ $(function(){
141
+ $('div.contextMenu').hide();
142
+ });
@@ -0,0 +1,308 @@
1
+ /*
2
+ * jquery.suggest 1.1 - 2007-08-06
3
+ *
4
+ * Uses code and techniques from following libraries:
5
+ * 1. http://www.dyve.net/jquery/?autocomplete
6
+ * 2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js
7
+ *
8
+ * All the new stuff written by Peter Vulgaris (www.vulgarisoip.com)
9
+ * Feel free to do whatever you want with this file
10
+ *
11
+ */
12
+
13
+ (function($) {
14
+ $.fn.caret = function(options,opt2){
15
+ var start,end,t=this[0];
16
+ if(typeof options==="object" && typeof options.start==="number" && typeof options.end==="number") {
17
+ start=options.start;
18
+ end=options.end;
19
+ } else if(typeof options==="number" && typeof opt2==="number"){
20
+ start=options;
21
+ end=opt2;
22
+ } else if(typeof options==="string"){
23
+ if ((start = t.value.indexOf(options)) > -1) {
24
+ end = start + options.length;
25
+ }
26
+ else {
27
+ start = null;
28
+ }
29
+ } else if(Object.prototype.toString.call(options)==="[object RegExp]"){
30
+ var re=options.exec(t.value);
31
+ if(re) {
32
+ start=re.index;
33
+ end=start+re[0].length;
34
+ }
35
+ }
36
+ if(typeof start!="undefined"){
37
+ if($.browser.msie){
38
+ var selRange = this[0].createTextRange();
39
+ selRange.collapse(true);
40
+ selRange.moveStart('character', start);
41
+ selRange.moveEnd('character', end-start);
42
+ selRange.select();
43
+ } else {
44
+ this[0].selectionStart=start;
45
+ this[0].selectionEnd=end;
46
+ }
47
+ this[0].focus();
48
+ return this;
49
+ } else {
50
+ var s, e;
51
+ if($.browser.msie){
52
+ var val = this.val();
53
+ var range = document.selection.createRange().duplicate();
54
+ range.moveEnd("character", val.length);
55
+ s = (range.text == "" ? val.length : val.lastIndexOf(range.text));
56
+ range = document.selection.createRange().duplicate();
57
+ range.moveStart("character", -val.length);
58
+ e = range.text.length;
59
+ } else {
60
+ s=t.selectionStart;
61
+ e=t.selectionEnd;
62
+ }
63
+ var te=t.value.substring(s,e);
64
+ return {start:s,end:e,text:te,replace:function(st){
65
+ t.value = t.value.substring(0,s)+st+t.value.substring(e,t.value.length);
66
+ }};
67
+ }
68
+ return this;
69
+ };
70
+
71
+ $.suggest = function(input, options) {
72
+ var $input = $(input).attr("autocomplete", "off");
73
+ var $results = $(document.createElement("ul"));
74
+ var timeout = false; // hold timeout ID for suggestion results to appear
75
+ var prevLength = 0; // last recorded length of $input.val()
76
+ var cache = []; // cache MRU list
77
+ var cacheSize = 0; // size of cache in chars (bytes?)
78
+
79
+ var $em = $(document.createElement('div')).css({
80
+ left: 0,
81
+ top: 0,
82
+ position: 'absolute',
83
+ visibility: 'hidden',
84
+ border: 'none',
85
+ padding: '0px'
86
+ }).appendTo('body');
87
+
88
+ $results.addClass(options.resultsClass).appendTo('body');
89
+
90
+ var resetPosition = function() {
91
+ // requires jquery.dimension plugin
92
+ var offset = $input.offset();
93
+ $results.css({
94
+ top: (offset.top + input.offsetHeight) + 'px',
95
+ left: offset.left + 'px'
96
+ });
97
+ };
98
+
99
+ var processKey = function(e) {
100
+ // handling up/down/escape requires results to be visible
101
+ // handling enter/tab requires that AND a result to be selected
102
+ if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
103
+ (/^13$|^9$/.test(e.keyCode) && getCurrentResult())) {
104
+
105
+ if (e.preventDefault) {
106
+ e.preventDefault();
107
+ }
108
+
109
+ if (e.stopPropagation) {
110
+ e.stopPropagation();
111
+ }
112
+
113
+ e.cancelBubble = true;
114
+ e.returnValue = false;
115
+
116
+ switch(e.keyCode) {
117
+ case 38: // up
118
+ prevResult();
119
+ break;
120
+
121
+ case 40: // down
122
+ nextResult();
123
+ break;
124
+
125
+ case 9: // tab
126
+ case 13: // return
127
+ selectCurrentResult();
128
+ break;
129
+
130
+ case 27: // escape
131
+ $results.hide();
132
+ break;
133
+ }
134
+ }
135
+ else if ($input.val().length != prevLength) {
136
+ if (timeout) {
137
+ clearTimeout(timeout);
138
+ }
139
+ timeout = setTimeout(suggest, options.delay);
140
+ prevLength = $input.val().length;
141
+ }
142
+ };
143
+
144
+ var suggest = function() {
145
+ var q = $input.val();
146
+
147
+ $results.hide();
148
+ if (q.length >= options.minchars) {
149
+ var obj = options.source(q, $input.caret(), function(_obj) {
150
+ displayItems(_obj);
151
+ });
152
+
153
+ if (obj) {
154
+ displayItems(obj);
155
+ }
156
+ }
157
+ };
158
+
159
+ var displayItems = function(obj) {
160
+ if ($.isArray(obj)) {
161
+ obj = { items: items };
162
+ }
163
+
164
+ if (!obj || !obj.items || !obj.items.length) {
165
+ return;
166
+ }
167
+
168
+ var html = '';
169
+ for (var i = 0; i < obj.items.length; i++) {
170
+ html += '<li id="' + i + '">' + obj.items[i] + '</li>';
171
+ }
172
+
173
+ $results.html(html);
174
+ if (options.complete) {
175
+ var caret = $input.caret();
176
+ var text = $input.val().substring(0, caret.end);
177
+ var width = $em.text(text).offset().width;
178
+ var offset = $input.offset();
179
+ $results.css({
180
+ top: (offset.top + input.offsetHeight) + 'px',
181
+ left: (offset.left + width) + 'px'
182
+ });
183
+ $results.find('li').each(function() {
184
+ $.data(this, 'jquery.suggest', obj);
185
+ });
186
+ }
187
+ $results.show();
188
+
189
+ $results
190
+ .children('li')
191
+ .mouseover(function() {
192
+ $results.children('li').removeClass(options.selectClass);
193
+ $(this).addClass(options.selectClass);
194
+ })
195
+ .click(function(e) {
196
+ e.preventDefault();
197
+ e.stopPropagation();
198
+ selectCurrentResult();
199
+ });
200
+ };
201
+
202
+ var getCurrentResult = function() {
203
+ if (!$results.is(':visible')) {
204
+ return false;
205
+ }
206
+
207
+ var $currentResult = $results.children('li.' + options.selectClass);
208
+
209
+ if (!$currentResult.length) {
210
+ $currentResult = false;
211
+ }
212
+
213
+ return $currentResult;
214
+ };
215
+
216
+ var selectCurrentResult = function() {
217
+ $currentResult = getCurrentResult();
218
+
219
+ if ($currentResult) {
220
+ if (options.complete) {
221
+ var obj = $.data($currentResult.get(0), 'jquery.suggest');
222
+ var id = parseInt($currentResult.attr('id'), 10);
223
+ var text = obj.complete ? obj.complete[id] : obj.items[id];
224
+ $input.caret({ start: obj.start, end: obj.end });
225
+ $input.caret().replace(text);
226
+ var pos = obj.start + text.length;
227
+ $input.caret({ start: pos, end: pos });
228
+ } else {
229
+ $input.val($currentResult.text());
230
+ }
231
+ $results.hide();
232
+
233
+ if (options.onSelect) {
234
+ options.onSelect.apply($input[0]);
235
+ }
236
+ }
237
+ };
238
+
239
+ var nextResult = function() {
240
+ $currentResult = getCurrentResult();
241
+
242
+ if ($currentResult) {
243
+ $currentResult.removeClass(options.selectClass).next().addClass(options.selectClass);
244
+ }
245
+ else {
246
+ $results.children('li:first-child').addClass(options.selectClass);
247
+ }
248
+ };
249
+
250
+ var prevResult = function() {
251
+ $currentResult = getCurrentResult();
252
+
253
+ if ($currentResult) {
254
+ $currentResult.removeClass(options.selectClass).prev().addClass(options.selectClass);
255
+ }
256
+ else {
257
+ $results.children('li:last-child').addClass(options.selectClass);
258
+ }
259
+ };
260
+
261
+ resetPosition();
262
+ $(window)
263
+ .load(resetPosition) // just in case user is changing size of page while loading
264
+ .resize(resetPosition);
265
+
266
+ $input.blur(function() {
267
+ setTimeout(function() { $results.hide(); }, 200);
268
+ });
269
+
270
+ // help IE users if possible
271
+ try {
272
+ $results.bgiframe();
273
+ } catch(e) { }
274
+
275
+ // I really hate browser detection, but I don't see any other way
276
+ if ($.browser.mozilla) {
277
+ $input.keypress(processKey); // onkeypress repeats arrow keys in Mozilla/Opera
278
+ }
279
+ else {
280
+ $input.keydown(processKey); // onkeydown repeats arrow keys in IE/Safari
281
+ }
282
+ };
283
+
284
+ $.fn.suggest = function(source, options) {
285
+ if (!source) {
286
+ return;
287
+ }
288
+
289
+ options = options || {};
290
+ options.source = source;
291
+ options.delay = options.delay || 100;
292
+ options.complete = options.complete || false;
293
+ options.resultsClass = options.resultsClass || 'ac_results';
294
+ options.selectClass = options.selectClass || 'ac_over';
295
+ options.matchClass = options.matchClass || 'ac_match';
296
+ options.minchars = options.minchars || 2;
297
+ options.delimiter = options.delimiter || '\n';
298
+ options.onSelect = options.onSelect || false;
299
+ options.maxCacheSize = options.maxCacheSize || 65536;
300
+
301
+ this.each(function() {
302
+ $.suggest(this, options);
303
+ });
304
+
305
+ return this;
306
+ };
307
+ })(jQuery);
308
+