moonrope 1.3.3 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +47 -0
  4. data/MIT-LICENCE +20 -0
  5. data/README.md +24 -0
  6. data/bin/moonrope +28 -0
  7. data/docs/authentication.md +114 -0
  8. data/docs/controllers.md +106 -0
  9. data/docs/exceptions.md +27 -0
  10. data/docs/introduction.md +29 -0
  11. data/docs/structures.md +214 -0
  12. data/example/authentication.rb +50 -0
  13. data/example/controllers/meta_controller.rb +14 -0
  14. data/example/controllers/users_controller.rb +92 -0
  15. data/example/structures/pet_structure.rb +12 -0
  16. data/example/structures/user_structure.rb +35 -0
  17. data/lib/moonrope.rb +5 -4
  18. data/lib/moonrope/action.rb +170 -40
  19. data/lib/moonrope/authenticator.rb +42 -0
  20. data/lib/moonrope/base.rb +67 -6
  21. data/lib/moonrope/controller.rb +4 -2
  22. data/lib/moonrope/doc_context.rb +94 -0
  23. data/lib/moonrope/doc_server.rb +123 -0
  24. data/lib/moonrope/dsl/action_dsl.rb +159 -9
  25. data/lib/moonrope/dsl/authenticator_dsl.rb +35 -0
  26. data/lib/moonrope/dsl/base_dsl.rb +21 -18
  27. data/lib/moonrope/dsl/controller_dsl.rb +60 -9
  28. data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
  29. data/lib/moonrope/dsl/structure_dsl.rb +28 -2
  30. data/lib/moonrope/errors.rb +13 -0
  31. data/lib/moonrope/eval_environment.rb +82 -3
  32. data/lib/moonrope/eval_helpers.rb +47 -8
  33. data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
  34. data/lib/moonrope/guard.rb +35 -0
  35. data/lib/moonrope/html_generator.rb +65 -0
  36. data/lib/moonrope/param_set.rb +11 -1
  37. data/lib/moonrope/rack_middleware.rb +66 -37
  38. data/lib/moonrope/railtie.rb +31 -14
  39. data/lib/moonrope/request.rb +43 -15
  40. data/lib/moonrope/structure.rb +100 -18
  41. data/lib/moonrope/structure_attribute.rb +39 -0
  42. data/lib/moonrope/version.rb +1 -1
  43. data/moonrope.gemspec +21 -0
  44. data/spec/spec_helper.rb +32 -0
  45. data/spec/specs/action_spec.rb +455 -0
  46. data/spec/specs/base_spec.rb +29 -0
  47. data/spec/specs/controller_spec.rb +31 -0
  48. data/spec/specs/param_set_spec.rb +31 -0
  49. data/templates/basic/_action_form.erb +77 -0
  50. data/templates/basic/_errors_table.erb +32 -0
  51. data/templates/basic/_structure_attributes_list.erb +55 -0
  52. data/templates/basic/action.erb +168 -0
  53. data/templates/basic/assets/lock.svg +3 -0
  54. data/templates/basic/assets/reset.css +101 -0
  55. data/templates/basic/assets/style.css +348 -0
  56. data/templates/basic/assets/tool.svg +4 -0
  57. data/templates/basic/assets/try.js +157 -0
  58. data/templates/basic/authenticator.erb +52 -0
  59. data/templates/basic/controller.erb +20 -0
  60. data/templates/basic/index.erb +114 -0
  61. data/templates/basic/layout.erb +46 -0
  62. data/templates/basic/structure.erb +23 -0
  63. data/test/test_helper.rb +81 -0
  64. data/test/tests/action_access_test.rb +63 -0
  65. data/test/tests/actions_test.rb +524 -0
  66. data/test/tests/authenticators_test.rb +87 -0
  67. data/test/tests/base_test.rb +35 -0
  68. data/test/tests/controllers_test.rb +49 -0
  69. data/test/tests/eval_environment_test.rb +136 -0
  70. data/test/tests/evel_helpers_test.rb +60 -0
  71. data/test/tests/examples_test.rb +11 -0
  72. data/test/tests/helpers_test.rb +97 -0
  73. data/test/tests/param_set_test.rb +44 -0
  74. data/test/tests/rack_middleware_test.rb +131 -0
  75. data/test/tests/request_test.rb +232 -0
  76. data/test/tests/structures_param_extensions_test.rb +159 -0
  77. data/test/tests/structures_test.rb +398 -0
  78. metadata +71 -56
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'moonrope/base'
3
+
4
+ describe Moonrope::Base do
5
+ subject(:base) { Moonrope::Base.new }
6
+
7
+ context "the base" do
8
+ it "should be able to define & return a controller" do
9
+ base.dsl.controller :users
10
+ expect(base.controller(:users)).to be_a(Moonrope::Controller)
11
+ end
12
+
13
+ it "should be able to define & return a structure" do
14
+ base.dsl.structure :user
15
+ expect(base.structure(:user)).to be_a(Moonrope::Structure)
16
+ end
17
+
18
+ it "should be able to define & return an authenticator" do
19
+ base.dsl.authenticator :admin
20
+ expect(base.authenticators[:admin]).to be_a(Moonrope::Authenticator)
21
+ end
22
+
23
+ it "should be able to define & return an authenticator" do
24
+ base.dsl.shared_action(:find_something) { 1234 }
25
+ expect(base.shared_actions[:find_something]).to be_a(Proc)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'moonrope/controller'
3
+ require 'moonrope/base'
4
+
5
+ describe Moonrope::Controller do
6
+ context "a controller" do
7
+ it "should be able to define & return an action" do
8
+ controller = Moonrope::Controller.new(Moonrope::Base.new, :users) do
9
+ action :list
10
+ end
11
+ expect(controller.action(:list)).to be_a(Moonrope::Action)
12
+ end
13
+
14
+ it "should be able to define & return a before filter" do
15
+ controller = Moonrope::Controller.new(Moonrope::Base.new, :users) do
16
+ before {}
17
+ end
18
+ expect(controller.befores.size).to eq(1)
19
+ expect(controller.befores.first).to be_a(Moonrope::BeforeAction)
20
+ end
21
+
22
+ it "should be able to define & return a shared action" do
23
+ controller = Moonrope::Controller.new(Moonrope::Base.new, :users) do
24
+ shared_action :example do
25
+ end
26
+ end
27
+ expect(controller.shared_actions.size).to eq(1)
28
+ expect(controller.shared_actions[:example]).to be_a(Proc)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'moonrope/param_set'
3
+
4
+ describe Moonrope::ParamSet do
5
+
6
+ context "a param set" do
7
+ subject(:param_set) { Moonrope::ParamSet.new('example' => 'Hello') }
8
+
9
+ it "should return values in hash format" do
10
+ expect(param_set[:example]).to eq('Hello')
11
+ expect(param_set['example']).to eq('Hello')
12
+ end
13
+
14
+ it "should return values in dot format" do
15
+ expect(param_set.example).to eq('Hello')
16
+ end
17
+
18
+ it "should be able to say if a param exists or not" do
19
+ expect(param_set.has?(:example)).to be true
20
+ expect(param_set.has?('example')).to be true
21
+ expect(param_set.has?(:unknown)).to be false
22
+ end
23
+
24
+ it "should return a default if one exists and there's no other value" do
25
+ param_set._defaults = {'fruit' =>'Apple'}
26
+ expect(param_set.has?(:fruit)).to be true
27
+ expect(param_set.fruit).to eq 'Apple'
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,77 @@
1
+ <% unless host.nil? %>
2
+ <p class='tryFormActivate'><a class='tryFormActivate__button' href='#'>Try this request in your browser</a></p>
3
+ <form class='tryForm'>
4
+ <input type='hidden' name='controller' value='<%= controller.name %>'>
5
+ <input type='hidden' name='action' value='<%= action.name %>'>
6
+ <div class='tryForm__header'>
7
+ <input type='text' id='host' name='host' value='<%= host %>'>
8
+ /api/
9
+ <input type='text' id='version' name='version' value='<%= version %>' class='v'>
10
+ /<%= controller.name %>/<%= action.name %>
11
+ </div>
12
+
13
+ <% if action.authenticator_to_use.is_a?(Moonrope::Authenticator) %>
14
+ <p class='tryForm__heading'>Headers</p>
15
+ <table class='tryForm__table'>
16
+ <% for name, options in action.authenticator_to_use.headers %>
17
+ <tr>
18
+ <td width="50%"><code><%= name %></code></td>
19
+ <td width="50%"><input type='text' class='tryForm__tableField headerField' name='<%= name %>'></td>
20
+ </tr>
21
+ <% end %>
22
+ </table>
23
+ <% end %>
24
+
25
+ <% unless action.params.empty? %>
26
+ <p class='tryForm__heading'>Parameters</p>
27
+ <table class='tryForm__table'>
28
+ <% for name, param in action.params %>
29
+ <tr>
30
+ <td width="30%"><code><%= name %></code></td>
31
+ <td width="20%"><%= friendly_type param[:type] %></td>
32
+ <td width="50%"><input type='text' class='tryForm__tableField paramField' name='<%= name %>' placeholder='<%= param[:default] %>' data-type='<%= param[:type] %>'></td>
33
+ </tr>
34
+ <% end %>
35
+ </table>
36
+ <% end %>
37
+
38
+ <% if action.can_change_full? || action.can_change_expansions? %>
39
+ <p class='tryForm__heading'>Structures</p>
40
+ <table class='tryForm__table'>
41
+ <% if action.can_change_full? %>
42
+ <tr>
43
+ <td width="50%">Include extended attributes?</td>
44
+ <td width="50%">
45
+ <div class='tryForm__checkbox'>
46
+ <input type='checkbox' class='tryForm__fullAttrs' name='full' id="full_attrs" <% if action.includes_full_attributes? %>checked='checked'<%end%>>
47
+ <label for="full_attrs">Yes - include extended attributes</label>
48
+ </div>
49
+ </td>
50
+ </tr>
51
+ <% end %>
52
+ <% if action.can_change_expansions? %>
53
+ <tr>
54
+ <td width="50%">Include expansions?</td>
55
+ <td width="50%">
56
+ <% for expansion in action.available_expansions %>
57
+ <div class='tryForm__checkbox'>
58
+ <input type='checkbox' class='tryForm__expansions' name='<%= expansion%>' id="expan_<%= expansion %>" <% if action.includes_expansion?(expansion) %>checked='checked'<%end%>>
59
+ <label for="expan_<%= expansion %>"><%= expansion %></label>
60
+ </div>
61
+ <% end %>
62
+ </td>
63
+ </tr>
64
+ <% end %>
65
+
66
+ </table>
67
+
68
+ <% end %>
69
+
70
+ <p class='tryForm__button'>
71
+ <button class='tryForm__buttonLink' type='submit'>Make this request</button>
72
+ <button class='tryForm__buttonLink tryFormCancel' type='button'>Cancel</button>
73
+ </p>
74
+
75
+ <pre class='tryForm__output'>The request output will be shown here...</pre>
76
+ </form>
77
+ <% end %>
@@ -0,0 +1,32 @@
1
+ <table class='table errorsTable'>
2
+ <thead>
3
+ <tr>
4
+ <th width="60%">Error</th>
5
+ <th width="40%">Attributes</th>
6
+ </tr>
7
+ </thead>
8
+ <% for name, error in errors %>
9
+ <tr>
10
+ <td>
11
+ <p>
12
+ <span class='paramTable__name'><%= name %></span>
13
+ <% if error[:description] %>
14
+ <p class='paramTable__description'><%= error[:description] %></p>
15
+ <% end %>
16
+ </p>
17
+ </td>
18
+ <td>
19
+ <% if error[:attributes].is_a?(Hash) %>
20
+ <ul class='errorAttributeList'>
21
+ <% for name, description in error[:attributes] %>
22
+ <li>
23
+ <p class='errorAttributeList__name'><%= name %></p>
24
+ <p class='errorAttributeList__desc'><%= description %></p>
25
+ </li>
26
+ <% end %>
27
+ </ul>
28
+ <% end %>
29
+ </td>
30
+ </tr>
31
+ <% end %>
32
+ </table>
@@ -0,0 +1,55 @@
1
+ <table class='table paramTable'>
2
+ <thead>
3
+ <tr>
4
+ <th width="45%">Attribute</th>
5
+ <th width="20%">Type</th>
6
+ <th width="35%">Example</th>
7
+ </tr>
8
+ </thead>
9
+ <% for attribute in attributes %>
10
+ <tr>
11
+ <td>
12
+ <p>
13
+ <span class='paramTable__name'><%= attribute.name_with_groups %></span>
14
+ </p>
15
+ <% if attribute.description %>
16
+ <p class='paramTable__description'><%= attribute.description %></p>
17
+ <% end %>
18
+
19
+ <% conditions = attribute.conditions.map { |c| structure.description_for_condition(c) }.compact %>
20
+ <% unless conditions.empty? %>
21
+ <ul class='paramTable__restrictedList'>
22
+ <% for condition in conditions %>
23
+ <li><%= condition %></li>
24
+ <% end %>
25
+ </ul>
26
+ <% end %>
27
+ </td>
28
+ <td><%= friendly_type(attribute.value_type) %></td>
29
+ <td>
30
+ <% if substructure = attribute.structure %>
31
+ <a class='link' href="<%= path("structures/#{substructure}.html")%>"><%= humanize(substructure.to_s.capitalize) %> structure</a>
32
+ <% else %>
33
+ <%= attribute.example %>
34
+ <% end %>
35
+ </td>
36
+ </tr>
37
+ <% end %>
38
+
39
+ <% if vars[:expansions] && !vars[:expansions].empty? %>
40
+ <% for name, expansion in vars[:expansions] %>
41
+ <tr>
42
+ <td>
43
+ <p>
44
+ <span class='paramTable__name'><%= name %></span>
45
+ </p>
46
+ <% if expansion[:description] %>
47
+ <p class='paramTable__description'><%= expansion[:description] %></p>
48
+ <% end %>
49
+ </td>
50
+ <td><%= friendly_type(expansion[:type]) %></td>
51
+ <td><%= expansion[:eg] || expansion[:example] %></td>
52
+ </tr>
53
+ <% end %>
54
+ <% end %>
55
+ </table>
@@ -0,0 +1,168 @@
1
+ <% set_page_title "#{action.title || action.name} - #{action.controller.friendly_name || action.controller.name}" %>
2
+ <% set_active_nav "controller-#{controller.name}" %>
3
+
4
+ <h1><%= action.title || action.name %></h1>
5
+ <% if action.description %>
6
+ <p class='text'><%= action.description %></p>
7
+ <% end %>
8
+
9
+ <%= partial 'action_form', :controller => controller, :action => action %>
10
+
11
+ <h2>URL</h2>
12
+ <p class='apiURLFull'><span><%= full_prefix %>/</span><%= action.controller.name %>/<%= action.name %></p>
13
+
14
+ <% if action.authenticator_to_use.is_a?(Moonrope::Authenticator) %>
15
+ <% if rule = action.authenticator_to_use.rules[action.access_rule_to_use] %>
16
+ <% if rule[:description] %>
17
+ <h2>Access</h2>
18
+ <p class='text'>
19
+ <%= rule[:description] %>
20
+ <% if rule[:error_code] %>
21
+ If not authorised, a <code><%= rule[:error_code] %></code> error will be returned.
22
+ <% end %>
23
+ </p>
24
+ <% end %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <h2>Parameters</h2>
29
+ <% if action.params.empty? %>
30
+ <p><em>This action doesn't support any parameters.</em></p>
31
+ <% else %>
32
+ <table class='table paramTable'>
33
+ <thead>
34
+ <tr>
35
+ <th width="60%">Parameter</th>
36
+ <th width="20%">Type</th>
37
+ <th width="20%">Default</th>
38
+ </tr>
39
+ </thead>
40
+ <% for name, param in action.params %>
41
+ <tr>
42
+ <td>
43
+ <p>
44
+ <span class='paramTable__name'><%= name %></span>
45
+ <% if param[:required] && param[:default].nil? %><span class='paramTable__req'>Required</span><% end %>
46
+ </p>
47
+ <% if param[:description] %>
48
+ <p class='paramTable__description'><%= param[:description] %></p>
49
+ <% end %>
50
+ </td>
51
+ <td><%= friendly_type(param[:type]) %></td>
52
+ <td>
53
+ <% if param[:default].nil? %>
54
+ <span class='paramTable__nil'>null</span>
55
+ <% else %>
56
+ <%= param[:default] %>
57
+ <% end %>
58
+ </td>
59
+ </tr>
60
+ <% end %>
61
+ </table>
62
+ <% end %>
63
+
64
+ <% unless action.filters.empty? %>
65
+ <h2>Filtering</h2>
66
+ <p class='text'>
67
+ This action supports filtering. You can filter the results which you receive by
68
+ providing filters in the <code>filters</code> parameter. The following attributes
69
+ are supported for filtering.
70
+ </p>
71
+ <table class='table paramTable'>
72
+ <thead>
73
+ <tr>
74
+ <th width="40%">Attribute</th>
75
+ <th width="60%">Supported Operators</th>
76
+ </tr>
77
+ </thead>
78
+ <% for name, filter in action.filters %>
79
+ <tr>
80
+ <td><span class='paramTable__name'><%= name %></span></td>
81
+ <td><%= filter[:operators].map(&:to_s).join(', ') %></td>
82
+ </tr>
83
+ <% end %>
84
+ </table>
85
+ <% end %>
86
+
87
+ <h2>Errors</h2>
88
+
89
+ <% if action.errors.empty? %>
90
+ <p><em>There are no action-specific errors which can be raised.</em></p>
91
+ <% else %>
92
+ <%= partial "errors_table", :errors => action.errors %>
93
+ <% end %>
94
+
95
+ <% if action.returns %>
96
+ <h2>Response Data</h2>
97
+ <% if action.returns[:structure] %>
98
+ <% if action.returns[:type] == :array %>
99
+ <p class='text'>This action will return an array of <a class='link' href='<%= path("structures/#{action.returns[:structure]}") %>'><%= humanize(action.returns[:structure]) %> structures</a>.</p>
100
+ <% else %>
101
+ <p class='text'>This action will return a <a class='link' href='<%= path("structures/#{action.returns[:structure]}") %>'><%= humanize(action.returns[:structure]) %> structure</a>.</p>
102
+ <% end %>
103
+
104
+ <% if opts = action.returns[:structure_opts] %>
105
+ <% if opts[:paramable] == true %>
106
+ <p class='text'>
107
+ You'll receive this structure in the most basic form, without extended data or
108
+ any expansions. You can choose to receive extended attributes by providing the <code>_full</code> parameter. You can
109
+ also choose to receive any expansions by providing an array in the <code>_expansions</code>
110
+ parameter. A full list of expansions can be found on the
111
+ <a class='link' href='<%= path("structures/#{action.returns[:structure]}") %>'>structure page</a>.
112
+ </p>
113
+ <% elsif opts[:paramable].is_a?(Hash) %>
114
+ <p class='text'>
115
+ <% if opts[:paramable].has_key?(:full) %>
116
+ <% if opts[:paramable][:full] %>
117
+ You'll receive all extended data with this structure, by default.
118
+ <% else %>
119
+ You won't receive any extended data with this structure, by default.
120
+ <% end %>
121
+ You can change this behaviour by passing true or false in the <code>_full</code>
122
+ parameter on the request.
123
+ <% else %>
124
+ You will only receive basic data for this structure, no extended data is available.
125
+ <% end %>
126
+
127
+ <% if opts[:paramable].has_key?(:expansions) %>
128
+ <% if opts[:paramable][:expansions].is_a?(Array) %>
129
+ By default, you'll receive expansions for <b><%= opts[:paramable][:expansions].join(', ') %></b>.
130
+ You can change these by providing an array of expansion names in the <code>_expansions</code>
131
+ parameter on the request.
132
+ <% elsif opts[:paramable][:expansions] == true %>
133
+ By default, you'll receive all expansions for the structure. You remove any/all of them by
134
+ providing an array of new expansion names in the <code>_expansions</code> parameter on the
135
+ request.
136
+ <% elsif opts[:paramable][:expansions] == false %>
137
+ By default, you'll receive no expansions for the structure. You can add them by providing
138
+ an array of new expansion names in the <code>_expansions</code> parameter on the request.
139
+ You can send <code>true</code> rather than array to receive all expansions.
140
+ <% end %>
141
+ <% else %>
142
+ No expansions will be provided.
143
+ <% end %>
144
+ </p>
145
+ <% else %>
146
+ <% if opts[:full] %>
147
+ You'll receive all attributes for this structure (basic and extended attributes).
148
+ <% else %>
149
+ You'll only receive basic attributes for this structure.
150
+ <% end %>
151
+ <% if opts[:expansions].is_a?(Array) %>
152
+ You'll receive expansions for <b><%= opts[:expansions].join(', ') %></b>.
153
+ <% elsif opts[:expansions] == true %>
154
+ You'll receive all expansions for this stucture.
155
+ <% end %>
156
+ <% end %>
157
+ <% else %>
158
+ You'll receive just the basic attributes for this structure. No expansions are provided.
159
+ <% end %>
160
+ <% else %>
161
+ <p class='text'>
162
+ This action will return a <%= friendly_type(action.returns[:type]) %>.
163
+ </p>
164
+ <% if eg = (action.returns[:eg] || action.returns[:example]) %>
165
+ <pre class='code'><%= eg %></pre>
166
+ <% end %>
167
+ <% end %>
168
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
2
+ <path fill="#ed4300" d="M3 0c-1.1 0-2 .9-2 2v1h-1v4h6v-4h-1v-1c0-1.1-.9-2-2-2zm0 1c.56 0 1 .44 1 1v1h-2v-1c0-.56.44-1 1-1z" transform="translate(1)" />
3
+ </svg>
@@ -0,0 +1,101 @@
1
+ html, body, body div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, figure, footer, header, hgroup, menu, nav, section, time, mark, audio, video {
2
+ margin: 0;
3
+ padding: 0;
4
+ border: 0;
5
+ outline: 0;
6
+ font-size: 100%;
7
+ letter-spacing:0;
8
+ vertical-align: baseline;
9
+ background: transparent;
10
+ font-weight:inherit;
11
+ }
12
+
13
+ * {
14
+ -webkit-box-sizing: border-box;
15
+ -moz-box-sizing: border-box;
16
+ box-sizing: border-box;
17
+ }
18
+ u { text-decoration: none;}
19
+ b { font-weight:normal;}
20
+ article, aside, figure, footer, header, hgroup, nav, section {display: block;}
21
+
22
+ object,embed {max-width: 100%;}
23
+ ul {list-style: none;}
24
+ blockquote, q {quotes: none;}
25
+ b,strong { font-weight:bold;}
26
+ blockquote:before, blockquote:after, q:before, q:after {content: ''; content: none;}
27
+
28
+ a {margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent;}
29
+
30
+ del {text-decoration: line-through;}
31
+
32
+ abbr[title], dfn[title] {border-bottom: 1px dotted #000; cursor: help;}
33
+
34
+ /* tables still need cellspacing="0" in the markup */
35
+ table {border-collapse: collapse; border-spacing: 0;}
36
+ mark { color:inherit;}
37
+
38
+ hr {display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0;}
39
+
40
+ input, select {vertical-align: middle;}
41
+
42
+ pre {
43
+ white-space: pre; /* CSS2 */
44
+ white-space: pre-wrap; /* CSS 2.1 */
45
+ white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
46
+ word-wrap: break-word; /* IE */
47
+ }
48
+
49
+ input[type="radio"] {vertical-align: text-bottom;}
50
+ input[type="checkbox"] {vertical-align: bottom; *vertical-align: baseline;}
51
+ .ie6 input {vertical-align: text-bottom;}
52
+
53
+ select, input, textarea {font: 99% sans-serif;}
54
+
55
+ table {font-size: inherit; font: 100%;}
56
+
57
+ /* Accessible focus treatment
58
+ people.opera.com/patrickl/experiments/keyboard/test */
59
+ a:hover, a:active {outline: none;}
60
+
61
+ small {font-size: 85%;}
62
+
63
+ strong, th {font-weight: bold;}
64
+
65
+ td, td img {vertical-align: top;}
66
+
67
+ /* Make sure sup and sub don't screw with your line-heights
68
+ gist.github.com/413930 */
69
+ sub, sup {font-size: 75%; line-height: 0; position: relative;}
70
+ sup {top: -0.5em;}
71
+ sub {bottom: -0.25em;}
72
+
73
+ /* standardize any monospaced elements */
74
+ pre, code, kbd, samp {font-family: monospace, sans-serif;}
75
+
76
+ /* hand cursor on clickable elements */
77
+ .clickable,
78
+ label,
79
+ input[type=button],
80
+ input[type=submit],
81
+ button {cursor: pointer;}
82
+
83
+ /* Webkit browsers add a 2px margin outside the chrome of form elements */
84
+ button, input, select, textarea {margin: 0;}
85
+
86
+ /* make buttons play nice in IE */
87
+ button {width: auto; overflow: visible;}
88
+
89
+ /* scale images in IE7 more attractively */
90
+ .ie7 img {-ms-interpolation-mode: bicubic;}
91
+
92
+ /* prevent BG image flicker upon hover */
93
+ .ie6 html {filter: expression(document.execCommand("BackgroundImageCache", false, true));}
94
+
95
+ /* let's clear some floats */
96
+ .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
97
+ .clearfix:after { clear: both; }
98
+ .clearfix { zoom: 1; }
99
+
100
+ select, input, textarea, a { outline: none;}
101
+ a { color:inherit;}