web_sandbox_console 0.1.0 → 0.6.0
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.
- checksums.yaml +4 -4
- data/README.md +143 -6
- data/app/assets/images/web_sandbox_console/logo-icon.png +0 -0
- data/app/assets/javascripts/web_sandbox_console/application.js +0 -1
- data/app/assets/javascripts/web_sandbox_console/code_editor.js +0 -0
- data/app/assets/javascripts/web_sandbox_console/codemirror.js +9778 -0
- data/app/assets/javascripts/web_sandbox_console/matchbrackets.js +158 -0
- data/app/assets/javascripts/web_sandbox_console/ruby.js +298 -0
- data/app/assets/stylesheets/web_sandbox_console/application.css +85 -14
- data/app/assets/stylesheets/web_sandbox_console/codemirror.css +349 -0
- data/app/assets/stylesheets/web_sandbox_console/common.css +231 -0
- data/app/assets/stylesheets/web_sandbox_console/docs.css +274 -0
- data/app/assets/stylesheets/web_sandbox_console/home.css +47 -0
- data/app/assets/stylesheets/web_sandbox_console/lucario.css +45 -0
- data/app/controllers/web_sandbox_console/application_controller.rb +4 -0
- data/app/controllers/web_sandbox_console/authorization_controller.rb +82 -0
- data/app/controllers/web_sandbox_console/home_controller.rb +44 -4
- data/app/views/layouts/web_sandbox_console/application.html.erb +82 -11
- data/app/views/web_sandbox_console/authorization/auth_page.html.erb +33 -0
- data/app/views/web_sandbox_console/home/do_view_file.js.erb +14 -0
- data/app/views/web_sandbox_console/home/download_page.html.erb +22 -0
- data/app/views/web_sandbox_console/home/eval_code.js.erb +1 -1
- data/app/views/web_sandbox_console/home/index.html.erb +34 -7
- data/app/views/web_sandbox_console/home/view_file.html.erb +39 -0
- data/config/routes.rb +12 -0
- data/lib/generators/web_sandbox_console/templates/web_sandbox_console.rb +20 -3
- data/lib/generators/web_sandbox_console/templates/web_sandbox_console.yml +5 -0
- data/lib/generators/web_sandbox_console/web_sandbox_console_generator.rb +5 -0
- data/lib/web_sandbox_console.rb +4 -0
- data/lib/web_sandbox_console/common.rb +29 -8
- data/lib/web_sandbox_console/configuration.rb +9 -1
- data/lib/web_sandbox_console/safe_ruby.rb +116 -16
- data/lib/web_sandbox_console/sandbox.rb +119 -20
- data/lib/web_sandbox_console/sandbox_error.rb +4 -0
- data/lib/web_sandbox_console/version.rb +1 -1
- data/lib/web_sandbox_console/view_file.rb +257 -0
- data/lib/web_sandbox_console/view_file_error.rb +4 -0
- metadata +28 -6
- data/app/jobs/web_sandbox_console/application_job.rb +0 -4
@@ -2,3 +2,50 @@
|
|
2
2
|
Place all the styles related to the matching controller here.
|
3
3
|
They will automatically be included in application.css.
|
4
4
|
*/
|
5
|
+
|
6
|
+
|
7
|
+
.file_or_dir{
|
8
|
+
width: 450px;
|
9
|
+
height: 30px;
|
10
|
+
}
|
11
|
+
|
12
|
+
.h30{
|
13
|
+
height: 30px;
|
14
|
+
}
|
15
|
+
|
16
|
+
.view-file-button{
|
17
|
+
background: #272822;
|
18
|
+
height: 36px;
|
19
|
+
width: 132px;
|
20
|
+
font-size: 15px;
|
21
|
+
color: white;
|
22
|
+
cursor: pointer;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* 执行代码页面样式 */
|
26
|
+
.wrapper-console {
|
27
|
+
position: relative;
|
28
|
+
top: 8px;
|
29
|
+
width: 100%;
|
30
|
+
height: 300px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.left {
|
34
|
+
height: 100%;
|
35
|
+
/* 为了不占用绝对定位的宽度 这里计算下宽度*/
|
36
|
+
width: calc(100% - 200px);
|
37
|
+
}
|
38
|
+
|
39
|
+
.right {
|
40
|
+
position: absolute;
|
41
|
+
width: 180px;
|
42
|
+
top: 0;
|
43
|
+
bottom: 0;
|
44
|
+
right: 0;
|
45
|
+
padding-left: 15px;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* 选中后code背景色*/
|
49
|
+
.CodeMirror-selected {
|
50
|
+
background: #20aee3 !important;
|
51
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/*
|
2
|
+
Name: lucario
|
3
|
+
Author: Raphael Amorim
|
4
|
+
|
5
|
+
Original Lucario color scheme (https://github.com/raphamorim/lucario)
|
6
|
+
*/
|
7
|
+
|
8
|
+
.cm-s-lucario.CodeMirror, .cm-s-lucario .CodeMirror-gutters {
|
9
|
+
background-color: #2b3e50 !important;
|
10
|
+
color: #f8f8f2 !important;
|
11
|
+
border: none;
|
12
|
+
}
|
13
|
+
.cm-s-lucario .CodeMirror-gutters { color: #2b3e50; }
|
14
|
+
.cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; }
|
15
|
+
.cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; }
|
16
|
+
.cm-s-lucario .CodeMirror-selected { background: #243443; }
|
17
|
+
.cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; }
|
18
|
+
.cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; }
|
19
|
+
.cm-s-lucario span.cm-comment { color: #5c98cd; }
|
20
|
+
.cm-s-lucario span.cm-string, .cm-s-lucario span.cm-string-2 { color: #E6DB74; }
|
21
|
+
.cm-s-lucario span.cm-number { color: #ca94ff; }
|
22
|
+
.cm-s-lucario span.cm-variable { color: #f8f8f2; }
|
23
|
+
.cm-s-lucario span.cm-variable-2 { color: #f8f8f2; }
|
24
|
+
.cm-s-lucario span.cm-def { color: #72C05D; }
|
25
|
+
.cm-s-lucario span.cm-operator { color: #66D9EF; }
|
26
|
+
.cm-s-lucario span.cm-keyword { color: #ff6541; }
|
27
|
+
.cm-s-lucario span.cm-atom { color: #bd93f9; }
|
28
|
+
.cm-s-lucario span.cm-meta { color: #f8f8f2; }
|
29
|
+
.cm-s-lucario span.cm-tag { color: #ff6541; }
|
30
|
+
.cm-s-lucario span.cm-attribute { color: #66D9EF; }
|
31
|
+
.cm-s-lucario span.cm-qualifier { color: #72C05D; }
|
32
|
+
.cm-s-lucario span.cm-property { color: #f8f8f2; }
|
33
|
+
.cm-s-lucario span.cm-builtin { color: #72C05D; }
|
34
|
+
.cm-s-lucario span.cm-variable-3, .cm-s-lucario span.cm-type { color: #ffb86c; }
|
35
|
+
|
36
|
+
.cm-s-lucario .CodeMirror-activeline-background { background: #243443; }
|
37
|
+
.cm-s-lucario .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
|
38
|
+
|
39
|
+
|
40
|
+
/* 特殊部分 补充 */
|
41
|
+
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
|
42
|
+
.cm-s-default span.cm-arrow { color: red; }
|
43
|
+
|
44
|
+
|
45
|
+
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module WebSandboxConsole
|
2
2
|
class ApplicationController < ActionController::Base
|
3
3
|
protect_from_forgery with: :exception
|
4
|
+
|
5
|
+
before_action :restrict_ip
|
6
|
+
http_basic_authenticate_with name: WebSandboxConsole.http_basic_auth[:name].to_s, password: WebSandboxConsole.http_basic_auth[:password].to_s if WebSandboxConsole.http_basic_auth.present?
|
7
|
+
|
4
8
|
|
5
9
|
# 限制ip
|
6
10
|
def restrict_ip
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require_dependency "web_sandbox_console/application_controller"
|
2
|
+
|
3
|
+
module WebSandboxConsole
|
4
|
+
class AuthorizationController < ApplicationController
|
5
|
+
before_action :restrict_fetch_token_times, only: :fetch_token
|
6
|
+
|
7
|
+
# 获取令牌
|
8
|
+
def fetch_token
|
9
|
+
@token = SecureRandom.uuid
|
10
|
+
save_cache_token(@token)
|
11
|
+
flash[:notice] = "令牌: #{@token},此令牌先保存,后续使用。"
|
12
|
+
redirect_to auth_page_path
|
13
|
+
end
|
14
|
+
|
15
|
+
# 授权
|
16
|
+
def auth
|
17
|
+
if params[:secret_text].blank?
|
18
|
+
flash[:notice] = '密文为空'
|
19
|
+
return redirect_to root_path
|
20
|
+
end
|
21
|
+
|
22
|
+
if public_key.blank?
|
23
|
+
flash[:notice] = '公钥未配置'
|
24
|
+
return redirect_to root_path
|
25
|
+
end
|
26
|
+
|
27
|
+
result_hash = decrypt_secret_text(params[:secret_text])
|
28
|
+
token = result_hash[:content]
|
29
|
+
if result_hash[:success] && fetch_cache_token(token)
|
30
|
+
flash[:notice] = "授权成功"
|
31
|
+
session[:pass_auth] = true
|
32
|
+
else
|
33
|
+
flash[:notice] = "授权失败:#{result_hash[:content]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
redirect_to root_path
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
# 限制获取token次数 一天内不允许超过20次
|
41
|
+
def restrict_fetch_token_times
|
42
|
+
cache = Rails.cache
|
43
|
+
times = cache.fetch('fetch_token_times', expires_in: 1.day) {0}
|
44
|
+
|
45
|
+
if times > 20
|
46
|
+
flash[:notice] = '一天内获取令牌不允许超过20次'
|
47
|
+
redirect_to root_path
|
48
|
+
end
|
49
|
+
cache.write('fetch_token_times', times + 1)
|
50
|
+
end
|
51
|
+
|
52
|
+
# 保存token 到缓存
|
53
|
+
def save_cache_token(key, value = nil)
|
54
|
+
Rails.cache.write(key.to_s, value.presence || key.to_s, expires_in: 5.minutes)
|
55
|
+
end
|
56
|
+
|
57
|
+
# 获取 缓存中 token
|
58
|
+
def fetch_cache_token(key)
|
59
|
+
Rails.cache.read(key.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
# 公钥
|
63
|
+
def public_key
|
64
|
+
WebSandboxConsole.public_key
|
65
|
+
end
|
66
|
+
|
67
|
+
# 解密
|
68
|
+
def decrypt_secret_text(secret_text)
|
69
|
+
begin
|
70
|
+
base_text = Base64.decode64(secret_text)
|
71
|
+
p_key = OpenSSL::PKey::RSA.new public_key
|
72
|
+
text = p_key.public_decrypt(base_text)
|
73
|
+
{success: true, content: text}
|
74
|
+
rescue OpenSSL::PKey::RSAError
|
75
|
+
{success: false, content: "密钥匹配失败"}
|
76
|
+
rescue Exception => e
|
77
|
+
{success: false, content: "发生未知错误: #{e.inspect};#{e.backtrace[0..2].join('\r\n')}"}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -2,14 +2,54 @@ require_dependency "web_sandbox_console/application_controller"
|
|
2
2
|
|
3
3
|
module WebSandboxConsole
|
4
4
|
class HomeController < ApplicationController
|
5
|
-
|
6
|
-
http_basic_authenticate_with name: WebSandboxConsole.http_basic_auth[:name], password: WebSandboxConsole.http_basic_auth[:password] if WebSandboxConsole.http_basic_auth.present?
|
7
|
-
|
5
|
+
|
8
6
|
def index
|
9
7
|
end
|
10
8
|
|
9
|
+
# 执行代码
|
11
10
|
def eval_code
|
12
|
-
|
11
|
+
sandbox = Sandbox.new(params[:code], session[:pass_auth])
|
12
|
+
|
13
|
+
@results = if params[:commit] == '异步执行'
|
14
|
+
sandbox.asyn_evalotor
|
15
|
+
else
|
16
|
+
sandbox.evalotor
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def view_file
|
21
|
+
end
|
22
|
+
|
23
|
+
# 查看文件
|
24
|
+
def do_view_file
|
25
|
+
@result_hash = ViewFile.new(params).view
|
26
|
+
@tip_hash = WebSandboxConsole::ViewFile::PageTips
|
27
|
+
end
|
28
|
+
|
29
|
+
# 下载文件页面
|
30
|
+
def download_page
|
13
31
|
end
|
32
|
+
|
33
|
+
# 下载文件
|
34
|
+
def download
|
35
|
+
if params[:file_name].blank?
|
36
|
+
flash[:notice] = "文件名不能为空"
|
37
|
+
return redirect_to download_page_path
|
38
|
+
end
|
39
|
+
|
40
|
+
file_full_path = "#{Rails.root}/log/#{params[:file_name]}"
|
41
|
+
unless File.exists?(file_full_path)
|
42
|
+
flash[:notice] = '文件不存在,请检查文件名;或在其它服务器请多次尝试'
|
43
|
+
return redirect_to download_page_path
|
44
|
+
end
|
45
|
+
|
46
|
+
# 打包
|
47
|
+
`tar czf #{file_full_path}.tar.gz #{file_full_path}`
|
48
|
+
# 如果是csv文件,需删除
|
49
|
+
File.delete(file_full_path) if file_full_path.split(".").last == 'csv'
|
50
|
+
|
51
|
+
send_file "#{file_full_path}.tar.gz"
|
52
|
+
end
|
53
|
+
|
14
54
|
end
|
15
55
|
end
|
@@ -1,14 +1,85 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
|
-
<head>
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
</head>
|
9
|
-
<body>
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
<head>
|
4
|
+
<title>Web sandbox console</title>
|
5
|
+
<%= stylesheet_link_tag "web_sandbox_console/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "web_sandbox_console/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<div id="main-wrapper">
|
11
|
+
<header class="topbar">
|
12
|
+
<nav class="navbar top-navbar">
|
13
|
+
<div class="navbar-header">
|
14
|
+
<a class="navbar-brand" href="/web_sandbox_console">
|
15
|
+
<b>
|
16
|
+
<img src="/assets/web_sandbox_console/logo-icon.png" />
|
17
|
+
</b>
|
18
|
+
<span style="left-padding: 10px;" class="font-color">运维控制台</span>
|
19
|
+
</a>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div class="navbar-collapse">
|
23
|
+
</div>
|
24
|
+
</nav>
|
25
|
+
</header>
|
26
|
+
|
27
|
+
<aside class="left-sidebar">
|
28
|
+
<div class="scroll-sidebar ps">
|
29
|
+
<nav class="sidebar-nav">
|
30
|
+
<ul id="sidebar-nav">
|
31
|
+
<li>
|
32
|
+
<%= link_to root_path, class: 'waves-effect waves-dark' do %>
|
33
|
+
<i class="fa fa-bookmark-o"></i>
|
34
|
+
<span class="hide-menu <%= action_name == 'index' ? 'menu-active' : '' %>">执行代码</span>
|
35
|
+
<% end %>
|
36
|
+
</li>
|
37
|
+
|
38
|
+
<li>
|
39
|
+
<%= link_to web_sandbox_console.view_file_path, class: 'waves-effect waves-dark' do %>
|
40
|
+
<i class="fa fa-bookmark-o"></i>
|
41
|
+
<span class="hide-menu <%= action_name == 'view_file' ? 'menu-active' : '' %>">查看文件</span>
|
42
|
+
<% end %>
|
43
|
+
</li>
|
44
|
+
|
45
|
+
<li>
|
46
|
+
<%= link_to web_sandbox_console.download_page_path, class: 'waves-effect waves-dark' do %>
|
47
|
+
<i class="fa fa-bookmark-o"></i>
|
48
|
+
<span class="hide-menu <%= action_name == 'download_page' ? 'menu-active' : '' %>">下载文件</span>
|
49
|
+
<% end %>
|
50
|
+
</li>
|
51
|
+
|
52
|
+
<li>
|
53
|
+
<%= link_to web_sandbox_console.auth_page_path, class: 'waves-effect waves-dark' do %>
|
54
|
+
<i class="fa fa-bookmark-o"></i>
|
55
|
+
<span class="hide-menu <%= action_name == 'auth_page' ? 'menu-active' : '' %>">升级授权</span>
|
56
|
+
<% end %>
|
57
|
+
</li>
|
58
|
+
|
59
|
+
<li>
|
60
|
+
<%= link_to "https://github.com/dongmy54/web_sandbox_console", target: "_blank", class: 'waves-effect waves-dark' do %>
|
61
|
+
<i class="fa fa-bookmark-o"></i>
|
62
|
+
<span class="hide-menu">说明文档</span>
|
63
|
+
<% end %>
|
64
|
+
</li>
|
65
|
+
</ul>
|
66
|
+
</nav>
|
67
|
+
|
68
|
+
</div>
|
69
|
+
</aside>
|
70
|
+
|
71
|
+
<div class="page-wrapper">
|
72
|
+
<div class="container-fluid">
|
73
|
+
<%= yield %>
|
74
|
+
</div>
|
75
|
+
</div>
|
76
|
+
</div>
|
77
|
+
</body>
|
14
78
|
</html>
|
79
|
+
|
80
|
+
<script type="text/javascript">
|
81
|
+
<% flash.each do |type, msg| %>
|
82
|
+
<% tip = type == 'notice' ? '提示' : '其它' %>
|
83
|
+
alert("<%= tip %>: <%= msg %>");
|
84
|
+
<% end %>
|
85
|
+
</script>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<h3>升级授权</h3>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<%= link_to '获取令牌', fetch_token_path %>
|
5
|
+
<span> PS: 注意获取令牌一天最多20次,有效期仅5分钟</span>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<div class="">
|
9
|
+
<%= form_tag web_sandbox_console.auth_path, method: :post do %>
|
10
|
+
<table>
|
11
|
+
<tr>
|
12
|
+
<td>加密密文</td>
|
13
|
+
<td>
|
14
|
+
<%= text_area_tag :secret_text, '', style: "width: 300px;height: 100px;" %>
|
15
|
+
</td>
|
16
|
+
<td><%= submit_tag '提交', data: { disable_with: "已发送,处理中..." }, class: 'view-file-button' %></td>
|
17
|
+
</table>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<h4>说明令牌使用说明:</h4>
|
22
|
+
<div>
|
23
|
+
<pre class="no-border">
|
24
|
+
require 'openssl'
|
25
|
+
require 'base64'
|
26
|
+
|
27
|
+
private_key = "你的私钥"
|
28
|
+
p_key = OpenSSL::PKey::RSA.new private_key
|
29
|
+
secret_text = p_key.private_encrypt("你的令牌")
|
30
|
+
encode_text = Base64.encode64(secret_text)
|
31
|
+
puts encode_text
|
32
|
+
</pre>
|
33
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$(".output-content").empty();
|
2
|
+
|
3
|
+
<% line_num_show = @result_hash[:total_line_num] ? "原始文件总行数:#{@result_hash[:total_line_num]}" : "" %>
|
4
|
+
$(".output-content").append("<p>============ <%= Time.current %> 查找结果如下 <%= line_num_show %> ===============</p>");
|
5
|
+
|
6
|
+
<% @tip_hash.each do |key,value| %>
|
7
|
+
<% if @result_hash[key.to_sym] %>
|
8
|
+
$(".output-content").append("<p>PS: <%= value %></p>");
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% @result_hash[:lines].each do |result| %>
|
13
|
+
$(".output-content").append('<pre><%= escape_javascript result %></pre>');
|
14
|
+
<% end %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<h3>下载文件</h3>
|
2
|
+
<div class="">
|
3
|
+
<%= form_tag web_sandbox_console.download_path, method: :get do %>
|
4
|
+
<table>
|
5
|
+
<tr>
|
6
|
+
<td>文件名</td>
|
7
|
+
<td>
|
8
|
+
<%= text_field_tag :file_name, '', style: "width: 400px;height: 35px;font-size: 15px;" %>
|
9
|
+
</td>
|
10
|
+
<td><%= submit_tag '提交', data: { disable_with: "已发送,处理中..." }, class: 'view-file-button' %></td>
|
11
|
+
</table>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<h4>说明:</h4>
|
16
|
+
<div>
|
17
|
+
<pre class="no-border">
|
18
|
+
1. 只可下载log目录下文件
|
19
|
+
2. 下载时文件名需要带上后缀如:production.log
|
20
|
+
3. csv文件下载后会被删除,不能重复下载
|
21
|
+
</pre>
|
22
|
+
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
$(".output-content").append(
|
1
|
+
$(".output-content").append("<p>============ <%= Time.current %> 本次输出如下 ===============</p>");
|
2
2
|
<% @results.each do |result| %>
|
3
3
|
$(".output-content").append('<p><%= escape_javascript result %></p>');
|
4
4
|
<% end %>
|
@@ -1,15 +1,42 @@
|
|
1
|
-
|
1
|
+
<h3>执行代码</h3>
|
2
2
|
|
3
|
-
<div class="console">
|
3
|
+
<div class="wrapper-console">
|
4
4
|
<%= form_tag(web_sandbox_console.eval_code_path, remote: true, class: 'form') do %>
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
<div class= "left">
|
6
|
+
<%= text_area_tag :code, '# 这里输入ruby代码...', class: 'text_area_box'%>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="right">
|
10
|
+
<div style="position: absolute;bottom: 0;">
|
11
|
+
<% if session[:pass_auth] %>
|
12
|
+
<p class="tip">授权成功</p>
|
13
|
+
<p class="tip">(当前修改将写入数据库)</p>
|
14
|
+
<% end %>
|
15
|
+
<%= submit_tag '提交', data: { disable_with: "已发送,处理中..." }, class: 'send-button margin-t-10' %>
|
16
|
+
<%= submit_tag '异步执行', data: { disable_with: "已发送,处理中..." }, class: 'send-button margin-t-10' %>
|
17
|
+
</div>
|
18
|
+
</div>
|
8
19
|
<% end %>
|
9
|
-
|
10
20
|
</div>
|
11
21
|
|
12
|
-
|
22
|
+
<div style="margin-top: 50px;">
|
23
|
+
<%= button_tag '清除输出', type: 'button', onclick: "$('.output-content').empty();", class: 'clear-button' %>
|
24
|
+
<div>
|
13
25
|
|
14
26
|
<div class="output-content">
|
15
27
|
</div>
|
28
|
+
|
29
|
+
|
30
|
+
<script>
|
31
|
+
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
32
|
+
mode: "text/x-ruby",
|
33
|
+
matchBrackets: true,
|
34
|
+
indentUnit: 2,
|
35
|
+
indentWithTabs: true,
|
36
|
+
theme: 'lucario',
|
37
|
+
tabSize: 2,
|
38
|
+
lineNumbers: true,
|
39
|
+
lineWrapping: true, /* 自动换行 */
|
40
|
+
fixedGutter: false
|
41
|
+
});
|
42
|
+
</script>
|