moonrope 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  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/html/assets/lock.svg +3 -0
  18. data/html/assets/reset.css +101 -0
  19. data/html/assets/style.css +348 -0
  20. data/html/assets/tool.svg +4 -0
  21. data/html/assets/try.js +151 -0
  22. data/html/authenticators/default.html +191 -0
  23. data/html/controllers/meta/version.html +144 -0
  24. data/html/controllers/meta.html +73 -0
  25. data/html/controllers/users/create.html +341 -0
  26. data/html/controllers/users/list.html +348 -0
  27. data/html/controllers/users/show.html +261 -0
  28. data/html/controllers/users/update.html +387 -0
  29. data/html/controllers/users.html +93 -0
  30. data/html/index.html +166 -0
  31. data/html/moonrope.txt +0 -0
  32. data/html/structures/pet.html +176 -0
  33. data/html/structures/user.html +338 -0
  34. data/lib/moonrope/action.rb +165 -37
  35. data/lib/moonrope/authenticator.rb +39 -0
  36. data/lib/moonrope/base.rb +24 -6
  37. data/lib/moonrope/controller.rb +4 -2
  38. data/lib/moonrope/doc_context.rb +94 -0
  39. data/lib/moonrope/doc_server.rb +123 -0
  40. data/lib/moonrope/dsl/action_dsl.rb +159 -9
  41. data/lib/moonrope/dsl/authenticator_dsl.rb +31 -0
  42. data/lib/moonrope/dsl/base_dsl.rb +21 -18
  43. data/lib/moonrope/dsl/controller_dsl.rb +60 -9
  44. data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
  45. data/lib/moonrope/dsl/structure_dsl.rb +27 -2
  46. data/lib/moonrope/errors.rb +3 -0
  47. data/lib/moonrope/eval_environment.rb +82 -3
  48. data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
  49. data/lib/moonrope/eval_helpers.rb +28 -5
  50. data/lib/moonrope/guard.rb +35 -0
  51. data/lib/moonrope/html_generator.rb +65 -0
  52. data/lib/moonrope/param_set.rb +11 -1
  53. data/lib/moonrope/rack_middleware.rb +1 -1
  54. data/lib/moonrope/railtie.rb +31 -14
  55. data/lib/moonrope/request.rb +25 -14
  56. data/lib/moonrope/structure.rb +74 -11
  57. data/lib/moonrope/structure_attribute.rb +15 -0
  58. data/lib/moonrope/version.rb +1 -1
  59. data/lib/moonrope.rb +5 -4
  60. data/moonrope.gemspec +21 -0
  61. data/spec/spec_helper.rb +32 -0
  62. data/spec/specs/action_spec.rb +455 -0
  63. data/spec/specs/base_spec.rb +29 -0
  64. data/spec/specs/controller_spec.rb +31 -0
  65. data/spec/specs/param_set_spec.rb +31 -0
  66. data/templates/basic/_action_form.erb +77 -0
  67. data/templates/basic/_errors_table.erb +32 -0
  68. data/templates/basic/_structure_attributes_list.erb +55 -0
  69. data/templates/basic/action.erb +168 -0
  70. data/templates/basic/assets/lock.svg +3 -0
  71. data/templates/basic/assets/reset.css +101 -0
  72. data/templates/basic/assets/style.css +348 -0
  73. data/templates/basic/assets/tool.svg +4 -0
  74. data/templates/basic/assets/try.js +151 -0
  75. data/templates/basic/authenticator.erb +51 -0
  76. data/templates/basic/controller.erb +20 -0
  77. data/templates/basic/index.erb +114 -0
  78. data/templates/basic/layout.erb +46 -0
  79. data/templates/basic/structure.erb +23 -0
  80. data/test/test_helper.rb +81 -0
  81. data/test/tests/action_access_test.rb +63 -0
  82. data/test/tests/actions_test.rb +524 -0
  83. data/test/tests/authenticators_test.rb +87 -0
  84. data/test/tests/base_test.rb +35 -0
  85. data/test/tests/controllers_test.rb +49 -0
  86. data/test/tests/eval_environment_test.rb +136 -0
  87. data/test/tests/evel_helpers_test.rb +60 -0
  88. data/test/tests/examples_test.rb +11 -0
  89. data/test/tests/helpers_test.rb +97 -0
  90. data/test/tests/param_set_test.rb +44 -0
  91. data/test/tests/rack_middleware_test.rb +109 -0
  92. data/test/tests/request_test.rb +232 -0
  93. data/test/tests/structures_param_extensions_test.rb +159 -0
  94. data/test/tests/structures_test.rb +335 -0
  95. metadata +82 -48
@@ -0,0 +1,50 @@
1
+ authenticator :default do
2
+
3
+ description <<-DESCRIPTION
4
+ To authenticate to the API, you need to pass an appropriate API token with your
5
+ request. To find out how to obtain an API token, please refer to the Authentication
6
+ API documentaton which outlines the available methods available for this.
7
+ DESCRIPTION
8
+
9
+ header "X-Auth-Application", "The API application which is generated by us and provided to you.", :example => "abc123abc123abc123"
10
+ header "X-Auth-Token", "The API token for the user you wish to authenticate as.", :example => "abc123abc123abc123"
11
+
12
+ error "InvalidApplicationToken", "The application token provided in X-Auth-Application is not valid.", :attributes => {:token => "The token used to find the application"}
13
+ error "InvalidAuthToken", "The auth token provided in X-Auth-Token is not valid.", :attributes => {:token => "The token that was used"}
14
+ error "ExpiredAuthToken", "The auth token provided in X-Auth-Token has expired.", :attributes => {:expired_at => "The time the token expired"}
15
+
16
+ lookup do
17
+ if app_token = header['X-Auth-Application']
18
+ api_application = APIApplication.find_by_token(app_token)
19
+ if api_application.nil?
20
+ error "InvalidApplicationToken", :token => app_token
21
+ end
22
+
23
+ if auth_token = header['X-Auth-Token']
24
+ api_token = api_application.api_tokens.find_by_token(auth_token)
25
+ if api_token.nil? || api_token.inactive?
26
+ error "InvalidAuthToken", :token => auth_token
27
+ end
28
+
29
+ if api_token.expired?
30
+ error "ExpiredAuthToken", :expired_at => api_token.expired_at
31
+ end
32
+
33
+ api_token
34
+ end
35
+ end
36
+ end
37
+
38
+ rule :default, "NotAuthenticated", "Must be authenticated with a valid user API token." do
39
+ identity.is_a?(APIToken) && identity.user
40
+ end
41
+
42
+ rule :must_be_admin, "MustBeAdmin", "Must be authenticated as a valid admin user." do
43
+ identity.is_a?(APIToken) && identity.user && identity.user.admin?
44
+ end
45
+
46
+ rule :anonymous, "MustBeAnonymous", "Must not be authenticated (no auth headers provided)." do
47
+ identity == :anonymous
48
+ end
49
+
50
+ end
@@ -0,0 +1,14 @@
1
+ controller :meta do
2
+
3
+ friendly_name "Meta API"
4
+ description <<-DESC
5
+ The meta API provides you with access to information about the API itself.
6
+ DESC
7
+
8
+ action :version do
9
+ description "Return the current software version"
10
+ returns :string, :eg => "v1.2.3"
11
+ action { LlamaCom::VERSION }
12
+ end
13
+
14
+ end
@@ -0,0 +1,92 @@
1
+ controller :users do
2
+
3
+ friendly_name "Users API"
4
+ description <<-DESC
5
+ The Users API provides full access to manage the users
6
+ which exist on your account.
7
+ DESC
8
+
9
+ action :list do
10
+ title "List all users"
11
+ description "This action will return a list of all users which the authenticated user has access to."
12
+ param :page, "The page number", :default => 1, :type => Integer
13
+ param :per_page, "The number of items to return per page", :default => 30, :type => Integer
14
+ sortable :username, :id, :created_at, :updated_at
15
+ paginated
16
+ filterable do
17
+ attribute :username, :type => String
18
+ attribute :age, :type => Integer
19
+ attribute :admin, :type => :boolean
20
+ end
21
+ returns :array, :structure => :user
22
+ action do
23
+ paginate(User.all) do |user|
24
+ structure user, :return => true
25
+ end
26
+ end
27
+ end
28
+
29
+ action :show do
30
+ title "Get unit information"
31
+ param :username, "The user's username", :type => String, :required => true
32
+ returns :hash, :structure => :user, :structure_opts => {:paramable => true}
33
+ error "UserNotFound", "No user was found matching the given username", :attributes => {:username => "The username which was looked up"}
34
+ action do
35
+ if user = User.find_by_username(params.username)
36
+ structure user, :return => true
37
+ else
38
+ error 'UserNotFound', :username => params.username
39
+ end
40
+ end
41
+ end
42
+
43
+ shared_action :properties do
44
+ param :username, "The user's username", :type => String
45
+ param :first_name, "The user's first name", :type => String
46
+ param :last_name, "The user's last name", :type => String
47
+ param :email_address, "The user's e-mail address", :type => String
48
+ param :password, "The user's password", :type => String
49
+ param :admin, "Should this user be an admin?", :type => :boolean do |object, value|
50
+ if identity.admin?
51
+ object.admin = value
52
+ end
53
+ end
54
+ end
55
+
56
+ action :create do
57
+ title "Create a new user"
58
+ description <<-DESCRIPTION
59
+ This action will create a new user with the properties which have been provided.
60
+ DESCRIPTION
61
+ use :properties
62
+ returns :hash, :structure => :user, :structure_opts => {:full => true}
63
+ error "ValidationError", "The details provided were not sufficient to save the user", :attributes => {:errors => "An array of errors for each field"}
64
+ action do
65
+ user = User.new
66
+ if user.save
67
+ structure user, :return => true
68
+ else
69
+ error 'ValidationError', :errors => user.errors
70
+ end
71
+ end
72
+ end
73
+
74
+ action :update do
75
+ title "Update an existing user"
76
+ description "This action will update an existing user with the properties provided."
77
+ param :id, "The ID of the user to update", :type => Integer, :required => true
78
+ use :properties
79
+ returns :hash, :structure => :user, :structure_opts => {:full => true}
80
+ error 'UserNotFound', "The user specified could not be found", :attributes => {:id => "The ID that was looked up"}
81
+ error "ValidationError", "The details provided were not sufficient to save the user", :attributes => {:errors => "An array of errors for each field"}
82
+ action do
83
+ user = User.find_by_id(params.id) || error('UserNotFound', :id => params.id)
84
+ if user.save
85
+ structure user, :return => true
86
+ else
87
+ error 'ValidationError', :errors => user.errors
88
+ end
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,12 @@
1
+ structure :pet do
2
+
3
+ # Uncomment the below line to stop this structure being documented.
4
+ # no_doc!
5
+
6
+ basic :id, "The ID of the pet", :type => Integer, :eg => 148
7
+ basic :name, "The name of the pet", :type => String, :eg => "Fido"
8
+ basic :color, "What color is the pet?", :type => String, :eg => "Green"
9
+
10
+ expansion :user, "The user who owns this pet", :type => Hash, :structure => :user
11
+
12
+ end
@@ -0,0 +1,35 @@
1
+ structure :user do
2
+
3
+ basic :id, "The user's internal system ID", :type => Integer, :eg => 123
4
+ basic :username, "The user's unique username", :type => String, :eg => "adamcooke"
5
+ group :name do
6
+ basic :first, "The user's first name", :type => String, :eg => "Adam", :source_attribute => :first_name
7
+ basic :last, "The user's last name", :type => String, :eg => "Cooke", :source_attribute => :last_name
8
+ end
9
+
10
+ full :admin, "Is this user an administrator?", :type => :boolean
11
+ full :age, "The user's age", :type => Integer, :doc => false
12
+ full :created_at, "The timestamp the user was created", :type => :timestamp
13
+ full :updated_at, "The timestamp the user was updated", :type => :timestamp
14
+
15
+ expansion :pets, "All pets that belong to this user", :structure => :pet, :type => Array
16
+
17
+ expansion :balance, "The user's balance", :type => Float, :eg => 12.50 do
18
+ o.user.balance
19
+ end
20
+
21
+ expansion :hidden, "This is a hidden expansion", :doc => false do
22
+ o.user.hidden
23
+ end
24
+
25
+ condition Proc.new { identity.admin? }, "Can only be accessed by API users with admin access" do
26
+ # This value will only be provided to users who are accesing the API with
27
+ # the permission to view
28
+ full :support_pin, "The PIN this user needs to use to access support", :type => String, :eg => "4953"
29
+ end
30
+
31
+ condition :default => :anonymous do
32
+ full :mask, "The unique mask that represents this user", :type => String, :eg => 'abc123abc123'
33
+ end
34
+
35
+ 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;}
@@ -0,0 +1,348 @@
1
+ html {
2
+ font-family: Lato, Arial, sans-serif;
3
+ font-size:16px;
4
+ }
5
+
6
+ a {
7
+ text-decoration: none;
8
+ }
9
+
10
+ .sidebarBackground {
11
+ background:#2f3e4d;
12
+ width:200px;
13
+ position:fixed;
14
+ top:0;
15
+ bottom:0;
16
+ z-index:1;
17
+ }
18
+
19
+ .sidebar {
20
+ width:200px;
21
+ float:left;
22
+ z-index:10;
23
+ position:absolute;
24
+ }
25
+ .sidebar a {
26
+ display:block;
27
+ padding:7px 15px;
28
+ border-bottom:1px solid #394959;
29
+ color:#889db1;
30
+ font-size:85%;
31
+ }
32
+
33
+ .sidebar a:hover {
34
+ background-color:#26323f;
35
+ }
36
+
37
+ .sidebar a.active {
38
+ background-color:#1d2630;
39
+ color:#fff;
40
+ }
41
+
42
+ .footer {
43
+ margin-left:200px;
44
+ border-top:3px solid #efefef;
45
+ padding:20px 40px 100px 40px;
46
+ font-size:90%;
47
+ color:#999;
48
+ }
49
+
50
+ .content {
51
+ margin-left:200px;
52
+ padding:40px;
53
+ padding-right:15%;
54
+ }
55
+
56
+
57
+ .content h1 {
58
+ font-size:32px;
59
+ font-weight:900;
60
+ margin-bottom:15px;
61
+ }
62
+
63
+ .content h2 {
64
+ font-size:24px;
65
+ font-weight:700;
66
+ color:#f65552;
67
+ margin-bottom:10px;
68
+ margin-top:30px;
69
+ }
70
+
71
+ .content h3 {
72
+ font-size:18px;
73
+ font-weight:700;
74
+ color:#888;
75
+ margin-bottom:10px;
76
+ margin-top:30px;
77
+ }
78
+
79
+ .content p.text {
80
+ line-height:1.5;
81
+ margin-bottom:15px;
82
+ }
83
+
84
+
85
+ .content .standardList {
86
+ margin-bottom:15px;
87
+ line-height:1.5;
88
+ }
89
+
90
+ .content .standardList li {
91
+ list-style:square;
92
+ margin-bottom:15px;
93
+ margin-left:35px;
94
+ }
95
+
96
+ .content code {
97
+ font-family:'Droid Sans Mono', fixed;
98
+ color:#f65552;
99
+ padding:1px 2px;
100
+ font-size:90%;
101
+ }
102
+
103
+ .content pre.code {
104
+ font-family:'Droid Sans Mono', fixed;
105
+ white-space: pre;
106
+ background:#efefef;
107
+ padding:10px 10px 10px;
108
+ font-size:90%;
109
+ margin-bottom:15px;
110
+ border-radius:7px 7px 7px 7px;
111
+ }
112
+
113
+ .content pre.code span.jsonKey {
114
+ color:#7f55ad;
115
+ font-weight:bold;
116
+ }
117
+
118
+ .content pre.code span.jsonString {
119
+ color:#9eb503;
120
+ }
121
+
122
+ .content pre.code span.jsonComment {
123
+ color:#bbb;
124
+ font-style:italic;
125
+ }
126
+
127
+ .content a.link {
128
+ color:#2d80c8;
129
+ font-weight:700;
130
+ border-bottom:1px solid #2d80c8;
131
+ }
132
+
133
+ .content p.apiURL span {
134
+ color:#aaa;
135
+ }
136
+
137
+ .table {
138
+ width:100%;
139
+ }
140
+
141
+ .table th, .table td {
142
+ border-bottom:1px solid #ccc;
143
+ text-align: left;
144
+ padding:7px 0;
145
+ }
146
+
147
+ .table th {
148
+ border-bottom:2px solid #666;
149
+ font-size:90%;
150
+ }
151
+
152
+ .paramTable__req {
153
+ background:#ea4c89;
154
+ color:#fff;
155
+ font-weight:bold;
156
+ font-size:10px;
157
+ text-transform: uppercase;
158
+ padding:1px 3px;
159
+ border-radius: 2px;
160
+ vertical-align: 1px;
161
+ margin-left:5px;
162
+ }
163
+
164
+ .paramTable__field {
165
+ width:100%;
166
+ border:0;
167
+ padding:0;
168
+ font:inherit;
169
+ color:#7f55ad;
170
+ }
171
+
172
+ .paramTable__description {
173
+ font-size:90%;
174
+ color:#999;
175
+ margin-top:3px;
176
+ }
177
+
178
+ .paramTable__name {
179
+ font-family:'Droid Sans Mono', fixed;
180
+ font-size:90%;
181
+ }
182
+
183
+ .paramTable__restrictedList {
184
+ font-size:80%;
185
+ margin-top:7px;
186
+ background:url(lock.svg) no-repeat 0 1px;
187
+ background-size:14px;
188
+ color:#ed4300;
189
+ padding-left:20px;
190
+ }
191
+
192
+ .paramTable__nil {
193
+ color:#ccc;
194
+ font-size:90%;
195
+ }
196
+
197
+ .apiURLFull {
198
+ font-size:110%;
199
+ font-weight:bold;
200
+ }
201
+
202
+ .apiURLFull span {
203
+ color:#aaaaaa;
204
+ font-weight:normal;
205
+ }
206
+
207
+ .errorAttributeList {
208
+ font-size:80%;
209
+ }
210
+
211
+ .errorAttributeList li {
212
+ margin-bottom:8px;
213
+ list-style:square;
214
+ margin-left:16px;
215
+ }
216
+ .errorAttributeList li:last-child {
217
+ margin-bottom:0;
218
+ }
219
+
220
+ .errorAttributeList__name {
221
+ font-family:'Droid Sans Mono', fixed;
222
+ }
223
+
224
+ .errorAttributeList__desc {
225
+ color:#999;
226
+ }
227
+
228
+ /* Try Action Form */
229
+
230
+ .tryForm {
231
+ display:none;
232
+ border:2px solid #ccc;
233
+ background:#f7f7f7;
234
+ border-radius:7px;
235
+ overflow: hidden;
236
+ }
237
+
238
+ .tryForm__header {
239
+ background:#ddd;
240
+ padding:15px 25px;
241
+ font-weight:700;
242
+ color:#999;
243
+
244
+ }
245
+
246
+ .tryForm__header input {
247
+ background:none;
248
+ border:0;
249
+ padding:0;
250
+ vertical-align:0px;
251
+ font:inherit;
252
+ font-weight:700;
253
+ color:#000;
254
+ width:auto;
255
+ }
256
+
257
+ .tryForm__output {
258
+ display:none;
259
+ background:#111;
260
+ color:#fff;
261
+ padding:15px;
262
+ font-family:'Droid Sans Mono', fixed;
263
+ white-space: pre;
264
+ word-wrap:normal;
265
+ font-size:90%;
266
+ overflow-x:auto;
267
+ }
268
+
269
+ .tryForm__output--success {
270
+ border-top:7px solid #68be28;
271
+ }
272
+
273
+ .tryForm__output--error {
274
+ border-top:7px solid #d4172e;
275
+ }
276
+
277
+ .tryForm__heading {
278
+ border-bottom:1px solid #ddd;
279
+ border-top:4px solid #aaa;
280
+ margin-bottom:15px;
281
+ padding:8px 25px;
282
+ background:#efefef;
283
+ font-weight:700;
284
+ font-size:80%;
285
+ text-transform: uppercase;
286
+ color:#888;
287
+ }
288
+
289
+ .tryForm__table {
290
+ font-size:90%;
291
+ width:calc(100% - 50px);
292
+ margin:0 25px;
293
+ margin-bottom:15px;
294
+ }
295
+
296
+ .tryForm__table td {
297
+ padding:5px 0;
298
+ background:#f8f8f8;
299
+ }
300
+
301
+ .tryForm__tableField {
302
+ border:0;
303
+ background:none;
304
+ border-bottom:1px solid #ccc;
305
+ padding:0;
306
+ padding-bottom:4px;
307
+ width:100%;
308
+ font:inherit;
309
+ color:#7f55ad;
310
+ font-weight:700;
311
+ }
312
+
313
+ .tryForm__tableField:focus {
314
+ border-color:#7f55ad;
315
+ }
316
+
317
+ .tryForm__button {
318
+ margin:15px 25px;
319
+ text-align: right;
320
+ }
321
+
322
+ .tryFormActivate {
323
+ margin:20px 0;
324
+ }
325
+ .tryFormActivate__button {
326
+ background:url(tool.svg) #fffce0 no-repeat 12px 7px;
327
+ background-size:12px;
328
+ border:1px solid #dad7bb;
329
+ color:#6c6a55;
330
+ border-radius:4px;
331
+ padding:6px 12px 6px 30px;
332
+ font-size:12px;
333
+ font-weight:700;
334
+ }
335
+
336
+ .tryForm__checkbox {
337
+ margin-bottom:4px;
338
+ }
339
+
340
+ .tryForm__checkbox:last-child {
341
+ margin-bottom:0;
342
+ }
343
+
344
+ .tryForm__checkbox input {
345
+ float:left;
346
+ margin-right:4px;
347
+ margin-top:4px;
348
+ }
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
2
+ <path fill="#6c6a55" d="M5.5 0c-1.38 0-2.5 1.12-2.5 2.5 0 .32.08.62.19.91l-2.91 2.88c-.39.39-.39 1.05 0 1.44.2.2.46.28.72.28.26 0 .52-.09.72-.28l2.88-2.91c.28.11.58.19.91.19 1.38 0 2.5-1.12 2.5-2.5 0-.16 0-.32-.03-.47l-.97.97h-2v-2l.97-.97c-.15-.03-.31-.03-.47-.03zm-4.5 6.5c.28 0 .5.22.5.5s-.22.5-.5.5-.5-.22-.5-.5.22-.5.5-.5z"
3
+ />
4
+ </svg>