mathieuravaux-god_web 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.textile ADDED
@@ -0,0 +1,82 @@
1
+ h2. Description
2
+
3
+ iPhone friendly web UI "God":http://god.rubyforge.org/
4
+
5
+ h2. Screenshots
6
+
7
+ "!http://farm3.static.flickr.com/2281/2505507050_2f8fc39795_m.jpg!":http://www.flickr.com/photos/jnewland/2505507050/
8
+ "!http://farm3.static.flickr.com/2420/2504730261_06ac1ba923_m.jpg!":http://www.flickr.com/photos/jnewland/2504730261/
9
+
10
+ h2. Requirements
11
+
12
+ * "God":http://god.rubyforge.org/
13
+ * "Sinatra":http://sinatrarb.com/
14
+
15
+ h2. Install
16
+
17
+ <pre>
18
+ <code>
19
+ git clone git://github.com/jnewland/god_web.git
20
+ cd god_web
21
+ gem build god_web.gemspec
22
+ sudo gem install -l god_web-*.gem
23
+ </code>
24
+ </pre>
25
+
26
+ h2. Usage
27
+
28
+ In your God config:
29
+
30
+ <pre>
31
+ <code>
32
+ require 'god_web'
33
+ GodWeb.watch
34
+ </code>
35
+ </pre>
36
+
37
+ This will create a God watch that runs and monitors GodWeb on port 8888.
38
+
39
+ Optionally, you can password protect your @god_web@ instance. To do so, create
40
+ a YAML config file with username and password keys, like so:
41
+
42
+ <pre>
43
+ <code>
44
+ username: foo
45
+ password: sekret
46
+ </code>
47
+ </pre>
48
+
49
+ Then provide the full path to that yaml file as an option to the @GodWeb.watch@
50
+ call:
51
+
52
+ <pre>
53
+ <code>
54
+ require 'god_web'
55
+ GodWeb.watch(:config => '/full/path/to/god_web.yaml')
56
+ </code>
57
+ </pre>
58
+
59
+ h2. Contributing
60
+
61
+ god_web uses "ditz":http://ditz.rubyforge.org for issue tracking. Fork
62
+ god_web, clone your copy and then run:
63
+
64
+ @ditz todo@
65
+
66
+ For more details on a specific issue:
67
+
68
+ @ditz show god_web-1@
69
+
70
+ Make your changes that fix a bug, then resolve it.
71
+
72
+ @ditz close god_web-1@
73
+
74
+ Commit, push your changes to GitHub, then send a pull request!
75
+
76
+ h3. Author
77
+
78
+ "Jesse Newland":http://jnewland.com/
79
+
80
+ h3. License
81
+
82
+ "WTFPL":http://sam.zoy.org/wtfpl/
data/bin/god_web ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/environment'
4
+
5
+ OptionParser.new { |op|
6
+ op.on('-e env') { |val| set :environment, val.to_sym }
7
+ op.on('-s server') { |val| set :server, val }
8
+ op.on('-p port') { |val| set :port, val.to_i }
9
+ }.parse!(ARGV.dup)
10
+
11
+ set :run, true
12
+
13
+ before do
14
+ unless (GODWEB_CONFIG['username'].nil? && GODWEB_CONFIG['password'].nil?) || self.request.path_info == '/heartbeat'
15
+ authenticate_or_request_with_http_basic "GodWeb" do
16
+ |user, pass| user == GODWEB_CONFIG['username'] && pass == GODWEB_CONFIG['password']
17
+ end
18
+ end
19
+ GODWEB.ping
20
+ end
21
+
22
+ get '/' do
23
+ @statuses = GODWEB.status
24
+ @watches = []
25
+ @statuses.each do |watch, status|
26
+ @watches << watch.to_s
27
+ end
28
+ @watches.sort!
29
+ @groups = GODWEB.groups
30
+ show(:status)
31
+ end
32
+
33
+ get '/w/:watch' do
34
+ @watch = params["watch"]
35
+ @status = GODWEB.status[@watch][:state]
36
+ @commands = GodWeb.possible_statuses(@status)
37
+ show(:watch, "#{@watch} [#{@status}]")
38
+ end
39
+
40
+ get '/g/:group' do
41
+ @watch = @group = params["group"]
42
+ @status = nil
43
+ @commands = GodWeb.possible_statuses(@status)
44
+ show(:watch, "#{@group} [group]")
45
+ end
46
+
47
+ get '/w/:watch/:command' do
48
+ @watch = params["watch"]
49
+ @command = params["command"]
50
+ @success = GODWEB.send(@command, @watch)
51
+ @success = false if @success == []
52
+ show(:command, "#{@command}ing #{@watch}")
53
+ end
54
+
55
+ get '/heartbeat' do
56
+ @statuses = GODWEB.status
57
+ 'OK'
58
+ end
59
+
60
+ private
61
+
62
+ def show(template, title = 'GodWeb')
63
+ @title = title
64
+ erb(template)
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'god'
3
+ require 'sinatra'
4
+ require 'stringio'
5
+ require 'yaml'
6
+ require 'erb'
7
+ require 'optparse'
8
+ #included until http://sinatra.lighthouseapp.com/projects/9779/tickets/16-patch-http-authentication is in a released version
9
+ require File.dirname(__FILE__) + '/sinatra_http_auth'
10
+ require File.dirname(__FILE__) + '/god_web'
11
+
12
+ config = {
13
+ 'god_port' => 17165,
14
+ 'username' => nil,
15
+ 'password' => nil
16
+ }
17
+ begin
18
+ config.merge!(YAML.load(File.read(ARGV[0])))
19
+ GODWEB_CONFIG = config
20
+ rescue
21
+ GODWEB_CONFIG = config
22
+ end
23
+
24
+ GODWEB = GodWeb.new(config)
25
+
26
+ Sinatra::Application.public = File.dirname(__FILE__) + "/../public"
27
+ Sinatra::Application.views = File.dirname(__FILE__) + "/../views"
28
+
data/lib/god_web.rb ADDED
@@ -0,0 +1,165 @@
1
+ class GodWeb
2
+ def initialize(config)
3
+ @config = config
4
+ setup
5
+ ping
6
+ end
7
+
8
+ def self.watch(options = {})
9
+ options[:port] ||= 8888
10
+ options[:environment] ||= 'production'
11
+ start_string = "god_web #{options[:config]} -e #{options[:environment]} -p #{options[:port]}"
12
+ God.watch do |w|
13
+ w.name = "god_web"
14
+ w.interval = 1.minute
15
+ w.start = start_string
16
+ w.start_grace = 10.seconds
17
+ w.restart_grace = 10.seconds
18
+
19
+ w.start_if do |start|
20
+ start.condition(:process_running) do |c|
21
+ c.running = false
22
+ end
23
+ end
24
+
25
+ w.restart_if do |restart|
26
+ restart.condition(:memory_usage) do |c|
27
+ c.above = 20.megabytes
28
+ c.times = [3, 5]
29
+ end
30
+
31
+ restart.condition(:cpu_usage) do |c|
32
+ c.above = 25.percent
33
+ c.times = 5
34
+ end
35
+ end
36
+
37
+ w.lifecycle do |on|
38
+ on.condition(:flapping) do |c|
39
+ c.to_state = [:start, :restart]
40
+ c.times = 5
41
+ c.within = 5.minute
42
+ c.transition = :unmonitored
43
+ c.retry_in = 10.minutes
44
+ c.retry_times = 5
45
+ c.retry_within = 2.hours
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def setup
52
+ DRb.start_service
53
+ @server = DRbObject.new(nil, God::Socket.socket(@config['god_port']))
54
+ end
55
+
56
+ # ping server to ensure that it is responsive
57
+ def ping
58
+ tries = 3
59
+ begin
60
+ @server.ping
61
+ rescue Exception => e
62
+ if (tries -= 1) > 0
63
+ retry
64
+ end
65
+ raise e, "The server is not available (or you do not have permissions to access it)"
66
+ end
67
+ end
68
+
69
+ def self.possible_statuses(status)
70
+ case status
71
+ when :up
72
+ return %w{stop restart unmonitor}
73
+ when :unmonitored
74
+ return %w{start monitor}
75
+ else
76
+ return %w{start stop restart}
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def method_missing(meth,*args)
83
+ if %w{groups status log quit terminate}.include?(meth.to_s)
84
+ ping
85
+ send("#{meth}_command")
86
+ elsif %w{start stop restart unmonitor monitor}.include?(meth.to_s)
87
+ ping
88
+ lifecycle_command(args.first, meth.to_s)
89
+ else
90
+ raise NoMethodError
91
+ end
92
+ end
93
+
94
+ def groups_command
95
+ groups = []
96
+ @server.groups.each do |key, value|
97
+ groups << key
98
+ end
99
+ groups.sort
100
+ end
101
+
102
+ def status_command
103
+ @server.status
104
+ end
105
+
106
+ #TODO
107
+ # def log_command
108
+ # begin
109
+ # Signal.trap('INT') { exit }
110
+ # name = @args[1]
111
+ #
112
+ # unless name
113
+ # puts "You must specify a Task or Group name"
114
+ # exit!
115
+ # end
116
+ #
117
+ # t = Time.at(0)
118
+ # loop do
119
+ # print @server.running_log(name, t)
120
+ # t = Time.now
121
+ # sleep 1
122
+ # end
123
+ # rescue God::NoSuchWatchError
124
+ # puts "No such watch"
125
+ # rescue DRb::DRbConnError
126
+ # puts "The server went away"
127
+ # end
128
+ # end
129
+
130
+ def quit_command
131
+ begin
132
+ @server.terminate
133
+ return false
134
+ rescue DRb::DRbConnError
135
+ return true
136
+ end
137
+ end
138
+
139
+ def terminate_command
140
+ stopped_all = false
141
+ if @server.stop_all
142
+ stopped_all = true
143
+ end
144
+
145
+ begin
146
+ @server.terminate
147
+ return false
148
+ rescue DRb::DRbConnError
149
+ return stopped_all
150
+ end
151
+ end
152
+
153
+
154
+ def lifecycle_command(*args)
155
+ # get the name of the watch/group
156
+ name = args.first
157
+ command = args.last
158
+
159
+ # send @command
160
+ watches = @server.control(name, command)
161
+
162
+ watches.empty? ? [] : watches
163
+ end
164
+
165
+ end
@@ -0,0 +1,53 @@
1
+ module HttpAuthentication
2
+ module Basic
3
+
4
+ def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
5
+ authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
6
+ end
7
+
8
+ def authenticate_with_http_basic(&login_procedure)
9
+ authenticate(&login_procedure)
10
+ end
11
+
12
+ def request_http_basic_authentication(realm = "Application")
13
+ authentication_request(realm)
14
+ end
15
+
16
+ private
17
+
18
+ def authenticate(&login_procedure)
19
+ if authorization
20
+ login_procedure.call(*user_name_and_password)
21
+ end
22
+ end
23
+
24
+ def user_name_and_password
25
+ decode_credentials.split(/:/, 2)
26
+ end
27
+
28
+ def authorization
29
+ request.env['HTTP_AUTHORIZATION'] ||
30
+ request.env['X-HTTP_AUTHORIZATION'] ||
31
+ request.env['X_HTTP_AUTHORIZATION'] ||
32
+ request.env['REDIRECT_X_HTTP_AUTHORIZATION']
33
+ end
34
+
35
+ # Base64
36
+ def decode_credentials
37
+ (authorization.split.last || '').unpack("m").first
38
+ end
39
+
40
+ def authentication_request(realm)
41
+ status(401)
42
+ header("WWW-Authenticate" => %(Basic realm="#{realm.gsub(/"/, "")}"))
43
+ throw :halt, "HTTP Basic: Access denied.\n"
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ module Sinatra
50
+ class EventContext
51
+ include HttpAuthentication::Basic
52
+ end
53
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,372 @@
1
+ /* iui.css (c) 2007 by iUI Project Members, see LICENSE.txt for license */
2
+ body {
3
+ margin: 0;
4
+ font-family: Helvetica;
5
+ background: #FFFFFF;
6
+ color: #000000;
7
+ overflow-x: hidden;
8
+ -webkit-user-select: none;
9
+ -webkit-text-size-adjust: none;
10
+ }
11
+
12
+ body > *:not(.toolbar) {
13
+ display: none;
14
+ position: absolute;
15
+ margin: 0;
16
+ padding: 0;
17
+ left: 0;
18
+ top: 45px;
19
+ width: 100%;
20
+ min-height: 372px;
21
+ }
22
+
23
+ body[orient="landscape"] > *:not(.toolbar) {
24
+ min-height: 268px;
25
+ }
26
+
27
+ body > *[selected="true"] {
28
+ display: block;
29
+ }
30
+
31
+ a[selected], a:active {
32
+ background-color: #194fdb !important;
33
+ background-image: url(listArrowSel.png), url(selection.png) !important;
34
+ background-repeat: no-repeat, repeat-x;
35
+ background-position: right center, left top;
36
+ color: #FFFFFF !important;
37
+ }
38
+
39
+ a[selected="progress"] {
40
+ background-image: url(loading.gif), url(selection.png) !important;
41
+ }
42
+
43
+ /************************************************************************************************/
44
+
45
+ body > .toolbar {
46
+ box-sizing: border-box;
47
+ -moz-box-sizing: border-box;
48
+ -webkit-box-sizing: border-box;
49
+ border-bottom: 1px solid #2d3642;
50
+ border-top: 1px solid #6d84a2;
51
+ padding: 10px;
52
+ height: 45px;
53
+ background: url(toolbar.png) #6d84a2 repeat-x;
54
+ }
55
+
56
+ .toolbar > h1 {
57
+ position: absolute;
58
+ overflow: hidden;
59
+ left: 50%;
60
+ margin: 1px 0 0 -75px;
61
+ height: 45px;
62
+ font-size: 20px;
63
+ width: 150px;
64
+ font-weight: bold;
65
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
66
+ text-align: center;
67
+ text-overflow: ellipsis;
68
+ white-space: nowrap;
69
+ color: #FFFFFF;
70
+ }
71
+
72
+ body[orient="landscape"] > .toolbar > h1 {
73
+ margin-left: -125px;
74
+ width: 250px;
75
+ }
76
+
77
+ .button {
78
+ position: absolute;
79
+ overflow: hidden;
80
+ top: 8px;
81
+ right: 6px;
82
+ margin: 0;
83
+ border-width: 0 5px;
84
+ padding: 0 3px;
85
+ width: auto;
86
+ height: 30px;
87
+ line-height: 30px;
88
+ font-family: inherit;
89
+ font-size: 12px;
90
+ font-weight: bold;
91
+ color: #FFFFFF;
92
+ text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0;
93
+ text-overflow: ellipsis;
94
+ text-decoration: none;
95
+ white-space: nowrap;
96
+ background: none;
97
+ -webkit-border-image: url(toolButton.png) 0 5 0 5;
98
+ }
99
+
100
+ .blueButton {
101
+ -webkit-border-image: url(blueButton.png) 0 5 0 5;
102
+ border-width: 0 5px;
103
+ }
104
+
105
+ .leftButton {
106
+ left: 6px;
107
+ right: auto;
108
+ }
109
+
110
+ #backButton {
111
+ display: none;
112
+ left: 6px;
113
+ right: auto;
114
+ padding: 0;
115
+ max-width: 55px;
116
+ border-width: 0 8px 0 14px;
117
+ -webkit-border-image: url(backButton.png) 0 8 0 14;
118
+ }
119
+
120
+ .whiteButton,
121
+ .grayButton {
122
+ display: block;
123
+ border-width: 0 12px;
124
+ padding: 10px;
125
+ text-align: center;
126
+ font-size: 20px;
127
+ font-weight: bold;
128
+ text-decoration: inherit;
129
+ color: inherit;
130
+ }
131
+
132
+ .whiteButton {
133
+ -webkit-border-image: url(whiteButton.png) 0 12 0 12;
134
+ text-shadow: rgba(255, 255, 255, 0.7) 0 1px 0;
135
+ }
136
+
137
+ .grayButton {
138
+ -webkit-border-image: url(grayButton.png) 0 12 0 12;
139
+ color: #FFFFFF;
140
+ }
141
+
142
+ /************************************************************************************************/
143
+
144
+ body > ul > li {
145
+ position: relative;
146
+ margin: 0;
147
+ border-bottom: 1px solid #E0E0E0;
148
+ padding: 8px 0 8px 10px;
149
+ font-size: 20px;
150
+ font-weight: bold;
151
+ list-style: none;
152
+ }
153
+
154
+ body > ul > li.group {
155
+ position: relative;
156
+ top: -1px;
157
+ margin-bottom: -2px;
158
+ border-top: 1px solid #7d7d7d;
159
+ border-bottom: 1px solid #999999;
160
+ padding: 1px 10px;
161
+ background: url(listGroup.png) repeat-x;
162
+ font-size: 17px;
163
+ font-weight: bold;
164
+ text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
165
+ color: #FFFFFF;
166
+ }
167
+
168
+ body > ul > li.group:first-child {
169
+ top: 0;
170
+ border-top: none;
171
+ }
172
+
173
+ body > ul > li > a {
174
+ display: block;
175
+ margin: -8px 0 -8px -10px;
176
+ padding: 8px 32px 8px 10px;
177
+ text-decoration: none;
178
+ color: inherit;
179
+ background: url(listArrow.png) no-repeat right center;
180
+ }
181
+
182
+ a[target="_replace"] {
183
+ box-sizing: border-box;
184
+ -webkit-box-sizing: border-box;
185
+ padding-top: 25px;
186
+ padding-bottom: 25px;
187
+ font-size: 18px;
188
+ color: cornflowerblue;
189
+ background-color: #FFFFFF;
190
+ background-image: none;
191
+ }
192
+
193
+ /************************************************************************************************/
194
+
195
+ body > .dialog {
196
+ top: 0;
197
+ width: 100%;
198
+ min-height: 417px;
199
+ z-index: 2;
200
+ background: rgba(0, 0, 0, 0.8);
201
+ padding: 0;
202
+ text-align: right;
203
+ }
204
+
205
+ .dialog > fieldset {
206
+ box-sizing: border-box;
207
+ -webkit-box-sizing: border-box;
208
+ width: 100%;
209
+ margin: 0;
210
+ border: none;
211
+ border-top: 1px solid #6d84a2;
212
+ padding: 10px 6px;
213
+ background: url(toolbar.png) #7388a5 repeat-x;
214
+ }
215
+
216
+ .dialog > fieldset > h1 {
217
+ margin: 0 10px 0 10px;
218
+ padding: 0;
219
+ font-size: 20px;
220
+ font-weight: bold;
221
+ color: #FFFFFF;
222
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
223
+ text-align: center;
224
+ }
225
+
226
+ .dialog > fieldset > label {
227
+ position: absolute;
228
+ margin: 16px 0 0 6px;
229
+ font-size: 14px;
230
+ color: #999999;
231
+ }
232
+
233
+ input {
234
+ box-sizing: border-box;
235
+ -webkit-box-sizing: border-box;
236
+ width: 100%;
237
+ margin: 8px 0 0 0;
238
+ padding: 6px 6px 6px 44px;
239
+ font-size: 16px;
240
+ font-weight: normal;
241
+ }
242
+
243
+ /************************************************************************************************/
244
+
245
+ body > .panel {
246
+ box-sizing: border-box;
247
+ -webkit-box-sizing: border-box;
248
+ padding: 10px;
249
+ background: #c8c8c8 url(pinstripes.png);
250
+ }
251
+
252
+ .panel > fieldset {
253
+ position: relative;
254
+ margin: 0 0 20px 0;
255
+ padding: 0;
256
+ background: #FFFFFF;
257
+ -webkit-border-radius: 10px;
258
+ border: 1px solid #999999;
259
+ text-align: right;
260
+ font-size: 16px;
261
+ }
262
+
263
+ .row {
264
+ position: relative;
265
+ min-height: 42px;
266
+ border-bottom: 1px solid #999999;
267
+ -webkit-border-radius: 0;
268
+ text-align: right;
269
+ }
270
+
271
+ fieldset > .row:last-child {
272
+ border-bottom: none !important;
273
+ }
274
+
275
+ .row > input {
276
+ box-sizing: border-box;
277
+ -webkit-box-sizing: border-box;
278
+ margin: 0;
279
+ border: none;
280
+ padding: 12px 10px 0 110px;
281
+ height: 42px;
282
+ background: none;
283
+ }
284
+
285
+ .row > label {
286
+ position: absolute;
287
+ margin: 0 0 0 14px;
288
+ line-height: 42px;
289
+ font-weight: bold;
290
+ }
291
+
292
+ .row > .toggle {
293
+ position: absolute;
294
+ top: 6px;
295
+ right: 6px;
296
+ width: 100px;
297
+ height: 28px;
298
+ }
299
+
300
+ .toggle {
301
+ border: 1px solid #888888;
302
+ -webkit-border-radius: 6px;
303
+ background: #FFFFFF url(toggle.png) repeat-x;
304
+ font-size: 19px;
305
+ font-weight: bold;
306
+ line-height: 30px;
307
+ }
308
+
309
+ .toggle[toggled="true"] {
310
+ border: 1px solid #143fae;
311
+ background: #194fdb url(toggleOn.png) repeat-x;
312
+ }
313
+
314
+ .toggleOn {
315
+ display: none;
316
+ position: absolute;
317
+ width: 60px;
318
+ text-align: center;
319
+ left: 0;
320
+ top: 0;
321
+ color: #FFFFFF;
322
+ text-shadow: rgba(0, 0, 0, 0.4) 0px -1px 0;
323
+ }
324
+
325
+ .toggleOff {
326
+ position: absolute;
327
+ width: 60px;
328
+ text-align: center;
329
+ right: 0;
330
+ top: 0;
331
+ color: #666666;
332
+ }
333
+
334
+ .toggle[toggled="true"] > .toggleOn {
335
+ display: block;
336
+ }
337
+
338
+ .toggle[toggled="true"] > .toggleOff {
339
+ display: none;
340
+ }
341
+
342
+ .thumb {
343
+ position: absolute;
344
+ top: -1px;
345
+ left: -1px;
346
+ width: 40px;
347
+ height: 28px;
348
+ border: 1px solid #888888;
349
+ -webkit-border-radius: 6px;
350
+ background: #ffffff url(thumb.png) repeat-x;
351
+ }
352
+
353
+ .toggle[toggled="true"] > .thumb {
354
+ left: auto;
355
+ right: -1px;
356
+ }
357
+
358
+ .panel > h2 {
359
+ margin: 0 0 8px 14px;
360
+ font-size: inherit;
361
+ font-weight: bold;
362
+ color: #4d4d70;
363
+ text-shadow: rgba(255, 255, 255, 0.75) 2px 2px 0;
364
+ }
365
+
366
+ /************************************************************************************************/
367
+
368
+ #preloader {
369
+ display: none;
370
+ background-image: url(loading.gif), url(selection.png),
371
+ url(blueButton.png), url(listArrowSel.png), url(listGroup.png);
372
+ }
data/public/iui/iui.js ADDED
@@ -0,0 +1,383 @@
1
+ /*
2
+ Copyright (c) 2007, iUI Project Members
3
+ See LICENSE.txt for licensing terms
4
+ */
5
+
6
+
7
+ (function() {
8
+
9
+ var slideSpeed = 20;
10
+ var slideInterval = 0;
11
+
12
+ var currentPage = null;
13
+ var currentDialog = null;
14
+ var currentWidth = 0;
15
+ var currentHash = location.hash;
16
+ var hashPrefix = "#_";
17
+ var pageHistory = [];
18
+ var newPageCount = 0;
19
+ var checkTimer;
20
+
21
+ // *************************************************************************************************
22
+
23
+ window.iui =
24
+ {
25
+ showPage: function(page, backwards)
26
+ {
27
+ if (page)
28
+ {
29
+ if (currentDialog)
30
+ {
31
+ currentDialog.removeAttribute("selected");
32
+ currentDialog = null;
33
+ }
34
+
35
+ if (hasClass(page, "dialog"))
36
+ showDialog(page);
37
+ else
38
+ {
39
+ var fromPage = currentPage;
40
+ currentPage = page;
41
+
42
+ if (fromPage)
43
+ setTimeout(slidePages, 0, fromPage, page, backwards);
44
+ else
45
+ updatePage(page, fromPage);
46
+ }
47
+ }
48
+ },
49
+
50
+ showPageById: function(pageId)
51
+ {
52
+ var page = $(pageId);
53
+ if (page)
54
+ {
55
+ var index = pageHistory.indexOf(pageId);
56
+ var backwards = index != -1;
57
+ if (backwards)
58
+ pageHistory.splice(index, pageHistory.length);
59
+
60
+ iui.showPage(page, backwards);
61
+ }
62
+ },
63
+
64
+ showPageByHref: function(href, args, method, replace, cb)
65
+ {
66
+ var req = new XMLHttpRequest();
67
+ req.onerror = function()
68
+ {
69
+ if (cb)
70
+ cb(false);
71
+ };
72
+
73
+ req.onreadystatechange = function()
74
+ {
75
+ if (req.readyState == 4)
76
+ {
77
+ if (replace)
78
+ replaceElementWithSource(replace, req.responseText);
79
+ else
80
+ {
81
+ var frag = document.createElement("div");
82
+ frag.innerHTML = req.responseText;
83
+ iui.insertPages(frag.childNodes);
84
+ }
85
+ if (cb)
86
+ setTimeout(cb, 1000, true);
87
+ }
88
+ };
89
+
90
+ if (args)
91
+ {
92
+ req.open(method || "GET", href, true);
93
+ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
94
+ req.setRequestHeader("Content-Length", args.length);
95
+ req.send(args.join("&"));
96
+ }
97
+ else
98
+ {
99
+ req.open(method || "GET", href, true);
100
+ req.send(null);
101
+ }
102
+ },
103
+
104
+ insertPages: function(nodes)
105
+ {
106
+ var targetPage;
107
+ for (var i = 0; i < nodes.length; ++i)
108
+ {
109
+ var child = nodes[i];
110
+ if (child.nodeType == 1)
111
+ {
112
+ if (!child.id)
113
+ child.id = "__" + (++newPageCount) + "__";
114
+
115
+ var clone = $(child.id);
116
+ if (clone)
117
+ clone.parentNode.replaceChild(child, clone);
118
+ else
119
+ document.body.appendChild(child);
120
+
121
+ if (child.getAttribute("selected") == "true" || !targetPage)
122
+ targetPage = child;
123
+
124
+ --i;
125
+ }
126
+ }
127
+
128
+ if (targetPage)
129
+ iui.showPage(targetPage);
130
+ },
131
+
132
+ getSelectedPage: function()
133
+ {
134
+ for (var child = document.body.firstChild; child; child = child.nextSibling)
135
+ {
136
+ if (child.nodeType == 1 && child.getAttribute("selected") == "true")
137
+ return child;
138
+ }
139
+ }
140
+ };
141
+
142
+ // *************************************************************************************************
143
+
144
+ addEventListener("load", function(event)
145
+ {
146
+ var page = iui.getSelectedPage();
147
+ if (page)
148
+ iui.showPage(page);
149
+
150
+ setTimeout(preloadImages, 0);
151
+ setTimeout(checkOrientAndLocation, 0);
152
+ checkTimer = setInterval(checkOrientAndLocation, 300);
153
+ }, false);
154
+
155
+ addEventListener("click", function(event)
156
+ {
157
+ var link = findParent(event.target, "a");
158
+ if (link)
159
+ {
160
+ function unselect() { link.removeAttribute("selected"); }
161
+
162
+ if (link.href && link.hash && link.hash != "#")
163
+ {
164
+ link.setAttribute("selected", "true");
165
+ iui.showPage($(link.hash.substr(1)));
166
+ setTimeout(unselect, 500);
167
+ }
168
+ else if (link == $("backButton"))
169
+ history.back();
170
+ else if (link.getAttribute("type") == "submit")
171
+ submitForm(findParent(link, "form"));
172
+ else if (link.getAttribute("type") == "cancel")
173
+ cancelDialog(findParent(link, "form"));
174
+ else if (link.target == "_replace")
175
+ {
176
+ link.setAttribute("selected", "progress");
177
+ iui.showPageByHref(link.href, null, null, link, unselect);
178
+ }
179
+ else if (!link.target)
180
+ {
181
+ link.setAttribute("selected", "progress");
182
+ iui.showPageByHref(link.href, null, null, null, unselect);
183
+ }
184
+ else
185
+ return;
186
+
187
+ event.preventDefault();
188
+ }
189
+ }, true);
190
+
191
+ addEventListener("click", function(event)
192
+ {
193
+ var div = findParent(event.target, "div");
194
+ if (div && hasClass(div, "toggle"))
195
+ {
196
+ div.setAttribute("toggled", div.getAttribute("toggled") != "true");
197
+ event.preventDefault();
198
+ }
199
+ }, true);
200
+
201
+ function checkOrientAndLocation()
202
+ {
203
+ if (window.innerWidth != currentWidth)
204
+ {
205
+ currentWidth = window.innerWidth;
206
+ var orient = currentWidth == 320 ? "profile" : "landscape";
207
+ document.body.setAttribute("orient", orient);
208
+ setTimeout(scrollTo, 100, 0, 1);
209
+ }
210
+
211
+ if (location.hash != currentHash)
212
+ {
213
+ var pageId = location.hash.substr(hashPrefix.length)
214
+ iui.showPageById(pageId);
215
+ }
216
+ }
217
+
218
+ function showDialog(page)
219
+ {
220
+ currentDialog = page;
221
+ page.setAttribute("selected", "true");
222
+
223
+ if (hasClass(page, "dialog") && !page.target)
224
+ showForm(page);
225
+ }
226
+
227
+ function showForm(form)
228
+ {
229
+ form.onsubmit = function(event)
230
+ {
231
+ event.preventDefault();
232
+ submitForm(form);
233
+ };
234
+
235
+ form.onclick = function(event)
236
+ {
237
+ if (event.target == form && hasClass(form, "dialog"))
238
+ cancelDialog(form);
239
+ };
240
+ }
241
+
242
+ function cancelDialog(form)
243
+ {
244
+ form.removeAttribute("selected");
245
+ }
246
+
247
+ function updatePage(page, fromPage)
248
+ {
249
+ if (!page.id)
250
+ page.id = "__" + (++newPageCount) + "__";
251
+
252
+ location.href = currentHash = hashPrefix + page.id;
253
+ pageHistory.push(page.id);
254
+
255
+ var pageTitle = $("pageTitle");
256
+ if (page.title)
257
+ pageTitle.innerHTML = page.title;
258
+
259
+ if (page.localName.toLowerCase() == "form" && !page.target)
260
+ showForm(page);
261
+
262
+ var backButton = $("backButton");
263
+ if (backButton)
264
+ {
265
+ var prevPage = $(pageHistory[pageHistory.length-2]);
266
+ if (prevPage && !page.getAttribute("hideBackButton"))
267
+ {
268
+ backButton.style.display = "inline";
269
+ backButton.innerHTML = prevPage.title ? prevPage.title : "Back";
270
+ }
271
+ else
272
+ backButton.style.display = "none";
273
+ }
274
+ }
275
+
276
+ function slidePages(fromPage, toPage, backwards)
277
+ {
278
+ var axis = (backwards ? fromPage : toPage).getAttribute("axis");
279
+ if (axis == "y")
280
+ (backwards ? fromPage : toPage).style.top = "100%";
281
+ else
282
+ toPage.style.left = "100%";
283
+
284
+ toPage.setAttribute("selected", "true");
285
+ scrollTo(0, 1);
286
+ clearInterval(checkTimer);
287
+
288
+ var percent = 100;
289
+ slide();
290
+ var timer = setInterval(slide, slideInterval);
291
+
292
+ function slide()
293
+ {
294
+ percent -= slideSpeed;
295
+ if (percent <= 0)
296
+ {
297
+ percent = 0;
298
+ if (!hasClass(toPage, "dialog"))
299
+ fromPage.removeAttribute("selected");
300
+ clearInterval(timer);
301
+ checkTimer = setInterval(checkOrientAndLocation, 300);
302
+ setTimeout(updatePage, 0, toPage, fromPage);
303
+ }
304
+
305
+ if (axis == "y")
306
+ {
307
+ backwards
308
+ ? fromPage.style.top = (100-percent) + "%"
309
+ : toPage.style.top = percent + "%";
310
+ }
311
+ else
312
+ {
313
+ fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%";
314
+ toPage.style.left = (backwards ? -percent : percent) + "%";
315
+ }
316
+ }
317
+ }
318
+
319
+ function preloadImages()
320
+ {
321
+ var preloader = document.createElement("div");
322
+ preloader.id = "preloader";
323
+ document.body.appendChild(preloader);
324
+ }
325
+
326
+ function submitForm(form)
327
+ {
328
+ iui.showPageByHref(form.action || "POST", encodeForm(form), form.method);
329
+ }
330
+
331
+ function encodeForm(form)
332
+ {
333
+ function encode(inputs)
334
+ {
335
+ for (var i = 0; i < inputs.length; ++i)
336
+ {
337
+ if (inputs[i].name)
338
+ args.push(inputs[i].name + "=" + escape(inputs[i].value));
339
+ }
340
+ }
341
+
342
+ var args = [];
343
+ encode(form.getElementsByTagName("input"));
344
+ encode(form.getElementsByTagName("select"));
345
+ return args;
346
+ }
347
+
348
+ function findParent(node, localName)
349
+ {
350
+ while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
351
+ node = node.parentNode;
352
+ return node;
353
+ }
354
+
355
+ function hasClass(self, name)
356
+ {
357
+ var re = new RegExp("(^|\\s)"+name+"($|\\s)");
358
+ return re.exec(self.getAttribute("class")) != null;
359
+ }
360
+
361
+ function replaceElementWithSource(replace, source)
362
+ {
363
+ var page = replace.parentNode;
364
+ var parent = replace;
365
+ while (page.parentNode != document.body)
366
+ {
367
+ page = page.parentNode;
368
+ parent = parent.parentNode;
369
+ }
370
+
371
+ var frag = document.createElement(parent.localName);
372
+ frag.innerHTML = source;
373
+
374
+ page.removeChild(parent);
375
+
376
+ while (frag.firstChild)
377
+ page.appendChild(frag.firstChild);
378
+ }
379
+
380
+ function $(id) { return document.getElementById(id); }
381
+ function ddd() { console.log.apply(console, arguments); }
382
+
383
+ })();
@@ -0,0 +1 @@
1
+ body{margin:0;font-family:Helvetica;background:#FFF;color:#000;overflow-x:hidden;-webkit-user-select:none;-webkit-text-size-adjust:none;}body>*:not(.toolbar){display:none;position:absolute;margin:0;padding:0;left:0;top:45px;width:100%;min-height:372px;}body[orient="landscape"]>*:not(.toolbar){min-height:268px;}body>*[selected="true"]{display:block;}a[selected],a:active{background-color:#194fdb!important;background-image:url(listArrowSel.png),url(selection.png)!important;background-repeat:no-repeat,repeat-x;background-position:right center,left top;color:#FFF!important;}a[selected="progress"]{background-image:url(loading.gif),url(selection.png)!important;}body>.toolbar{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-bottom:1px solid #2d3642;border-top:1px solid #6d84a2;padding:10px;height:45px;background:url(toolbar.png) #6d84a2 repeat-x;}.toolbar>h1{position:absolute;overflow:hidden;left:50%;margin:1px 0 0 -75px;height:45px;font-size:20px;width:150px;font-weight:bold;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;text-align:center;text-overflow:ellipsis;white-space:nowrap;color:#FFF;}body[orient="landscape"]>.toolbar>h1{margin-left:-125px;width:250px;}.button{position:absolute;overflow:hidden;top:8px;right:6px;margin:0;border-width:0 5px;padding:0 3px;width:auto;height:30px;line-height:30px;font-family:inherit;font-size:12px;font-weight:bold;color:#FFF;text-shadow:rgba(0,0,0,0.6) 0 -1px 0;text-overflow:ellipsis;text-decoration:none;white-space:nowrap;background:none;-webkit-border-image:url(toolButton.png) 0 5 0 5;}.blueButton{-webkit-border-image:url(blueButton.png) 0 5 0 5;border-width:0 5px;}.leftButton{left:6px;right:auto;}#backButton{display:none;left:6px;right:auto;padding:0;max-width:55px;border-width:0 8px 0 14px;-webkit-border-image:url(backButton.png) 0 8 0 14;}.whiteButton,.grayButton{display:block;border-width:0 12px;padding:10px;text-align:center;font-size:20px;font-weight:bold;text-decoration:inherit;color:inherit;}.whiteButton{-webkit-border-image:url(whiteButton.png) 0 12 0 12;text-shadow:rgba(255,255,255,0.7) 0 1px 0;}.grayButton{-webkit-border-image:url(grayButton.png) 0 12 0 12;color:#FFF;}body>ul>li{position:relative;margin:0;border-bottom:1px solid #E0E0E0;padding:8px 0 8px 10px;font-size:20px;font-weight:bold;list-style:none;}body>ul>li.group{position:relative;top:-1px;margin-bottom:-2px;border-top:1px solid #7d7d7d;border-bottom:1px solid #999;padding:1px 10px;background:url(listGroup.png) repeat-x;font-size:17px;font-weight:bold;text-shadow:rgba(0,0,0,0.4) 0 1px 0;color:#FFF;}body>ul>li.group:first-child{top:0;border-top:none;}body>ul>li>a{display:block;margin:-8px 0 -8px -10px;padding:8px 32px 8px 10px;text-decoration:none;color:inherit;background:url(listArrow.png) no-repeat right center;}a[target="_replace"]{box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:25px;padding-bottom:25px;font-size:18px;color:cornflowerblue;background-color:#FFF;background-image:none;}body>.dialog{top:0;width:100%;min-height:417px;z-index:2;background:rgba(0,0,0,0.8);padding:0;text-align:right;}.dialog>fieldset{box-sizing:border-box;-webkit-box-sizing:border-box;width:100%;margin:0;border:none;border-top:1px solid #6d84a2;padding:10px 6px;background:url(toolbar.png) #7388a5 repeat-x;}.dialog>fieldset>h1{margin:0 10px 0 10px;padding:0;font-size:20px;font-weight:bold;color:#FFF;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;text-align:center;}.dialog>fieldset>label{position:absolute;margin:16px 0 0 6px;font-size:14px;color:#999;}input{box-sizing:border-box;-webkit-box-sizing:border-box;width:100%;margin:8px 0 0 0;padding:6px 6px 6px 44px;font-size:16px;font-weight:normal;}body>.panel{box-sizing:border-box;-webkit-box-sizing:border-box;padding:10px;background:#c8c8c8 url(pinstripes.png);}.panel>fieldset{position:relative;margin:0 0 20px 0;padding:0;background:#FFF;-webkit-border-radius:10px;border:1px solid #999;text-align:right;font-size:16px;}.row{position:relative;min-height:42px;border-bottom:1px solid #999;-webkit-border-radius:0;text-align:right;}fieldset>.row:last-child{border-bottom:none!important;}.row>input{box-sizing:border-box;-webkit-box-sizing:border-box;margin:0;border:none;padding:12px 10px 0 110px;height:42px;background:none;}.row>label{position:absolute;margin:0 0 0 14px;line-height:42px;font-weight:bold;}.row>.toggle{position:absolute;top:6px;right:6px;width:100px;height:28px;}.toggle{border:1px solid #888;-webkit-border-radius:6px;background:#FFF url(toggle.png) repeat-x;font-size:19px;font-weight:bold;line-height:30px;}.toggle[toggled="true"]{border:1px solid #143fae;background:#194fdb url(toggleOn.png) repeat-x;}.toggleOn{display:none;position:absolute;width:60px;text-align:center;left:0;top:0;color:#FFF;text-shadow:rgba(0,0,0,0.4) 0 -1px 0;}.toggleOff{position:absolute;width:60px;text-align:center;right:0;top:0;color:#666;}.toggle[toggled="true"]>.toggleOn{display:block;}.toggle[toggled="true"]>.toggleOff{display:none;}.thumb{position:absolute;top:-1px;left:-1px;width:40px;height:28px;border:1px solid #888;-webkit-border-radius:6px;background:#fff url(thumb.png) repeat-x;}.toggle[toggled="true"]>.thumb{left:auto;right:-1px;}.panel>h2{margin:0 0 8px 14px;font-size:inherit;font-weight:bold;color:#4d4d70;text-shadow:rgba(255,255,255,0.75) 2px 2px 0;}#preloader{display:none;background-image:url(loading.gif),url(selection.png),url(blueButton.png),url(listArrowSel.png),url(listGroup.png);}
@@ -0,0 +1 @@
1
+ (function(){var _1=20;var _2=0;var _3=null;var _4=null;var _5=0;var _6=location.hash;var _7="#_";var _8=[];var _9=0;var _a;window.iui={showPage:function(_b,_c){if(_b){if(_4){_4.removeAttribute("selected");_4=null;}if(hasClass(_b,"dialog")){showDialog(_b);}else{var _d=_3;_3=_b;if(_d){setTimeout(slidePages,0,_d,_b,_c);}else{updatePage(_b,_d);}}}},showPageById:function(_e){var _f=$(_e);if(_f){var _10=_8.indexOf(_e);var _11=_10!=-1;if(_11){_8.splice(_10,_8.length);}iui.showPage(_f,_11);}},showPageByHref:function(_12,_13,_14,_15,cb){var req=new XMLHttpRequest();req.onerror=function(){if(cb){cb(false);}};req.onreadystatechange=function(){if(req.readyState==4){if(_15){replaceElementWithSource(_15,req.responseText);}else{var _18=document.createElement("div");_18.innerHTML=req.responseText;iui.insertPages(_18.childNodes);}if(cb){setTimeout(cb,1000,true);}}};if(_13){req.open(_14||"GET",_12,true);req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");req.setRequestHeader("Content-Length",_13.length);req.send(_13.join("&"));}else{req.open(_14||"GET",_12,true);req.send(null);}},insertPages:function(_19){var _1a;for(var i=0;i<_19.length;++i){var _1c=_19[i];if(_1c.nodeType==1){if(!_1c.id){_1c.id="__"+(++_9)+"__";}var _1d=$(_1c.id);if(_1d){_1d.parentNode.replaceChild(_1c,_1d);}else{document.body.appendChild(_1c);}if(_1c.getAttribute("selected")=="true"||!_1a){_1a=_1c;}--i;}}if(_1a){iui.showPage(_1a);}},getSelectedPage:function(){for(var _1e=document.body.firstChild;_1e;_1e=_1e.nextSibling){if(_1e.nodeType==1&&_1e.getAttribute("selected")=="true"){return _1e;}}}};addEventListener("load",function(_1f){var _20=iui.getSelectedPage();if(_20){iui.showPage(_20);}setTimeout(preloadImages,0);setTimeout(checkOrientAndLocation,0);_a=setInterval(checkOrientAndLocation,300);},false);addEventListener("click",function(_21){var _22=findParent(_21.target,"a");if(_22){function unselect(){_22.removeAttribute("selected");}if(_22.href&&_22.hash&&_22.hash!="#"){_22.setAttribute("selected","true");iui.showPage($(_22.hash.substr(1)));setTimeout(unselect,500);}else{if(_22==$("backButton")){history.back();}else{if(_22.getAttribute("type")=="submit"){submitForm(findParent(_22,"form"));}else{if(_22.getAttribute("type")=="cancel"){cancelDialog(findParent(_22,"form"));}else{if(_22.target=="_replace"){_22.setAttribute("selected","progress");iui.showPageByHref(_22.href,null,null,_22,unselect);}else{if(!_22.target){_22.setAttribute("selected","progress");iui.showPageByHref(_22.href,null,null,null,unselect);}else{return;}}}}}}_21.preventDefault();}},true);addEventListener("click",function(_23){var div=findParent(_23.target,"div");if(div&&hasClass(div,"toggle")){div.setAttribute("toggled",div.getAttribute("toggled")!="true");_23.preventDefault();}},true);function checkOrientAndLocation(){if(window.innerWidth!=_5){_5=window.innerWidth;var _25=_5==320?"profile":"landscape";document.body.setAttribute("orient",_25);setTimeout(scrollTo,100,0,1);}if(location.hash!=_6){var _26=location.hash.substr(_7.length);iui.showPageById(_26);}}function showDialog(_27){_4=_27;_27.setAttribute("selected","true");if(hasClass(_27,"dialog")&&!_27.target){showForm(_27);}}function showForm(_28){_28.onsubmit=function(_29){_29.preventDefault();submitForm(_28);};_28.onclick=function(_2a){if(_2a.target==_28&&hasClass(_28,"dialog")){cancelDialog(_28);}};}function cancelDialog(_2b){_2b.removeAttribute("selected");}function updatePage(_2c,_2d){if(!_2c.id){_2c.id="__"+(++_9)+"__";}location.href=_6=_7+_2c.id;_8.push(_2c.id);var _2e=$("pageTitle");if(_2c.title){_2e.innerHTML=_2c.title;}if(_2c.localName.toLowerCase()=="form"&&!_2c.target){showForm(_2c);}var _2f=$("backButton");if(_2f){var _30=$(_8[_8.length-2]);if(_30&&!_2c.getAttribute("hideBackButton")){_2f.style.display="inline";_2f.innerHTML=_30.title?_30.title:"Back";}else{_2f.style.display="none";}}}function slidePages(_31,_32,_33){var _34=(_33?_31:_32).getAttribute("axis");if(_34=="y"){(_33?_31:_32).style.top="100%";}else{_32.style.left="100%";}_32.setAttribute("selected","true");scrollTo(0,1);clearInterval(_a);var _35=100;slide();var _36=setInterval(slide,_2);function slide(){_35-=_1;if(_35<=0){_35=0;if(!hasClass(_32,"dialog")){_31.removeAttribute("selected");}clearInterval(_36);_a=setInterval(checkOrientAndLocation,300);setTimeout(updatePage,0,_32,_31);}if(_34=="y"){_33?_31.style.top=(100-_35)+"%":_32.style.top=_35+"%";}else{_31.style.left=(_33?(100-_35):(_35-100))+"%";_32.style.left=(_33?-_35:_35)+"%";}}}function preloadImages(){var _37=document.createElement("div");_37.id="preloader";document.body.appendChild(_37);}function submitForm(_38){iui.showPageByHref(_38.action||"POST",encodeForm(_38),_38.method);}function encodeForm(_39){function encode(_3a){for(var i=0;i<_3a.length;++i){if(_3a[i].name){args.push(_3a[i].name+"="+escape(_3a[i].value));}}}var _3c=[];encode(_39.getElementsByTagName("input"));encode(_39.getElementsByTagName("select"));return _3c;}function findParent(_3d,_3e){while(_3d&&(_3d.nodeType!=1||_3d.localName.toLowerCase()!=_3e)){_3d=_3d.parentNode;}return _3d;}function hasClass(_3f,_40){var re=new RegExp("(^|\\s)"+_40+"($|\\s)");return re.exec(_3f.getAttribute("class"))!=null;}function replaceElementWithSource(_42,_43){var _44=_42.parentNode;var _45=_42;while(_44.parentNode!=document.body){_44=_44.parentNode;_45=_45.parentNode;}var _46=document.createElement(_45.localName);_46.innerHTML=_43;_44.removeChild(_45);while(_46.firstChild){_44.appendChild(_46.firstChild);}}function $(id){return document.getElementById(id);}function ddd(){console.log.apply(console,arguments);}})();
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/views/command.erb ADDED
@@ -0,0 +1,3 @@
1
+ <div id="<%= @command %>ing_<%= @watch %>" class="panel" title="<%= @title %>">
2
+ <h2><%= @success ? 'Success' : 'Failed' %></h2>
3
+ </div>
data/views/status.erb ADDED
@@ -0,0 +1,27 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @title %></title>
4
+ <meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
5
+ <style type="text/css" media="screen">@import "/iui/iui.css";</style>
6
+ <script type="application/x-javascript" src="/iui/iui.js"></script>
7
+ </head>
8
+ <body>
9
+ <div class="toolbar">
10
+ <h1 id="pageTitle"><%= @title %></h1>
11
+ <a id="backButton" class="button" href="#"></a>
12
+ <a class="button" href="/" target="_self">Refresh</a>
13
+ </div>
14
+ <ul id="home" selected="true" title="GodWeb">
15
+ <% unless @groups.empty? %>
16
+ <li class="group">Groups</li>
17
+ <% @groups.each do |watch| %>
18
+ <li id="<%= watch %>"><a href="/g/<%= watch %>"><%= watch %></a></li>
19
+ <% end %>
20
+ <% end %>
21
+ <li class="group">Watches</li>
22
+ <% @watches.each do |watch| %>
23
+ <li id="<%= watch %>" class="<%= @statuses[watch][:state] %>"><a href="/w/<%= watch %>"><%= watch %>[<%= @statuses[watch][:state] %>]</a></li>
24
+ <% end %>
25
+ </ul>
26
+ </body>
27
+ </html>
data/views/watch.erb ADDED
@@ -0,0 +1,5 @@
1
+ <ul id="<%= @watch %>_commands" title="<%= @title %>">
2
+ <% @commands.each do |command| %>
3
+ <li id="<%= command %>_<%= @watch %>" class="<%= command %>"><a href="/w/<%= @watch %>/<%= command %>"><%= command %></a></li>
4
+ <% end %>
5
+ </ul>
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mathieuravaux-god_web
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Jesse Newland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-19 00:00:00 -07:00
13
+ default_executable: god_web
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: god
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.7.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: sinatra
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.2
34
+ version:
35
+ description: iPhone friendly web UI for God
36
+ email: jnewland@gmail.com
37
+ executables:
38
+ - god_web
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - Readme.textile
43
+ files:
44
+ - bin/god_web
45
+ - lib/environment.rb
46
+ - lib/god_web.rb
47
+ - lib/sinatra_http_auth.rb
48
+ - views/command.erb
49
+ - views/status.erb
50
+ - views/watch.erb
51
+ - public/iui/backButton.png
52
+ - public/iui/blueButton.png
53
+ - public/iui/cancel.png
54
+ - public/iui/grayButton.png
55
+ - public/iui/iui.css
56
+ - public/iui/iui.js
57
+ - public/iui/iuix.css
58
+ - public/iui/iuix.js
59
+ - public/iui/listArrow.png
60
+ - public/iui/listArrowSel.png
61
+ - public/iui/listGroup.png
62
+ - public/iui/loading.gif
63
+ - public/iui/pinstripes.png
64
+ - public/iui/selection.png
65
+ - public/iui/thumb.png
66
+ - public/iui/toggle.png
67
+ - public/iui/toggleOn.png
68
+ - public/iui/toolButton.png
69
+ - public/iui/toolbar.png
70
+ - public/iui/whiteButton.png
71
+ - Readme.textile
72
+ has_rdoc: false
73
+ homepage: http://github.com/jnewland/god_web
74
+ licenses:
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project: god_web
95
+ rubygems_version: 1.3.5
96
+ signing_key:
97
+ specification_version: 2
98
+ summary: iPhone friendly web UI for God
99
+ test_files: []
100
+