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 +82 -0
- data/bin/god_web +65 -0
- data/lib/environment.rb +28 -0
- data/lib/god_web.rb +165 -0
- data/lib/sinatra_http_auth.rb +53 -0
- data/public/iui/backButton.png +0 -0
- data/public/iui/blueButton.png +0 -0
- data/public/iui/cancel.png +0 -0
- data/public/iui/grayButton.png +0 -0
- data/public/iui/iui.css +372 -0
- data/public/iui/iui.js +383 -0
- data/public/iui/iuix.css +1 -0
- data/public/iui/iuix.js +1 -0
- data/public/iui/listArrow.png +0 -0
- data/public/iui/listArrowSel.png +0 -0
- data/public/iui/listGroup.png +0 -0
- data/public/iui/loading.gif +0 -0
- data/public/iui/pinstripes.png +0 -0
- data/public/iui/selection.png +0 -0
- data/public/iui/thumb.png +0 -0
- data/public/iui/toggle.png +0 -0
- data/public/iui/toggleOn.png +0 -0
- data/public/iui/toolButton.png +0 -0
- data/public/iui/toolbar.png +0 -0
- data/public/iui/whiteButton.png +0 -0
- data/views/command.erb +3 -0
- data/views/status.erb +27 -0
- data/views/watch.erb +5 -0
- metadata +100 -0
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
|
data/lib/environment.rb
ADDED
@@ -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
|
data/public/iui/iui.css
ADDED
@@ -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
|
+
})();
|
data/public/iui/iuix.css
ADDED
@@ -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);}
|
data/public/iui/iuix.js
ADDED
@@ -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
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
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
|
+
|