ruby_uml_class 0.1.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 +7 -0
- data/.rspec +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +83 -0
- data/LICENSE.txt +21 -0
- data/README.md +33 -0
- data/Rakefile +8 -0
- data/bin/start_ruby_uml_class.rb +52 -0
- data/bin/start_ruby_uml_class.rbw +52 -0
- data/img/RubyUmlClass.mp4 +0 -0
- data/lib/app_load.rb +2 -0
- data/lib/config/browser.json +4 -0
- data/lib/config/setting.json +19 -0
- data/lib/config.ru +107 -0
- data/lib/create_uml_class.rb +297 -0
- data/lib/css/index.css +178 -0
- data/lib/history/history.json +3 -0
- data/lib/html/index.html +80 -0
- data/lib/js/main.js +463 -0
- data/lib/ruby_uml_class/version.rb +5 -0
- data/lib/ruby_uml_class.rb +55 -0
- data/lib/server.rb +58 -0
- data/lib/server_app_base.rb +63 -0
- data/lib/start.rb +130 -0
- data/lib/wsserver.rb +147 -0
- data/ruby_uml_class.gemspec +42 -0
- data/sig/ruby_uml_class.rbs +4 -0
- metadata +103 -0
@@ -0,0 +1,297 @@
|
|
1
|
+
require "tempfile"
|
2
|
+
|
3
|
+
CStruct = Struct.new(:type,
|
4
|
+
:name,
|
5
|
+
:block_count,
|
6
|
+
:var_list,
|
7
|
+
:method_list,
|
8
|
+
:inherit_list,
|
9
|
+
:composition_list)
|
10
|
+
|
11
|
+
def print_uml(out, out_list)
|
12
|
+
out_list.each do |o_list|
|
13
|
+
if o_list.type == :class_start
|
14
|
+
# nop
|
15
|
+
elsif o_list.type == :module_start
|
16
|
+
out.push "namespace #{o_list.name} {"
|
17
|
+
elsif o_list.type == :class_end
|
18
|
+
pp o_list if o_list.name == ""
|
19
|
+
out.push "class #{o_list.name} {"
|
20
|
+
# インスタンス変数の出力
|
21
|
+
o_list.var_list.uniq.each do |iv|
|
22
|
+
out.push iv
|
23
|
+
end
|
24
|
+
# メソッドの出力
|
25
|
+
o_list.method_list.each do |ml|
|
26
|
+
out.push ml
|
27
|
+
end
|
28
|
+
out.push "}"
|
29
|
+
# 継承リストの出力
|
30
|
+
o_list.inherit_list.each do |ih|
|
31
|
+
out.push "#{o_list.name} --|> #{ih}"
|
32
|
+
end
|
33
|
+
# compo
|
34
|
+
o_list.composition_list.uniq.each do |co|
|
35
|
+
out.push "#{o_list.name} *-- #{co}"
|
36
|
+
end
|
37
|
+
elsif o_list.type == :module_end
|
38
|
+
# インスタンス変数がある場合はモジュール名と同じクラスを定義
|
39
|
+
if o_list.var_list.size != 0 or
|
40
|
+
o_list.method_list.size != 0 or
|
41
|
+
o_list.inherit_list.size != 0 or
|
42
|
+
o_list.composition_list.size != 0
|
43
|
+
pp o_list if o_list.name == ""
|
44
|
+
out.push "class #{o_list.name} {"
|
45
|
+
# インスタンス変数の出力
|
46
|
+
o_list.var_list.uniq.each do |iv|
|
47
|
+
out.push iv
|
48
|
+
end
|
49
|
+
# メソッドの出力
|
50
|
+
o_list.method_list.each do |ml|
|
51
|
+
out.push ml
|
52
|
+
end
|
53
|
+
out.push "}"
|
54
|
+
# 継承リストの出力
|
55
|
+
o_list.inherit_list.each do |ih|
|
56
|
+
out.push "#{o_list.name} --|> #{ih}"
|
57
|
+
end
|
58
|
+
# compo
|
59
|
+
o_list.composition_list.uniq.each do |co|
|
60
|
+
out.push "#{o_list.name} *-- #{co}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
out.push "}"
|
64
|
+
else
|
65
|
+
# error
|
66
|
+
puts "error!"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return out
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_here_doc(buf)
|
73
|
+
new_buf = []
|
74
|
+
here_doc = false
|
75
|
+
here_word = ""
|
76
|
+
buf.each_line do |line|
|
77
|
+
if line =~ /(<<|<<~|<<-)[A-Z]+/
|
78
|
+
here_doc = true
|
79
|
+
here_word = line.match(/(<<|<<~|<<-)[A-Z]+/).to_s.gsub(/[<~-]/, "")
|
80
|
+
end
|
81
|
+
if here_word != "" and line =~ Regexp.new("^\s*#{here_word}$")
|
82
|
+
here_word = ""
|
83
|
+
here_doc = false
|
84
|
+
pp line
|
85
|
+
end
|
86
|
+
if here_doc == false
|
87
|
+
new_buf.push line
|
88
|
+
else
|
89
|
+
pp line
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return new_buf.join("")
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_uml_class(in_dir, out_file)
|
96
|
+
out = []
|
97
|
+
out.push "@startuml"
|
98
|
+
|
99
|
+
puts "in_dir = #{in_dir}"
|
100
|
+
main_composition_list = []
|
101
|
+
main_method_list = []
|
102
|
+
global_var = []
|
103
|
+
|
104
|
+
Dir.glob("#{in_dir}/**/*.{rb,ru}") do |f|
|
105
|
+
puts f
|
106
|
+
buf = ""
|
107
|
+
Tempfile.create("rufo") do |tmp_file|
|
108
|
+
FileUtils.cp(f, tmp_file.path)
|
109
|
+
open("|rufo #{tmp_file.path}") do |f|
|
110
|
+
if f.read =~ /error/
|
111
|
+
puts "rufo error #{f}"
|
112
|
+
return
|
113
|
+
else
|
114
|
+
buf = File.binread tmp_file.path
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# コメント削除
|
120
|
+
buf.gsub!(/(([\/\"\'].*?[\/\"\'])|([^\/\"\'\)\s]*#.+?$))/) do |m|
|
121
|
+
if m[0] == "#" and m[0] != "{"
|
122
|
+
#puts "comment #{m}"
|
123
|
+
# コメント
|
124
|
+
""
|
125
|
+
else
|
126
|
+
#puts "not comment #{m}"
|
127
|
+
# コメント以外
|
128
|
+
m
|
129
|
+
end
|
130
|
+
end
|
131
|
+
# ヒアドキュメント削除
|
132
|
+
buf = delete_here_doc(buf)
|
133
|
+
|
134
|
+
out_list = []
|
135
|
+
cstruct_list = []
|
136
|
+
block_count = 0
|
137
|
+
method_type = :public
|
138
|
+
class_name = ""
|
139
|
+
# ソースを解析
|
140
|
+
buf.each_line do |line|
|
141
|
+
next if line =~ /^$/ # 空行は対象外
|
142
|
+
|
143
|
+
# ブロックの開始/終了
|
144
|
+
indent_num = line.match(/^[ ]+/).to_s.size / 2
|
145
|
+
if block_count == indent_num
|
146
|
+
# 変化なし
|
147
|
+
elsif block_count > indent_num
|
148
|
+
# ブロックの終了
|
149
|
+
block_count = indent_num
|
150
|
+
else
|
151
|
+
# ブロックの開始
|
152
|
+
block_count = indent_num
|
153
|
+
end
|
154
|
+
|
155
|
+
#line.gsub!(/\".+\"/, "\"delete_string\"") # 文字列を削除
|
156
|
+
if line =~ /^\s*class\s/
|
157
|
+
unless line =~ /<</ # 特異クラスではない
|
158
|
+
work = line.gsub(/class\s/, "")
|
159
|
+
class_name = work.split("<")[0].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
|
160
|
+
base_name = work.split("<")[1].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
|
161
|
+
class_name.gsub!(/::/, ".")
|
162
|
+
if out_list.size != 0 and out_list[-1].type == :class_start # classが連続している
|
163
|
+
class_name = out_list[-1].name + "." + class_name
|
164
|
+
out_list[-1].name = class_name
|
165
|
+
cstruct_list[-1].name = class_name
|
166
|
+
else
|
167
|
+
out_list.push CStruct.new(:class_start, class_name, block_count, [], [], [], [])
|
168
|
+
cstruct_list.push CStruct.new(:class_end, class_name, block_count, [], [], [], [])
|
169
|
+
end
|
170
|
+
pp line if class_name == ""
|
171
|
+
if base_name != ""
|
172
|
+
#base_name.gsub!(/::/, ".")
|
173
|
+
cstruct_list[-1].inherit_list.push base_name
|
174
|
+
end
|
175
|
+
end
|
176
|
+
next unless line =~ /end\s*$/ # 1行で終了しない場合
|
177
|
+
elsif line =~ /^\s*module\s/
|
178
|
+
module_name = line.split(" ")[1].to_s.chomp
|
179
|
+
module_name.gsub!(/^[:]+/, "")
|
180
|
+
module_name.gsub!(/::/, ".")
|
181
|
+
out_list.push CStruct.new(:module_start, module_name, block_count, [], [], [], [])
|
182
|
+
cstruct_list.push CStruct.new(:module_end, module_name, block_count, [], [], [], [])
|
183
|
+
next unless line =~ /end\s*$/ # 1行で終了しない場合
|
184
|
+
end
|
185
|
+
|
186
|
+
if line =~ /^\s*private$/
|
187
|
+
method_type = :private
|
188
|
+
elsif line =~ /^\s*protected$/
|
189
|
+
method_type = :protected
|
190
|
+
elsif line =~ /^\s*public$/
|
191
|
+
method_type = :public
|
192
|
+
end
|
193
|
+
|
194
|
+
if line =~ /^\s*def\s/
|
195
|
+
# 関数名を取り出す
|
196
|
+
method = line.chomp.gsub(/\s*def\s*/, "")
|
197
|
+
unless method =~ /\(/
|
198
|
+
# 関数名にカッコをつける
|
199
|
+
sp = method.split(" ")
|
200
|
+
if sp.size > 1
|
201
|
+
method = sp[0].to_s + "(" + sp[1..-1].to_s + ")"
|
202
|
+
else
|
203
|
+
method = method + "()"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
if cstruct_list.size != 0
|
207
|
+
method_list = cstruct_list[-1].method_list
|
208
|
+
case method_type
|
209
|
+
when :public
|
210
|
+
method_list.push "+ #{method}"
|
211
|
+
when :private
|
212
|
+
method_list.push "- #{method}"
|
213
|
+
when :protected
|
214
|
+
method_list.push "# #{method}"
|
215
|
+
end
|
216
|
+
else
|
217
|
+
main_method_list.push "+ #{method}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# composition_list
|
222
|
+
line.match(/(([\/\"\')].*?\.new.*?[\/\"\'])|(?![\/\"\'])([a-zA-Z0-9_]+\.new))/) do |m|
|
223
|
+
if m.to_s[0] != "/" and m.to_s[0] != "\"" and m.to_s[0] != "'"
|
224
|
+
name = m.to_s.gsub(/\.new/, "").match(/[A-Z][A-Za-z0-9_]+/).to_s
|
225
|
+
if name != ""
|
226
|
+
if cstruct_list.size != 0
|
227
|
+
cstruct_list[-1].composition_list.push name
|
228
|
+
else
|
229
|
+
main_composition_list.push "main *-- #{name}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# インスタンス変数
|
236
|
+
if line =~ /\s*@\S+/
|
237
|
+
if cstruct_list.size != 0
|
238
|
+
line.match(/@[a-zA-Z0-9_]+/) { |m|
|
239
|
+
instance_var = cstruct_list[-1].var_list
|
240
|
+
val = m.to_s.gsub(/@/, "")
|
241
|
+
case method_type
|
242
|
+
when :public
|
243
|
+
instance_var.push "+ #{val}"
|
244
|
+
when :private
|
245
|
+
instance_var.push "- #{val}"
|
246
|
+
when :protected
|
247
|
+
instance_var.push "# #{val}"
|
248
|
+
end
|
249
|
+
}
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# 外部変数
|
254
|
+
line.match(/\$[a-zA-Z0-9_]+/) { |m|
|
255
|
+
global_var.push "+ #{m.to_s}"
|
256
|
+
}
|
257
|
+
|
258
|
+
# クラスの終了
|
259
|
+
if cstruct_list.size != 0
|
260
|
+
if block_count == cstruct_list[-1].block_count # block_countが一致
|
261
|
+
#puts "end of #{cstruct_list[-1].name}"
|
262
|
+
out_list.push cstruct_list[-1]
|
263
|
+
cstruct_list.slice!(-1) # 最後の要素を削除
|
264
|
+
end
|
265
|
+
end
|
266
|
+
#puts "#{block_count} #{line.chomp}"
|
267
|
+
end
|
268
|
+
if block_count != 0
|
269
|
+
# エラー
|
270
|
+
puts f
|
271
|
+
return ""
|
272
|
+
end
|
273
|
+
|
274
|
+
# UMLの出力
|
275
|
+
out = print_uml(out, out_list)
|
276
|
+
end
|
277
|
+
|
278
|
+
if main_method_list.size != 0 or
|
279
|
+
main_composition_list.size != 0 or
|
280
|
+
main_method_list.size != 0
|
281
|
+
out.push "class main {"
|
282
|
+
main_method_list.each do |mml|
|
283
|
+
out.push mml
|
284
|
+
end
|
285
|
+
# グローバル変数の出力
|
286
|
+
global_var.uniq.each do |gv|
|
287
|
+
out.push gv
|
288
|
+
end
|
289
|
+
out.push "}"
|
290
|
+
main_composition_list.uniq.each do |mcl|
|
291
|
+
out.push mcl
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
out.push "@enduml"
|
296
|
+
return out.join("\n")
|
297
|
+
end
|
data/lib/css/index.css
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
body {
|
2
|
+
color: #000000;
|
3
|
+
background-color: #cac3ec4f;
|
4
|
+
overflow: hidden;
|
5
|
+
font-size: 12px;
|
6
|
+
}
|
7
|
+
|
8
|
+
hr {
|
9
|
+
color: #ffffff;
|
10
|
+
background-color: #000000;
|
11
|
+
height: 1px;
|
12
|
+
/* 線の太さ */
|
13
|
+
border: 1px;
|
14
|
+
/* 枠の太さ */
|
15
|
+
border-style: solid;
|
16
|
+
/* 枠の種類 */
|
17
|
+
}
|
18
|
+
|
19
|
+
.error {
|
20
|
+
color: red;
|
21
|
+
}
|
22
|
+
|
23
|
+
.outarea {
|
24
|
+
background-color: #FFFFFF;
|
25
|
+
margin: 5px;
|
26
|
+
padding: 5px;
|
27
|
+
width: 95vw;
|
28
|
+
height: 50vh;
|
29
|
+
overflow: auto;
|
30
|
+
}
|
31
|
+
|
32
|
+
.inarea {
|
33
|
+
border: thin solid #000000;
|
34
|
+
margin: 5px;
|
35
|
+
padding: 5px;
|
36
|
+
width: 98%;
|
37
|
+
}
|
38
|
+
|
39
|
+
input.long {
|
40
|
+
width: 98%;
|
41
|
+
background-color: #FAFAFA;
|
42
|
+
margin: 5px;
|
43
|
+
padding: 5px;
|
44
|
+
}
|
45
|
+
|
46
|
+
textarea.long {
|
47
|
+
width: 95vw;
|
48
|
+
height: 50vh;
|
49
|
+
}
|
50
|
+
|
51
|
+
.ui-widget {
|
52
|
+
font-size: 12px;
|
53
|
+
}
|
54
|
+
|
55
|
+
.ui-autocomplete {
|
56
|
+
max-height: 45vh;
|
57
|
+
max-width: 90wh;
|
58
|
+
overflow-y: auto;
|
59
|
+
overflow-x: auto;
|
60
|
+
padding-right: 10px;
|
61
|
+
}
|
62
|
+
|
63
|
+
#jquery-ui-autocomplete label {
|
64
|
+
float: left;
|
65
|
+
margin-right: 0.5em;
|
66
|
+
color: black;
|
67
|
+
}
|
68
|
+
|
69
|
+
.ui-autocomplete.ui-front {
|
70
|
+
max-height: 250px;
|
71
|
+
overflow-y: auto;
|
72
|
+
/* prevent horizontal scrollbar */
|
73
|
+
overflow-x: hidden;
|
74
|
+
/* add padding to account for vertical scrollbar */
|
75
|
+
z-index: 1000 !important;
|
76
|
+
}
|
77
|
+
|
78
|
+
.ui-dialog {
|
79
|
+
position: absolute;
|
80
|
+
top: 0;
|
81
|
+
left: 0;
|
82
|
+
padding: .2em;
|
83
|
+
outline: 0;
|
84
|
+
}
|
85
|
+
|
86
|
+
.long {
|
87
|
+
width: 90%;
|
88
|
+
}
|
89
|
+
|
90
|
+
#setting_dialog {
|
91
|
+
color: #ffffff;
|
92
|
+
background-color: #000000;
|
93
|
+
}
|
94
|
+
|
95
|
+
.setting_name {
|
96
|
+
width: 200px;
|
97
|
+
color: #ffffff;
|
98
|
+
background-color: #000000;
|
99
|
+
}
|
100
|
+
|
101
|
+
.setting_value {
|
102
|
+
width: 300px;
|
103
|
+
color: #ffffff;
|
104
|
+
background-color: #000000;
|
105
|
+
}
|
106
|
+
|
107
|
+
.setting_checkbox {
|
108
|
+
color: #ffffff;
|
109
|
+
background-color: #000000;
|
110
|
+
}
|
111
|
+
|
112
|
+
ul.log {
|
113
|
+
list-style-type: none;
|
114
|
+
font-size: 12px;
|
115
|
+
color: #000000;
|
116
|
+
}
|
117
|
+
|
118
|
+
input[type="search"] {
|
119
|
+
-webkit-appearance: searchfield;
|
120
|
+
}
|
121
|
+
|
122
|
+
input[type="search"]::-webkit-search-cancel-button {
|
123
|
+
-webkit-appearance: searchfield-cancel-button;
|
124
|
+
}
|
125
|
+
|
126
|
+
/* menu */
|
127
|
+
.menu {
|
128
|
+
display: flex;
|
129
|
+
justify-content: flex-start;
|
130
|
+
list-style-type: none;
|
131
|
+
color: #393737;
|
132
|
+
padding: 0;
|
133
|
+
font-size: 12px;
|
134
|
+
font-weight: bold;
|
135
|
+
}
|
136
|
+
|
137
|
+
.menu li {
|
138
|
+
position: relative;
|
139
|
+
width: 100px;
|
140
|
+
margin-left: 1px;
|
141
|
+
padding: 5px;
|
142
|
+
background: #d8dada;
|
143
|
+
list-style-type: none;
|
144
|
+
}
|
145
|
+
|
146
|
+
.menu li a {
|
147
|
+
color: rgb(20, 114, 192);
|
148
|
+
}
|
149
|
+
|
150
|
+
.menu li a:hover {
|
151
|
+
background: #eba399;
|
152
|
+
}
|
153
|
+
|
154
|
+
.menuSub {
|
155
|
+
position: absolute;
|
156
|
+
margin-left: -6px;
|
157
|
+
padding: 0;
|
158
|
+
display: none;
|
159
|
+
}
|
160
|
+
|
161
|
+
/*.openが付与された時、表示の設定*/
|
162
|
+
.menuSub.open {
|
163
|
+
display: block;
|
164
|
+
}
|
165
|
+
|
166
|
+
.menuSub li a {
|
167
|
+
padding: 5px;
|
168
|
+
margin-left: -5px;
|
169
|
+
margin-right: -5px;
|
170
|
+
margin-bottom: -5px;
|
171
|
+
display: block;
|
172
|
+
color: rgb(20, 114, 192);
|
173
|
+
text-decoration: none;
|
174
|
+
}
|
175
|
+
|
176
|
+
.menuSub li a:hover {
|
177
|
+
background: #eba399;
|
178
|
+
}
|
data/lib/html/index.html
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
7
|
+
<title>RubyUMLClass</title>
|
8
|
+
<!-- jQuery -->
|
9
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
10
|
+
<!-- jQuery UI -->
|
11
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
|
12
|
+
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
|
13
|
+
|
14
|
+
<script src="js/main.js"></script>
|
15
|
+
<link rel="stylesheet" href="css/index.css" type="text/css">
|
16
|
+
</head>
|
17
|
+
|
18
|
+
<body>
|
19
|
+
<div id="msg_dialog" style="display:none;">
|
20
|
+
<div id="msg_text">message</div>
|
21
|
+
</div>
|
22
|
+
<hr>
|
23
|
+
<!-- menu -->
|
24
|
+
<div id="setting_dialog" style="display:none;">
|
25
|
+
<dl id="wrap"></dl>
|
26
|
+
</div>
|
27
|
+
<div>
|
28
|
+
<ul class="menu">
|
29
|
+
<Li><a href="#" id="exec" name="exec">実行</a></li>
|
30
|
+
<li><a href="#" id="stop" name="stop">停止</a></li>
|
31
|
+
<li>
|
32
|
+
設定
|
33
|
+
<ul class="menuSub">
|
34
|
+
<li><a href="#" id="setting">設定</a></li>
|
35
|
+
<li><a href="#" id="save_setting">設定保存</a></li>
|
36
|
+
<li><a href="#" id="load_setting">設定読み込み</a></li>
|
37
|
+
</ul>
|
38
|
+
</li>
|
39
|
+
<!--
|
40
|
+
<li>
|
41
|
+
menu3
|
42
|
+
<ul class="menuSub">
|
43
|
+
<li><a href="#">menu3-1</a></li>
|
44
|
+
<li><a href="#">menu3-2</a></li>
|
45
|
+
</ul>
|
46
|
+
</li>
|
47
|
+
-->
|
48
|
+
</ul>
|
49
|
+
</div>
|
50
|
+
|
51
|
+
<table>
|
52
|
+
<tr>
|
53
|
+
<td>
|
54
|
+
<div id="dialog1" style="display:none;">
|
55
|
+
<input class="inarea" type="search" name="search_str" id="search_str">
|
56
|
+
</div>
|
57
|
+
</td>
|
58
|
+
<td class="long"><input class="inarea" type="search" id="inDir" name="inDir"></td>
|
59
|
+
<td><input type="button" id="select_dir" value="対象フォルダ" /></td>
|
60
|
+
</tr>
|
61
|
+
<tr>
|
62
|
+
<td>
|
63
|
+
<div id="dialog2" style="display:none;">
|
64
|
+
<input class="inarea" type="search" name="search_str2" id="search_str2">
|
65
|
+
</div>
|
66
|
+
</td>
|
67
|
+
<td class="long"><input class="inarea" type="search" id="outFile" name="outFile"></td>
|
68
|
+
<td><input type="button" id="select_file" value="出力ファイル" /></td>
|
69
|
+
<td><input type="button" id="open_file" value="開く" /></td>
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
|
73
|
+
<div class="outarea">
|
74
|
+
<ul name="log" id="log" class="log">
|
75
|
+
</ul>
|
76
|
+
</div>
|
77
|
+
|
78
|
+
</body>
|
79
|
+
|
80
|
+
</html>
|