lurker 0.6.8 → 1.0.0
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.
- checksums.yaml +5 -5
- data/.hound.yml +4 -78
- data/.jshintrc +33 -0
- data/.rspec +1 -2
- data/.rubocop.yml +0 -1
- data/.travis.yml +30 -19
- data/Gemfile +0 -33
- data/README.md +32 -53
- data/Rakefile +3 -3
- data/cucumber.yml +1 -2
- data/features/atom_persistent_within_the_same_type.feature +4 -4
- data/features/controller_nested_schema_scaffolding.feature +7 -10
- data/features/controller_schema_scaffolding.feature +1 -3
- data/features/dereferencing_through_inlining.feature +1 -3
- data/features/html_generation.feature +26 -4
- data/features/minitest.feature +3 -8
- data/features/multidomain_support.feature +6 -10
- data/features/multitype_request_support.feature +1 -3
- data/features/partials.feature +3 -8
- data/features/request_nested_schema_scaffolding.feature +0 -2
- data/features/request_schema_scaffolding.feature +0 -2
- data/features/schema_suffixes.feature +2 -18
- data/features/schema_updating_within_test_suite.feature +2 -6
- data/features/step_definitions/additional_cli_steps.rb +16 -12
- data/features/support/env.rb +50 -10
- data/features/test_endpoint.feature +2 -9
- data/gemfiles/rails_4.gemfile +14 -0
- data/gemfiles/rails_5.gemfile +10 -0
- data/gemfiles/rails_6.gemfile +10 -0
- data/lib/lurker.rb +9 -2
- data/lib/lurker/cli.rb +148 -128
- data/lib/lurker/endpoint.rb +11 -7
- data/lib/lurker/form_builder.rb +22 -31
- data/lib/lurker/json/concerns/validatable.rb +5 -1
- data/lib/lurker/json/parser.rb +1 -1
- data/lib/lurker/json/schema.rb +19 -6
- data/lib/lurker/json/{writter.rb → writer.rb} +2 -2
- data/lib/lurker/presenters/base_presenter.rb +10 -34
- data/lib/lurker/presenters/endpoint_presenter.rb +19 -8
- data/lib/lurker/presenters/schema_presenter.rb +6 -5
- data/lib/lurker/presenters/service_presenter.rb +41 -7
- data/lib/lurker/rendering_controller.rb +14 -7
- data/lib/lurker/service.rb +27 -11
- data/lib/lurker/spec_helper/rspec.rb +0 -4
- data/lib/lurker/spy.rb +3 -1
- data/lib/lurker/templates/documentation.md.tt +1 -0
- data/lib/lurker/templates/javascripts/lurker.js +133 -91
- data/lib/lurker/templates/layouts/_sidemenu.html.erb +2 -2
- data/lib/lurker/templates/layouts/application.html.erb +54 -57
- data/lib/lurker/templates/layouts/print.html.erb +31 -0
- data/lib/lurker/templates/lurker/rendering/_endpoint.html.erb +37 -0
- data/lib/lurker/templates/lurker/rendering/_param_form_element.html.erb +1 -1
- data/lib/lurker/templates/lurker/rendering/_service.html.erb +7 -0
- data/lib/lurker/templates/lurker/rendering/_submit_form.html.erb +77 -73
- data/lib/lurker/templates/lurker/rendering/all.html.erb +5 -0
- data/lib/lurker/templates/lurker/rendering/index.html.erb +1 -10
- data/lib/lurker/templates/lurker/rendering/show.html.erb +1 -37
- data/lib/lurker/templates/public/application.css +6 -2
- data/lib/lurker/templates/public/application.js +13 -13
- data/lib/lurker/templates/stylesheets/application.scss +3 -0
- data/lib/lurker/version.rb +1 -1
- data/lurker.gemspec +31 -33
- data/spec/spec_helper.rb +0 -1
- data/tasks/build.rake +12 -8
- data/tasks/generate.rake +44 -17
- data/templates/Dockerfile +26 -0
- data/templates/generate_stuff.rb +59 -26
- data/templates/lurker_app.rb +27 -48
- data/templates/rails4_ruby26_thread_error_fix.rb +20 -0
- metadata +149 -106
- checksums.yaml.gz.sig +0 -2
- data.tar.gz.sig +0 -3
- data/Appraisals +0 -20
- data/gemfiles/rails_32.gemfile +0 -27
- data/gemfiles/rails_40.gemfile +0 -27
- data/gemfiles/rails_41.gemfile +0 -27
- data/gemfiles/rails_42.gemfile +0 -27
- data/lib/lurker/templates/lurker/rendering/_param_form_legend.html.erb +0 -1
- data/lib/lurker/templates/meta_service.md.erb +0 -20
- data/lib/lurker/validation_error.rb +0 -4
- data/templates/rails32_http_patch_support.rb +0 -125
- metadata.gz.sig +0 -0
@@ -2,28 +2,30 @@ require 'ostruct'
|
|
2
2
|
require 'abstract_controller'
|
3
3
|
require 'action_view'
|
4
4
|
require 'action_dispatch/http/mime_type'
|
5
|
+
require 'action_dispatch/routing'
|
5
6
|
|
6
7
|
module Lurker
|
7
8
|
class RenderingController < ::AbstractController::Base
|
8
9
|
# Include all the concerns we need to make this work
|
10
|
+
include AbstractController::Logger
|
9
11
|
include AbstractController::Helpers
|
10
12
|
include AbstractController::Rendering
|
11
|
-
include
|
12
|
-
include ActionView::Layouts if defined?(ActionView::Layouts) # Rails 4.1.x
|
13
|
+
include AbstractController::AssetPaths
|
13
14
|
include AbstractController::Layouts if defined?(AbstractController::Layouts) # Rails 3.2.x, 4.0.x
|
15
|
+
include ActionView::Layouts if defined?(ActionView::Layouts) # Rails 4.1.x
|
16
|
+
include ActionView::Rendering if defined?(ActionView::Rendering)
|
14
17
|
include ActionView::Context
|
15
18
|
|
16
|
-
|
19
|
+
attr_writer :service_presenter, :endpoint_presenter
|
17
20
|
|
18
21
|
# Define additional helpers, this one is for csrf_meta_tag
|
19
|
-
helper_method :
|
22
|
+
helper_method :title, :tag_with_anchor, :protect_against_forgery?
|
20
23
|
|
21
24
|
# override the layout in your subclass if needed.
|
22
25
|
layout 'application'
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
false
|
27
|
+
def title
|
28
|
+
[@service_presenter.try(:title), @endpoint_presenter.try(:title)].compact.join ' | '
|
27
29
|
end
|
28
30
|
|
29
31
|
def tag_with_anchor(tag, content, anchor_slug = nil)
|
@@ -37,6 +39,11 @@ module Lurker
|
|
37
39
|
EOS
|
38
40
|
end
|
39
41
|
|
42
|
+
# we are not in a browser, no need for this
|
43
|
+
def protect_against_forgery?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
40
47
|
# so that your flash calls still work
|
41
48
|
def flash
|
42
49
|
{}
|
data/lib/lurker/service.rb
CHANGED
@@ -3,8 +3,17 @@ require 'yaml'
|
|
3
3
|
# Services represent a group of Lurker API endpoints in a directory
|
4
4
|
class Lurker::Service
|
5
5
|
attr_reader :service_dir, :schema
|
6
|
+
attr_writer :documentation
|
6
7
|
attr_accessor :opened_endpoints
|
7
8
|
SUFFIX = '.service.yml'
|
9
|
+
DEFAULT_SCHEMA = {
|
10
|
+
'name' => '',
|
11
|
+
'basePath' => '',
|
12
|
+
'description' => '',
|
13
|
+
'domains' => {},
|
14
|
+
'consumes' => %w(application/x-www-form-urlencode application/json),
|
15
|
+
'produces' => %w(application/json)
|
16
|
+
}
|
8
17
|
|
9
18
|
def self.default_service
|
10
19
|
new(Lurker.service_path)
|
@@ -15,14 +24,9 @@ class Lurker::Service
|
|
15
24
|
@service_dir = File.expand_path(service_dir)
|
16
25
|
@service_filename = service_name
|
17
26
|
@schema = if persisted? && (schema = YAML.load_file(service_path)).is_a?(Hash)
|
18
|
-
Lurker::Json::Schema.new(schema)
|
27
|
+
Lurker::Json::Schema.new(schema.stringify_keys, uri: service_path)
|
19
28
|
else
|
20
|
-
Lurker::Json::Schema.new(
|
21
|
-
'name' => service_filename,
|
22
|
-
'basePath' => '',
|
23
|
-
'description' => '',
|
24
|
-
'domains' => {}
|
25
|
-
)
|
29
|
+
Lurker::Json::Schema.new(DEFAULT_SCHEMA.merge('name' => service_filename), uri: service_path)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -39,7 +43,7 @@ class Lurker::Service
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def persist!
|
42
|
-
Lurker::Json::
|
46
|
+
Lurker::Json::Writer.write(schema, service_path) unless File.exist?(service_path)
|
43
47
|
@opened_endpoints.each { |ep| ep.persist! if ep.respond_to?(:persist!) }
|
44
48
|
end
|
45
49
|
|
@@ -97,19 +101,31 @@ class Lurker::Service
|
|
97
101
|
if base_path && !base_path.end_with?('/')
|
98
102
|
base_path + '/'
|
99
103
|
else
|
100
|
-
base_path
|
104
|
+
base_path || '/'
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
104
108
|
def description
|
105
|
-
|
109
|
+
schema['description']
|
106
110
|
end
|
107
111
|
|
108
112
|
def discussion
|
109
|
-
|
113
|
+
schema['discussion']
|
110
114
|
end
|
111
115
|
|
112
116
|
def domains
|
113
117
|
schema['domains']
|
114
118
|
end
|
119
|
+
|
120
|
+
def request_media_types
|
121
|
+
schema['consumes']
|
122
|
+
end
|
123
|
+
|
124
|
+
def response_media_types
|
125
|
+
schema['produces']
|
126
|
+
end
|
127
|
+
|
128
|
+
def documentation
|
129
|
+
@documentation ||= schema.documentation
|
130
|
+
end
|
115
131
|
end
|
data/lib/lurker/spy.rb
CHANGED
@@ -16,7 +16,9 @@ module Lurker
|
|
16
16
|
@block = block
|
17
17
|
|
18
18
|
@service = if defined?(Rails)
|
19
|
-
|
19
|
+
rails_app_class = Rails.application.class
|
20
|
+
rails_app_name = rails_app_class.respond_to?(:module_parent_name) ? rails_app_class.module_parent_name : rails_app_class.parent_name
|
21
|
+
Service.new(Rails.root.join(DEFAULT_SERVICE_PATH).to_s, rails_app_name)
|
20
22
|
else
|
21
23
|
Service.default_service
|
22
24
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This is an autogenerated documentation stub. You can edit it in: `<%= config[:path] %>`
|
@@ -1,101 +1,143 @@
|
|
1
|
-
|
2
|
-
var $ = window
|
3
|
-
var
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
(function() {
|
2
|
+
var $ = window.jQuery;
|
3
|
+
var hljs = window.hljs;
|
4
|
+
|
5
|
+
var Lurker = {
|
6
|
+
disableSubmitButton: function() {
|
7
|
+
$("#submit-api").attr("disabled", true);
|
8
|
+
},
|
9
|
+
|
10
|
+
enableSubmitButton: function() {
|
11
|
+
$("#submit-api").attr("disabled", false);
|
12
|
+
},
|
13
|
+
|
14
|
+
fillInInfoTab: function($tab, xhr) {
|
15
|
+
$tab.find('.status td.value').text(xhr.status + " " + xhr.statusText);
|
16
|
+
$tab.find('#headers').text(xhr.getAllResponseHeaders());
|
17
|
+
|
18
|
+
var realTimeTaken = Lurker.lastRequest.endTime - Lurker.lastRequest.startTime;
|
19
|
+
$tab.find('.time td.value').text(realTimeTaken + " ms");
|
20
|
+
},
|
21
|
+
|
22
|
+
fillInRawTab: function($tab, xhr) {
|
23
|
+
var content;
|
24
|
+
switch (Lurker.detectContentType(xhr)) {
|
25
|
+
case "json":
|
26
|
+
var json = JSON.stringify(JSON.parse(xhr.responseText), null, 2);
|
27
|
+
content = hljs.highlightAuto(json).value;
|
28
|
+
break;
|
29
|
+
default:
|
30
|
+
content = xhr.responseText;
|
31
|
+
}
|
32
|
+
$tab.html(content);
|
33
|
+
},
|
34
|
+
|
35
|
+
detectContentType: function(response) {
|
36
|
+
var contentType = response.getResponseHeader("Content-Type");
|
37
|
+
var detectedContentType = null;
|
38
|
+
|
39
|
+
if (contentType.match(/application\/json/)) {
|
40
|
+
detectedContentType = 'json';
|
41
|
+
}
|
42
|
+
|
43
|
+
return detectedContentType;
|
44
|
+
},
|
45
|
+
|
46
|
+
buildActionUrl: function(host, template, values) {
|
47
|
+
for (var i = 0; i < values.length; i++) {
|
48
|
+
var placeholder = new RegExp(':' + values[i].label);
|
49
|
+
template = template.replace(placeholder, encodeURIComponent(values[i].value));
|
50
|
+
}
|
51
|
+
return host + template;
|
52
|
+
},
|
53
|
+
|
54
|
+
serializePayload: function(payload, contentType) {
|
55
|
+
if (contentType === 'application/json' || /\+json$/.test(contentType)) {
|
56
|
+
return JSON.stringify(payload);
|
57
|
+
} else {
|
58
|
+
// default to 'application/x-www-form-urlencoded'
|
59
|
+
return jQuery.param(payload);
|
60
|
+
}
|
61
|
+
},
|
62
|
+
|
63
|
+
generateCurlCommand: function(targetUrl, method, payload, contentType) {
|
64
|
+
var serializedPayload = Lurker.serializePayload(payload, contentType);
|
65
|
+
var results = [];
|
66
|
+
results.push('curl');
|
67
|
+
results.push('-X ' + method);
|
68
|
+
if (serializedPayload.length > 0) {
|
69
|
+
if (contentType != 'application/x-www-form-urlencoded') {
|
70
|
+
results.push("-H 'Content-Type: " + contentType + "'");
|
71
|
+
}
|
72
|
+
results.push("-d '" + serializedPayload + "'");
|
73
|
+
}
|
74
|
+
results.push("'" + targetUrl + "'");
|
75
|
+
return results.join(' ');
|
76
|
+
},
|
77
|
+
|
78
|
+
performRequest: function(host, method, template, values, payload, contentType) {
|
79
|
+
Lurker.disableSubmitButton();
|
80
|
+
|
81
|
+
$.ajax({
|
82
|
+
url: Lurker.buildActionUrl(host, template, values),
|
83
|
+
data: Lurker.serializePayload(payload, contentType),
|
84
|
+
method: method,
|
85
|
+
contentType: contentType,
|
86
|
+
processData: false
|
87
|
+
}).complete(Lurker.onComplete);
|
88
|
+
|
89
|
+
Lurker.lastRequest = {};
|
90
|
+
Lurker.lastRequest.startTime = Date.now();
|
91
|
+
|
92
|
+
return false;
|
93
|
+
},
|
94
|
+
|
95
|
+
onComplete: function(xhr) {
|
96
|
+
Lurker.lastRequest.endTime = Date.now();
|
97
|
+
Lurker.enableSubmitButton();
|
98
|
+
|
99
|
+
var $responseDiv = $("#show-api-response-div");
|
100
|
+
$responseDiv.find("[ref^='response']").hide();
|
101
|
+
|
102
|
+
Lurker.fillInInfoTab($responseDiv.showNavTab("info"), xhr);
|
103
|
+
Lurker.fillInRawTab($responseDiv.showNavTab("raw"), xhr);
|
104
|
+
}
|
105
|
+
};
|
12
106
|
|
13
|
-
|
14
|
-
var contentType = response.getResponseHeader("Content-Type");
|
15
|
-
var detectedContentType = null;
|
107
|
+
window.Lurker = Lurker;
|
16
108
|
|
17
|
-
|
18
|
-
|
109
|
+
$(function($) {
|
110
|
+
var activeMenuItem = $('#side-menu').find('a[href="' + window.location.pathname + '"]');
|
111
|
+
if (activeMenuItem.length === 1) {
|
112
|
+
activeMenuItem.addClass('hovered')
|
113
|
+
.parents('.collapse').addClass('in')
|
114
|
+
.parents('.endpoint-group').addClass('active');
|
19
115
|
}
|
20
116
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
var realTimeTaken = Lurker.lastRequest.endTime - Lurker.lastRequest.startTime;
|
29
|
-
$tab.find('.time td.value').text(realTimeTaken + " ms");
|
30
|
-
},
|
31
|
-
|
32
|
-
fillInRawTab: function($tab, xhr) {
|
33
|
-
switch (Lurker.detectContentType(xhr)) {
|
34
|
-
case "json":
|
35
|
-
var json = JSON.stringify(JSON.parse(xhr.responseText), null, 2);
|
36
|
-
var content = hljs.highlightAuto(json).value;
|
37
|
-
break;
|
38
|
-
default:
|
39
|
-
var content = xhr.responseText;
|
117
|
+
window.domain = window.localStorage.lastDomain || '/';
|
118
|
+
window.domainName = window.localStorage.lastDomainName || 'Local';
|
119
|
+
function currentDomain(domain, domainName) {
|
120
|
+
$('.domains').find('.current')
|
121
|
+
.text(domainName)
|
122
|
+
.data('domain', domain);
|
40
123
|
}
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
$(
|
49
|
-
|
50
|
-
|
51
|
-
Lurker.fillInRawTab($("#show-api-response-div").showNavTab("raw"), xhr);
|
52
|
-
},
|
53
|
-
|
54
|
-
onSubmit: function($form) {
|
55
|
-
Lurker.disableSubmitButton();
|
56
|
-
|
57
|
-
$.ajax({
|
58
|
-
url: $form.attr('action'),
|
59
|
-
method: $form.attr('method'),
|
60
|
-
data: $form.serialize()
|
61
|
-
}).complete(Lurker.onComplete);
|
62
|
-
|
63
|
-
Lurker.lastRequest = {};
|
64
|
-
Lurker.lastRequest.startTime = Date.now();
|
65
|
-
|
66
|
-
return false;
|
67
|
-
}
|
68
|
-
};
|
69
|
-
|
70
|
-
$(function($) {
|
71
|
-
var activeMenuItem = $('#side-menu a[href="' + window.location.pathname + '"]');
|
72
|
-
if (activeMenuItem.length === 1) {
|
73
|
-
activeMenuItem.addClass('hovered').parents('.collapse').addClass('in').parents('.endpoint-group').addClass('active');
|
74
|
-
}
|
75
|
-
|
76
|
-
window.domain = window.localStorage.lastDomain || '/';
|
77
|
-
window.domainName = window.localStorage.lastDomainName || 'Local';
|
78
|
-
function currentDomain(domain, domainName) {
|
79
|
-
$('.domains').find('.current')
|
80
|
-
.text(domainName)
|
81
|
-
.data('domain', domain);
|
82
|
-
}
|
83
|
-
|
84
|
-
$('.domains .domain').click(function() {
|
85
|
-
window.domain = window.localStorage.lastDomain = $(this).data('domain');
|
86
|
-
window.domainName = window.localStorage.lastDomainName = $(this).text() + " (" + window.domain + ")";
|
124
|
+
|
125
|
+
$('.domains .domain').click(function() {
|
126
|
+
window.domain = window.localStorage.lastDomain = $(this).data('domain');
|
127
|
+
window.domainName = window.localStorage.lastDomainName = $(this).text() + " (" + window.domain + ")";
|
128
|
+
currentDomain(window.domain, window.domainName);
|
129
|
+
});
|
130
|
+
|
131
|
+
$('.domains .current.btn').click(function() {
|
132
|
+
window.location = $(this).data('domain');
|
133
|
+
});
|
87
134
|
currentDomain(window.domain, window.domainName);
|
88
135
|
});
|
89
136
|
|
90
|
-
|
91
|
-
|
137
|
+
$.fn.extend({
|
138
|
+
showNavTab: function(name) {
|
139
|
+
return $(this).find("[ref=response-" + name + "]").show();
|
140
|
+
}
|
92
141
|
});
|
93
|
-
|
94
|
-
});
|
95
|
-
|
96
|
-
$.fn.extend({
|
97
|
-
showNavTab: function(name) {
|
98
|
-
return $(this).find("[ref=response-" + name + "]").show();
|
99
|
-
},
|
100
|
-
});
|
142
|
+
})();
|
101
143
|
|
@@ -5,9 +5,9 @@
|
|
5
5
|
<% endpoints.each do |endpoint| %>
|
6
6
|
<li class="<%= (@endpoint_presenter.nil? && 'opened') || (endpoint.url == @endpoint_presenter.url && 'active') %>">
|
7
7
|
<a href="<%= endpoint.url %>">
|
8
|
-
<span class="btn btn-<%= endpoint.verb_colorname %> btn-xs"><%= endpoint.verb %> <%= endpoint.named_path %></span>
|
9
|
-
<br>
|
10
8
|
<span><%= endpoint.title %></span>
|
9
|
+
<br>
|
10
|
+
<span class="btn btn-<%= endpoint.verb_colorname %> btn-xs"><%= endpoint.verb %> <%= endpoint.named_path %></span>
|
11
11
|
</a>
|
12
12
|
</li>
|
13
13
|
<% end %>
|
@@ -1,70 +1,67 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
|
-
|
4
3
|
<head>
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
}
|
22
|
-
</style>
|
23
|
-
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title><%= title %></title>
|
7
|
+
<link href="<%= @service_presenter.asset_path('application.css') %>" media="all" rel="stylesheet">
|
8
|
+
<style type="text/css">
|
9
|
+
@font-face {
|
10
|
+
font-family: 'FontAwesome';
|
11
|
+
src: url("<%= @service_presenter.asset_path '/fonts/fontawesome-webfont.eot?v=4.0.3' %>");
|
12
|
+
src: url("<%= @service_presenter.asset_path '/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3' %>") format("embedded-opentype"),
|
13
|
+
url("<%= @service_presenter.asset_path '/fonts/fontawesome-webfont.woff?v=4.0.3' %>") format("woff"),
|
14
|
+
url("<%= @service_presenter.asset_path '/fonts/fontawesome-webfont.ttf?v=4.0.3' %>") format("truetype"),
|
15
|
+
url("<%= @service_presenter.asset_path '/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular' %>") format("svg");
|
16
|
+
font-weight: normal;
|
17
|
+
font-style: normal;
|
18
|
+
}
|
19
|
+
</style>
|
24
20
|
</head>
|
25
|
-
|
26
21
|
<body>
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
<header class="navbar navbar-static-top bs-docs-nav" id="top" role="banner">
|
24
|
+
<div class="container">
|
25
|
+
<div class="navbar-header">
|
26
|
+
<a class="navbar-brand" href="<%= @service_presenter.html_directory %>"><%= @service_presenter.name %></a>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</header>
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
<div class="col-md-3">
|
44
|
-
<div class="bs-docs-sidebar hidden-print" role="complementary">
|
45
|
-
<ul class="nav bs-docs-sidenav">
|
46
|
-
<%= render 'layouts/sidemenu' %>
|
47
|
-
</ul>
|
48
|
-
</div>
|
49
|
-
</div>
|
31
|
+
<div class="container bs-docs-container">
|
32
|
+
<div class="row">
|
33
|
+
<div class="col-md-9" role="main">
|
34
|
+
<div class="bs-docs-section">
|
35
|
+
<%= yield %>
|
50
36
|
</div>
|
51
37
|
</div>
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
<li>·</li>
|
57
|
-
<% if @service_presenter.options[:footer].present? %>
|
58
|
-
<li><%= @service_presenter.name %> <%= @service_presenter.options[:footer] %></li>
|
59
|
-
<li>·</li>
|
60
|
-
<% end %>
|
61
|
-
<% if @service_presenter.options[:lurker].present? %>
|
62
|
-
<li><%= @service_presenter.options[:lurker] %></li>
|
63
|
-
<li>·</li>
|
64
|
-
<% end %>
|
38
|
+
<div class="col-md-3">
|
39
|
+
<div class="bs-docs-sidebar hidden-print" role="complementary">
|
40
|
+
<ul class="nav bs-docs-sidenav">
|
41
|
+
<%= render 'layouts/sidemenu' %>
|
65
42
|
</ul>
|
66
43
|
</div>
|
67
|
-
</
|
68
|
-
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
<footer class="bs-docs-footer" role="contentinfo">
|
49
|
+
<div class="container">
|
50
|
+
<ul class="bs-docs-footer-links muted">
|
51
|
+
<li>·</li>
|
52
|
+
<% if @service_presenter.footer.present? %>
|
53
|
+
<li><%= raw @service_presenter.footer %></li>
|
54
|
+
<li>·</li>
|
55
|
+
<% end %>
|
56
|
+
<% if @service_presenter.lurker.present? %>
|
57
|
+
<li><%= raw @service_presenter.lurker %></li>
|
58
|
+
<li>·</li>
|
59
|
+
<% end %>
|
60
|
+
</ul>
|
61
|
+
</div>
|
62
|
+
</footer>
|
63
|
+
|
64
|
+
<script src="<%= @service_presenter.asset_path 'application.js' %>"></script>
|
65
|
+
|
69
66
|
</body>
|
70
67
|
</html>
|