wycats-merb-core 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +992 -0
- data/CONTRIBUTORS +94 -0
- data/LICENSE +20 -0
- data/PUBLIC_CHANGELOG +142 -0
- data/README +21 -0
- data/Rakefile +458 -0
- data/TODO +0 -0
- data/bin/merb +11 -0
- data/bin/merb-specs +5 -0
- data/lib/merb-core.rb +598 -0
- data/lib/merb-core/autoload.rb +31 -0
- data/lib/merb-core/bootloader.rb +717 -0
- data/lib/merb-core/config.rb +305 -0
- data/lib/merb-core/constants.rb +45 -0
- data/lib/merb-core/controller/abstract_controller.rb +568 -0
- data/lib/merb-core/controller/exceptions.rb +315 -0
- data/lib/merb-core/controller/merb_controller.rb +256 -0
- data/lib/merb-core/controller/mime.rb +107 -0
- data/lib/merb-core/controller/mixins/authentication.rb +123 -0
- data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
- data/lib/merb-core/controller/mixins/controller.rb +319 -0
- data/lib/merb-core/controller/mixins/render.rb +513 -0
- data/lib/merb-core/controller/mixins/responder.rb +469 -0
- data/lib/merb-core/controller/template.rb +254 -0
- data/lib/merb-core/core_ext.rb +9 -0
- data/lib/merb-core/core_ext/hash.rb +7 -0
- data/lib/merb-core/core_ext/kernel.rb +340 -0
- data/lib/merb-core/dispatch/cookies.rb +130 -0
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +94 -0
- data/lib/merb-core/dispatch/dispatcher.rb +176 -0
- data/lib/merb-core/dispatch/request.rb +729 -0
- data/lib/merb-core/dispatch/router.rb +151 -0
- data/lib/merb-core/dispatch/router/behavior.rb +566 -0
- data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
- data/lib/merb-core/dispatch/router/resources.rb +191 -0
- data/lib/merb-core/dispatch/router/route.rb +511 -0
- data/lib/merb-core/dispatch/session.rb +222 -0
- data/lib/merb-core/dispatch/session/container.rb +74 -0
- data/lib/merb-core/dispatch/session/cookie.rb +173 -0
- data/lib/merb-core/dispatch/session/memcached.rb +68 -0
- data/lib/merb-core/dispatch/session/memory.rb +99 -0
- data/lib/merb-core/dispatch/session/store_container.rb +150 -0
- data/lib/merb-core/dispatch/worker.rb +28 -0
- data/lib/merb-core/gem_ext/erubis.rb +77 -0
- data/lib/merb-core/logger.rb +203 -0
- data/lib/merb-core/plugins.rb +67 -0
- data/lib/merb-core/rack.rb +25 -0
- data/lib/merb-core/rack/adapter.rb +44 -0
- data/lib/merb-core/rack/adapter/ebb.rb +25 -0
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
- data/lib/merb-core/rack/adapter/irb.rb +118 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/runner.rb +28 -0
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/thin.rb +39 -0
- data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
- data/lib/merb-core/rack/adapter/webrick.rb +36 -0
- data/lib/merb-core/rack/application.rb +32 -0
- data/lib/merb-core/rack/handler/mongrel.rb +97 -0
- data/lib/merb-core/rack/middleware.rb +20 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +29 -0
- data/lib/merb-core/rack/middleware/content_length.rb +18 -0
- data/lib/merb-core/rack/middleware/csrf.rb +73 -0
- data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
- data/lib/merb-core/rack/middleware/profiler.rb +19 -0
- data/lib/merb-core/rack/middleware/static.rb +45 -0
- data/lib/merb-core/rack/middleware/tracer.rb +20 -0
- data/lib/merb-core/server.rb +284 -0
- data/lib/merb-core/tasks/audit.rake +68 -0
- data/lib/merb-core/tasks/gem_management.rb +229 -0
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +80 -0
- data/lib/merb-core/tasks/stats.rake +71 -0
- data/lib/merb-core/test.rb +11 -0
- data/lib/merb-core/test/helpers.rb +9 -0
- data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
- data/lib/merb-core/test/helpers/request_helper.rb +393 -0
- data/lib/merb-core/test/helpers/route_helper.rb +39 -0
- data/lib/merb-core/test/helpers/view_helper.rb +121 -0
- data/lib/merb-core/test/matchers.rb +9 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +351 -0
- data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +375 -0
- data/lib/merb-core/test/run_specs.rb +49 -0
- data/lib/merb-core/test/tasks/spectasks.rb +68 -0
- data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
- data/lib/merb-core/test/test_ext/object.rb +14 -0
- data/lib/merb-core/test/test_ext/string.rb +14 -0
- data/lib/merb-core/vendor/facets.rb +2 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
- data/lib/merb-core/vendor/facets/inflect.rb +342 -0
- data/lib/merb-core/version.rb +3 -0
- metadata +253 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
module Merb
|
2
|
+
|
3
|
+
class Cookies < Mash
|
4
|
+
|
5
|
+
def initialize(constructor = {})
|
6
|
+
@_options_lookup = Mash.new
|
7
|
+
@_cookie_defaults = { "domain" => Merb::Controller._default_cookie_domain, "path" => '/' }
|
8
|
+
super constructor
|
9
|
+
end
|
10
|
+
|
11
|
+
# Implicit assignment of cookie key and value.
|
12
|
+
#
|
13
|
+
# ==== Parameters
|
14
|
+
# name<~to_s>:: Name of the cookie.
|
15
|
+
# value<~to_s>:: Value of the cookie.
|
16
|
+
#
|
17
|
+
# ==== Notes
|
18
|
+
# By using this method, a cookie key is marked for being
|
19
|
+
# included in the Set-Cookie response header.
|
20
|
+
def []=(key, value)
|
21
|
+
@_options_lookup[key] ||= {}
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
# Explicit assignment of cookie key, value and options
|
26
|
+
#
|
27
|
+
# ==== Parameters
|
28
|
+
# name<~to_s>:: Name of the cookie.
|
29
|
+
# value<~to_s>:: Value of the cookie.
|
30
|
+
# options<Hash>:: Additional options for the cookie (see below).
|
31
|
+
#
|
32
|
+
# ==== Options (options)
|
33
|
+
# :path<String>:: The path for which this cookie applies. Defaults to "/".
|
34
|
+
# :expires<Time>:: Cookie expiry date.
|
35
|
+
# :domain<String>:: The domain for which this cookie applies.
|
36
|
+
# :secure<Boolean>:: Security flag.
|
37
|
+
#
|
38
|
+
# ==== Notes
|
39
|
+
# By using this method, a cookie key is marked for being
|
40
|
+
# included in the Set-Cookie response header.
|
41
|
+
def set_cookie(name, value, options = {})
|
42
|
+
@_options_lookup[name] = options
|
43
|
+
self[name] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
# Removes the cookie on the client machine by setting the value to an empty
|
47
|
+
# string and setting its expiration date into the past.
|
48
|
+
#
|
49
|
+
# ==== Parameters
|
50
|
+
# name<~to_s>:: Name of the cookie to delete.
|
51
|
+
# options<Hash>:: Additional options to pass to +set_cookie+.
|
52
|
+
def delete(name, options = {})
|
53
|
+
set_cookie(name, "", options.merge("expires" => Time.at(0)))
|
54
|
+
end
|
55
|
+
|
56
|
+
# Generate any necessary headers.
|
57
|
+
#
|
58
|
+
# ==== Returns
|
59
|
+
# Hash:: The headers to set, or an empty array if no cookies are set.
|
60
|
+
def extract_headers(controller_defaults = {})
|
61
|
+
defaults = @_cookie_defaults.merge(controller_defaults)
|
62
|
+
cookies = []
|
63
|
+
self.each do |name, value|
|
64
|
+
# Only set cookies that marked for inclusion in the response header.
|
65
|
+
next unless @_options_lookup[name]
|
66
|
+
options = defaults.merge(@_options_lookup[name])
|
67
|
+
if (expiry = options["expires"]).respond_to?(:gmtime)
|
68
|
+
options["expires"] = expiry.gmtime.strftime(Merb::Const::COOKIE_EXPIRATION_FORMAT)
|
69
|
+
end
|
70
|
+
secure = options.delete("secure")
|
71
|
+
kookie = "#{name}=#{Merb::Request.escape(value)}; "
|
72
|
+
# WebKit in particular doens't like empty cookie options - skip them.
|
73
|
+
options.each { |k, v| kookie << "#{k}=#{v}; " unless v.blank? }
|
74
|
+
kookie << 'secure' if secure
|
75
|
+
cookies << kookie.rstrip
|
76
|
+
end
|
77
|
+
cookies.empty? ? {} : { 'Set-Cookie' => cookies }
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
module CookiesMixin
|
83
|
+
|
84
|
+
def self.included(base)
|
85
|
+
# Allow per-controller default cookie domains (see callback below)
|
86
|
+
base.class_inheritable_accessor :_default_cookie_domain
|
87
|
+
base._default_cookie_domain = Merb::Config[:default_cookie_domain]
|
88
|
+
|
89
|
+
# Add a callback to enable Set-Cookie headers
|
90
|
+
base._after_dispatch_callbacks << lambda do |c|
|
91
|
+
headers = c.request.cookies.extract_headers("domain" => c._default_cookie_domain)
|
92
|
+
c.headers.update(headers)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# ==== Returns
|
97
|
+
# Merb::Cookies::
|
98
|
+
# A new Merb::Cookies instance representing the cookies that came in
|
99
|
+
# from the request object
|
100
|
+
#
|
101
|
+
# ==== Notes
|
102
|
+
# Headers are passed into the cookie object so that you can do:
|
103
|
+
# cookies[:foo] = "bar"
|
104
|
+
def cookies
|
105
|
+
request.cookies
|
106
|
+
end
|
107
|
+
|
108
|
+
module RequestMixin
|
109
|
+
|
110
|
+
# ==== Returns
|
111
|
+
# Hash:: The cookies for this request.
|
112
|
+
#
|
113
|
+
# ==== Notes
|
114
|
+
# If a method #default_cookies is defined it will be called. This can
|
115
|
+
# be used for session fixation purposes for example. The method returns
|
116
|
+
# a Hash of key => value pairs.
|
117
|
+
def cookies
|
118
|
+
@cookies ||= begin
|
119
|
+
values = self.class.query_parse(@env[Merb::Const::HTTP_COOKIE], ';,')
|
120
|
+
cookies = Merb::Cookies.new(values)
|
121
|
+
cookies.update(default_cookies) if respond_to?(:default_cookies)
|
122
|
+
cookies
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Merb
|
2
|
+
class Dispatcher
|
3
|
+
module DefaultExceptionHelper
|
4
|
+
def humanize_exception(e)
|
5
|
+
e.class.name.split("::").last.gsub(/([a-z])([A-Z])/, '\1 \2')
|
6
|
+
end
|
7
|
+
|
8
|
+
def error_codes(exception)
|
9
|
+
if @show_details
|
10
|
+
message, message_details = exception.message.split("\n", 2)
|
11
|
+
"<h2>#{escape_html(message)}</h2><p>#{escape_html(message_details)}</p>"
|
12
|
+
else
|
13
|
+
"<h2>Sorry about that...</h2>"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def frame_details(line)
|
18
|
+
filename, lineno, location = line.split(":")
|
19
|
+
if filename.index(Merb.framework_root)
|
20
|
+
type = "framework"
|
21
|
+
shortname = Pathname.new(filename).relative_path_from(Pathname.new(Merb.framework_root))
|
22
|
+
elsif filename.index(Merb.root)
|
23
|
+
type = "app"
|
24
|
+
shortname = Pathname.new(filename).relative_path_from(Pathname.new(Merb.root))
|
25
|
+
elsif path = Gem.path.find {|p| filename.index(p)}
|
26
|
+
type = "gem"
|
27
|
+
shortname = Pathname.new(filename).relative_path_from(Pathname.new(path))
|
28
|
+
else
|
29
|
+
type = "other"
|
30
|
+
shortname = filename
|
31
|
+
end
|
32
|
+
[type, shortname, filename, lineno, location]
|
33
|
+
end
|
34
|
+
|
35
|
+
def listing(key, value, arr)
|
36
|
+
ret = []
|
37
|
+
ret << "<table class=\"listing\" style=\"display: none\">"
|
38
|
+
ret << " <thead>"
|
39
|
+
ret << " <tr><th width='25%'>#{key}</th><th width='75%'>#{value}</th></tr>"
|
40
|
+
ret << " </thead>"
|
41
|
+
ret << " <tbody>"
|
42
|
+
(arr || []).each_with_index do |(key, val), i|
|
43
|
+
klass = i % 2 == 0 ? "even" : "odd"
|
44
|
+
ret << " <tr class=#{klass}><td>#{key}</td><td>#{val.inspect}</td></tr>"
|
45
|
+
end
|
46
|
+
if arr.blank?
|
47
|
+
ret << " <tr class='odd'><td colspan='2'>None</td></tr>"
|
48
|
+
end
|
49
|
+
ret << " </tbody>"
|
50
|
+
ret << "</table>"
|
51
|
+
ret.join("\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
def textmate_url(filename, line)
|
55
|
+
"<a href='txmt://open?url=file://#{filename}&line=#{line}'>#{line}</a>"
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_source(filename, line)
|
59
|
+
line = line.to_i
|
60
|
+
ret = []
|
61
|
+
ret << "<tr class='source'>"
|
62
|
+
ret << " <td class='collapse'></td>"
|
63
|
+
str = " <td class='code' colspan='2'><div>"
|
64
|
+
|
65
|
+
__caller_lines__(filename, line, 5) do |lline, lcode|
|
66
|
+
str << "<a href='txmt://open?url=file://#{filename}&line=#{lline}'>#{lline}</a>"
|
67
|
+
str << "<em>" if line == lline
|
68
|
+
str << Erubis::XmlHelper.escape_xml(lcode)
|
69
|
+
str << "</em>" if line == lline
|
70
|
+
str << "\n"
|
71
|
+
end
|
72
|
+
str << "</div></td>"
|
73
|
+
ret << str
|
74
|
+
ret << "</tr>"
|
75
|
+
ret.join("\n")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class DefaultException < Merb::Controller
|
80
|
+
self._template_root = File.dirname(__FILE__) / "views"
|
81
|
+
|
82
|
+
def _template_location(context, type = nil, controller = controller_name)
|
83
|
+
"#{context}.#{type}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def index
|
87
|
+
@exceptions = request.exceptions
|
88
|
+
@show_details = Merb::Config[:exception_details]
|
89
|
+
render :format => :html
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
<style type="text/css" media="screen">
|
2
|
+
body {
|
3
|
+
font-family:arial;
|
4
|
+
font-size:11px;
|
5
|
+
}
|
6
|
+
p.options {
|
7
|
+
text-align: right;
|
8
|
+
}
|
9
|
+
p.options label {
|
10
|
+
margin-left: 10px;
|
11
|
+
}
|
12
|
+
p.options span.all {
|
13
|
+
padding: 5px;
|
14
|
+
border: 1px solid #000;
|
15
|
+
background-color: #fff;
|
16
|
+
}
|
17
|
+
p.options input {
|
18
|
+
position: relative;
|
19
|
+
}
|
20
|
+
h1 {
|
21
|
+
font-size:48px;
|
22
|
+
letter-spacing:-4px;
|
23
|
+
margin:0 0 20px 0;
|
24
|
+
line-height:36px;
|
25
|
+
color:#333;
|
26
|
+
}
|
27
|
+
h1 sup {
|
28
|
+
font-size: 0.5em;
|
29
|
+
}
|
30
|
+
h1 sup.error_500, h1 sup.error_400 {
|
31
|
+
color:#990E05;
|
32
|
+
}
|
33
|
+
h1 sup.error_100, h1 sup.error_200 {
|
34
|
+
color:#00BF10;
|
35
|
+
}
|
36
|
+
h1 sup.error_300 {
|
37
|
+
/* pretty sure you cant 'see' status 300
|
38
|
+
errors but if you could I think they
|
39
|
+
would be blue */
|
40
|
+
color:#1B2099;
|
41
|
+
}
|
42
|
+
h2 {
|
43
|
+
font-size:24px;
|
44
|
+
letter-spacing:-1px;
|
45
|
+
margin:0;
|
46
|
+
line-height:28px;
|
47
|
+
color:#444;
|
48
|
+
}
|
49
|
+
h3 {
|
50
|
+
cursor: pointer;
|
51
|
+
color: #006;
|
52
|
+
text-decoration: underline;
|
53
|
+
}
|
54
|
+
a, a:visited {
|
55
|
+
color:#00BF10;
|
56
|
+
}
|
57
|
+
.internalError {
|
58
|
+
width:800px;
|
59
|
+
margin:50px auto;
|
60
|
+
}
|
61
|
+
.header {
|
62
|
+
border-bottom:10px solid #333;
|
63
|
+
margin-bottom:1px;
|
64
|
+
background-image: url("data:image/gif;base64,R0lGODlhAwADAIAAAP///8zMzCH5BAAAAAAALAAAAAADAAMAAAIEBHIJBQA7");
|
65
|
+
padding:20px;
|
66
|
+
}
|
67
|
+
.header ul {
|
68
|
+
padding: 5px;
|
69
|
+
background-color: white;
|
70
|
+
}
|
71
|
+
.header ul li {
|
72
|
+
list-style-type: none;
|
73
|
+
font-size: 16px;
|
74
|
+
margin-bottom: 6px;
|
75
|
+
}
|
76
|
+
|
77
|
+
table.listing {
|
78
|
+
border-collapse: collapse;
|
79
|
+
font-size: 12px;
|
80
|
+
width: 100%;
|
81
|
+
}
|
82
|
+
|
83
|
+
table.listing th {
|
84
|
+
background-color: #000;
|
85
|
+
color: #fff;
|
86
|
+
}
|
87
|
+
|
88
|
+
table.listing td, table.listing th {
|
89
|
+
padding: 5px;
|
90
|
+
text-align: left;
|
91
|
+
vertical-align: top;
|
92
|
+
}
|
93
|
+
|
94
|
+
table.listing tr.odd {
|
95
|
+
background-color: #ccc;
|
96
|
+
}
|
97
|
+
|
98
|
+
table.listing tr.even {
|
99
|
+
background-color: #aaa;
|
100
|
+
}
|
101
|
+
|
102
|
+
table.listing td[colspan=2] {
|
103
|
+
text-align: center;
|
104
|
+
}
|
105
|
+
|
106
|
+
table.trace {
|
107
|
+
width:100%;
|
108
|
+
font-family:courier, monospace;
|
109
|
+
letter-spacing:-1px;
|
110
|
+
border-collapse: collapse;
|
111
|
+
border-spacing:0;
|
112
|
+
}
|
113
|
+
table.trace tr td{
|
114
|
+
padding:0;
|
115
|
+
height:26px;
|
116
|
+
font-size:13px;
|
117
|
+
vertical-align:middle;
|
118
|
+
}
|
119
|
+
table.trace tr.file{
|
120
|
+
border-top:2px solid #fff;
|
121
|
+
background-color:#F3F3F3;
|
122
|
+
}
|
123
|
+
table.trace tr.source {
|
124
|
+
background-color:#F8F8F8;
|
125
|
+
display:none;
|
126
|
+
}
|
127
|
+
table.trace .open tr.source {
|
128
|
+
display:table-row;
|
129
|
+
}
|
130
|
+
table.trace tr.file td.expand {
|
131
|
+
width:23px;
|
132
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAIAAABvSEP3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdVJREFUeNqMVL+TwUAYxaRIOlEhlZHGDAUzzOQ61+AqXMV1lJSU7q/QRqm8KFUcJTNn5qJkaPyoKKVz7y4mF8na5Kt29tt9+/Z97/u81+vVQ4r9frdarS6Xi7ETDIZisRjxMGPfmk4niNPpZE+xLAugbPaZ53nzvtfMBe/3+/3dbuehBrAKhZdUKkVAWa9Xsiybv0CPZDJZLr/qa5/BwgwRjYqOKIvFYjQa/aNommZh0Ww2K5UqzwfoQOPxaLPZ3FAmk0+7lplMpt1u53J5OpBOR0eZEE9wHJfP5zud93g88QhluwWbjW+5VOmKBgKBer3eaDTDYeGBQF8+x7rqIYoiPgixWJazpA6HA+MSxRArkUgMh0M409g8Ho8+9wYxxCqVSq1W26EDHGM2m4HOHQrEc38f/Yn7cLmlIRhBENzcx8cVRZnPZ/YUep2BWkjTIfA+PKVpZAXR5QxsjiqCKvGEqqp443w+0dvy17swqD0HB3S73V5PpkNg1qBqt8kwGCjmPkinM0QJbIoEa7U6UG6ToVgs4V9G2g0ESoP5Aoi7KYX5oCgf8IKbkvn9/mr1LRQKESamzgJy0g0tSZIuB3nuGqRU9Vv9C4sKkUhEkp4soxvxI8AAhWrrtXa3X8EAAAAASUVORK5CYII=);
|
133
|
+
background-position:top left;
|
134
|
+
background-repeat:no-repeat;
|
135
|
+
}
|
136
|
+
table.trace tr.file td.expand div {
|
137
|
+
width:23px;
|
138
|
+
}
|
139
|
+
table.trace .open tr.file td.expand {
|
140
|
+
width:23px;
|
141
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNrslK1ywkAUhcMOBomEOiSdqLxEBJX0NaijOsjyHGGmCGyQQYaiiiw4gktkcOmZbpsuuzQ/M5XnqJ2d3S/n3nM3rTzPLUP7/Tt0+pLcGQwG3W53OLyHzPMtjYL7q9UqSRLrD4E1Gj1orCvKYuFHUWTVkOM44/HjDcp8/lL4r6NerzeZPMm1KFw0QkDn83m5fP2lHA4fNQvRtNvtjsfDd0WzmSfb2e/fdTqdOvdh/HLJZLOn0+d2HJ+KRGzbdl23EpFlmed5cp2maRzHQq1lvQ5KMi6EUZBGfup6E1pTfd+vrGW7jbQ2C9hTt9BpqNyIWaAwAy6xg2eBz5iRC/NomiZhGN5sqmnkauo0BUGgVQoBjQ80oCACgNQdZHfTYBkF2mxCtWWAqunWpahxIDUt3QYUxIFQpJHyIWpXjinabKbbwItMHT+NyjchrP8QKaSQQgoppJBCCimkkEIKKaSQQgoppJBCCimkkEIKKaSo+hRgAEFD17X08O2NAAAAAElFTkSuQmCC);
|
142
|
+
background-position:top left;
|
143
|
+
background-repeat:no-repeat;
|
144
|
+
}
|
145
|
+
table.trace .open tr.file td.expand div {
|
146
|
+
width:23px;
|
147
|
+
}
|
148
|
+
table.trace tr.source td.collapse {
|
149
|
+
width:23px;
|
150
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVxJREFUeNrs0zFygkAUBmBlUkgJHdABlQwVkVJKKUxBYWbkALTxMJwhltyDFkss03IF8pudIcwaDaDl/6pd2P327b7d+eHwMXs4lNkzggoVKlSoUKFChQoVKlSoUKFChQoVKlSoUKFChQqVEYqm6ft9+qiSJEkYho7jTlcw2fd9NOI4nq4gEdFwXXe1Cqco63VkWVbXRTqLhTpOwQRpF7quR1E0TgGhqvLKUFCyoQqG/rks3O6kZKW/eRFpevOCoGTXVTcMQ5EyxyDEkML1c5RzuZOICIyXqn7JBVez6282MWrx731HOv2qB8Hri2lamNk0DfpVVdV1Peodappmmua8bdvzuc7zfNprzrLMth1FnGh/X8MjCAIQv/cFz/+65PcDh7rbvYv2ZUfdj+PxsyzLgVl0hKwgTqeqKApx2LeOc7t98zyv/1FWOgvx9RPii23bmL9cetJ8Ed8CDAC6aFW8bCzFhwAAAABJRU5ErkJggg==);
|
151
|
+
background-position:bottom left;
|
152
|
+
background-repeat:no-repeat;
|
153
|
+
background-color:#6F706F;
|
154
|
+
}
|
155
|
+
table.trace tr td.path {
|
156
|
+
padding-left:10px;
|
157
|
+
}
|
158
|
+
table.trace tbody.app td.path {
|
159
|
+
color: #900;
|
160
|
+
}
|
161
|
+
table.trace tbody.framework td.path {
|
162
|
+
color: #009;
|
163
|
+
}
|
164
|
+
table.trace tbody.gem td.path {
|
165
|
+
color: #090;
|
166
|
+
}
|
167
|
+
table.trace tr td.code {
|
168
|
+
padding: 10px 0 10px 20px;
|
169
|
+
white-space: pre;
|
170
|
+
}
|
171
|
+
table.trace tr td.code div {
|
172
|
+
width: 700px;
|
173
|
+
overflow-x: auto;
|
174
|
+
overflow-y: hidden;
|
175
|
+
}
|
176
|
+
table.trace tr td.code em {
|
177
|
+
font-weight:bold;
|
178
|
+
color:#00BF10;
|
179
|
+
}
|
180
|
+
table.trace tr td.code a {
|
181
|
+
width: 20px;
|
182
|
+
float: left;
|
183
|
+
}
|
184
|
+
table.trace tr td.code .more {
|
185
|
+
color:#666;
|
186
|
+
}
|
187
|
+
table.trace tr td.line {
|
188
|
+
width:30px;
|
189
|
+
text-align:right;
|
190
|
+
padding-right:4px;
|
191
|
+
}
|
192
|
+
.footer {
|
193
|
+
margin-top:5px;
|
194
|
+
font-size:11px;
|
195
|
+
color:#444;
|
196
|
+
text-align:right;
|
197
|
+
}
|
198
|
+
</style>
|
@@ -0,0 +1,73 @@
|
|
1
|
+
<script type="text/javascript" charset="utf-8">
|
2
|
+
(function() {
|
3
|
+
els = document.getElementsByTagName('td');
|
4
|
+
var forEach = function(arr, fn) {
|
5
|
+
for(var i=0; i<arr.length; i++) {
|
6
|
+
var res = fn(arr[i]);
|
7
|
+
if(res === false) break;
|
8
|
+
}
|
9
|
+
}
|
10
|
+
var toggleClasses = function(node, first, second) {
|
11
|
+
var classes = node.className.split(" ");
|
12
|
+
var newClasses = [];
|
13
|
+
forEach(classes, function(k) {
|
14
|
+
if(k == first) newClasses.push(second);
|
15
|
+
else if(k == second) newClasses.push(first);
|
16
|
+
else newClasses.push(k);
|
17
|
+
});
|
18
|
+
node.className = newClasses.join(" ");
|
19
|
+
}
|
20
|
+
forEach(els, function(el) {
|
21
|
+
// swap the open & closed classes
|
22
|
+
if(hasClass(el, "expand") || hasClass(el, "collapse")) {
|
23
|
+
el.onclick = function(e){
|
24
|
+
tbody = this.parentNode.parentNode;
|
25
|
+
toggleClasses(tbody, "open", "close");
|
26
|
+
}
|
27
|
+
}
|
28
|
+
})
|
29
|
+
forEach(document.getElementsByTagName("h3"), function(el) {
|
30
|
+
el.onclick = function(e) {
|
31
|
+
var tag = this.nextSibling;
|
32
|
+
while(tag.nodeType != 1) tag = tag.nextSibling;
|
33
|
+
tag.style.display = tag.style.display == "none" ? "" : "none";
|
34
|
+
}
|
35
|
+
})
|
36
|
+
function hasClass(node, matchClass) {
|
37
|
+
var classes = node.className.split(" ");
|
38
|
+
for(var i=0,className;className=classes[i];i++)
|
39
|
+
if(className == matchClass) return true;
|
40
|
+
return false;
|
41
|
+
}
|
42
|
+
var els = document.getElementsByTagName("p");
|
43
|
+
forEach(els, function(tag) {
|
44
|
+
if(tag.className != "options") return true;
|
45
|
+
var checkboxes = tag.getElementsByTagName("input");
|
46
|
+
forEach(checkboxes, function(box) {
|
47
|
+
if(window.navigator.userAgent.match(/Firefox/)) {
|
48
|
+
box.style.top = "3px";
|
49
|
+
}
|
50
|
+
});
|
51
|
+
tag.getElementsByTagName("input")[0].onclick = function(e) {
|
52
|
+
forEach(checkboxes, function(box) {
|
53
|
+
if(box == e.target) return true;
|
54
|
+
box.checked = e.target.checked;
|
55
|
+
toggleTraces(box, box);
|
56
|
+
})
|
57
|
+
};
|
58
|
+
var toggleTraces = function(box, target) {
|
59
|
+
var tbodies = tag.parentNode.getElementsByTagName("tbody");
|
60
|
+
forEach(tbodies, function(tbody) {
|
61
|
+
if(hasClass(tbody, target.parentNode.className)) {
|
62
|
+
if(target.checked) tbody.style.display = "";
|
63
|
+
else tbody.style.display = "none";
|
64
|
+
}
|
65
|
+
})
|
66
|
+
}
|
67
|
+
forEach(checkboxes, function(box) {
|
68
|
+
if(box == checkboxes[0]) return true;
|
69
|
+
box.onchange = function(e) { toggleTraces(box, e.target) }
|
70
|
+
})
|
71
|
+
})
|
72
|
+
})();
|
73
|
+
</script>
|