-
Notifications
You must be signed in to change notification settings - Fork 0
/
loco_ruby.js
313 lines (272 loc) · 14.3 KB
/
loco_ruby.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
var LocoRuby = LocoRuby ? LocoRuby : function() {
(function() {
var head = document.getElementsByTagName('head')[0],
style = document.createElement('style'),
rules = document.createTextNode('.RubyLoco_loaded { display: none }');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = rules.nodeValue;
} else {
style.appendChild(rules);
}
head.appendChild(style);
})();
var initialized = false;
var $j
var session_id = (function() {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('');
var length = 20;
var str = '';
for (var i = 0; i < length; i++) {
str += chars[Math.floor(Math.random() * chars.length)];
}
return str;
})()
var window_dimensions
var title
var module_name
var encrypt = function (s, fn) {fn("")}
var onload = function (){}
var z_order = 'HWND_TOP'
var host = "127.0.0.1:8000"
var connection_failure = function() {
alert ("Could not contact LocoRuby. Make sure LocoRuby.exe is running.");
self.close()
}
var verification_failure = function() {
alert ("Failed security checks. Make sure LocoRuby is using same key as your server.");
self.close()
}
var popup_timeout = 10000
var popup_blocked = function() {
document.body.innerHTML = 'Turn off popup blocker and reload'
}
var eval_timeout = 10000
var public = {
init: function(params) {
if (params==undefined) params = {}
title = params.title
if (params.encrypt!=undefined) encrypt = params.encrypt
if (params.dimensions != undefined) window_dimensions = params.dimensions
if (params.onload != undefined) onload = params.onload
if (params.stay_on_top != undefined && params.stay_on_top) z_order = 'HWND_TOPMOST'
if (params.host != undefined) host = params.host
if (params.connection_failure != undefined) connection_failure = params.connection_failure
if (params.verification_failure != undefined) verification_failure = params.verification_failure
if (params.popup_timeout != undefined) popup_timeout = params.popup_timeout
if (params.popup_blocked != undefined) popup_blocked = params.popup_blocked
if (params.eval_timeout != undefined) eval_timeout = params.eval_timeout
if (typeof jQuery == 'undefined') {
load_jquery()
} else {
init_jquery_loaded(jQuery)
}},
/* LocoRuby.eval("string",fn) -> result of evaluation is passed to fn, if evaluation fails undefined is sent to fn */
eval: function (s,fn, timeout) {
if (timeout == undefined) timeout = eval_timeout;
encrypt(s, function(e_s) {
call_loco_ruby_server('loco_ruby_eval/'+module_name, {ruby_expression: s, encrypted_ruby_expression: e_s}, timeout, fn)})
},
debug: function() {this.eval("debugger")}
}
var load_jquery = function() {
var callback = function () {
init_jquery_loaded(jQuery.noConflict())
}
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "http://code.jquery.com/jquery-1.6.3.min.js" ;
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback
// fire the loading
head.appendChild(script);
}
var init_jquery_loaded = function($) {
if (initialized) return
initialized = true
$j = $
if (title==undefined) title = window.document.title
module_name = title.replace(" ", "_").replace(/[^a-zA-Z0-9_]/,"").replace(/_+/g, '_').replace( /(_)([a-z])/g, function(t,a,b) { return b.toUpperCase(); })
$j(window).load(function () {
//setup session_id and module_name variables
if (window_dimensions) {
/* if this window has a specified size, then it must be opened as a popup, in order to specify the size.
There are two cases that we need to handle:
1) this browser window has been opened from the desktop in which case it has no history, and it
should be closed, once the popup is running.
2) this browser window has history, in which case we got here from a link from a previous page,
in this case we want the browser window to go back to previous page, so it looks like the popup
was opened as a target=_BLANK but with specified window parameters.
In addition the current implementation only supports one instance running of each application.
(note: This is actually not hard to change, we just need to check if there is a server instance running, and
make sure the backing file is the same as the one we are going to send down. )
So for now we close all windows on the desktop with the name of the application, this will close the
opener browser window, unless its changed first.
The final complication is dealing with popup blockers. In particular chrome actually opens the popup
but makes its dimensions 0,0,0,0. So what we do is wait a little bit and display a message. If the popup
worked then we will either close the window or go back to the previous page, so the message will never
be seen. To handle the chrome case we just exit out if innerHeight == 0.
*/
if (window.innerWidth == 0 && window.innerHeight == 0) {
return
} else if (!opener || !openerAccessible()) {
if (history.length > 1) {
// change title so auto closer can't find us...
document.title = "APPLICATION LOADING..."+document.title
}
var newWindow = popUpWindow(document.URL);
setTimeout(function () {popup_blocked()}, popup_timeout)
} else {
// if opener has history (meaning it was not opened from a desk top icon) go back to previous page
if (opener.history.length > 1) {
opener.history.go(-1)
}
// change document title so auto closer can't find us
document.title = session_id;
send_ruby_code();
window.focus();
}
} else { /* window size not specified so we just run in current window */
document.title = "APPLICATION LOADING..." + document.title
send_ruby_code();
window.focus();
}})}
var call_loco_ruby_server = function(name, json, timeout, fn) {
var timer
if (fn != undefined) timer = setTimeout(function() {
timer = undefined
if (fn!=undefined) {
fn();
}}, timeout);
jQuery.ajax({
url: "http://"+host+"/"+name,
data: json,
dataType: 'jsonp',
success: function (responseObject) {
if (timer != undefined) {
clearTimeout(timer);
fn(responseObject);
}}})}
var gather_ruby_app_code = function() {
var code = ([
'class LocoRubyEvalServer < WEBrick::HTTPServlet::AbstractServlet',
'def do_GET(request, response)',
'response.content_type = "text/plain"',
'begin',
'raise "Failed Validation" if LocoRuby::encrypt(request.query["ruby_expression"])!=request.query["encrypted_ruby_expression"]',
'result = eval(request.query["ruby_expression"])',
'response.body = "#{request.query[\'callback\']}(\'#{result}\')"',
'response.status = 200',
'rescue Exception => e',
'LocoRuby::Log.error "AppCode evaluation failed #{e.message} see http response for backtrace"',
'response.body = "#{e.message}\\n#{e.backtrace}"',
'response.status = 500',
'end',
'end'].concat((window_dimensions!=undefined)?[
// get rid of any old windows with same app, name, get rid of parent window, and bring me to the top
'HWND_TOPMOST = -1',
'HWND_TOP = 0',
'SWP_NOSIZE = 1',
'SWP_NOMOVE = 2',
'WM_SYSCOMMAND = 0x112',
'SC_CLOSE = 0xF060',
'my_window_handles = []',
'Title = "'+title+'"',
'LocoRuby::Log.info "Looking for windows to close and bring to top..."',
'handles_to_close = []',
'Autogui::EnumerateDesktopWindows.new().find do |w|',
'if w.title[0, Title.length] == Title',
'LocoRuby::Log.info "Matched App Title. Adding to close list"',
'handles_to_close.push(w.handle)',
'elsif w.title[0, "'+session_id+'".length] == "'+session_id+'"',
'my_window_handles.push(w)',
'end',
'nil',
'end',
'my_window_handles.each do |h|',
'LocoRuby::Log.info "Matched session id. Setting Window Position"',
'Win32API.new("user32", "SetWindowPos", ["P", "P", "I", "I", "I", "I", "I"], "I").call(',
'h.handle, '+z_order+', 0, 0, '+window_dimensions.width+', '+window_dimensions.height+', SWP_NOMOVE)',
'h.set_focus',
'LocoRuby::Log.info "Window Position Set #{h.handle}"',
'end',
'handles_to_close.each do |h|',
'Win32API.new("user32", "SendMessage", "LLLP", "L").call(h, WM_SYSCOMMAND, SC_CLOSE, 0)',
'end',
'LocoRuby::Log.info "Done!"'] : []).concat([
'end',
//# add class to server
'LocoRuby::Server.mount "/loco_ruby_eval/'+module_name+'",LocoRubyEvalServer'])).join("\n")
$j('script[type="text/ruby"]').each(function(i, b){
code = code + "\n" + b.innerHTML
});
return code
}
var send_ruby_code = function() {
encrypt(session_id, function(encrypted_session_id) {
call_loco_ruby_server("load_slave", {session_id: session_id}, 3000, function (responseObject) {
if (responseObject==undefined ) {
document.title = title
connection_failure()
} else if (responseObject.session_id != encrypted_session_id) {
document.title = title
verification_failure()
} else {
send_ruby_code2(session_id, responseObject.response_id)
}
})})}
var send_ruby_code2 = function(session_id, response_id) {
encrypt(response_id, function(response) {
var formDiv = '<div style="display:none">'+
'<form id="frmLocoRubyCrossDomainPost" action="http://'+host+'/load_slave"'+
'method="post" target="iframeLocoRubyCrossDomainTarget"'+
'style="border: 0px solid rgb(255, 255, 255); width: 0pt; height: 0pt;">'+
'<input type="hidden" name="code" id="loco_ruby_cdp_code"/>'+
'<input type="hidden" name="response_id" id="loco_ruby_cdp_response_id"/>'+
'<input type="hidden" name="session_id" id="loco_ruby_cdp_session_id"/>'+
'<input type="hidden" name="file_name" id="loco_ruby_cdp_file_name_id"/>'+
'</form>'+
'<iframe id="iframeLocoRubyCrossDomainTarget" name="iframeLocoRubyCrossDomainTarget"'+
'src="#" style="border: 0px solid rgb(255, 255, 255);'+
'width: 0pt; height: 0pt;">'+
'</iframe>'+
'</div>'
$j(document.body).append(formDiv)
$j('#loco_ruby_cdp_code')[0].value = gather_ruby_app_code();
$j('#loco_ruby_cdp_response_id')[0].value = response;
$j('#loco_ruby_cdp_session_id')[0].value = session_id;
$j('#loco_ruby_cdp_file_name_id')[0].value = module_name+'.rb';
$j('#frmLocoRubyCrossDomainPost')[0].submit();
var looper = setInterval(function(){
if (document.title != title) {
call_loco_ruby_server("ready", {session_id: session_id, response_id: response}, 1000, function (responseObject) {
if (responseObject=="ready") {
document.title = title;
$j('.RubyLoco_loading').hide()
$j('.RubyLoco_loaded').show()
onload()
}})
} else {
clearInterval(looper)
}}, 1000)}
)}
var popUpWin;
var popUpWindow = function(URLStr) {
if (popUpWin) {
if(!popUpWin.closed) popUpWin.close();
}
popUpWin = open(URLStr, session_id, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=yes, width='+window_dimensions.width+', height='+window_dimensions.height+', left='+window_dimensions.left+', top='+window_dimensions.top+', screenX='+window_dimensions.left+', screenY='+window_dimensions.top+'');
return popUpWin
}
var openerAccessible = function () {
try {
var foo = opener.history.length;
return true
} catch (e) {
return false
}}
return public;
} ();
LocoRuby.init()