nexmo_markdown_renderer 0.2.1 → 0.4.1
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 +4 -4
- data/config/locales/en.yml +1 -0
- data/lib/nexmo_markdown_renderer.rb +24 -1
- data/lib/nexmo_markdown_renderer/filters/block_escape_filter.rb +3 -3
- data/lib/nexmo_markdown_renderer/filters/code_filter.rb +17 -17
- data/lib/nexmo_markdown_renderer/filters/code_snippet/binding.rb +41 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/create_application.rb +61 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/import_dependencies.rb +38 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/initialize_dependencies.rb +41 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/install_dependencies.rb +38 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/instructions.rb +46 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/renderable.rb +62 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet/run.rb +29 -0
- data/lib/nexmo_markdown_renderer/filters/code_snippet_filter.rb +22 -159
- data/lib/nexmo_markdown_renderer/filters/concerns/prism_code_snippet.rb +22 -0
- data/lib/nexmo_markdown_renderer/filters/markdown_filter.rb +13 -10
- data/lib/nexmo_markdown_renderer/filters/partial_filter.rb +1 -1
- data/lib/nexmo_markdown_renderer/filters/screenshot_filter.rb +1 -1
- data/lib/nexmo_markdown_renderer/filters/tab_filter.rb +73 -70
- data/lib/nexmo_markdown_renderer/filters/utils.rb +50 -0
- data/lib/nexmo_markdown_renderer/models/code_language.rb +1 -1
- data/lib/nexmo_markdown_renderer/models/tutorial.rb +116 -72
- data/lib/nexmo_markdown_renderer/models/tutorial/file_loader.rb +32 -0
- data/lib/nexmo_markdown_renderer/models/tutorial/metadata.rb +57 -0
- data/lib/nexmo_markdown_renderer/models/tutorial/prerequisite.rb +35 -0
- data/lib/nexmo_markdown_renderer/models/tutorial/task.rb +49 -0
- data/lib/nexmo_markdown_renderer/models/use_case.rb +3 -16
- data/lib/nexmo_markdown_renderer/services/doc_finder.rb +7 -2
- data/lib/nexmo_markdown_renderer/views/code_snippets/_application_rtc.html.erb +1 -1
- data/lib/nexmo_markdown_renderer/views/code_snippets/_application_voice.html.erb +1 -1
- data/lib/nexmo_markdown_renderer/views/code_snippets/_configure_client.html.erb +2 -2
- data/lib/nexmo_markdown_renderer/views/code_snippets/_import_dependencies.html.erb +18 -0
- data/lib/version.rb +1 -1
- metadata +17 -2
@@ -0,0 +1,29 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module Markdown
|
3
|
+
module Filters
|
4
|
+
module CodeSnippet
|
5
|
+
class Run
|
6
|
+
include OcticonsHelper
|
7
|
+
include Renderable
|
8
|
+
|
9
|
+
def initialize(config, snippet)
|
10
|
+
@config = config
|
11
|
+
@snippet = snippet
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_command
|
15
|
+
@run_command ||= begin
|
16
|
+
if @config['run_command']
|
17
|
+
@config['run_command'].gsub('{filename}', file_name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def render
|
23
|
+
renderer.run_command(run_command, file_name, @config['code']['source']).to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -5,183 +5,46 @@ module Nexmo
|
|
5
5
|
|
6
6
|
def call(input)
|
7
7
|
input.gsub(/```single_code_snippet(.+?)```/m) do |_s|
|
8
|
-
config = YAML.safe_load($1)
|
8
|
+
@config = YAML.safe_load($1)
|
9
|
+
@binding = ::Nexmo::Markdown::Filters::CodeSnippet::Binding.new(@config)
|
9
10
|
|
10
|
-
|
11
|
+
return instructions if @config['code_only']
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
application_html = generate_application_block(config['application'])
|
16
|
-
|
17
|
-
# Read the client
|
18
|
-
if config['client']
|
19
|
-
highlighted_client_source = generate_code_block(config['language'], config['client'], config['unindent'])
|
20
|
-
end
|
21
|
-
|
22
|
-
# Read the code
|
23
|
-
highlighted_code_source = generate_code_block(config['language'], config['code'], config['unindent'])
|
24
|
-
|
25
|
-
dependency_html = ''
|
26
|
-
if config['dependencies']
|
27
|
-
dependency_html = generate_dependencies(lexer.tag, config['dependencies'])
|
28
|
-
end
|
29
|
-
|
30
|
-
source_url = generate_source_url(config['code'])
|
31
|
-
|
32
|
-
client_html = ''
|
33
|
-
if highlighted_client_source
|
34
|
-
client_url = generate_source_url(config['client'])
|
35
|
-
id = SecureRandom.hex
|
36
|
-
create_instructions = @renderer.create_instructions(config['file_name']).render_markdown
|
37
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_configure_client.html.erb")
|
38
|
-
client_html = ERB.new(erb).result(binding)
|
39
|
-
end
|
40
|
-
|
41
|
-
add_instructions = @renderer.add_instructions(config['file_name']).render_markdown
|
42
|
-
if config['code_only']
|
43
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_code_only.html.erb")
|
44
|
-
else
|
45
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_write_code.html.erb")
|
46
|
-
end
|
47
|
-
|
48
|
-
code_html = ERB.new(erb).result(binding)
|
49
|
-
|
50
|
-
return code_html if config['code_only']
|
51
|
-
|
52
|
-
config['run_command'] = config['run_command'].gsub('{filename}', config['file_name']) if config['run_command']
|
53
|
-
run_html = @renderer.run_command(config['run_command'], config['file_name'], config['code']['source']).to_s
|
13
|
+
"#{prerequisites}#{instructions}#{run}"
|
14
|
+
end
|
15
|
+
end
|
54
16
|
|
55
|
-
|
17
|
+
def prerequisites
|
18
|
+
@prerequisites ||= begin
|
19
|
+
prereqs = [application_html, install_dependencies, import_dependencies, initialize_dependencies].join.strip
|
56
20
|
prereqs = "<h2>#{::I18n.t('.filters.prerequisites')}</h2>#{prereqs}" unless prereqs.empty?
|
57
|
-
prereqs
|
21
|
+
prereqs
|
58
22
|
end
|
59
23
|
end
|
60
24
|
|
61
|
-
|
62
|
-
|
63
|
-
def highlight(source, lexer)
|
64
|
-
formatter = Rouge::Formatters::HTML.new
|
65
|
-
formatter.format(lexer.lex(source))
|
25
|
+
def application_html
|
26
|
+
@application_html ||= ::Nexmo::Markdown::Filters::CodeSnippet::CreateApplication.new(@config['application']).render
|
66
27
|
end
|
67
28
|
|
68
|
-
def
|
69
|
-
|
70
|
-
return '' unless input
|
71
|
-
raise "CodeSnippetFilter - Could not load #{filename} for language #{language}" unless File.exist?(filename)
|
72
|
-
|
73
|
-
code = File.read(filename)
|
74
|
-
lexer = Nexmo::Markdown::CodeLanguage.find(language).lexer
|
75
|
-
|
76
|
-
total_lines = code.lines.count
|
77
|
-
|
78
|
-
# Minus one since lines are not zero-indexed
|
79
|
-
from_line = (input['from_line'] || 1) - 1
|
80
|
-
to_line = (input['to_line'] || total_lines) - 1
|
81
|
-
|
82
|
-
code = code.lines[from_line..to_line].join
|
83
|
-
code.unindent! if unindent
|
84
|
-
|
85
|
-
highlight(code, lexer)
|
29
|
+
def install_dependencies
|
30
|
+
@install_dependencies ||= ::Nexmo::Markdown::Filters::CodeSnippet::InstallDependencies.new(@config['dependencies'], @binding).render
|
86
31
|
end
|
87
32
|
|
88
|
-
def
|
89
|
-
|
90
|
-
case language
|
91
|
-
when 'curl'
|
92
|
-
Nexmo::Markdown::CodeSnippetRenderer::Curl
|
93
|
-
when 'node'
|
94
|
-
Nexmo::Markdown::CodeSnippetRenderer::Javascript
|
95
|
-
when 'javascript'
|
96
|
-
Nexmo::Markdown::CodeSnippetRenderer::Javascript
|
97
|
-
when 'java'
|
98
|
-
Nexmo::Markdown::CodeSnippetRenderer::Java
|
99
|
-
when 'dotnet'
|
100
|
-
Nexmo::Markdown::CodeSnippetRenderer::Dotnet
|
101
|
-
when 'python'
|
102
|
-
Nexmo::Markdown::CodeSnippetRenderer::Python
|
103
|
-
when 'ruby'
|
104
|
-
Nexmo::Markdown::CodeSnippetRenderer::Ruby
|
105
|
-
when 'php'
|
106
|
-
Nexmo::Markdown::CodeSnippetRenderer::Php
|
107
|
-
when 'android'
|
108
|
-
Nexmo::Markdown::CodeSnippetRenderer::Android
|
109
|
-
when 'kotlin'
|
110
|
-
Nexmo::Markdown::CodeSnippetRenderer::Kotlin
|
111
|
-
when 'objective_c'
|
112
|
-
Nexmo::Markdown::CodeSnippetRenderer::ObjectiveC
|
113
|
-
when 'swift'
|
114
|
-
Nexmo::Markdown::CodeSnippetRenderer::Swift
|
115
|
-
else
|
116
|
-
raise "Unknown language: #{language}"
|
117
|
-
end
|
33
|
+
def import_dependencies
|
34
|
+
@import_dependencies ||= ::Nexmo::Markdown::Filters::CodeSnippet::ImportDependencies.new(@config['import_dependencies'], @binding).render
|
118
35
|
end
|
119
36
|
|
120
|
-
def
|
121
|
-
|
122
|
-
if dependencies.map(&:upcase).include?('JWT')
|
123
|
-
title = ::I18n.t('filters.generate_your_jwt')
|
124
|
-
else
|
125
|
-
title = ::I18n.t('filters.install_dependencies')
|
126
|
-
end
|
127
|
-
deps = @renderer.dependencies(dependencies)
|
128
|
-
id = SecureRandom.hex
|
129
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_dependencies.html.erb")
|
130
|
-
ERB.new(erb).result(binding)
|
37
|
+
def initialize_dependencies
|
38
|
+
@initialize_dependencies ||= ::Nexmo::Markdown::Filters::CodeSnippet::InitializeDependencies.new(@config['client'], @binding).render
|
131
39
|
end
|
132
40
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
base_url = 'http://demo.ngrok.io'
|
137
|
-
base_url = 'https://example.com' if app['disable_ngrok']
|
138
|
-
|
139
|
-
app['name'] = 'ExampleProject' unless app['name']
|
140
|
-
|
141
|
-
# We should remove this default once we're sure that all Code Snippets
|
142
|
-
# have a type set e.g audit
|
143
|
-
app['type'] ||= 'voice'
|
144
|
-
|
145
|
-
if ['voice', 'rtc'].include? app['type']
|
146
|
-
app['event_url'] = "#{base_url}/webhooks/events" unless app['event_url']
|
147
|
-
app['answer_url'] = "#{base_url}/webhooks/answer" unless app['answer_url']
|
148
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_application_#{app['type']}.html.erb")
|
149
|
-
elsif ['messages', 'dispatch'].include? app['type']
|
150
|
-
erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_application_messages_dispatch.html.erb")
|
151
|
-
else
|
152
|
-
raise "Invalid application type when creating code snippet: '#{app['type']}'"
|
153
|
-
end
|
154
|
-
|
155
|
-
id = SecureRandom.hex
|
156
|
-
|
157
|
-
ERB.new(erb).result(binding)
|
41
|
+
def instructions
|
42
|
+
@instructions ||= ::Nexmo::Markdown::Filters::CodeSnippet::Instructions.new(@config, @binding).render
|
158
43
|
end
|
159
44
|
|
160
|
-
def
|
161
|
-
|
162
|
-
# Direct link on GitHub is in form https://github.com/nexmo/nexmo-java-code-snippets/blob/master/ExampleClass.java
|
163
|
-
start_section = 'https://github.com'
|
164
|
-
|
165
|
-
# Insert "blob/master" and strip ".repos"
|
166
|
-
repo_path = '\\0blob/master/'
|
167
|
-
file_section = code['source'].sub('.repos', '').sub(%r{(-quickstart|-code-snippets|-code-snippets)/}, repo_path)
|
168
|
-
|
169
|
-
# Line highlighting
|
170
|
-
line_section = ''
|
171
|
-
if code['from_line']
|
172
|
-
line_section += "#L#{code['from_line']}"
|
173
|
-
if code['to_line']
|
174
|
-
# If we've provided a to_line, use that
|
175
|
-
line_section += "-L#{code['to_line']}" if code['to_line']
|
176
|
-
else
|
177
|
-
# By default we read to the end of the file
|
178
|
-
line_section += "-L#{File.read(code['source']).lines.count}"
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
start_section + file_section + line_section
|
45
|
+
def run
|
46
|
+
@run ||= ::Nexmo::Markdown::Filters::CodeSnippet::Run.new(@config, @binding).render
|
183
47
|
end
|
184
48
|
end
|
185
|
-
|
186
49
|
end
|
187
50
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module Markdown
|
3
|
+
module Concerns
|
4
|
+
module PrismCodeSnippet
|
5
|
+
def code_snippet_body(lexer, body)
|
6
|
+
<<~HEREDOC
|
7
|
+
<pre class="#{prism_css_classes(lexer)}"><code>#{body}</code></pre>
|
8
|
+
HEREDOC
|
9
|
+
end
|
10
|
+
|
11
|
+
def code_language_to_prism(code_language)
|
12
|
+
code_language == 'objective_c' && 'objectivec' || code_language
|
13
|
+
end
|
14
|
+
|
15
|
+
def prism_css_classes(lexer)
|
16
|
+
code_language = code_language_to_prism(lexer.tag)
|
17
|
+
"main-code Vlt-prism--dark language-#{code_language} Vlt-prism--copy-disabled"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,16 +1,17 @@
|
|
1
1
|
module Nexmo
|
2
2
|
module Markdown
|
3
3
|
class MarkdownFilter < Banzai::Filter
|
4
|
+
|
4
5
|
def call(input)
|
5
6
|
markdown.render(input)
|
6
7
|
end
|
7
|
-
|
8
|
+
|
8
9
|
private
|
9
|
-
|
10
|
+
|
10
11
|
def renderer
|
11
12
|
@renderer ||= VoltaRender.new(options)
|
12
13
|
end
|
13
|
-
|
14
|
+
|
14
15
|
def markdown
|
15
16
|
@markdown ||= Redcarpet::Markdown.new(renderer, {
|
16
17
|
no_intra_emphasis: true,
|
@@ -27,17 +28,19 @@ module Nexmo
|
|
27
28
|
end
|
28
29
|
|
29
30
|
class VoltaRender < HTML
|
31
|
+
include Nexmo::Markdown::Concerns::PrismCodeSnippet
|
32
|
+
|
30
33
|
def initialize(options)
|
31
34
|
@options = options
|
32
35
|
super(options)
|
33
36
|
end
|
34
|
-
|
37
|
+
|
35
38
|
def paragraph(text)
|
36
39
|
return text if @options[:skip_paragraph_surround]
|
37
|
-
|
40
|
+
|
38
41
|
"<p>#{text}</p>"
|
39
42
|
end
|
40
|
-
|
43
|
+
|
41
44
|
def table(header, body)
|
42
45
|
'<div class="Vlt-table Vlt-table--bordered">' \
|
43
46
|
'<table>' \
|
@@ -46,7 +49,7 @@ module Nexmo
|
|
46
49
|
'</table>' \
|
47
50
|
'</div>'
|
48
51
|
end
|
49
|
-
|
52
|
+
|
50
53
|
def block_quote(quote)
|
51
54
|
'<div class="Vlt-callout Vlt-callout--tip">' \
|
52
55
|
'<i></i>' \
|
@@ -55,7 +58,7 @@ module Nexmo
|
|
55
58
|
'</div>' \
|
56
59
|
'</div>'
|
57
60
|
end
|
58
|
-
|
61
|
+
|
59
62
|
def image(link, _title, _alt_text)
|
60
63
|
'<figure>' \
|
61
64
|
'<img src="'\
|
@@ -63,7 +66,7 @@ module Nexmo
|
|
63
66
|
'" alt="#{alt_text}">' \
|
64
67
|
'</figure>'
|
65
68
|
end
|
66
|
-
|
69
|
+
|
67
70
|
def list(contents, list_type)
|
68
71
|
if "#{list_type}" == 'unordered'
|
69
72
|
'<ul class="Vlt-list Vlt-list--simple">' \
|
@@ -86,7 +89,7 @@ module Nexmo
|
|
86
89
|
code.gsub! /^ /, "\t"
|
87
90
|
end
|
88
91
|
|
89
|
-
formatter = ::Rouge::Formatters::HTMLLegacy.new(:css_class =>
|
92
|
+
formatter = ::Rouge::Formatters::HTMLLegacy.new(:css_class => prism_css_classes(lexer))
|
90
93
|
formatter.format(lexer.lex(code))
|
91
94
|
end
|
92
95
|
end
|
@@ -5,7 +5,7 @@ module Nexmo
|
|
5
5
|
input.gsub(/```partial(.+?)```/m) do |_s|
|
6
6
|
config = YAML.safe_load($1)
|
7
7
|
file_path = if config['source'].starts_with? 'app/views'
|
8
|
-
config['source']
|
8
|
+
"#{Rails.root}/#{config['source']}"
|
9
9
|
else
|
10
10
|
"#{Nexmo::Markdown::Config.docs_base_path}/#{config['source']}"
|
11
11
|
end
|
@@ -4,7 +4,7 @@ module Nexmo
|
|
4
4
|
def call(input)
|
5
5
|
input.gsub(/```screenshot(.+?)```/m) do |_s|
|
6
6
|
config = YAML.safe_load($1)
|
7
|
-
if config['image'] && File.file?(config['image'])
|
7
|
+
if config['image'] && File.file?("#{Nexmo::Markdown::Config.docs_base_path}/#{config['image']}")
|
8
8
|
"})"
|
9
9
|
else
|
10
10
|
<<~HEREDOC
|
@@ -1,16 +1,18 @@
|
|
1
1
|
module Nexmo
|
2
2
|
module Markdown
|
3
3
|
class TabFilter < Banzai::Filter
|
4
|
+
include Nexmo::Markdown::Concerns::PrismCodeSnippet
|
5
|
+
|
4
6
|
def call(input)
|
5
7
|
input.gsub(/^(\s*)```tabbed_(examples|content|folder)(.+?)```/m) do |_s|
|
6
8
|
@indentation = $1
|
7
9
|
@mode = $2
|
8
10
|
@config = YAML.safe_load($3)
|
9
|
-
|
11
|
+
|
10
12
|
if tabbed_folder?
|
11
|
-
raise "#{@config['source']} is not a directory" unless File.directory? "#{
|
12
|
-
|
13
|
-
@tabbed_config = YAML.safe_load(File.read("#{
|
13
|
+
raise "#{@config['source']} is not a directory" unless File.directory? "#{@config['source']}"
|
14
|
+
|
15
|
+
@tabbed_config = YAML.safe_load(File.read("#{@config['source']}/.config.yml"))
|
14
16
|
@path = @config['source']
|
15
17
|
validate_folder_config
|
16
18
|
else
|
@@ -19,28 +21,28 @@ module Nexmo
|
|
19
21
|
html
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
24
|
+
|
23
25
|
private
|
24
|
-
|
26
|
+
|
25
27
|
def create_tabs(content)
|
26
28
|
tab = Nokogiri::XML::Element.new 'div', @document
|
27
29
|
tab['class'] = 'Vlt-tabs__link'
|
28
30
|
tab['class'] += ' Vlt-tabs__link_active' if content[:active]
|
29
31
|
tab['role'] = 'tab'
|
30
|
-
|
32
|
+
|
31
33
|
if content[:language]
|
32
34
|
tab['data-language'] = content[:language].key
|
33
35
|
tab['data-language-type'] = content[:language].type
|
34
36
|
tab['data-language-linkable'] = content[:language].linkable?
|
35
37
|
end
|
36
|
-
|
38
|
+
|
37
39
|
if content[:platform]
|
38
40
|
tab['data-language'] = content[:platform].languages.map(&:key).join(',')
|
39
41
|
tab['data-platform'] = content[:platform].key
|
40
42
|
tab['data-platform-type'] = content[:platform].type
|
41
43
|
tab['data-platform-linkable'] = content[:platform].linkable?
|
42
44
|
end
|
43
|
-
|
45
|
+
|
44
46
|
tab_link = Nokogiri::XML::Element.new 'span', @document
|
45
47
|
if content[:language]
|
46
48
|
# We don't currently have icons for JSON/XML
|
@@ -48,6 +50,8 @@ module Nexmo
|
|
48
50
|
tab_link.content = content[:tab_title]
|
49
51
|
elsif content[:language].key == 'objective_c' || content[:language].key == 'swift'
|
50
52
|
tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/ios.svg#ios\" /></svg><span>" + content[:tab_title] + '</span>'
|
53
|
+
elsif content[:language].key == 'kotlin'
|
54
|
+
tab_link.inner_html = "<img class=\"Vlt-icon Vlt-icon--small\" src=\"/assets/images/brands/kotlin.svg#kotlin\" /><span>" + content[:tab_title] + '</span>'
|
51
55
|
else
|
52
56
|
tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/#{content[:language].key}.svg##{content[:language].key}\" /></svg><span>" + content[:tab_title] + '</span>'
|
53
57
|
end
|
@@ -56,37 +60,37 @@ module Nexmo
|
|
56
60
|
else
|
57
61
|
tab_link.content = content[:tab_title]
|
58
62
|
end
|
59
|
-
|
63
|
+
|
60
64
|
tab.add_child(tab_link)
|
61
65
|
@tabs.add_child(tab)
|
62
66
|
end
|
63
|
-
|
67
|
+
|
64
68
|
def create_content(content)
|
65
69
|
tabs_panel = Nokogiri::XML::Element.new 'div', @document
|
66
70
|
tabs_panel['class'] = 'Vlt-tabs__panel'
|
67
71
|
tabs_panel['class'] += ' Vlt-tabs__panel_active' if content[:active]
|
68
|
-
|
72
|
+
|
69
73
|
element = Nokogiri::XML::Element.new 'p', @document
|
70
74
|
element['aria-labelledby'] = "\"#{content[:id]}\""
|
71
75
|
element['aria-hidden'] = true
|
72
76
|
element.inner_html = content[:body]
|
73
|
-
|
77
|
+
|
74
78
|
tabs_panel.add_child(element)
|
75
79
|
@tabs_content.add_child(tabs_panel)
|
76
80
|
end
|
77
|
-
|
81
|
+
|
78
82
|
def tabbed_code_examples?
|
79
83
|
@mode == 'examples'
|
80
84
|
end
|
81
|
-
|
85
|
+
|
82
86
|
def tabbed_content?
|
83
87
|
@mode == 'content'
|
84
88
|
end
|
85
|
-
|
89
|
+
|
86
90
|
def tabbed_folder?
|
87
91
|
@mode == 'folder'
|
88
92
|
end
|
89
|
-
|
93
|
+
|
90
94
|
def html
|
91
95
|
html = <<~HEREDOC
|
92
96
|
<div class="Vlt-tabs">
|
@@ -95,97 +99,97 @@ module Nexmo
|
|
95
99
|
</div>
|
96
100
|
</div>
|
97
101
|
HEREDOC
|
98
|
-
|
102
|
+
|
99
103
|
@document = Nokogiri::HTML::DocumentFragment.parse(html)
|
100
104
|
@tabs = @document.at_css('.Vlt-tabs__header')
|
101
105
|
@tabs_content = @document.at_css('.Vlt-tabs__content')
|
102
|
-
|
106
|
+
|
103
107
|
contents.each do |content|
|
104
108
|
create_tabs(content)
|
105
109
|
create_content(content)
|
106
110
|
end
|
107
|
-
|
111
|
+
|
108
112
|
source = @document.to_html
|
109
|
-
|
113
|
+
|
110
114
|
"#{@indentation}FREEZESTART#{Base64.urlsafe_encode64(source)}FREEZEEND"
|
111
115
|
end
|
112
|
-
|
116
|
+
|
113
117
|
def contents
|
114
118
|
list = content_from_folder if tabbed_folder?
|
115
119
|
list ||= content_from_source if @config['source']
|
116
120
|
list ||= content_from_tabs if @config['tabs']
|
117
|
-
|
121
|
+
|
118
122
|
list ||= []
|
119
|
-
|
123
|
+
|
120
124
|
return list unless list.any?
|
121
|
-
|
125
|
+
|
122
126
|
list = resolve_language(list)
|
123
|
-
|
127
|
+
|
124
128
|
if tabbed_code_examples?
|
125
129
|
list = format_code(list)
|
126
130
|
list = resolve_code(list)
|
127
131
|
list = resolve_tab_title(list)
|
128
132
|
end
|
129
|
-
|
133
|
+
|
130
134
|
list = sort_contents(list)
|
131
135
|
resolve_active_tab(list)
|
132
|
-
|
136
|
+
|
133
137
|
list
|
134
138
|
end
|
135
|
-
|
139
|
+
|
136
140
|
def validate_config
|
137
141
|
return if @config && (@config['source'] || @config['tabs'])
|
138
|
-
|
142
|
+
|
139
143
|
raise 'Source or tabs must be present in this tabbed_example config'
|
140
144
|
end
|
141
|
-
|
145
|
+
|
142
146
|
def validate_folder_config
|
143
147
|
return if @tabbed_config && @tabbed_config['tabbed'] == true
|
144
|
-
|
148
|
+
|
145
149
|
raise 'Tabbed must be set to true in the folder config YAML file'
|
146
150
|
end
|
147
|
-
|
151
|
+
|
148
152
|
def content_from_source
|
149
153
|
source_path = "#{Nexmo::Markdown::Config.docs_base_path}/#{@config['source']}"
|
150
154
|
source_path += '/*' if tabbed_code_examples?
|
151
155
|
source_path += '/*.md' if tabbed_content?
|
152
|
-
|
156
|
+
|
153
157
|
files = Dir.glob(source_path)
|
154
158
|
raise "Empty content_from_source file list in #{source_path}" if files.empty?
|
155
|
-
|
159
|
+
|
156
160
|
files.map do |content_path|
|
157
161
|
raise "Could not find content_from_source file: #{content_path}" unless File.exist? content_path
|
158
|
-
|
162
|
+
|
159
163
|
source = File.read(content_path)
|
160
|
-
|
164
|
+
|
161
165
|
next generate_tabbed_code_examples(source, content_path) if tabbed_code_examples?
|
162
|
-
|
166
|
+
|
163
167
|
generate_tabbed_content(source) if tabbed_content?
|
164
168
|
end
|
165
169
|
end
|
166
|
-
|
170
|
+
|
167
171
|
def content_from_folder
|
168
|
-
source_path = "#{
|
172
|
+
source_path = "#{@config['source']}"
|
169
173
|
source_path += '/*.md'
|
170
|
-
|
174
|
+
|
171
175
|
files = Dir.glob(source_path)
|
172
176
|
raise "Empty content_from_source file list in #{source_path}" if files.empty?
|
173
|
-
|
177
|
+
|
174
178
|
files.map do |content_path|
|
175
179
|
raise "Could not find content_from_source file: #{content_path}" unless File.exist? content_path
|
176
|
-
|
180
|
+
|
177
181
|
source = File.read(content_path)
|
178
|
-
|
182
|
+
|
179
183
|
generate_tabbed_content(source)
|
180
184
|
end
|
181
185
|
end
|
182
|
-
|
186
|
+
|
183
187
|
def content_from_tabs
|
184
188
|
@config['tabs'].map do |title, config|
|
185
189
|
raise "Could not find content_from_tabs file: #{Nexmo::Markdown::Config.docs_base_path}/#{@config['source']}" unless File.exist? "#{Nexmo::Markdown::Config.docs_base_path}/#{@config['source']}"
|
186
|
-
|
190
|
+
|
187
191
|
source = File.read("#{Nexmo::Markdown::Config.docs_base_path}/#{@config['source']}")
|
188
|
-
|
192
|
+
|
189
193
|
config.symbolize_keys.merge({
|
190
194
|
id: SecureRandom.hex,
|
191
195
|
source: source,
|
@@ -193,22 +197,22 @@ module Nexmo
|
|
193
197
|
})
|
194
198
|
end
|
195
199
|
end
|
196
|
-
|
200
|
+
|
197
201
|
def generate_tabbed_content(source)
|
198
202
|
content = {
|
199
203
|
id: SecureRandom.hex,
|
200
204
|
source: source,
|
201
205
|
}
|
202
|
-
|
206
|
+
|
203
207
|
content[:frontmatter] = YAML.safe_load(source)
|
204
208
|
content[:language_key] = content[:frontmatter]['language']
|
205
209
|
content[:platform_key] = content[:frontmatter]['platform']
|
206
210
|
content[:tab_title] = content[:frontmatter]['title']
|
207
211
|
content[:body] = Nexmo::Markdown::Renderer.new(options).call(source)
|
208
|
-
|
212
|
+
|
209
213
|
content
|
210
214
|
end
|
211
|
-
|
215
|
+
|
212
216
|
def generate_tabbed_code_examples(source, content_path)
|
213
217
|
content = {
|
214
218
|
id: SecureRandom.hex,
|
@@ -216,24 +220,24 @@ module Nexmo
|
|
216
220
|
}
|
217
221
|
language_key = File.basename(content_path, '.*').downcase
|
218
222
|
content[:language_key] = language_key
|
219
|
-
|
223
|
+
|
220
224
|
content
|
221
225
|
end
|
222
|
-
|
226
|
+
|
223
227
|
def resolve_language(contents)
|
224
228
|
contents.map do |content|
|
225
229
|
if content[:language_key]
|
226
230
|
content[:language] = CodeLanguage.find(content[:language_key])
|
227
231
|
end
|
228
|
-
|
232
|
+
|
229
233
|
if content[:platform_key]
|
230
234
|
content[:platform] = CodeLanguage.find(content[:platform_key])
|
231
235
|
end
|
232
|
-
|
236
|
+
|
233
237
|
content
|
234
238
|
end
|
235
239
|
end
|
236
|
-
|
240
|
+
|
237
241
|
def format_code(contents)
|
238
242
|
contents.each do |content|
|
239
243
|
if content[:from_line] || content[:to_line]
|
@@ -243,43 +247,42 @@ module Nexmo
|
|
243
247
|
to_line = (content[:to_line] || total_lines) - 1
|
244
248
|
content[:source] = lines[from_line..to_line].join
|
245
249
|
end
|
246
|
-
|
250
|
+
|
247
251
|
content[:source].unindent! if content[:unindent]
|
248
252
|
end
|
249
253
|
end
|
250
|
-
|
254
|
+
|
251
255
|
def resolve_code(contents)
|
252
256
|
contents.map do |content|
|
253
257
|
@formatter ||= Rouge::Formatters::HTML.new
|
254
258
|
lexer = content[:language].lexer
|
255
259
|
highlighted_source = @formatter.format(lexer.lex(content[:source]))
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
+
|
261
|
+
body = code_snippet_body(lexer, highlighted_source)
|
262
|
+
|
260
263
|
content.merge!({ body: body })
|
261
264
|
end
|
262
265
|
end
|
263
|
-
|
266
|
+
|
264
267
|
def resolve_tab_title(contents)
|
265
268
|
contents.map do |content|
|
266
269
|
content.merge!({ tab_title: content[:language].label })
|
267
270
|
end
|
268
271
|
end
|
269
|
-
|
272
|
+
|
270
273
|
def sort_contents(contents)
|
271
274
|
contents.sort_by do |content|
|
272
275
|
next content[:language].weight if content[:language]
|
273
|
-
|
276
|
+
|
274
277
|
next content[:frontmatter]['menu_weight'] || 999 if content[:frontmatter]
|
275
|
-
|
278
|
+
|
276
279
|
999
|
277
280
|
end
|
278
281
|
end
|
279
|
-
|
282
|
+
|
280
283
|
def resolve_active_tab(contents)
|
281
284
|
active_index = nil
|
282
|
-
|
285
|
+
|
283
286
|
if options[:code_language]
|
284
287
|
contents.each_with_index do |content, index|
|
285
288
|
%i[language_key platform_key].each do |key|
|
@@ -287,10 +290,10 @@ module Nexmo
|
|
287
290
|
end
|
288
291
|
end
|
289
292
|
end
|
290
|
-
|
293
|
+
|
291
294
|
@tabs['data-has-initial-tab'] = active_index.present?
|
292
295
|
active_index ||= 0
|
293
|
-
|
296
|
+
|
294
297
|
contents[active_index][:active] = true
|
295
298
|
end
|
296
299
|
end
|