rhack 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ })();