maglev-webtools 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +25 -0
- data/README.rdoc +121 -0
- data/bin/webtools +15 -0
- data/lib/web_tools/#debugger.rb# +212 -0
- data/lib/web_tools/browser.rb +45 -0
- data/lib/web_tools/debugger.rb +219 -0
- data/lib/web_tools/info.rb +29 -0
- data/lib/web_tools/middleware/debugger.rb +118 -0
- data/lib/web_tools/support/app_model.rb +117 -0
- data/lib/web_tools/support/code_browser.rb +109 -0
- data/lib/web_tools/support/ruby.rb +132 -0
- data/lib/web_tools/support/service_helper.rb +22 -0
- data/lib/web_tools/support/smalltalk_extensions.rb +65 -0
- data/lib/web_tools/support/smalltalk_tools.rb +16 -0
- data/lib/web_tools/ui.rb +67 -0
- data/lib/web_tools.rb +10 -0
- data/public/images/favicon.ico +0 -0
- data/public/javascript/CodeMirror/LICENSE +23 -0
- data/public/javascript/CodeMirror/css/Smalltalk.css +34 -0
- data/public/javascript/CodeMirror/js/codemirror.js +582 -0
- data/public/javascript/CodeMirror/js/editor.js +1671 -0
- data/public/javascript/CodeMirror/js/highlight.js +68 -0
- data/public/javascript/CodeMirror/js/parseSmalltalk.js +126 -0
- data/public/javascript/CodeMirror/js/parsedummy.js +32 -0
- data/public/javascript/CodeMirror/js/select.js +699 -0
- data/public/javascript/CodeMirror/js/stringstream.js +159 -0
- data/public/javascript/CodeMirror/js/tokenize.js +57 -0
- data/public/javascript/CodeMirror/js/undo.js +413 -0
- data/public/javascript/CodeMirror/js/util.js +133 -0
- data/public/javascript/CodeMirror/testSmalltalkParser.html +116 -0
- data/public/javascript/ace/ace-uncompressed.js +17299 -0
- data/public/javascript/ace/ace.js +1 -0
- data/public/javascript/ace/keybinding-emacs.js +1 -0
- data/public/javascript/ace/keybinding-vim.js +1 -0
- data/public/javascript/ace/mode-c_cpp.js +1 -0
- data/public/javascript/ace/mode-clojure.js +1 -0
- data/public/javascript/ace/mode-coffee.js +1 -0
- data/public/javascript/ace/mode-csharp.js +1 -0
- data/public/javascript/ace/mode-css.js +1 -0
- data/public/javascript/ace/mode-groovy.js +1 -0
- data/public/javascript/ace/mode-html.js +1 -0
- data/public/javascript/ace/mode-java.js +1 -0
- data/public/javascript/ace/mode-javascript.js +1 -0
- data/public/javascript/ace/mode-json.js +1 -0
- data/public/javascript/ace/mode-lua.js +1 -0
- data/public/javascript/ace/mode-markdown.js +1 -0
- data/public/javascript/ace/mode-ocaml.js +1 -0
- data/public/javascript/ace/mode-perl.js +1 -0
- data/public/javascript/ace/mode-php.js +1 -0
- data/public/javascript/ace/mode-python.js +1 -0
- data/public/javascript/ace/mode-ruby.js +1 -0
- data/public/javascript/ace/mode-scad.js +1 -0
- data/public/javascript/ace/mode-scala.js +1 -0
- data/public/javascript/ace/mode-scss.js +1 -0
- data/public/javascript/ace/mode-svg.js +1 -0
- data/public/javascript/ace/mode-textile.js +1 -0
- data/public/javascript/ace/mode-xml.js +1 -0
- data/public/javascript/ace/theme-clouds.js +1 -0
- data/public/javascript/ace/theme-clouds_midnight.js +1 -0
- data/public/javascript/ace/theme-cobalt.js +1 -0
- data/public/javascript/ace/theme-crimson_editor.js +1 -0
- data/public/javascript/ace/theme-dawn.js +1 -0
- data/public/javascript/ace/theme-eclipse.js +1 -0
- data/public/javascript/ace/theme-idle_fingers.js +1 -0
- data/public/javascript/ace/theme-kr_theme.js +1 -0
- data/public/javascript/ace/theme-merbivore.js +1 -0
- data/public/javascript/ace/theme-merbivore_soft.js +1 -0
- data/public/javascript/ace/theme-mono_industrial.js +1 -0
- data/public/javascript/ace/theme-monokai.js +1 -0
- data/public/javascript/ace/theme-pastel_on_dark.js +1 -0
- data/public/javascript/ace/theme-solarized_dark.js +1 -0
- data/public/javascript/ace/theme-solarized_light.js +1 -0
- data/public/javascript/ace/theme-textmate.js +1 -0
- data/public/javascript/ace/theme-twilight.js +1 -0
- data/public/javascript/ace/theme-vibrant_ink.js +1 -0
- data/public/javascript/ace/worker-coffee.js +1 -0
- data/public/javascript/ace/worker-css.js +1 -0
- data/public/javascript/ace/worker-javascript.js +1 -0
- data/public/javascript/webtools/#debugger.coffee# +253 -0
- data/public/javascript/webtools/browser.js +260 -0
- data/public/javascript/webtools/debugger.coffee +286 -0
- data/public/javascript/webtools/debugger.js +366 -0
- data/public/javascript/webtools/sessions.coffee +17 -0
- data/public/javascript/webtools/sessions.js +27 -0
- data/public/javascript/webtools/version.coffee +14 -0
- data/public/javascript/webtools/version.js +20 -0
- data/public/stylesheets/base/images/ui-anim_basic_16x16.gif +0 -0
- data/public/stylesheets/base/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/public/stylesheets/base/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/public/stylesheets/base/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/public/stylesheets/base/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/public/stylesheets/base/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/public/stylesheets/base/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/public/stylesheets/base/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/public/stylesheets/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/public/stylesheets/base/images/ui-icons_222222_256x240.png +0 -0
- data/public/stylesheets/base/images/ui-icons_2e83ff_256x240.png +0 -0
- data/public/stylesheets/base/images/ui-icons_454545_256x240.png +0 -0
- data/public/stylesheets/base/images/ui-icons_888888_256x240.png +0 -0
- data/public/stylesheets/base/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/public/stylesheets/base/jquery.ui.accordion.css +12 -0
- data/public/stylesheets/base/jquery.ui.all.css +2 -0
- data/public/stylesheets/base/jquery.ui.autocomplete.css +39 -0
- data/public/stylesheets/base/jquery.ui.base.css +11 -0
- data/public/stylesheets/base/jquery.ui.button.css +35 -0
- data/public/stylesheets/base/jquery.ui.core.css +37 -0
- data/public/stylesheets/base/jquery.ui.datepicker.css +61 -0
- data/public/stylesheets/base/jquery.ui.dialog.css +13 -0
- data/public/stylesheets/base/jquery.ui.progressbar.css +4 -0
- data/public/stylesheets/base/jquery.ui.resizable.css +13 -0
- data/public/stylesheets/base/jquery.ui.selectable.css +3 -0
- data/public/stylesheets/base/jquery.ui.slider.css +17 -0
- data/public/stylesheets/base/jquery.ui.tabs.css +11 -0
- data/public/stylesheets/base/jquery.ui.theme.css +247 -0
- data/public/stylesheets/jquery.contextMenu.css +62 -0
- data/public/stylesheets/reset.css +18 -0
- data/public/stylesheets/webtools.css +53 -0
- data/public/test.html +47 -0
- data/views/browser.rhtml +63 -0
- data/views/debugger.rhtml +59 -0
- data/views/index.rhtml +8 -0
- data/views/layout.rhtml +24 -0
- data/views/sessions.rhtml +12 -0
- data/views/version.rhtml +10 -0
- metadata +316 -0
@@ -0,0 +1,253 @@
|
|
1
|
+
window.escapeHTML = (str) ->
|
2
|
+
str = "" unless str?
|
3
|
+
str += str unless typeof str == "string"
|
4
|
+
$("<i></i>").text(str).html()
|
5
|
+
|
6
|
+
class Frame
|
7
|
+
constructor: (@server, @pid, @frame_idx, @container) ->
|
8
|
+
|
9
|
+
update_detail_view: (objectInfo) ->
|
10
|
+
@inspector.hide()
|
11
|
+
@inspector.children('.objInfoClass').text(objectInfo['(__class__)'])
|
12
|
+
@inspector.children('.objInfoValue').text(objectInfo['(__inspect__)'])
|
13
|
+
this.renderTableData @inspector.children('.objInstVars'), objectInfo, (idx, data) ->
|
14
|
+
$("<tr><td>#{idx}</td><td>#{data}</td></tr>")
|
15
|
+
@inspector.show()
|
16
|
+
|
17
|
+
renderTableData: (instVarsTable, object, formatFn) ->
|
18
|
+
ui = instVarsTable.children('tbody')
|
19
|
+
ui.empty()
|
20
|
+
$.each object, (key, value) ->
|
21
|
+
if key.indexOf("@") == 0
|
22
|
+
ui.append(formatFn(key, value))
|
23
|
+
|
24
|
+
create_detail_view: ->
|
25
|
+
@inspector = $('#objectInspector').clone()
|
26
|
+
@inspector.removeAttr('id')
|
27
|
+
@inspector.removeClass('hidden')
|
28
|
+
@container.append(@inspector)
|
29
|
+
|
30
|
+
create_source_code_holder: () ->
|
31
|
+
@container.prepend($('#editor'))
|
32
|
+
$('#editor').show()
|
33
|
+
|
34
|
+
create_inspector: (object, index, path) ->
|
35
|
+
index = 0 unless index?
|
36
|
+
path = "#{@server}/process/#{@pid}/frames/#{@frame_idx}" unless path?
|
37
|
+
options = $([])
|
38
|
+
$.each object, (key, value) ->
|
39
|
+
if "#{key}".indexOf("@") == 0 || key == "(__self__)" || key == "(__class__)"
|
40
|
+
options.push("#{key}")
|
41
|
+
if not @inspector_div?
|
42
|
+
@inspector_div = $(document.createElement("div"))
|
43
|
+
@inspector_div.addClass("inspectors")
|
44
|
+
@container.prepend(@inspector_div)
|
45
|
+
if @inspectors[index]?
|
46
|
+
inspector = @inspectors[index]
|
47
|
+
else
|
48
|
+
@inspectors[index] = (inspector = $(document.createElement("select")))
|
49
|
+
@inspector_div.append(inspector)
|
50
|
+
inspector.attr
|
51
|
+
multiple: true
|
52
|
+
class: 'inspector'
|
53
|
+
inspector.html("")
|
54
|
+
$(options).each (idx, o) =>
|
55
|
+
inspector.append("<option value=#{idx}>#{escapeHTML(o)}</option>")
|
56
|
+
this.create_evaluator(path)
|
57
|
+
inspector.bind "change", =>
|
58
|
+
value = options[inspector.val()]
|
59
|
+
url = "#{path}/objects/#{value}"
|
60
|
+
for i in @inspectors.slice(index + 1)
|
61
|
+
i.html("")
|
62
|
+
$.get "#{url}/objects", (object) =>
|
63
|
+
this.create_inspector(object, index + 1, url)
|
64
|
+
this.update_detail_view(object)
|
65
|
+
, 'json'
|
66
|
+
|
67
|
+
create_evaluator: (path) ->
|
68
|
+
unless @evaluator?
|
69
|
+
@evaluator = $(document.createElement("input"))
|
70
|
+
@evaluator.attr
|
71
|
+
type: "text"
|
72
|
+
name: "#{@frame_idx}_evaluator"
|
73
|
+
id: "#{@frame_idx}_evaluator"
|
74
|
+
class: "ui-widget-content ui-corner-all"
|
75
|
+
@container.prepend(@evaluator)
|
76
|
+
@evaluator.unbind("keypress")
|
77
|
+
@evaluator.bind "keypress", (e) =>
|
78
|
+
code = e.keyCode if e.keyCode?
|
79
|
+
code = e.which unless code
|
80
|
+
if code == 13 # RETURN
|
81
|
+
$.ajax
|
82
|
+
url: path
|
83
|
+
data:
|
84
|
+
"do-it": @evaluator.val()
|
85
|
+
success: (data) =>
|
86
|
+
result = data["do-it-result"]
|
87
|
+
@evaluator.val("#{@evaluator.val()} => #{result['(__inspect__)']}")
|
88
|
+
this.update_detail_view(result)
|
89
|
+
@evaluator.select()
|
90
|
+
dataType: 'json'
|
91
|
+
type: 'PUT'
|
92
|
+
|
93
|
+
render: ->
|
94
|
+
@container.html("")
|
95
|
+
@inspectors = []
|
96
|
+
this.create_source_code_holder()
|
97
|
+
$.get "#{@server}/process/#{@pid}/frames/#{@frame_idx}", (frame) =>
|
98
|
+
editor.getSession().setValue(frame.debug_info.source)
|
99
|
+
editor.frame_url = "#{@server}/process/#{@pid}/frames/#{@frame_idx}"
|
100
|
+
this.create_inspector(frame.debug_info.context)
|
101
|
+
this.create_detail_view()
|
102
|
+
, 'json'
|
103
|
+
|
104
|
+
class Process
|
105
|
+
constructor: (@server, @pid, @tab) ->
|
106
|
+
@info_div = $("##{@tab} .info-bar")
|
107
|
+
@stack_div = $("##{@tab} .frame-list")
|
108
|
+
|
109
|
+
render: ->
|
110
|
+
this.render_info()
|
111
|
+
this.render_stack()
|
112
|
+
|
113
|
+
render_info: ->
|
114
|
+
request = $.get "#{@server}/process/#{@pid}", (data) =>
|
115
|
+
@info_div.text("#{data.label} (#{data.timestamp})")
|
116
|
+
, 'json'
|
117
|
+
|
118
|
+
render_stack: ->
|
119
|
+
@stack_div.html("")
|
120
|
+
request = $.get "#{@server}/process/#{@pid}/frames", (framelist) =>
|
121
|
+
$(framelist).each (idx, f) =>
|
122
|
+
header = $(document.createElement("h3"))
|
123
|
+
link = $(document.createElement("a"))
|
124
|
+
link.attr
|
125
|
+
href: '#'
|
126
|
+
data_idx: idx
|
127
|
+
link.text("#{f.class}##{f.method_name}")
|
128
|
+
link.append("<small>#{escapeHTML(f.source_location)}</small>")
|
129
|
+
header.append(link)
|
130
|
+
restartLink = $('<a href="#">Restart frame</a>')
|
131
|
+
restartLink.bind "click", (e) =>
|
132
|
+
$.ajax
|
133
|
+
url: "#{@server}/process/#{@pid}/frames/#{idx}",
|
134
|
+
type: 'DELETE'
|
135
|
+
success: =>
|
136
|
+
|
137
|
+
e.preventDefault()
|
138
|
+
header.append(restartLink)
|
139
|
+
div = document.createElement("div")
|
140
|
+
$(div).text("Waiting for data...")
|
141
|
+
@stack_div.append(header)
|
142
|
+
@stack_div.append(div)
|
143
|
+
if idx == 0
|
144
|
+
@selected_frame = new Frame(@server, @pid, 0, $(div))
|
145
|
+
@selected_frame.render()
|
146
|
+
@stack_div.accordion
|
147
|
+
clearStyle: true
|
148
|
+
collapsible: true
|
149
|
+
changestart: (event, ui) =>
|
150
|
+
frame_idx = ui.newHeader.children("a").attr("data_idx")
|
151
|
+
if frame_idx?
|
152
|
+
@selected_frame = new Frame(@server, @pid, frame_idx, ui.newContent)
|
153
|
+
@selected_frame.render()
|
154
|
+
, 'json'
|
155
|
+
|
156
|
+
class Debugger
|
157
|
+
constructor: (@server) ->
|
158
|
+
@tab_content_template = $("#tab_content_template")
|
159
|
+
|
160
|
+
toString: ->
|
161
|
+
"Debugger on #{server}"
|
162
|
+
|
163
|
+
server_alive: () ->
|
164
|
+
request = $.ajax
|
165
|
+
url: "#{@server}/process"
|
166
|
+
async: false
|
167
|
+
request.status == 200
|
168
|
+
|
169
|
+
clone_template: () ->
|
170
|
+
@content = @tab_content_template.clone()
|
171
|
+
@content.show()
|
172
|
+
@content.removeAttr("id")
|
173
|
+
|
174
|
+
fill_process_selector: () ->
|
175
|
+
@process_box = @content.children("select[name='process-select-box']")
|
176
|
+
$.getJSON "#{@server}/process", (errors) =>
|
177
|
+
$(errors).each (idx, e) =>
|
178
|
+
@process_box.append("<option value='#{e.process_id}'>#{e.process_id}: #{escapeHTML(e.label)}</option>")
|
179
|
+
@process_box.bind "change", =>
|
180
|
+
@process = new Process(@server, @process_box.val(), @tab)
|
181
|
+
@process.render()
|
182
|
+
|
183
|
+
content_for: (ui_panel) ->
|
184
|
+
if not @content?
|
185
|
+
@tab = $(ui_panel).attr("id")
|
186
|
+
return "<p>The URL " + url + " could not be reached</p>" unless this.server_alive()
|
187
|
+
this.clone_template()
|
188
|
+
this.fill_process_selector()
|
189
|
+
ui_panel.append(@content)
|
190
|
+
@content
|
191
|
+
|
192
|
+
DebuggerApp =
|
193
|
+
setup: ->
|
194
|
+
debuggers = []
|
195
|
+
tab_server_input = $("#tab_server")
|
196
|
+
tab_counter = 2
|
197
|
+
|
198
|
+
# actual addTab function: adds new tab using the title input
|
199
|
+
# from the form above
|
200
|
+
add_tab = ->
|
201
|
+
tab_server = tab_server_input.val()
|
202
|
+
tabs.tabs("add", "#tabs-#{tab_counter}", tab_server)
|
203
|
+
tab_counter++
|
204
|
+
|
205
|
+
# tabs init with a custom tab template and an "add" callback
|
206
|
+
# filling in the content
|
207
|
+
tabs = $("#tabs").tabs
|
208
|
+
tabTemplate: '<li><a href=\'#{href}\'>#{label}</a>' +
|
209
|
+
"<span class='ui-icon ui-icon-close'>Remove Tab</span></li>"
|
210
|
+
add: (event, ui) ->
|
211
|
+
new_debugger = new Debugger(tab_server_input.val())
|
212
|
+
debuggers.push(new_debugger)
|
213
|
+
new_debugger.content_for($(ui.panel))
|
214
|
+
|
215
|
+
# modal dialog init: custom buttons and a "close" callback
|
216
|
+
# reseting the form inside
|
217
|
+
dialog = $("#dialog").dialog
|
218
|
+
autoOpen: false
|
219
|
+
modal: true
|
220
|
+
buttons:
|
221
|
+
Add: ->
|
222
|
+
add_tab()
|
223
|
+
dialog.dialog("close")
|
224
|
+
Cancel: ->
|
225
|
+
dialog.dialog("close")
|
226
|
+
open: ->
|
227
|
+
tab_server_input.focus()
|
228
|
+
close: ->
|
229
|
+
form[0].reset()
|
230
|
+
|
231
|
+
# addTab form: calls addTab function on submit and closes the
|
232
|
+
# dialog
|
233
|
+
form = $("form", this.dialog).submit ->
|
234
|
+
add_tab()
|
235
|
+
dialog.dialog("close")
|
236
|
+
false
|
237
|
+
|
238
|
+
# addTab button: just opens the dialog
|
239
|
+
$("#add_tab").button().click ->
|
240
|
+
dialog.dialog("open");
|
241
|
+
|
242
|
+
# close icon: removing the tab on click
|
243
|
+
$("#tabs span.ui-icon-close").live "click", ->
|
244
|
+
index = $("li", tabs).index($(this).parent())
|
245
|
+
tabs.tabs("remove", index);
|
246
|
+
|
247
|
+
$(document).ready ->
|
248
|
+
DebuggerApp.setup()
|
249
|
+
window.RubyMode = require("ace/mode/ruby").Mode
|
250
|
+
window.canon = require('pilot/canon')
|
251
|
+
window.editor = ace.edit('editor')
|
252
|
+
window.editor.getSession().setUseSoftTabs(true)
|
253
|
+
window.editor.getSession().setMode(new RubyMode())
|
@@ -0,0 +1,260 @@
|
|
1
|
+
maglevInfo = (function() {
|
2
|
+
var requestCount = 0, rubyEditor = null;
|
3
|
+
|
4
|
+
$(document).ready(function() {
|
5
|
+
setupSelectables();
|
6
|
+
setupEditor();
|
7
|
+
setupToolBar();
|
8
|
+
updateCodeBrowser(); // Not sure this is the best way to kick it off...
|
9
|
+
});
|
10
|
+
|
11
|
+
function setupToolBar() {
|
12
|
+
$('#toolBar').append(
|
13
|
+
$('<div>').button({label: 'Refresh View'}
|
14
|
+
).click(function () {
|
15
|
+
getJSON('/transaction/abort', null, function(data) {
|
16
|
+
clearRubyNav();
|
17
|
+
updateCodeBrowser();
|
18
|
+
});
|
19
|
+
}));
|
20
|
+
$('#toolBar').append($('<div>', { id: 'statusBar'}));
|
21
|
+
}
|
22
|
+
|
23
|
+
function clearRubyNav() {
|
24
|
+
$('ul.rubyList').empty();
|
25
|
+
clearDetailView();
|
26
|
+
}
|
27
|
+
|
28
|
+
function setupSelectables() {
|
29
|
+
$('#rubyModules').selectable({
|
30
|
+
selected: function(event, ui) { selectModule(ui.selected.title); }
|
31
|
+
});
|
32
|
+
$('#rubyConstants').selectable({
|
33
|
+
selected: function(event, ui) { selectConstant(ui.selected.title); }
|
34
|
+
});
|
35
|
+
$('#rubyModuleMethods').selectable({
|
36
|
+
selected: function(event, ui) { selectModuleMethod(ui.selected.title); }
|
37
|
+
});
|
38
|
+
$('#rubyInstanceMethods').selectable({
|
39
|
+
selected: function(event, ui) { selectInstanceMethod(ui.selected.title); }
|
40
|
+
});
|
41
|
+
}
|
42
|
+
|
43
|
+
function setupEditor() {
|
44
|
+
rubyEditor = CodeMirror.fromTextArea('rubyEditor',
|
45
|
+
{ height: "100%",
|
46
|
+
parserfile: "parseSmalltalk.js",
|
47
|
+
stylesheet: "CodeMirror/css/Smalltalk.css",
|
48
|
+
path: "CodeMirror/js/",
|
49
|
+
lineNumbers: true});
|
50
|
+
}
|
51
|
+
|
52
|
+
function selectedModuleName() {
|
53
|
+
return $('#rubyModules .ui-selected').attr('title');
|
54
|
+
}
|
55
|
+
|
56
|
+
function selectedConstantName() {
|
57
|
+
return $('#rubyConstants .ui-selected').attr('title');
|
58
|
+
}
|
59
|
+
|
60
|
+
function selectedModuleMethodName() {
|
61
|
+
return $('#rubyModuleMethods .ui-selected').attr('title');
|
62
|
+
}
|
63
|
+
|
64
|
+
function selectedInstanceMethodName() {
|
65
|
+
return $('#rubyInstanceMethods .ui-selected').attr('title');
|
66
|
+
}
|
67
|
+
|
68
|
+
function selectModule(className) {
|
69
|
+
clearSelections(['#rubyModuleMethods', '#rubyModuleMethods',
|
70
|
+
'#rubyInstanceMethods', '#rubyAncestors']);
|
71
|
+
clearDetailView();
|
72
|
+
getJSON('/module/' + className, null, renderCodeBrowser);
|
73
|
+
}
|
74
|
+
|
75
|
+
function selectConstant(constName) {
|
76
|
+
clearSelections(['#rubyModuleMethods', '#rubyInstanceMethods']);
|
77
|
+
getJSON('/module/' + selectedModuleName() + '/constant/' + selectedConstantName(),
|
78
|
+
null,
|
79
|
+
function(data) {
|
80
|
+
clearEditArea();
|
81
|
+
renderObject(data['const_value']);
|
82
|
+
});
|
83
|
+
}
|
84
|
+
|
85
|
+
function selectModuleMethod(methodName) {
|
86
|
+
clearSelections(['#rubyConstants', '#rubyInstanceMethods']);
|
87
|
+
getJSON('/module/' + selectedModuleName() + '/method',
|
88
|
+
{ 'method_name': selectedModuleMethodName(),
|
89
|
+
'is_instance_method': false },
|
90
|
+
renderMethod);
|
91
|
+
}
|
92
|
+
|
93
|
+
function selectInstanceMethod(methodName) {
|
94
|
+
clearSelections(['#rubyConstants', '#rubyModuleMethods']);
|
95
|
+
getJSON('/module/' + selectedModuleName() + '/method',
|
96
|
+
{ 'method_name': selectedInstanceMethodName(),
|
97
|
+
'is_instance_method': true },
|
98
|
+
renderMethod);
|
99
|
+
}
|
100
|
+
|
101
|
+
function clearSelections(selections) {
|
102
|
+
console.log('clearSelections: ' + selections);
|
103
|
+
$.each(selections, function(i, el) {
|
104
|
+
$(el + ' .ui-selected').removeClass('ui-selected');
|
105
|
+
});
|
106
|
+
clearEditArea();
|
107
|
+
}
|
108
|
+
|
109
|
+
// Makes a JSON request, and decorates it with timing information.
|
110
|
+
// It then passes the bundled data object to the callback.
|
111
|
+
function getJSON(url, data, callback) {
|
112
|
+
var startTime = new Date().getTime();
|
113
|
+
var statusBar = $('#statusBar');
|
114
|
+
url = window.WebTools.location + url
|
115
|
+
$(statusBar).text('Sent request #' + (++requestCount) + ' for ' + url);
|
116
|
+
$.getJSON(url, data, success);
|
117
|
+
return;
|
118
|
+
|
119
|
+
function success(data) {
|
120
|
+
debugMsg('getJSON Success');
|
121
|
+
debugMsg(data);
|
122
|
+
|
123
|
+
var serverTime = data['_time'];
|
124
|
+
var networkTime = new Date().getTime() - startTime - serverTime;
|
125
|
+
startTime = new Date().getTime();
|
126
|
+
var error = data['_error'];
|
127
|
+
if (error) {
|
128
|
+
alert(error + ' (see console log for stack)');
|
129
|
+
debugMsg(data['_stack']);
|
130
|
+
} else {
|
131
|
+
(callback)(data);
|
132
|
+
};
|
133
|
+
var elapsed = new Date().getTime() - startTime;
|
134
|
+
$(statusBar).text(
|
135
|
+
'Request for ' + url + ' (roundtrip #' + requestCount + ') took ' +
|
136
|
+
serverTime + ' ms on server, ' + networkTime + ' ms on the network, and '
|
137
|
+
+ elapsed + ' ms on the client.'
|
138
|
+
);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
function updateCodeBrowser() {
|
143
|
+
getJSON('/modulelist', null, renderCodeBrowser);
|
144
|
+
}
|
145
|
+
|
146
|
+
function renderCodeBrowser(data) {
|
147
|
+
renderList(data['modules'], $('#rubyModules'));
|
148
|
+
renderList(data['constants'], $('#rubyConstants'));
|
149
|
+
renderList(data['module_methods'], $('#rubyModuleMethods'));
|
150
|
+
renderList(data['instance_methods'], $('#rubyInstanceMethods'));
|
151
|
+
renderList(data['ancestors'], $('#rubyAncestors'));
|
152
|
+
return;
|
153
|
+
|
154
|
+
function renderList(items, ui) {
|
155
|
+
if (items) {
|
156
|
+
ui.empty();
|
157
|
+
$.each(items, function(n, item) {
|
158
|
+
$('<li>', { title: item, 'class': 'ui-widget-content' }).html(item).appendTo(ui);
|
159
|
+
});
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
function setDetailViewCode(sym) {
|
165
|
+
console.log('setDetailViewCode()');
|
166
|
+
$('#objectInspector').addClass('hidden');
|
167
|
+
$('#rubyEditArea').removeClass('hidden');
|
168
|
+
}
|
169
|
+
|
170
|
+
function setDetailViewObject(sym) {
|
171
|
+
$('#rubyEditArea').addClass('hidden');
|
172
|
+
$('#objectInspector').removeClass('hidden');
|
173
|
+
}
|
174
|
+
|
175
|
+
function clearDetailView() {
|
176
|
+
$('#rubyEditArea').addClass('hidden');
|
177
|
+
$('#objectInspector').addClass('hidden');
|
178
|
+
}
|
179
|
+
|
180
|
+
function clearEditArea() {
|
181
|
+
if (rubyEditor.editor) {
|
182
|
+
rubyEditor.setCode('');
|
183
|
+
}
|
184
|
+
$('#fileInfo').empty();
|
185
|
+
}
|
186
|
+
|
187
|
+
function renderMethod(data) {
|
188
|
+
clearEditArea();
|
189
|
+
renderSource(data['method_source']);
|
190
|
+
var file = data['method_source_file'];
|
191
|
+
|
192
|
+
if (file) {
|
193
|
+
$('#fileInfo').html(file + ':' + data['method_line_number']);
|
194
|
+
} else {
|
195
|
+
$('#fileInfo').html('No file information available');
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
// Make the rubyEditor visible in the detail area and render the source
|
200
|
+
// code. High level api.
|
201
|
+
function renderSource(string) {
|
202
|
+
if (rubyEditor.editor) {
|
203
|
+
rubyEditor.setCode(string);
|
204
|
+
setDetailViewCode();
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
// Make the objectInspector visible in the detail area and render the
|
209
|
+
// Object. High level api.
|
210
|
+
function renderObject(objectInfo) {
|
211
|
+
console.log('renderObject()');
|
212
|
+
console.log(objectInfo);
|
213
|
+
setDetailViewObject();
|
214
|
+
|
215
|
+
$('#objInfoClass').text(objectInfo['class']);
|
216
|
+
$('#objInfoId').text(objectInfo['object_id']);
|
217
|
+
$('#objInfoValue').text(objectInfo['inspect']);
|
218
|
+
|
219
|
+
renderTableData('#objInstVars',
|
220
|
+
objectInfo['instance_variables'],
|
221
|
+
// Data is an array of [name, value, objid]
|
222
|
+
function(idx, data) {
|
223
|
+
return $('<tr><td>'+ data[0] + '</td><td objectId="'
|
224
|
+
+ escapeHTML(data[2]) + '">' + data[1] + '</td></tr>');
|
225
|
+
});
|
226
|
+
|
227
|
+
renderTableData('#objEnumValues',
|
228
|
+
objectInfo['enumerated'],
|
229
|
+
function(idx, data) {
|
230
|
+
return $('<tr><td>' + idx + '</td><td>' + escapeHTML(data) + '</td></tr>');
|
231
|
+
});
|
232
|
+
return;
|
233
|
+
|
234
|
+
function escapeHTML(text) {
|
235
|
+
return $('<div>').text(text).html();
|
236
|
+
}
|
237
|
+
|
238
|
+
function renderTableData(tableId, vals, formatFn) {
|
239
|
+
console.log('renderTableData: tableId: '+ tableId + ' # vals: ' + vals.length);
|
240
|
+
if (vals && vals.length > 0) {
|
241
|
+
$(tableId).removeClass('hidden');
|
242
|
+
var ui = $(tableId + ' tbody');
|
243
|
+
ui.empty();
|
244
|
+
$.each(vals, function(idx, data) { ui.append(formatFn(idx, data)) });
|
245
|
+
$(tableId).removeClass('hidden');
|
246
|
+
} else {
|
247
|
+
$(tableId).addClass('hidden');
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
// Some older browsers were complaining that console wasn't defined.
|
253
|
+
// (old firefox on solaris), so I'm wrapping console logging in this
|
254
|
+
// function.
|
255
|
+
function debugMsg(obj) {
|
256
|
+
if (console) {
|
257
|
+
console.log(obj);
|
258
|
+
}
|
259
|
+
}
|
260
|
+
})();
|