rhack 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. data/.gemtest +0 -0
  2. data/CURB-LICENSE +51 -0
  3. data/Gemfile +4 -0
  4. data/History.txt +4 -0
  5. data/LICENSE +51 -0
  6. data/License.txt +17 -0
  7. data/Manifest.txt +61 -0
  8. data/README.txt +12 -0
  9. data/Rakefile +34 -0
  10. data/ext/curb-original/curb.c +977 -0
  11. data/ext/curb-original/curb.h +52 -0
  12. data/ext/curb-original/curb_config.h +235 -0
  13. data/ext/curb-original/curb_easy.c +3455 -0
  14. data/ext/curb-original/curb_easy.h +90 -0
  15. data/ext/curb-original/curb_errors.c +647 -0
  16. data/ext/curb-original/curb_errors.h +129 -0
  17. data/ext/curb-original/curb_macros.h +159 -0
  18. data/ext/curb-original/curb_multi.c +704 -0
  19. data/ext/curb-original/curb_multi.h +26 -0
  20. data/ext/curb-original/curb_postfield.c +523 -0
  21. data/ext/curb-original/curb_postfield.h +40 -0
  22. data/ext/curb-original/curb_upload.c +80 -0
  23. data/ext/curb-original/curb_upload.h +30 -0
  24. data/ext/curb/Makefile +157 -0
  25. data/ext/curb/curb.c +977 -0
  26. data/ext/curb/curb.h +52 -0
  27. data/ext/curb/curb_config.h +235 -0
  28. data/ext/curb/curb_easy.c +3430 -0
  29. data/ext/curb/curb_easy.h +94 -0
  30. data/ext/curb/curb_errors.c +647 -0
  31. data/ext/curb/curb_errors.h +129 -0
  32. data/ext/curb/curb_macros.h +159 -0
  33. data/ext/curb/curb_multi.c +710 -0
  34. data/ext/curb/curb_multi.h +26 -0
  35. data/ext/curb/curb_postfield.c +523 -0
  36. data/ext/curb/curb_postfield.h +40 -0
  37. data/ext/curb/curb_upload.c +80 -0
  38. data/ext/curb/curb_upload.h +30 -0
  39. data/ext/curb/extconf.rb +399 -0
  40. data/lib/cache.rb +44 -0
  41. data/lib/curl-global.rb +151 -0
  42. data/lib/extensions/browser/env.js +697 -0
  43. data/lib/extensions/browser/jquery.js +7180 -0
  44. data/lib/extensions/browser/xmlsax.js +1564 -0
  45. data/lib/extensions/browser/xmlw3cdom_1.js +1444 -0
  46. data/lib/extensions/browser/xmlw3cdom_2.js +2744 -0
  47. data/lib/extensions/curb.rb +125 -0
  48. data/lib/extensions/declarative.rb +153 -0
  49. data/lib/extensions/johnson.rb +63 -0
  50. data/lib/frame.rb +766 -0
  51. data/lib/init.rb +36 -0
  52. data/lib/rhack.rb +16 -0
  53. data/lib/rhack.yml.template +19 -0
  54. data/lib/rhack/proxy/checker.rb +226 -0
  55. data/lib/rhack/proxy/list.rb +196 -0
  56. data/lib/rhack/services.rb +445 -0
  57. data/lib/rhack_in.rb +2 -0
  58. data/lib/scout.rb +591 -0
  59. data/lib/words.rb +37 -0
  60. data/test/test_frame.rb +107 -0
  61. data/test/test_rhack.rb +5 -0
  62. data/test/test_scout.rb +53 -0
  63. metadata +195 -0
data/lib/cache.rb ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ module HTTPAccessKit
3
+
4
+ class Cache < ActiveRecord::Base
5
+ declare CacheTable do |t|
6
+ t.integer :url_hash
7
+ t.string :url
8
+ t.string :path
9
+ t.string :date
10
+ t.string :ext
11
+ t.timestamps
12
+ end if DB
13
+ RAMCache = {}
14
+
15
+ def self.clean(time=7.days)
16
+ destroy_all("created_at < '#{time.ago}'").each {|c|
17
+ FileUtils.remove c.path if c.path and File.file?(c.path)}
18
+ end
19
+ CacheTTL and clean CacheTTL
20
+
21
+ def self.save(url, data, cache_data=true)
22
+ new(url, data).save
23
+ RAMCache[url.href] = data if cache_data
24
+ end
25
+
26
+ def self.load(url, cache_data=true)
27
+ if data = RAMCache[url.href]
28
+ data
29
+ elsif file = first(:select => 'date, path', :conditions => {:url_hash => url.href.hash})
30
+ RAMCache[url.href] = read(file.path) if cache_data
31
+ file
32
+ end
33
+ end
34
+
35
+ def initialize(url, data)
36
+ t = Time.now
37
+ path = "#{CacheDir}/#{t.to_i}-#{File.split(url.path)[1]}"
38
+ rw path, data
39
+ super :url => url.href, :url_hash => url.href.hash, :date => t.httpdate, :path => path, :ext => url.ext
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: utf-8
2
+ module Curl
3
+
4
+ def execute
5
+ # если ты ищешь, откуда оно запускается, то это наверное
6
+ # lib/extensions/johnson.rb:37:in `set_browser_for_curl'
7
+ if $CarierThread and s = $CarierThread.status
8
+ L.debug "Carier thread allready started and has status #{s}"
9
+ else
10
+ if s = Curl.status(false) then L.warn s end
11
+ L.debug($CarierThread ? "Resetting Carier thread" : "Setting Carier thread up")
12
+ $CarierThread = Thread.new {
13
+ error = nil
14
+ begin
15
+ # "why Thread#value is raising since it never raised before?"
16
+ yield if block_given?
17
+ rescue => error
18
+ nil
19
+ end
20
+ loop {
21
+ begin
22
+ # with true argument (idle) it would break only if no requests to perform
23
+ break unless $Carier.perform true
24
+ L.debug "Nothing to perform; idling..."
25
+ rescue => error
26
+ break
27
+ # but ruby mystically crashes if next sequence occur:
28
+ # Multi performs and can't see any requests so entering idle mode
29
+ # we add some requests and multi load them
30
+ # one of requests' callbacks raises error in *main* thread
31
+ # so we can't allow any raises here, instead, keep them in 'wait' section
32
+ end
33
+ } unless error
34
+ error
35
+ }
36
+ end
37
+ end
38
+ alias :run :execute
39
+ module_function :execute, :run
40
+
41
+ def wait
42
+ if $CarierThread
43
+ if !(within = Thread.current == $CarierThread)
44
+ # We can't set `perform' timeout lesser than 1 second in the curl binding
45
+ # because in that case thread status would always be "run"
46
+ # so here we wait for exactly 1 sec
47
+ sleep 1
48
+ end
49
+ # Also, if thread do Kernel.sleep, it would skip Curl.wait here
50
+ if !$Carier.sheduled and ($CarierThread.status == 'sleep' or within && $Carier.reqs.empty?)
51
+ L.debug "No shedule to wait"
52
+ else
53
+ L.log "Waiting for Carier to complete in #{within ? 'it\'s thread' : Thread.main == Thread.current ? 'main thread' : 'thread '+Thread.current.object_id}"
54
+ begin
55
+ L.log { "Trying to change $CarierThreadIsJoined #{$CarierThreadIsJoined} -> true from #{within ? 'it\'s thread' : Thread.main == Thread.current ? 'main thread' : 'thread '+Thread.current.object_id}" }
56
+ if within
57
+ L.debug "calling this from one of callbacks to wait for the rest to complete"
58
+ begin
59
+ $Carier.perform
60
+ rescue RuntimeError => e
61
+ L.warn [e, e.message]
62
+ L.info "$Carier $Carier.sheduled $CarierThread $CarierThread.status", binding
63
+ L.warn "Failed to run Multi#perform: nothing to perform"
64
+ end
65
+ else
66
+ $CarierThreadIsJoined = true
67
+ $CarierThread.join
68
+ end
69
+ rescue (defined?(IRB) ? IRB::Abort : NilClass)
70
+ recall!
71
+ L.info "Carier thread recalled by keyboard"
72
+ ensure
73
+ L.log "trying to change $CarierThreadIsJoined #{$CarierThreadIsJoined} -> false from #{within ? 'it\'s' : 'main'} thread"
74
+ if !within
75
+ $CarierThreadIsJoined = false
76
+ if $CarierThread and e = $CarierThread.value
77
+ # this will raise thread-safely in main thread
78
+ # in case of unrescued error in CarierThread
79
+ recall!
80
+ raise e
81
+ end
82
+ execute
83
+ end
84
+ end
85
+ end
86
+ else
87
+ L.debug "No thread to wait"
88
+ end
89
+ end
90
+ module_function :wait
91
+
92
+ def recall
93
+ L.debug caller
94
+ if $CarierThread
95
+ L.debug "Recalling Carier thread"
96
+ $CarierThread.kill
97
+ sleep 1
98
+ else
99
+ L.debug "No thread to recall"
100
+ end
101
+ end
102
+ alias :stop :recall
103
+
104
+ def recall!
105
+ if $CarierThread
106
+ L.info "Recalling thread and resetting Carier!!!"
107
+ $CarierThread.kill
108
+ $CarierThread = nil
109
+ $Carier.reset
110
+ else
111
+ L.debug "No thread to recall!"
112
+ end
113
+ end
114
+ alias :stop! :recall!
115
+ module_function :recall!, :stop!, :recall, :stop
116
+
117
+ def reset
118
+ recall
119
+ execute
120
+ end
121
+
122
+ def reset!
123
+ recall!
124
+ execute
125
+ end
126
+ module_function :reset!, :reset
127
+
128
+ def status(raise_e=true)
129
+ if $CarierThread and (s = $CarierThread.status)
130
+ L.log "Carier thread responding with status #{s}"
131
+ s
132
+ elsif $CarierThread
133
+ if e = $CarierThread.value
134
+ if raise_e
135
+ recall!
136
+ raise e
137
+ else
138
+ L.log "Carier Thread returned #{e.inspect}"
139
+ e
140
+ end
141
+ else
142
+ L.debug "Carier Thread is exited without error"
143
+ end
144
+ else
145
+ L.debug "There is no Carier Thread atm"
146
+ end
147
+ end
148
+ alias :st :status
149
+ module_function :status, :st
150
+
151
+ end
@@ -0,0 +1,697 @@
1
+ /*
2
+ * Simulated browser environment for Rhino
3
+ * By John Resig <http://ejohn.org/>
4
+ * Copyright 2007 John Resig, under the MIT License
5
+ */
6
+
7
+ // The window Object
8
+ var window = this;
9
+
10
+ //Ruby.require("uri");
11
+
12
+ print = function(txt) { Ruby.puts(txt); };
13
+
14
+ (function(){
15
+
16
+ // Browser Navigator
17
+
18
+ window.navigator = {
19
+ get userAgent(){
20
+ return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";
21
+ }
22
+ };
23
+ /*
24
+ var fileToUrl = function(file) {
25
+ return Ruby.URI.parse("file://" + Ruby.File.expand_path(file));
26
+ };
27
+
28
+ var curLocation = fileToUrl(".");
29
+ /*
30
+ window.__defineSetter__("location", function(url){
31
+ var xhr = new XMLHttpRequest();
32
+ xhr.open("GET", url);
33
+ xhr.onreadystatechange = function(){
34
+ curLocation = curLocation.merge(url);
35
+ window.document = xhr.responseXML;
36
+
37
+ if(window.document) {
38
+ var event = document.createEvent();
39
+ event.initEvent("load");
40
+ window.dispatchEvent( event );
41
+ }
42
+ };
43
+ xhr.send();
44
+ });
45
+
46
+ window.__defineGetter__("location", function(url){
47
+ return {
48
+ get protocol(){
49
+ return curLocation.scheme() + ":";
50
+ },
51
+ get href(){
52
+ return curLocation.toString();
53
+ },
54
+ toString: function(){
55
+ return this.href.toString();
56
+ }
57
+ };
58
+ });
59
+ */
60
+
61
+ // Timers
62
+
63
+ var timers = [];
64
+
65
+ window.setTimeout = function(fn, time){
66
+ var num;
67
+ return num = setInterval(function(){
68
+ fn();
69
+ clearInterval(num);
70
+ }, time);
71
+ };
72
+
73
+ window.setInterval = function(fn, time){
74
+ var num = timers.length;
75
+
76
+ timers[num] = new Ruby.Thread(function() {
77
+ while(true) {
78
+ Ruby.sleep(time);
79
+ fn();
80
+ }
81
+ });
82
+
83
+ return num;
84
+ };
85
+
86
+ window.clearInterval = function(num){
87
+ if ( timers[num] ) {
88
+ timers[num].kill();
89
+ delete timers[num];
90
+ }
91
+ };
92
+
93
+ // Window Events
94
+
95
+ var events = [{}];
96
+
97
+ window.addEventListener = function(type, fn){
98
+ if ( !this.uuid || this == window ) {
99
+ this.uuid = events.length;
100
+ events[this.uuid] = {};
101
+ }
102
+
103
+ if ( !events[this.uuid][type] )
104
+ events[this.uuid][type] = [];
105
+
106
+ if ( events[this.uuid][type].indexOf( fn ) < 0 )
107
+ events[this.uuid][type].push( fn );
108
+ };
109
+
110
+ window.removeEventListener = function(type, fn){
111
+ if ( !this.uuid || this == window ) {
112
+ this.uuid = events.length;
113
+ events[this.uuid] = {};
114
+ }
115
+
116
+ if ( !events[this.uuid][type] )
117
+ events[this.uuid][type] = [];
118
+
119
+ events[this.uuid][type] =
120
+ events[this.uuid][type].filter(function(f){
121
+ return f != fn;
122
+ });
123
+ };
124
+
125
+ window.dispatchEvent = function(event){
126
+ if ( event.type ) {
127
+ if ( this.uuid && events[this.uuid][event.type] ) {
128
+ var self = this;
129
+
130
+ events[this.uuid][event.type].forEach(function(fn){
131
+ fn.call( self, event );
132
+ });
133
+ }
134
+
135
+ if ( this["on" + event.type] )
136
+ this["on" + event.type].call( self, event );
137
+ }
138
+ };
139
+
140
+ // DOM Document
141
+
142
+ window.DOMDocument = function(file){
143
+ this._file = file;
144
+ var parser = new W3CDOMImplementation();
145
+ try {
146
+ this._dom = parser.loadXML(file);
147
+ } catch(e) {
148
+ Ruby.puts("*** wycats to fix: " + parser.translateErrCode(e.code));
149
+ throw parser.translateErrCode(e.code);
150
+ }
151
+
152
+ if ( !obj_nodes["key?"]( this._dom ) )
153
+ obj_nodes[this._dom] = this;
154
+ };
155
+
156
+ DOMDocument.prototype = {
157
+ nodeType: 1,
158
+ write: function(str) {
159
+ if (typeof(write_output) != 'undefined')
160
+ write_output += str;
161
+ },
162
+ createTextNode: function(text){
163
+ return makeNode( this._dom.createTextNode(
164
+ text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
165
+ },
166
+ createElement: function(name){
167
+ return makeNode( this._dom.createElement(name.toLowerCase()) );
168
+ },
169
+ getElementsByTagName: function(name){
170
+ return new DOMNodeList( this._dom.getElementsByTagName(
171
+ name.toLowerCase()) );
172
+ },
173
+ getElementById: function(id){
174
+ return makeNode( this._dom.getElementById(id) );
175
+ },
176
+ get body(){
177
+ return this.getElementsByTagName("body")[0];
178
+ },
179
+ get documentElement(){
180
+ return makeNode( this._dom.getDocumentElement() );
181
+ },
182
+ get ownerDocument(){
183
+ return null;
184
+ },
185
+ addEventListener: window.addEventListener,
186
+ removeEventListener: window.removeEventListener,
187
+ dispatchEvent: window.dispatchEvent,
188
+ get nodeName() {
189
+ return "#document";
190
+ },
191
+ importNode: function(node, deep){
192
+ return makeNode( this._dom.importNode(node._dom, deep) );
193
+ },
194
+ toString: function(){
195
+ return "Document" + (typeof this._file == "string" ?
196
+ ": " + this._file : "");
197
+ },
198
+ get innerHTML(){
199
+ return this.documentElement.outerHTML;
200
+ },
201
+
202
+ get defaultView(){
203
+ return {
204
+ getComputedStyle: function(elem){
205
+ return {
206
+ getPropertyValue: function(prop){
207
+ prop = prop.replace(/\-(\w)/g,function(m,c){
208
+ return c.toUpperCase();
209
+ });
210
+ var val = elem.style[prop];
211
+
212
+ if ( prop === "opacity" && val === "" )
213
+ val = "1";
214
+
215
+ return val;
216
+ }
217
+ };
218
+ }
219
+ };
220
+ },
221
+
222
+ createEvent: function(){
223
+ return {
224
+ type: "",
225
+ initEvent: function(type){
226
+ this.type = type;
227
+ }
228
+ };
229
+ }
230
+ };
231
+
232
+ function getDocument(node){
233
+ return obj_nodes[node];
234
+ }
235
+
236
+ // DOM NodeList
237
+
238
+ window.DOMNodeList = function(list){
239
+ this._dom = list;
240
+ this.length = list.getLength();
241
+
242
+ for ( var i = 0; i < this.length; i++ ) {
243
+ var node = list.item(i);
244
+ this[i] = makeNode( node );
245
+ }
246
+ };
247
+
248
+ DOMNodeList.prototype = {
249
+ toString: function(){
250
+ return "[ " +
251
+ Array.prototype.join.call( this, ", " ) + " ]";
252
+ },
253
+ get outerHTML(){
254
+ return Array.prototype.map.call(
255
+ this, function(node){return node.outerHTML;}).join('');
256
+ }
257
+ };
258
+
259
+ // DOM Node
260
+
261
+ window.DOMNode = function(node){
262
+ this._dom = node;
263
+ };
264
+
265
+ DOMNode.prototype = {
266
+ get nodeType(){
267
+ return this._dom.getNodeType();
268
+ },
269
+ get nodeValue(){
270
+ return this._dom.getNodeValue();
271
+ },
272
+ get nodeName() {
273
+ return this._dom.getNodeName();
274
+ },
275
+ cloneNode: function(deep){
276
+ return makeNode( this._dom.cloneNode(deep) );
277
+ },
278
+ get ownerDocument(){
279
+ return getDocument( this._dom.getOwnerDocument() );
280
+ },
281
+ get documentElement(){
282
+ return makeNode( this._dom.getDocumentElement() );
283
+ },
284
+ get parentNode() {
285
+ return makeNode( this._dom.getParentNode() );
286
+ },
287
+ get nextSibling() {
288
+ return makeNode( this._dom.getNextSibling() );
289
+ },
290
+ get previousSibling() {
291
+ return makeNode( this._dom.getPreviousSibling() );
292
+ },
293
+ toString: function(){
294
+ return '"' + this.nodeValue + '"';
295
+ },
296
+ get outerHTML(){
297
+ return this.nodeValue;
298
+ }
299
+ };
300
+
301
+ // DOM Element
302
+
303
+ window.DOMElement = function(elem){
304
+ this._dom = elem;
305
+ this.style = {
306
+ get opacity(){ return this._opacity; },
307
+ set opacity(val){ this._opacity = val + ""; }
308
+ };
309
+
310
+ // Load CSS info
311
+ var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
312
+
313
+ for ( var i = 0; i < styles.length; i++ ) {
314
+ var style = styles[i].split(/\s*:\s*/);
315
+ if ( style.length == 2 )
316
+ this.style[ style[0] ] = style[1];
317
+ }
318
+ };
319
+
320
+ DOMElement.prototype = extend( new DOMNode(), {
321
+ get nodeName(){
322
+ return this.tagName.toUpperCase();
323
+ },
324
+ get tagName(){
325
+ return this._dom.getTagName().toUpperCase();
326
+ },
327
+ toString: function(){
328
+ return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
329
+ },
330
+ get outerHTML(){
331
+ var ret = "<" + this.tagName, attr = this.attributes;
332
+
333
+ for ( var i in attr )
334
+ ret += " " + i + "='" + attr[i] + "'";
335
+
336
+ if ( this.childNodes.length || this.nodeName == "SCRIPT" )
337
+ ret += ">" + this.childNodes.outerHTML +
338
+ "</" + this.tagName + ">";
339
+ else
340
+ ret += "/>";
341
+
342
+ return ret;
343
+ },
344
+
345
+ get attributes(){
346
+ var attr = {}, attrs = this._dom.getAttributes();
347
+
348
+ for ( var i = 0; i < attrs.getLength(); i++ )
349
+ attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
350
+
351
+ return attr;
352
+ },
353
+
354
+ get innerHTML(){
355
+ return this.childNodes.outerHTML;
356
+ },
357
+ set innerHTML(html){
358
+ html = html.replace(/<\/?([A-Z]+)/g, function(m){
359
+ return m.toLowerCase();
360
+ });
361
+
362
+ var nodes = this.ownerDocument.importNode(
363
+ new DOMDocument( html ).documentElement, true
364
+ ).childNodes;
365
+
366
+ while (this.firstChild)
367
+ this.removeChild( this.firstChild );
368
+
369
+ for ( var i = 0; i < nodes.length; i++ )
370
+ this.appendChild( nodes[i] );
371
+ },
372
+
373
+ get textContent(){
374
+ function nav(nodes){
375
+ var str = "";
376
+ for ( var i = 0; i < nodes.length; i++ ) {
377
+ if ( nodes[i].nodeType == 3 )
378
+ str += nodes[i].nodeValue;
379
+ else if ( nodes[i].nodeType == 1 )
380
+ str += nav(nodes[i].childNodes);
381
+ }
382
+ return str;
383
+ }
384
+
385
+ return nav(this.childNodes);
386
+ },
387
+ set textContent(text){
388
+ while (this.firstChild)
389
+ this.removeChild( this.firstChild );
390
+ this.appendChild( this.ownerDocument.createTextNode(text) );
391
+ },
392
+
393
+ style: {},
394
+ clientHeight: 0,
395
+ clientWidth: 0,
396
+ offsetHeight: 0,
397
+ offsetWidth: 0,
398
+
399
+ get disabled() {
400
+ var val = this.getAttribute("disabled");
401
+ return val != "false" && !!val;
402
+ },
403
+ set disabled(val) { return this.setAttribute("disabled",val); },
404
+
405
+ get checked() {
406
+ var val = this.getAttribute("checked");
407
+ return val != "false" && !!val;
408
+ },
409
+ set checked(val) { return this.setAttribute("checked",val); },
410
+
411
+ get selected() {
412
+ if ( !this._selectDone ) {
413
+ this._selectDone = true;
414
+
415
+ if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
416
+ var opt = this.parentNode.getElementsByTagName("option");
417
+
418
+ if ( this == opt[0] ) {
419
+ var select = true;
420
+
421
+ for ( var i = 1; i < opt.length; i++ ) {
422
+ if ( opt[i].selected ) {
423
+ select = false;
424
+ break;
425
+ }
426
+ }
427
+
428
+ if ( select )
429
+ this.selected = true;
430
+ }
431
+ }
432
+ }
433
+
434
+ var val = this.getAttribute("selected");
435
+ return val != "false" && !!val;
436
+ },
437
+ set selected(val) { return this.setAttribute("selected",val); },
438
+
439
+ get className() { return this.getAttribute("class") || ""; },
440
+ set className(val) {
441
+ return this.setAttribute("class",
442
+ val.replace(/(^\s*|\s*$)/g,""));
443
+ },
444
+
445
+ get type() { return this.getAttribute("type") || ""; },
446
+ set type(val) { return this.setAttribute("type",val); },
447
+
448
+ get value() { return this.getAttribute("value") || ""; },
449
+ set value(val) { return this.setAttribute("value",val); },
450
+
451
+ get src() { return this.getAttribute("src") || ""; },
452
+ set src(val) { return this.setAttribute("src",val); },
453
+
454
+ get id() { return this.getAttribute("id") || ""; },
455
+ set id(val) { return this.setAttribute("id",val); },
456
+
457
+ getAttribute: function(name){
458
+ return this._dom.hasAttribute(name) ?
459
+ new String( this._dom.getAttribute(name) ) :
460
+ null;
461
+ },
462
+ setAttribute: function(name,value){
463
+ this._dom.setAttribute(name,value);
464
+ },
465
+ removeAttribute: function(name){
466
+ this._dom.removeAttribute(name);
467
+ },
468
+
469
+ get childNodes(){
470
+ return new DOMNodeList( this._dom.getChildNodes() );
471
+ },
472
+ get firstChild(){
473
+ return makeNode( this._dom.getFirstChild() );
474
+ },
475
+ get lastChild(){
476
+ return makeNode( this._dom.getLastChild() );
477
+ },
478
+ appendChild: function(node){
479
+ this._dom.appendChild( node._dom );
480
+ },
481
+ insertBefore: function(node,before){
482
+ this._dom.insertBefore( node._dom, before ? before._dom : before );
483
+ },
484
+ removeChild: function(node){
485
+ this._dom.removeChild( node._dom );
486
+ },
487
+
488
+ getElementsByTagName: DOMDocument.prototype.getElementsByTagName,
489
+
490
+ addEventListener: window.addEventListener,
491
+ removeEventListener: window.removeEventListener,
492
+ dispatchEvent: window.dispatchEvent,
493
+
494
+ click: function(){
495
+ var event = document.createEvent();
496
+ event.initEvent("click");
497
+ this.dispatchEvent(event);
498
+ },
499
+ submit: function(){
500
+ var event = document.createEvent();
501
+ event.initEvent("submit");
502
+ this.dispatchEvent(event);
503
+ },
504
+ focus: function(){
505
+ var event = document.createEvent();
506
+ event.initEvent("focus");
507
+ this.dispatchEvent(event);
508
+ },
509
+ blur: function(){
510
+ var event = document.createEvent();
511
+ event.initEvent("blur");
512
+ this.dispatchEvent(event);
513
+ },
514
+ get elements(){
515
+ return this.getElementsByTagName("*");
516
+ },
517
+ get contentWindow(){
518
+ return this.nodeName == "IFRAME" ? {
519
+ document: this.contentDocument
520
+ } : null;
521
+ },
522
+ get contentDocument(){
523
+ if ( this.nodeName == "IFRAME" ) {
524
+ if ( !this._doc )
525
+ this._doc = new DOMDocument(
526
+ "<html><head><title></title></head><body></body></html>"
527
+ );
528
+ return this._doc;
529
+ } else
530
+ return null;
531
+ }
532
+ });
533
+
534
+ DOMElement.prototype.toString = function() {
535
+ return "<" + this.tagName + (this.className !== "" ? " class='" + this.className + "'" : "") +
536
+ (this.id !== "" ? " id='" + this.id + "'" : "") + ">";
537
+ };
538
+
539
+ // Helper method for extending one object with another
540
+
541
+ function extend(a,b) {
542
+ for ( var i in b ) {
543
+ var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
544
+
545
+ if ( g || s ) {
546
+ if ( g )
547
+ a.__defineGetter__(i, g);
548
+ if ( s )
549
+ a.__defineSetter__(i, s);
550
+ } else
551
+ a[i] = b[i];
552
+ }
553
+ return a;
554
+ }
555
+
556
+ // Helper method for generating the right
557
+ // DOM objects based upon the type
558
+
559
+ var obj_nodes = new Ruby.Hash;
560
+
561
+ function makeNode(node){
562
+ if ( node ) {
563
+ if ( !obj_nodes['key?']( node ) )
564
+ obj_nodes[node] = node.getNodeType() ==
565
+ W3CDOMNode.ELEMENT_NODE ?
566
+ new DOMElement( node ) : new DOMNode( node );
567
+
568
+ return obj_nodes[node];
569
+ } else
570
+ return null;
571
+ }
572
+
573
+ // XMLHttpRequest
574
+ // Originally implemented by Yehuda Katz
575
+
576
+ window.XMLHttpRequest = function(){
577
+ this.headers = {};
578
+ this.responseHeaders = {};
579
+ };
580
+
581
+ XMLHttpRequest.prototype = {
582
+ open: function(method, url, async, user, password){
583
+ this.readyState = 1;
584
+ if (async)
585
+ this.async = true;
586
+ this.method = method || "GET";
587
+ this.url = url;
588
+ this.onreadystatechange();
589
+ },
590
+ setRequestHeader: function(header, value){
591
+ this.headers[header] = value;
592
+ },
593
+ getResponseHeader: function(header){ },
594
+ send: function(data){
595
+ var self = this;
596
+
597
+ function makeRequest(){
598
+ var url = curLocation.merge(self.url);
599
+ var connection;
600
+
601
+ if ( url.scheme == "file" ) {
602
+ if ( self.method == "PUT" ) {
603
+ var out = new Ruby.File(url.path);
604
+ var text = data || "";
605
+
606
+ out.puts( text );
607
+ out.flush();
608
+ out.close();
609
+ } else if ( self.method == "DELETE" ) {
610
+ var file = new Ruby.File(url.path());
611
+ file["delete"]();
612
+ } else if ( self.method == "GET" ) {
613
+ var file = Ruby.File.read(url.path);
614
+ connection = {
615
+ code: "200",
616
+ message: "Ok",
617
+ body: file,
618
+ }
619
+ handleResponse();
620
+ } else {
621
+ connection = Ruby.Net.HTTP.start(url.host, url.port, function(http) {
622
+ http.get(url.path);
623
+ });
624
+ handleResponse();
625
+ }
626
+ } else {
627
+ var http = Ruby.Net.HTTP.new(url.host, url.port);
628
+ var request = new Ruby.Net.HTTP.Get(url.path);
629
+ for (var header in self.headers)
630
+ request.add_field(header, self.headers[header]);
631
+
632
+ var connection = http.request(request);
633
+ connection.each_header(function(k,v) {
634
+ self.responseHeaders[k] = v;
635
+ });
636
+
637
+ handleResponse();
638
+ }
639
+
640
+ function handleResponse(){
641
+ self.readyState = 4;
642
+ self.status = parseInt(connection.code) || undefined;
643
+ self.statusText = connection.message || "";
644
+
645
+ self.responseText = connection.body;
646
+
647
+ self.responseXML = null;
648
+
649
+ if ( self.responseText.match(/^\s*</) ) {
650
+ self.responseXML = new DOMDocument( self.responseText );
651
+ }
652
+ }
653
+
654
+ self.onreadystatechange();
655
+ }
656
+
657
+ if (this.async)
658
+ new Ruby.Thread(function() { makeRequest(); });
659
+ else
660
+ makeRequest();
661
+ },
662
+ abort: function(){},
663
+ onreadystatechange: function(){},
664
+ getResponseHeader: function(header){
665
+ if (this.readyState < 3)
666
+ throw new Error("INVALID_STATE_ERR");
667
+ else {
668
+ var returnedHeaders = [];
669
+ for (var rHeader in this.responseHeaders) {
670
+ if (rHeader.match(new Regexp(header, "i")))
671
+ returnedHeaders.push(this.responseHeaders[rHeader]);
672
+ }
673
+
674
+ if (returnedHeaders.length)
675
+ return returnedHeaders.join(", ");
676
+ }
677
+
678
+ return null;
679
+ },
680
+ getAllResponseHeaders: function(header){
681
+ if (this.readyState < 3)
682
+ throw new Error("INVALID_STATE_ERR");
683
+ else {
684
+ var returnedHeaders = [];
685
+
686
+ for (var aHeader in this.responseHeaders)
687
+ returnedHeaders.push( aHeader + ": " + this.responseHeaders[aHeader] );
688
+
689
+ return returnedHeaders.join("\r\n");
690
+ }
691
+ },
692
+ async: true,
693
+ readyState: 0,
694
+ responseText: "",
695
+ status: 0
696
+ };
697
+ })();